U-BOOT构建脚本闪退之谜

前段时间在把U-BOOT的主线代码反向移植到幽兰代码本本来使用的v2017版本时,遇到构建脚本闪退的问题。因为这个问题涉及到多种程序文件和配置文件的配合,比较新颖,所以特别将其记录下来。

故事的起因是在引入了一些主线代码后,先是花了一些时间处理编译错误。处理好编译错误后,在镜像打包阶段,构建脚本突然退出,输出信息如下:

LD      tpl/arch/arm/cpu/armv8/built-in.o  LD      tpl/u-boot-tpl  OBJCOPY tpl/u-boot-tpl-nodtb.bin  COPY    tpl/u-boot-tpl.bin  COPY    u-boot.dtb  MKIMAGE u-boot-dtb.img  CHK     include/config.h  CFG     u-boot.cfg  CFGCHK  u-boot.cfgtoolchain select --arg not yaarch64SEC=1

最外层的构建脚本是用的bash脚本。默认是不开启调试信息的,而且带有-e选项,也就是如果脚本中的任何命令失败,整个脚本将立即停止执行。

为了方便调试,我在-e选项后面增加了-x选项。

set -eset -x

修改后,再次构建,这次闪退前的最后几行输出变为:

+ SPL_FIT_GENERATOR=arch/arm/mach-rockchip/make_fit_atf.sh+ [[ arch/arm/mach-rockchip/make_fit_atf.sh == *.py ]]+ arch/arm/mach-rockchip/make_fit_atf.sh -t 0x08400000+ ./tools/mkimage -f u-boot.its -E u-boot.itb

这意味着闪退前,执行的最后一个命令是tools/mkimage。更准确的说是:mkimage -f u-boot.its -E u-boot.itb

把这条命令单独执行,果然失败,得到的错误信息如下:

geduer@lupan:/gdvol/gewu/v2017.09-rk3588-taiyi$ ./tools/mkimage -f u-boot.its -E u-boot.itbsh: 1: -I: not found./tools/mkimage: Can't read u-boot.itb.tmp: Invalid argument

使用echo $?观察退出码,255,对应的是-1。

geduer@lupan:/gdvol/gewu/v2017.09-rk3588-taiyi$ echo $?255

mkimage是U-BOOT自带的一个工具,源代码就在tools下,默认编译的二进制没有调试符号,不方便调试,我修改tools下的Makefile,增加-g选项,重新构建。

构建之后便可以使用gdb单步跟踪mkimage了。这样跟踪很快就发现,那句-I: not found输出来自源代码的368行。

(gdb) 361                     if (tparams->fflag_handle)(gdb) 368                             retval = tparams->fflag_handle(&params);(gdb) [Detaching after vfork from child process 52756]sh: 1: -I: not found/gewu/yourland/v2017.09-rk3588-taiyi/tools/mkimage: Can't read fit/uboot.itb.tmp: Invalid argument370                     if (retval != EXIT_SUCCESS)

使用r命令再次执行到这一行,用s命令跟踪进去。函数指针指向的是fit_handle_file函数。函数的参数是个很大的params结构体。

