代码分析
1 Call graph
1.1 静态
1.1.1 Doxygen + Graphviz + Htmlhelp (windows)
使用 Doxygen + Graphviz + Htmlhelp,Doxygen 配置,再加上下面两图,不要选生成 Chinese,否则 chm 文件乱码
生成前将不用的第三方库代码移走
Doxygen error: failed to run html help compiler on index.hhp
报错似乎不影响
1.1.2 SciTools Understand (windows)
C/C++ 项目参考, Buildspy - For gcc/g++ Users
1 | # 使用 cygwin 的 /x86_64-w64-mingw32-gcc.exe 编译 openssl |
- 对于 openssl,一处非常奇怪的宏定义字符串导致编译不过问题,原 Makefile 是 -DOPENSSLDIR=”"$(OPENSSLDIR)",使用 gcc 编译没问题,但使用 gccwrapper 就要改成 -DOPENSSLDIR=’ “$(OPENSSLDIR)”‘,注意单引号与双引号间的空格不能省略。在同一行有 3 处都要改。宏定义问题可以通过 gcc 加 -v 参数来调试
1.1.3 SciTools Understand (linux)
1 | # 以 openssl 为例 |
1.1.4 Sourcetrail
用 compilation databases 新建项目
- linux 下用 bear 生成
- 全平台使用 cmake 生成,
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
参考这两个
https://aul12.me/embedded/2019/05/27/cubemx-cmake.html
https://clang.llvm.org/docs/JSONCompilationDatabase.html
- stm32 工程使用 cmake,从而生成 compilation databases
- 使用 stm32 官方 ide
1.2 动态
1.2.1 KcacheGrind (linux)
tools-to-get-a-pictorial-function-call-graph-of-code
1 | sudo apt install kcachegrind valgrind |
- 可以查看最大开销的调用栈 settings -> sidebars -> call stack ,实际的调用栈猜测是有多条的,还是 gdb 断点看吧
- call graph 右键设置好 caller 和 callee depth 后(设小点,防止之后产生的图太大),右键 node cost 可以设置为 no minimum,就可以看到所有的 callee 和 caller 了
- 要看某函数调的所有函数,除了上面改 cost 的方法,还可以看下面第一栏的 Callees
- 生成整张调用图(很大)的另一个工具
- 右键可以导出成 DOT、png、jpg 文件
1.2.2 gcc instrumental (linux)
看 etrace 部分的回答 、instrumental,这两个程序使用查找 elf 程序中符号“地址”与“名称“ map 的方式生成调用关系,通过调试 instrument 附带的 C 代码发现,linux 上 __cyg_profile_func_enter 传入的函数指针地址与符号表中的不同,可能的原因 (这篇文章是通过符号名查地址)
所以基于 instrumental 的代码改进,使用 dladdr 接口获得地址对应的符号名,除了
-finstrument-functions
,还要加-O0 -rdynamic -ldl
,不用加-g
类似的还有 backtrace_symbols
代码见 instrumental 文件夹,目前还不支持多线程,没有锁和分线程统计
1
2
3
4
5
6
7gcc -shared -fPIC -Wall inst.c -o inst.so -ldl
gcc -rdynamic -finstrument-functions -O0 -o code code.c
LD_PRELOAD=/home/inst.so ./code
# 以 openssl 为例,openssl 因为有 static 函数,所以效果不太好
export CC="gcc -rdynamic -finstrument-functions -O0 "
./configTODO 想支持多线程,把 openssl 的图画出来,把 static 函数批量替换会怎样?可参考 github 上 ftracer
1.3 手绘
- xmind 的逻辑图,比起 mindmaster 没有节点数目的限制,可以一个文件创建多个画布,免费导出 svg
2 内存占用
valgrind-3.16.1 交叉编译,参考
- Supported Platforms,对 kernel 和 glibc 的版本有要求
- –prefix 的路径要和最终运行的路径一致
- 修改 configure
armv7*)
改为armv7*|arm*)
- ./configure –prefix=/data/update/valgrind –host=arm-linux-gnueabi , make, make install
- 精简 lib/valgrind 目录下文件
rm callgrind-arm-linux helgrind-arm-linux cachegrind-arm-linux dhat-arm-linux drd-arm-linux lackey-arm-linux exp-bbv-arm-linux
,减少占用 - 要统计的程序使用 -g 编译,-O 优化等级不重要,不会影响堆内存统计
- 获得最大栈深,根据手册所说栈采样会慢 /data/update/valgrind/bin/valgrind –tool=massif –heap=no –stacks=yes ./sdk 。但这样无法得到最大栈深的调用栈,将线程的栈故意比最大栈深小一些,使用 gdb 调试,得到触发 stackoverflow 的地方。实测,用 ulimit -s 调用栈打不出来
栈统计的几种方法
Properly allocating stacks,这篇文章一共 3 部分、Computing your stack size ,google ”find max stack depth by stack overflow“ 可以看到 keil 和 IAR 的文章,linux 平台上能想到的办法是改 massif 的源码来记录 detailed snapshot
3 调试
3.1 gdb
https://www.linux.com/news/remote-cross-target-debugging-gdb-and-gdbserver/
https://sourceware.org/gdb/wiki/BuildingCrossGDBandGDBserver,包含 host、target 解释
1 | # 记得装这个 |
3.1.1 gdbserver
- 传入环境变量方法
- sudo gdbserver –wrapper env ‘LD_LIBRARY_PATH=/lib/libpcap/lib’ – :1234 ./tiny
3.1.2 修改
为了编译通过做得修改,ubuntu 18.04 环境。基于 master 分支 ee6d95574b 2019-09-04 (HEAD -> master, origin/master, origin/HEAD) Automatic date update in version.in
1 | # 拷贝到源码目录,使用 patch |
3.1.3 调试
1 | gdbserver <host-ip>:2345 tinyeye |