1. 编译环境1.1 工程结构src/ ├── mkenv_arm_st # 设置 ARM 交叉编译环境变量 ├── mk_define # 编译入口脚本 ├── include.mk # 公共编译配置编译器、编译选项、链接库 ├── Makefile # 顶层 Makefile ├── publib/ # 公共库 libpub.so │ └── Makefile ├── moduals/ │ ├── samplers/ # 采样器模块 │ ├── reporters/ # 上报模块 │ └── data_processor/ # 数据处理层 └── include/ └── base_defines/ # 基础类型、宏定义1.2 编译指令cd src dos2unix mk_define mkenv_arm_st # 转换换行符 source mkenv_arm_st # 加载 ARM 交叉编译环境 mkc # make clean mkd # make debug-g -ggdb 带符号表 mkr # make release-DNDEBUG strip去掉符号表 inst # make install 打包部署1.3 debug vs release 对比debug (mkd)release (mkr)CFLAGS-g -ggdb -rdynamic -D_DEBUG1-DNDEBUGLDFLAGS-Wl,-Map,$.map-Wl,-Map,map-file -s符号表有可 gdb 调试strip 掉体积小TRACE 宏printf输出调试信息编译优化掉不输出assert生效不生效1.4 产物路径src/../out/ # 编译产物 src/../pkg/ # 打包发布包 src/make_arm_debug.log # 编译日志2. 目标设备概览2.1 基本信息uname -r # 内核版本: 4.19.94-g269544b3b-dirty gdb --version # 已有 GDB 7.5 (arm-linux-gnueabihf) # BusyBox 环境没有 ldd/readelf/paste 等工具2.2 进程清单ps # 内核线程: kthreadd, ksoftirqd, kswapd0, watchdogd, kworker/*, rcu_* 等 # 系统服务: init, udevd, dbus-daemon, sshd, syslogd, crond, xinetd # 应用进程: # /app/bin/app_update - GUI 更新/升级程序也是进程守护者 # /app/bin/nccu_app - 充电桩主控程序需 debug 版 # web_server_main - Web 后端服务2.3 启动流程开机 ↓ app_update 启动Qt GUI ↓ 检查升级状态 ↓ 无升级/升级完成 ↓ 启动 system_hand共享内存 信号量初始化 ↓ system_hand 初始化完毕后 touch /var/volatile/syshand.run ↓ 启动 nccu_app检查 syshand.run 存在才继续 ↓ nccu_app 正常初始化加载配置、采样器、上报模块app_update还负责守护nccu_app挂了会自动重启。2.4 syshand.run 的作用main.c启动检查while (access(/var/volatile/syshand.run, R_OK) ! 0) { Sleep_Ex(100); nMaxWait; if (nMaxWait 10) // 超过 1 秒退出 { LogOut(..., Initialize FAILED as sys_hand NOT OK (maybe in upgrade).....); return 0; } }system_hand初始化共享内存后touch /var/volatile/syshand.run表示就绪。GDB 调试时可以临时绕过touch /var/volatile/syshand.run2.5 共享内存IPCsystem_hand创建一块共享内存 两个信号量/_semSysHandWait、/_semSysHandAnsw。nccu_app通过它心跳Do_Proc_HeartBeat()定期通知system_hand“我还活着”系统命令_SYSTEM()发重启、升级等指令不启动system_hand直接touch绕过的话这几个调用会报错但不影响主流程运行。3. 日志系统3.1 TRACE / TRACEX 宏include/base_defines/basetypes.h// debug 版-D_DEBUG1 #define TRACE printf #define TRACEX printf([%s--%s:%d] [%d]-- , __FILE__, __FUNCTION__, __LINE__, time(NULL)), printf // release 版 #define TRACE 1 ? (void)0 : (void)printf // 编译优化掉 #define TRACEX 1 ? (void)0 : (void)printf输出到stdout不落盘。如果是后台守护进程启动的stdout 被丢弃。3.2 LogOut 日志LogOut()写 SQLite 数据库nccu.data的Data_AppLog表不写文本文件。3.3 编译日志mk_define编译输出记录在src/make_arm_debug.log。3.4 运行时保存日志# 重定向到文件 nohup /app/bin/nccu_app /tmp/nccu.log 21 tail -f /tmp/nccu.log # 或 gdb 内保存 (gdb) set logging file /tmp/nccu_gdb.log (gdb) set logging on (gdb) r4. GDB 调试4.1 基础步骤# 先停掉所有相关进程 killall app_update nccu_app web_server_main # 绕过 syshand 检查 touch /var/volatile/syshand.run # 设好动态库路径 export LD_LIBRARY_PATH/app/bin:/app/bin/reporter:/app/bin/sampler # 启动 GDB cd /app gdb bin/nccu_app4.2 常用命令(gdb) break Intern_Set # 设断点 (gdb) break SetDateTime (gdb) break DAI_Set (gdb) r # 运行 (gdb) bt # 看调用栈 (gdb) p varV # 打印变量 (gdb) p *pSetData # 打印结构体 (gdb) n # 单步不进入函数 (gdb) s # 单步进入函数 (gdb) c # 继续 (gdb) info args # 当前函数参数 (gdb) info locals # 当前局部变量 (gdb) info b # 列出断点 (gdb) disable 1 # 禁用断点 1 (gdb) delete 1 # 删除断点 1 (gdb) q # 退出 (gdb) cd /app # 切换工作目录配置路径问题 (gdb) set environment LD_LIBRARY_PATH ...4.3 实战完整调试会话排错记录以下是在目标设备上实际操作中遇到的所有问题及解决过程。问题 1nccu_app: No such file or directoryrootimmu2:~# gdb nccu_app nccu_app: No such file or directory.现象GDB 在当前目录找不到可执行文件。原因nccu_app在/app/bin/下当前目录是/root。解决用绝对路径或用find先定位find / -name nccu_app 2/dev/null # /app/bin/nccu_app gdb /app/bin/nccu_app问题 2error while loading shared libraries: libdpr.so(gdb) r Starting program: /app/bin/nccu_app /app/bin/nccu_app: error while loading shared libraries: libdpr.so: cannot open shared object file: No such file or directory [Inferior 1 (process 865) exited with code 0177]现象动态库找不到。原因嵌入式系统默认库搜索路径只有/lib、/usr/libreporter/sampler 等模块的.so在/app/bin/子目录中。正常启动由app_update拉起时已经设好了环境变量gdb 直接run则没有。排查过程# 确认 .so 在哪里 find /app -name *.so* -type f 2/dev/null # 确认二进制里有没有硬编码 rpath设备上没有 readelf需在编译服务器上查 # arm-linux-gnueabihf-readelf -d nccu_app | grep -E RPATH|RUNPATH # 确认 init 脚本有没有设环境变量 grep -l nccu_app /etc/init.d/* /etc/rc*.d/* 2/dev/null grep nccu_app /etc/profile /etc/rc.local 2/dev/null解决# 方法 1shell 环境设好后启动 gdb export LD_LIBRARY_PATH$(find /app -name *.so* -type f -exec dirname {} \; 2/dev/null | sort -u | tr \n : | sed s/:$//) gdb /app/bin/nccu_app # 方法 2gdb 内设置 (gdb) set environment LD_LIBRARY_PATH /app/bin:/app/bin/reporter:/app/bin/sampler:... (gdb) r注意BusyBox 没有paste命令用tr \n :替代。问题 3Initialize FAILED as sys_hand NOT OK(gdb) r ... [Log 9660]: MAIN Main [3064590336] ***Initialize FAILED as sys_hand NOT OK (maybe in upgrade)..... [Inferior 1 (process 1110) exited normally]现象程序打印sys_hand NOT OK后直接退出没有断点也停了。原因main.c启动时检查/var/volatile/syshand.run是否存在不存在则 1 秒超时退出while (access(/var/volatile/syshand.run, R_OK) ! 0) { Sleep_Ex(100); nMaxWait; if (nMaxWait 10) // 1 秒超时 { LogOut(..., ***Initialize FAILED as sys_hand NOT OK (maybe in upgrade).....); return 0; // 直接退出 } }排查# 看看是否有升级标志 ls /tmp/*upgrade* /var/*upgrade* 2/dev/null find /app -name *.lock -o -name *.flag 2/dev/null解决正常流程由app_update拉起system_hand后者初始化共享内存后touch /var/volatile/syshand.run。调试时可手动创建绕过touch /var/volatile/syshand.run风险system_hand没跑后续心跳和系统命令的 IPC共享内存 信号量调用会报错但printf打个错误信息就算了不会崩。问题 4Thd CfgDB [./config/System.cfg] can NOT be opened(gdb) r ... Now Set Exit jmp! Now Init ThreadManager.Now Load Moduals. Can not create cfg database, so exit system! ------The Log_A Content[DPR InitLoader [3064590336] Thd CfgDB [./config/System.cfg] can NOT be opened, please check!] [Inferior 1 (process 1123) exited with code 0377]现象绕过了 syshand.run但卡在配置文件找不到。原因配置路径用了相对路径./config/System.cfggdb 在/root启动/root/config/不存在。解决切换到/app目录后再 gdbcd /app gdb bin/nccu_app (gdb) r # 或者已在 gdb 中用 (gdb) cd /app; (gdb) r问题 5gdb 退出后 nccu_app 还在跑(gdb) q # 退出 gdb rootimmu2:~# ps | grep nccu_app 5246 root 1728 S grep nccu_app # 不对有 nccu_app 在跑现象gdb 退出后ps还能看到nccu_app进程终端还在刷打印。原因app_updatePID 609是应用守护进程检测到nccu_app退出后自动重新拉起ps | grep app_update # 609 root 32424 S /app/bin/app_update -qws -nokeyboard -nomousegdb 里run的进程退出 →app_update以为它挂了 → 自动重启 → 新进程输出刷到你终端上。排查技巧如果ps看不到nccu_app但终端仍在刷打印检查是否web_server_main在跑——Web 模块里的TRACEX输出可能被误以为是nccu_app的ps | grep web_server_main # 1223 root 4424 S web_server_main -f /app/web/server/server_main.conf ...解决gdb 调试前先干掉守护者killall app_update nccu_app web_server_main问题 6Undefined command: gdb(gdb) gdb nccu_app Undefined command: gdb. Try help.现象在 gdb 提示符下又打了gdb。原因已经在 gdb 里面了。(gdb)就是 gdb 的命令提示符。解决q退出 gdb 回到 shell再gdb /app/bin/nccu_app。问题 7数据库表和 libz CRC 警告warning: File /lib/libthread_db.so.1 auto-loading has been declined... warning: Unable to find libthread_db matching inferiors thread library... warning: the debug information found in /usr/lib/libz.so.1.2.7 does not match... ---Execute sql[replace into Data_AppLog values (?,?,?,?);], errCode 21, errMsg [no such table: Data_AppLog]---现象三道警告/报错。原因libthread_dbGDB 的线程调试安全策略限制auto-load safe-path不影响调试libz.so设备上的 zlib 版本与编译时链接的不完全匹配但二进制兼容Data_AppLogSQLite 数据库是新创建的或者是旧版本数据库表结构还没初始化解决都可忽略。前两个只是警告不影响功能数据库表会在后续Init_CreadDataDB()中自动创建。问题 8ps没看到 nccu_app 但打印还在输出rootimmu2:~# ps | grep nccu_app 5246 root 1728 S grep nccu_app # 没有 nccu_app # 但终端还是在疯狂刷打印现象nccu_app进程不存在仍有TRACEX输出。原因打印来自web_server_main它加载了 Web 后端的.so。rundata_exchange.c等文件中的TRACEX宏输出到启动了该进程的终端。解决停掉或重启 Web 服务killall web_server_main或者用 maskprint 屏蔽特定文件的打印见第 6 章。问题 9SIGTTOU/SIGPIPE信号频繁打断 gdb(gdb) r Program received signal SIGTTOU, Stopped (tty output). 0xb6feaaf4 in _dl_debug_state () from /lib/ld-linux-armhf.so.3现象gdb 被SIGTTOU终端输出或SIGPIPE断开的管道打断无法继续。原因SIGTTOU程序尝试写 stdout/stderrgdb 默认会拦截这个信号SIGPIPE网络连接中断CCU/后台断开socket 写入触发解决启动 gdb 时预先忽略这两个信号gdb -ex handle SIGTTOU nostop noprint pass \ -ex handle SIGPIPE nostop noprint pass \ /app/bin/nccu_app每个参数的含义nostop—— 不要停止程序noprint—— 不要打印消息pass—— 把信号传给程序处理如果程序中间已经触发gdb 内补救(gdb) handle SIGTTOU nostop noprint pass (gdb) handle SIGPIPE nostop noprint pass (gdb) c问题 10xterm-256color终端乱码(gdb) xterm-256colorxterm-256colorxterm-256color... Undefined command: term-256colorxterm-256color......现象$TERM环境变量的值反复出现在 gdb 提示符中。原因程序刷屏输出与 gdb 共享同一个终端当 SIGTTOU 触发暂停时缓冲区中的残数据被冲入终端gdb 把$TERM的值当成命令解析。解决提前忽略SIGTTOU见问题 9或用exec-wrapper重定向输出见问题 12。问题 11set logging redirect on不屏蔽程序 stdout(gdb) set logging file /tmp/nccu_gdb.log (gdb) set logging on (gdb) set logging redirect on (gdb) r # 终端依然在刷打印!!! ← 为什么没生效现象gdb 日志重定向后终端依然输出程序的日志。原因GDB 7.5 的set logging redirect只重定向 gdb自身的输出bt/p/info不拦截被调试程序的 stdout。这是 GDB 旧版本的限制。解决用exec-wrapper见问题 12或gdb attach方式。问题 12用 exec-wrapper 彻底消停刷屏# 创建包装脚本把程序输出重定向到文件 cat /tmp/wrap.sh EOF #!/bin/sh exec /app/bin/nccu_app $ /tmp/nccu_run.log 21 EOF chmod x /tmp/wrap.sh # 启动 gdb 时指定 exec-wrapper gdb -ex handle SIGTTOU nostop noprint pass \ -ex handle SIGPIPE nostop noprint pass \ -ex set exec-wrapper /tmp/wrap.sh \ -ex set pagination off \ /app/bin/nccu_app (gdb) r原理gdb 不再直接执行nccu_app而是通过/tmp/wrap.sh启动脚本内把 stdout/stderr 重定向到/tmp/nccu_run.log。查看日志另一个终端里tail -f /tmp/nccu_run.log。注意exec-wrapper 会吞掉退出信息。程序异常退出时看日志确认原因tail -50 /tmp/nccu_run.log问题 13kill app_update 后 CCU Sampler 初始化失败(gdb) r ... Fails on initializing the Sampler -- [CCU_Tcp], please check! Thread [CCU_Tcp] is stopped, system will reboot now... Failed to load samplers! Failed to load moduals, now exit! [Inferior 1 (process 967) exited with code 0377]现象gdb 的run启动后 CCU TCP Sampler 无法初始化程序直接退出。原因app_update被杀后依赖它的 CCU 设备连接不上模块加载器判定采样器初始化失败 → 退出。解决改用gdb attach方式让app_update正常拉起进程后挂上去# 1. 确保 app_update 在跑 killall nccu_app touch /var/volatile/syshand.run /app/bin/app_update -qws -nokeyboard -nomouse # 2. 等待 nccu_app 被拉起 sleep 5 ps | grep nccu_app # 3. attach 挂上去调试 gdb -ex handle SIGTTOU nostop noprint pass \ -ex handle SIGPIPE nostop noprint pass \ -p $(pidof nccu_app) (gdb) break Intern_Set (gdb) crunvsattach对比方式适用场景gdb /app/bin/nccu_appr纯逻辑调试不依赖硬件/外部模块gdb -p $(pidof nccu_app)CCU/硬件/外部服务已正常运行时调试问题 14LD_LIBRARY_PATH遗漏系统库路径/app/bin/app_update: error while loading shared libraries: libts.so.0: cannot open shared object file: No such file or directory # 补上 /usr/lib/tslib/lib/ 后 /app/bin/app_update: error while loading shared libraries: /usr/bin/libcrypto.so.1.1: file too short现象补了库路径后反而报出更奇怪的错误。原因libts.so在/usr/lib/tslib/lib/不在/app下之前的find只搜了/app把find改成搜/usr后/usr/bin/libcrypto.so.1.1一个损坏的短文件污染了路径解决精确指定范围只搜库目录export LD_LIBRARY_PATH$(find /app /usr/lib -name *.so* -type f 2/dev/null -exec dirname {} \; | sort -u | tr \n : | sed s/:$//)最佳实践由于app_update默认启动时就已设好路径优先用gdb attach方式调试不要反复 kill/重启app_update这样就不需要手动设LD_LIBRARY_PATH。问题 15CtrlC不停所有线程^C Program received signal SIGINT, Interrupt. 0xb6fd14a4 in ?? () from /lib/libpthread.so.0 (gdb) [comm_ipc.c--HAL_CommOpen:95] [1783527599]-- IPC Comm Client Opened!!!现象CtrlC后回到(gdb)提示符但打印还在继续刷。原因CtrlC只暂停了当前命中的线程其他线程仍在跑。解决在(gdb)下用interrupt暂停所有线程(gdb) interrupt问题 16验证 maskprint 是否部署成功# 检查 libpub.so 是否包含 maskprint 相关符号 strings /app/lib/libpub.so | grep maskprint # 期望输出 # _maskprint_check # /data/maskprint # _maskprint_load没有输出说明新的libpub.so还没推到位需要重新部署。# 确认目标文件位置 find /app -name libpub* # /app/lib/libpub.so ← 实际路径scp 时用这个问题 17attach 模式下(gdb) r不能用(gdb) r The program being debugged has been started already. Start it from the beginning? (y or n)现象attach 后敲r被拒绝。原因rrun的语义是启动一个全新进程。attach 模式下进程已经在跑了r会要求你确认是否杀掉当前进程再重启。解决(gdb) n # 回答 n不重启 (gdb) break Intern_Set (gdb) c # 用 ccontinue继续不用 rrvsc的区别命令含义适用场景rrun重新启动进程gdb /app/bin/nccu_apprccontinue继续当前暂停的进程attach 模式、断点命中后问题 18pidof nccu_app为空 →gdb -p报错rootimmu2:~# gdb -p $(pidof nccu_app) gdb: option --p requires an argument现象gdb -p提示缺少参数。原因pidof nccu_app返回空字符串因为 nccu_app 没在跑$()展开后gdb -p后面没有 PID-p选项认为缺少参数。排查# 先确认进程是否存在 ps | grep nccu_app # 区分 grep 自己的进程 vs 真正的 nccu_app # 错误示例 # 681 root 1728 S grep nccu_app ← 这行是 grep 自己不是 nccu_app # 正确示例 # 809 root 108m S bin/nccu_app ← 这是真正的 nccu_app解决先确保 nccu_app 在跑再 attach# 如果没跑 cd /app export LD_LIBRARY_PATH$(find /app /usr/lib -name *.so* -type f 2/dev/null -exec dirname {} \; | sort -u | tr \n : | sed s/:$//) nohup bin/nccu_app /tmp/nccu.log 21 sleep 3 ps | grep nccu_app # 确认看到真正的进程 # 有 PID 后再 attach gdb -p $(pidof nccu_app)问题 19Done(127)/Done(255)— 进程启动后立刻退出rootimmu2:~# nohup bin/nccu_app /tmp/nccu.log 21 [1] 693 sleep 3 [1] Done(127) nohup bin/nccu_app /tmp/nccu.log 21现象nohup启动后进程自动退出Done(XXX)是退出码。常见退出码解读退出码含义典型原因127命令不存在或动态库找不到libdpr.so: cannot open shared object file255SSHer 退出码 / 非正常退出CCU Sampler 初始化失败 →Failed to load moduals0177/0377gdbgdb 内的正常退出程序调用exit(0)排查看日志定位具体错误tail -20 /tmp/nccu.log解决127→ 设LD_LIBRARY_PATH255→ CCU 硬件不在线正常调试环境用touch /var/volatile/syshand.run 确保app_update正常跑问题 20web_server_main被 kill 后 Web 页面进不去现象之前调试时killall web_server_main干掉了 Web 服务之后忘了重启。解决# 方法 1手动重启 cd /app/web/server nohup /app/bin/web_server_main -f /app/web/server/server_main.conf \ -m /app/web/server/lib /dev/null 21 # 方法 2让 app_update 接管一切 killall nccu_app /app/bin/app_update -qws -nokeyboard -nomouse # 它会自动拉起 web_server_main 和 nccu_app问题 21复制注释到终端导致 shell 报错rootimmu2:~# ps | grep nccu_app # 确认看到进程 PID 5305 root 1732 S grep nccu_app rootimmu2:~# # 确认 PID bin/ config/ lib/ ...现象把# 确认看到进程 PID注释一并贴到终端shell 把#后面的内容解析了。原因#在交互式终端里不是注释只有#!/bin/sh的脚本文件第一行才是。贴在终端里 shell 会把它当成普通命令片段。解决只复制命令本身不要复制注释。或者用CtrlShiftV前先看清楚选了哪些行。问题总结速查表现象根本原因解决命令nccu_app: No such file or directory路径不对gdb /app/bin/nccu_applibdpr.so: cannot open shared object file动态库路径未设export LD_LIBRARY_PATH...sys_hand NOT OKsyshand.run 不存在touch /var/volatile/syshand.runSystem.cfg can NOT be opened工作目录不对cd /app后再gdbgdb 退出后进程还在跑app_update 守护重启killall app_update先已进入 gdb 又打 gdb误在 (gdb) 提示符下q退出回到 shell没看到进程但打印还在web_server_main 输出killall web_server_mainlibthread_db/libz 警告版本不匹配可忽略Data_AppLog table not foundDB 表还没创建后续 Init_CreadDataDB 自动创建SIGTTOU/SIGPIPE 打断调试gdb 默认拦截handle SIGxxx nostop noprint passxterm-256color 终端乱码程序输出冲入终端忽略 SIGTTOU 并用 exec-wrapperset logging redirect无效GDB 7.5 限制不拦截程序 stdout用 exec-wrapper 或 attachCCU Sampler 初始化失败kill app_update 断了 CCU 连接用gdb attach方式libts.so.0: not foundfind 只搜了 /app加上/usr/lib到 find 范围CtrlC后打印仍刷屏只停了一个线程(gdb) interruptmaskprint 不生效libpub.so 没更新strings libpub.so | grep maskprint验证attach 后(gdb) r被拒进程已在跑r 是重启用ccontinue替代gdb: option --p requires an argumentpidof nccu_app为空先确认进程在跑再 attachgrep nccu_app误当 nccu_appps 输出含 grep 自身看 VSZ 列grep 只有 ~1700nccu_app 有 ~100mDone(127)进程秒退动态库找不到设LD_LIBRARY_PATHDone(255)进程秒退CCU Sampler 初始化失败确保 app_update 正常 touch syshand.runWeb 页面 404web_server_main 被 kill重启 web_server_main 或让 app_update 拉起shell 执行了注释内容把#注释贴进终端只复制命令去掉注释行4.4 GDB 调试完整流程推荐方式 Aattach依赖 CCU/硬件时推荐程序由app_update正常拉起gdb 挂上去调试# 第一步确保 app_update 正常运行 touch /var/volatile/syshand.run export LD_LIBRARY_PATH$(find /app /usr/lib -name *.so* -type f 2/dev/null -exec dirname {} \; | sort -u | tr \n : | sed s/:$//) /app/bin/app_update -qws -nokeyboard -nomouse # 第二步等待 nccu_app 被拉起 sleep 5 ps | grep nccu_app # 第三步attach 并设断点 gdb -ex handle SIGTTOU nostop noprint pass \ -ex handle SIGPIPE nostop noprint pass \ -ex set pagination off \ -p $(pidof nccu_app) (gdb) break Intern_Set (gdb) c方式 B独立 run纯逻辑/不依赖 CCU 时# 第一步清理环境 killall app_update nccu_app web_server_main # 第二步绕过启动检查 touch /var/volatile/syshand.run # 第三步设置动态库路径 export LD_LIBRARY_PATH$(find /app /usr/lib -name *.so* -type f 2/dev/null -exec dirname {} \; | sort -u | tr \n : | sed s/:$//) # 第四步切换到正确工作目录启动 GDB cd /app gdb -ex handle SIGTTOU nostop noprint pass \ -ex handle SIGPIPE nostop noprint pass \ -ex handle SIGUSR1 nostop noprint pass \ -ex handle SIGUSR2 nostop noprint pass \ -ex set pagination off \ bin/nccu_app # 第五步设断点 → 运行 (gdb) break Intern_Set (gdb) break DAI_Set (gdb) r # 如果刷屏严重干扰配合 exec-wrapper见问题 12方式 Cexec-wrapper 重定向彻底消停刷屏# 先创建包装脚本 cat /tmp/wrap.sh EOF #!/bin/sh exec /app/bin/nccu_app $ /tmp/nccu_run.log 21 EOF chmod x /tmp/wrap.sh cd /app gdb -ex handle SIGTTOU nostop noprint pass \ -ex handle SIGPIPE nostop noprint pass \ -ex handle SIGUSR1 nostop noprint pass \ -ex handle SIGUSR2 nostop noprint pass \ -ex set pagination off \ -ex set exec-wrapper /tmp/wrap.sh \ bin/nccu_app (gdb) break Intern_Set (gdb) r # 终端 2: tail -f /tmp/nccu_run.log5. perf 性能分析5.1 静态编译在编译服务器上# 下载匹配目标设备内核版本的源码 wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.94.tar.xz tar -xf linux-4.19.94.tar.xz cd linux-4.19.94/tools/perf # 静态交叉编译 export ARCHarm export CROSS_COMPILEarm-linux-gnueabihf- make LDFLAGS-static NO_LIBPERL1 NO_LIBPYTHON1 \ NO_LIBAUDIT1 NO_LIBUNWIND1 NO_LIBBABELTRACE1 \ NO_LZMA1 NO_BACKTRACE1 NO_DWARF1 NO_SLANG1 \ NO_GTK21 NO_LIBNUMA1 NO_LIBELF1 NO_DEMANGLE1 # 部署到设备 scp perf root设备IP:/usr/bin/为什么静态编译目标设备 BusyBox 环境缺少 libelf/libdw 等动态库静态编译让 perf 不依赖任何设备上的 .so。5.2 strace 系统调用追踪# 追踪 nccu_app 的系统调用 strace -f -e tracestime,clock_settime -p $(pidof nccu_app) # 追踪所有文件 I/O strace -f -e traceopen,read,write -p $(pidof nccu_app)5.3 tcpdump 抓包# 抓 CCU 通信 tcpdump -i eth0 tcp port ccu_port -X6. TRACE 打印过滤maskprint6.1 机制每次TRACE/TRACEX调用前先通过_maskprint_check(__FILE__)检查/data/maskprint文件// basetypes.h (debug 版) #define TRACE if(_maskprint_check(__FILE__)) printf黑名单0清单里的文件不打印其余打印白名单1清单里的文件才打印其余不打印文件不存在全部打印向后兼容6.2 配置示例# 黑名单屏蔽 rundata_exchange.c 和 fcgi_main.c 的打印 cat /data/maskprint EOF 0 rundata_exchange.c fcgi_main.c EOF # 白名单只看 apl.c 和 mem_mgmt 目录的打印 cat /data/maskprint EOF 1 src/apl/apl.c src/common/runtime/mem_mgmt EOF6.3 涉及文件文件说明include/base_defines/maskprint.h声明_maskprint_check()publib/iMaskPrint.c读取/data/maskprint缓存规则匹配路径include/base_defines/basetypes.hTRACE/TRACEX 宏集成过滤publib/MakefileOBJS 加入 iMaskPrint.o6.4 使用流程本地修改好的源码推到编译服务器编译部署source mkenv_arm_st; mkd; inst把新的libpub.soscp 到设备scp ../out/lib/libpub.so root设备IP:/app/bin/ scp ../out/lib/libpub.so root设备IP:/app/web/server/lib/设备上创建/data/maskprint配置文件重启服务即可生效7. 其他调试工具7.1 确认动态库依赖# 编译服务器上查看设备上没有 readelf arm-linux-gnueabihf-readelf -d nccu_app | grep -E RPATH|RUNPATH|NEEDED7.2 系统日志# 系统日志 cat /log/messages # 内核日志 dmesg | tail -507.3 查看进程树ps | grep -E app_update|nccu_app|web_server