361                     if (tparams->fflag_handle)(gdb) 368                             retval = tparams->fflag_handle(&params);(gdb) sfit_handle_file (params=0x5555555811a0 <params>) at tools/fit_image.c:686686     {(gdb) p params $1 = (struct image_tool_params *) 0x5555555811a0 <params>(gdb) p *params $2 = {dflag = 0, eflag = 0, fflag = 1, iflag = 0, lflag = 0, pflag = 0, vflag = 0, xflag = 0, skipcpy = 0, os = 5, arch = 7, type = 8, comp = 1,   dtc = 0x555555577c95 "-I dts -O dtb -p 500", addr = 0, ep = 0, imagename = 0x55555557428d "", imagename2 = 0x55555557428d "",   datafile = 0x7fffffffdfc2 "fit/u-boot.its", imagefile = 0x7fffffffdfde "fit/uboot.itb",   cmdname = 0x7fffffffdf8c "/gewu/yourland/v2017.09-rk3588-taiyi/tools/mkimage", outfile = 0x0, keydir = 0x0, keydest = 0x0, comment = 0x0, require_keys = 0,   file_size = 0, orig_file_size = 0, auto_its = false, fit_image_type = 2, fit_ramdisk = 0x0, content_head = 0x0, content_tail = 0x0, external_data = true,   quiet = false, external_offset = 4096, engine_id = 0x0, extraparams = 0x0}
[Detaching vfork parent process 54037 after child exit][Inferior 1 (process 54037) detached][Inferior 3 (process 54038) exited with code 0177]fit/u-boot.its: 3: Syntax error: "(" unexpected

这个函数里会准备一个命令行,放在cmd数组里,然后调用system(cmd)来执行它。

706             if (params->auto_its) {(gdb) 713             } else if (params->datafile) {(gdb) 715                     snprintf(cmd, sizeof(cmd), "%s %s \"%s\" > \"%s\"",(gdb) 722             if (*cmd && system(cmd) == -1) {(gdb) p cmd$1 = " -I dts -O dtb -p 500 \"fit/u-boot.its\" > \"fit/uboot.itb.tmp\"\000\177\000\000@\220\374\367\377\177\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\001", '\000' <repeats 15 times>, "\200\037\000\000\377\377\000\000\030\341\377\367\377\177\000\000\000\350\377\367\377\177\000\000\001\000\000\000\377\177\000\000\351\036\377\367\377\177\000\000\000\330\377\377\377\177\000\000HJ\356W\254\b", '\000' <repeats 26 times>, "(\022\374\367\377\177\000\000\000\000\000\000 ", '\000' <repeats 19 times>...(gdb)

单步跟踪到调用system的722行,观察cmd,内容是: -I dts -O dtb -p 500 ...

看起来是调用dtc来编译设备树文件的命令行,但是却没有关键的dtc程序名。

回头追查产生命令的代码,仔细看snprintf的第一个动态内容,来自一个名叫MKIMAGE_DTC的宏。

} else if (params->datafile) {        /* dtc -I dts -O dtb -p 500 datafile > tmpfile */        snprintf(cmd, sizeof(cmd), "%s %s \"%s\" > \"%s\"",             MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);        debug("Trying to execute \"%s\"\n", cmd);

搜索这个宏,它来自tools/Makefile,是通过-D选项来指定的:

HOSTCFLAGS_fit_image.o += -DMKIMAGE_DTC=\"$(CONFIG_MKIMAGE_DTC_PATH)\"

而选项的取值则来自另一个宏:CONFIG_MKIMAGE_DTC_PATH。

CONFIG_MKIMAGE_DTC_PATH宏是通过Kconfig机制定义和维护的。

U-BOOT的config机制是照搬的Linux模式。查看幽兰使用的config文件,里面包含了如下内容:

CONFIG_MKIMAGE_DTC_PATH=dtc

但是查看根目录下的.config,却没有上面这行。

查看到这里,我意识到问题根源了。应该是Kconfig里没有定义好这个配置项。去掉CONFIG_前缀,搜索MKIMAGE_DTC_PATH,发现它是定义在dts/Kconfig文件里,而主线仓库把它挪到了tools/Kconfig。按照主线代码更新tools/Kconfig,增加MKIMAGE_DTC_PATH后,问题便彻底解决了。

config MKIMAGE_DTC_PATH    string "Path to dtc binary for use within mkimage"    default "dtc"    help      The mkimage host tool will, in order to generate FIT images make      calls to the dtc application in order to create the output.  In      some cases the system dtc may not support all required features      and the path to a different version should be given here.

如果大家想重现和体验这个问题,那么非常简单,只要打开toosl/Kconfig, 找到config MKIMAGE_DTC_PATH这一行,将其修改为

config MKIMAGE_DTC_PATH_BUG

此文草成后,窗外风雨大作。酷热干旱多日,终于下了场大雨。

学,然后知不足。专门为底层技术同行开办的信创系统软件开发训练营(2025北京站)》正在招生中,欢迎感兴趣的同行联系我们。也希望大家帮忙把这个消息传播给其他可能需要的同行。

(写文章很辛苦,恳请各位读者点击“在看”,欢迎转发)

*************************************************

正心诚意,格物致知,以人文情怀审视软件,以软件技术改变人生

扫描下方二维码或者在微信中搜索“盛格塾”小程序,可以阅读更多文章和有声读物

Image

也欢迎关注格友公众号

Image

/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=51078:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/douhuorong/work/demo4/target/classes:/Users/douhuorong/Documents/work/maven仓库/org/springframework/boot/spring-boot-starter-freemarker/2.7.18/spring-boot-starter-freemarker-2.7.18.jar:/Users/douhuorong/Documents/work/maven仓库/org/springframework/boot/spring-boot-starter/2.7.18/spring-boot-starter-2.7.18.jar:/Users/douhuorong/Documents/work/maven仓库/org/springframework/boot/spring-boot/2.7.18/spring-boot-2.7.18.jar:/Users/douhuorong/Documents/work/maven仓库/org/springframework/boot/spring-boot-autoconfigure/2.7.18/spring-boot-autoconfigure-2.7.18.jar:/Users/douhuorong/Documents/work/maven仓库/org/springframework/boot/spring-boot-starter-logging/2.7.18/spring-boot-starter-logging-2.7.18.jar:/Users/douhuorong/Documents/work/maven仓库/ch/qos/logback/logback-classic/1.2.13/logback-classic-1.2.13.jar:/Users/douhuorong/Documents/work/maven仓库/ch/qos/logback/logback-core/1.2.13/logback-core-1.2.13.jar:/Users/douhuorong/Documents/work/maven仓库/org/apache/logging/log4j/log4j-to-slf4j/2.23.0/log4j-to-slf4j-2.23.0.jar:/Users/douhuorong/Documents/work/maven仓库/org/apache/logging/log4j/log4j-api/2.23.0/log4j-api-2.23.0.jar:/Users/douhuorong/Documents/work/maven仓库/org/slf4j/jul-to-slf4j/1.7.35/jul-to-slf4j-1.7.35.jar:/Users/douhuorong/Documents/work/maven仓库/jakarta/annotation/jakarta.annotation-api/2.1.1/jakarta.annotation-api-2.1.1.jar:/Users/douhuorong/Documents/work/maven仓库/org/yaml/snakeyaml/2.0/snakeyaml-2.0.jar:/Users/douhuorong/Documents/work/maven仓库/org/freemarker/freemarker/2.3.32/freemarker-2.3.32.jar:/Users/douhuorong/Documents/work/maven仓库/org/springframework/spring-context-support/5.3.39/spring-context-support-5.3.39.jar:/Users/douhuorong/Documents/work/maven仓库/org/springframework/spring-beans/5.3.39/spring-beans-5.3.39.jar:/Users/douhuorong/Documents/work/
09-30
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值