Call tree for embedded software [closed]

2020-07-06 02:15发布

问题:

Does anyone know some tools to create a call tree for C application that will run on a microcontroller (Cortex-M3)? It could be generated from source code (not ideal), object code (prefered solution), or at runtime (acceptable). I've looked at gprof, but there's still a lot missing to get it to work on an embedded system.

An added bonus would be that the tool also gives the maximum stack depth.

Update: solution is preferably free.

回答1:

One good way to achieve this is by using the --callgraph option to the ARM linker (armlink) that is part of RVCT (not free).

For more details - callgraph documentation.

I realize from one of the comments that you are looking for a gcc-based solution, which this isn't. But it may still be helpful.



回答2:

From source code, you can use Doxygen and GraphViz even if you don't already use Doxygen to document your code. It is possible to configure it so that it will include all functions and methods whether or not they have documentation comments. With AT&T Graphviz installed, Doxygen will include call and caller graphs for most functions and methods.

From object code, I don't have a ready answer. I would imagine that this would be highly target dependent since even with the debug information present, it would have to parse the object code to find calls and other stack users. In the worst case, that approach seems like it would require effectively simulating the target.

At runtime on the target hardware your choices are going to depend in part on what kind of embedded OS is present, and how it manages stacks for each thread.

A common approach is to initialize each stack to a known value that seems unlikely to be commonly stored in automatic variables. An interrupt handler or a thread can then inspect the stack(s) and measure an approximate high water mark.

Even without pre-filling the stack and later walking it to look for footprints, an interrupt could just sample the current value of the stack pointer (for each thread) and keep a record of its greatest observed extent. That would require storage for a copy of each threads SP, and the interrupt handler wouldn't have very much work to do to maintain the information. It would have to access the saved states of all the active threads, of course.

I don't know of a tool that does this explicitly.

If you happen to be using µC/OS-II from Micrium as your OS, you might take a look at their µC/Probe product. I haven't used it myself, but it claims to allow a connected PC to observe program and OS state information in near real time. I wouldn't be surprised if it is adaptable to another RTOS if needed.



回答3:

Call graphs from source code is no problem as mentioned above your compiler or doxygen can generate this information from source code. Most modern compilers can generate can generate a call graph as part of the compile process.

On a previous embedded projects I filled that stack with a pattern and ran a task. Check up to which point the stack destroyed my pattern. Reload stack with pattern and run the next task. This makes your code very ssslloowww .... but is free. It is not fully accurate because all the data is timing out the whole time and the code spends lots of time in error handlers.

On some processors you can get a trace pod so that you can monitor code cover and what not if your processor needs runs at full speed to tested and you can also not allow instrumented code. Unfortunately these types of tools are very expensive. Look at Green Hills Time machine if you have money. This make all types of debugging easier.



回答4:

I haven't used these, but are you aware of:

  • calltree
  • cflow

Since they analyse the source code, they don't calculate stack depth.

Note, Doxygen can do "call graphs" and "caller graphs" but I believe these are per-function and only show the tree up to a certain number of "hops" from each function.

Stack depth and/or call tree generation may be supported by compiler tools. For example, for Renesas micros there is a utility called Call Walker.



回答5:

My calltree graph generator, implemented in bash, using cscope and dot.

Can generate graphs of upstream callers, downstream callees, and call-associations between functions. You can set it up to view graphs in a number of ways, including xfig, .png viewers, and the dynamic dot visualiztion tool "zgrviewer".

http://toolchainguru.blogspot.com/2011/03/c-calltrees-in-bash-revisited.html



回答6:

Check out StackAnalyzer.



回答7:

Just a thought. Is it possible to run it in a virtual machine (like Valgrind) and take stack samples ?



回答8:

Eclipse with CDT has C/C++ indexing and will show you a call graphs. As far as I know, you don't need to be able to build in Eclipse to get the indexer to work, just make sure all your source files are in the project.

It works pretty nicely.

Visual Studio will do similar (but it's not free). I use Visual Studio to work on embedded projects; using a makefile project I can do all the work except debugging in the VS IDE.



回答9:

I have suggested this approach already in another discussion about embedded development, but if you really need a callgraph, as well as stack use info, and all this for free, I would personally consider using an open source emulator to simulate the whole thing, while instrumenting the object code by adding a handful hooks to the emulator itself to get this data.

I am not familiar with this particular target, but there is a whole number of open source ARM emulators available (freshmeat, sourceforge, google), and you are probably mostly interested in opcodes related to call/ret and push/pop? For example check out skyeye.

So, even if you find that it's not straightforward to extend a compiler or an emulator to provide this information, it should still be possible to create a simple script in order to look for the entrypoint and all calls/rets, as well as opcodes related to stack usage.

Of course, the only reliable information on stack usage is going to come from runtime instrumentation, preferably exercising all important code paths.



回答10:

A pretty light tool: Egypt



回答11:

Use Understand: http://www.scitools.com/

It's not free, and runs on source (not runtime), but it works, it works well, and it's well supported.

It will tell you much more than could ever want to know about your code.



回答12:

I know this is reponding to a very old question, but someone might stumble upon this with the same question...

I recently experimented with a Python script that analyses the assembler version of the application, extracts the stack usage and the call tree, and reports the maximum stack use. In my build system I then use this to create a stack of exactly that size.

I used it only on small applications, but it seems to work OK for AVR8, MSP430, and Cortex-M3. Obviously, there are strict limitations: no indirect calls (no function pointers, no virtual functions), no recursion, and stack-using assembler instruction patterns that are used are limited to what I found in GCC's output. If these limitations are not met, the script will report an error.

The Python source is 24k, free (boost license), not very fast, and still under development. Contact me if you are interested.