views:

866

answers:

8

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  A: 

Check out StackAnalyzer.

RegDwight
Nice suggestion, of course I forgot to add "preferably free" in the question. It seems they don't list ARM/gcc as a supported combination, but then again, an elf file is an elf file, so I'll contact them and see if it should work.
Ron
They do claim support for ARM elf. I'm pretty sure that GCC and ARM's own compiler use the same ABI, so it seems likely to work. The other concern might be support for thumb mode, since the Cortex family effectively only has thumb mode enabled.
RBerteig
Support let me know GCC is not supported but can be included for an extra fee. Not up to me to give you figures but it's faaaar from free.
Ron
+1  A: 

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

Mike Dunlavey
+2  A: 

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.

RBerteig
+2  A: 

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.

Hexagon
+1  A: 

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.

Gerhard
A: 

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

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.

Craig McQueen
A: 

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.

Michael Burr
A: 

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.

none