Building Complete Call Graphs with Phoenix
Windows Research Kernel @ HPIIn my last post, I told you that we use Phoenix for building the WRK, which allows us to apply Phoenix' comprehensive set of analysis capabilities to the WRK. One particular analysis might be the construction of complete call graphs for functions interest.
Unfortunately, the build process of the WRK compiles each module separately and links it into a static library. As a final step, all static libraries will be linked together with pre-compiled libraries to the ntoskrnl.exe executable image. So building complete call graphs may be a problem, especially when a function calls or is called by a function within another module as Phoenix is only aware of functions within the compiled module.
But fortunately, Phoenix provides a solution to this problem!
Phoenix supports link-time code generation (LTCG), which is originally intended for whole program analysis. When using LTCG, Phoenix does not compile modules separately into COFF object files. It rather stores the intermediate language representation of that module in the object file or static library, respectively. Then, at link time, Phoenix is invoked again to compile all the modules at the same time, which allows global optimization or, in our case, enables us to provide a Phoenix Phase plug-in to construct a complete call graph of a function.
In order to enable LTCG with the WRK, you have to modify the
provided makefiles a little bit. You must ensure that the compiler
does not generate object code. This is done by the GL
switch. As this is a target independent feature, add the
/GL
switch to the copts
variable in file
makefile.build, which is in directory
base/ntos/BUILD. Next, we must notify lib.exe that it has to link
itermediate language files into static libraries. For the record,
lib.exe determines that on its own, but declaring that fact
explicitly may reduce link time. So add the /LTCG
switch to the LIBFLAGS
variable of the same makefile
(base/ntos/BUILD/makefile.build).
Next, we need to inform the linker that it has to invoke Phoenix
before linking the static libraries together. This is done again by
the /LTCG
switch. So edit the makefile
(not makefile.build!) in directory
ntos/base/BUILD. I suggest here to modify the
LINKFLAGS
variable to contain the switch.
Finally, we need to inform Phoenix about what plug-in should be
used. I recommend using the phx
environment variable,
which Phoenix will evaluate for command line options. As we want
Phoenix to invoke the plug-in only at the link step and not for each
module, we suggest to set the variable only for the linker. Modify
therefore the kernelexe
rule in
build/ntos/BUILD/makefile. Below is a sample of our
modification:
kernelexe: @set phx=-plugin:path\to\plugin\plugin.dll <More Options> $(LINK) $(LINKFLAGS) $(ntoslinkopts) -out:$(fullkernel).exe -map:$(fullkernel).map -pdb:$(fullkernel).pdb -entry:$(entrypoint) \ $(hotpatch) PREBUILT\$(targ)\ntoskrnl.res $(OBJ)\ntkrnlmp.obj $(OBJ)\*.lib $(ntoswrklib) hal.lib $(fullkernel).exp $(bootlibs) $(LINKEDIT) -section:.rsrc,!d $(fullkernel).exe
The first line of this rule sets the environment variable
phx
. The -plugin
option allows to specify
the DLL that contains your Phoenix plug-in. You may or may not
specify other options as well.
I wrote a plug-in which generates a call graph in the dot format for each function being
compiled. The call graph contains both callers and callees of the
compiled function. To enhance readability, I limited the depth of
the graph to 4 levels for callers and callees. Potentially, you may
construct a complete call graph, but my experience shows, that this
generates graphs that are too complex to handle for dot. But you may
experiment about that on your own 😉 . Click on this
link to see the call graph that was generated for the
MiReplaceWorkingSetEntry
function. This function will
become important in one of my next posts. So keep watching …
Comments
3 Responses to "Building Complete Call Graphs with Phoenix"
Nice post, useful information. When compiling the WRK with Phenix on LTCG mode, did you get lots of alignment-related warnings in the linking stage? For example:
C:\Source\WRK-v1.2\base\ntos\mm\mmfault.c : warning C4742: '_MmAvailablePages' has different alignment in 'C:\Source\WRK-v1.2\base\ntos\mm\mmfault.c' and 'C:\Source\WRK-v1.2\base\ntos\mm\miglobal.c': 4 and 64
If yes, did you do anything to solve it or did you just ignore it?
Thanks!
Hi Martim,
I just ignore the C4742 warning right now, as I don't care if the WRK does boot or not. So I just disabled the warning for the compiler.
At the current release, I don't think Phoenix is capable of compiling the WRK as it is shipped without any modifications in such a way that it boots on a target machine. If you made it, just let me know what is necessary to fix it …
I too would like to know the fix. Disabling the warning gets rid of the message but I'd prefer not to have any warnings in the first place. Less buggy code means less trouble down the road.