Jay's some notes - linux
type: channel
link: https://notes.leconiot.com/category/linux/
items: Linux TC
items: ChatGPT 带你学习 iptables
items: GCC 未使用函数、变量和文件优化策略
items: 固件安全之 TF-A 和 SecureBoot
items: Linux capabilities
items: udp发送ip端口发送不可达
items: vscode 通过数据断点分析segmentation fault
items: socat
items: 学习uboot中 U_BOOT_CMD命令参数编程
items: 在linux 下通过vscode调试elf可执行文件

Linux TC
type: item
date: 2024-07-22T14:13:00+08:00
description: 目录 [隐藏] 1. 名称2. 语法3. 选项4. 描述4.1. QDISCS4.2. CLASSES4.3. FILTERS4.4. QEVENTS4.5. 无类 QDISCS4.6. 配置无类 QDISCS4.7. 类别 QDISCS4.8. 操作原理4.9. 命名4.10. 参数5. TC 命令5.1. 监控5.2. 选项5.3. 格式5.4. 示例6. 历史7. 参见8. 作者 TC1. 名称tc - 显示/操作流量控制（traffic control）设置2. 语法tc [ OPTIONS ] qdisc [ add | change | replace | link | delete ] dev DEV [ parent qdisc-id | root ] [ handle qdisc-id ] [ ingress_block BLOCK_INDEX ] [ egress_block BLOCK_INDEX ] qdisc [ qdisc specific parameters ] tc [ OPTIONS ] class [ add | change | replace | delete ] dev DEV parent qdisc-id [ classid class-id ] qdisc [ qdisc specific parameters ] tc [ OPTIONS ] filter [ add | change | replace | delete | get ] dev DEV [ parent qdisc-id | root ] [ handle filter-id ] protocol protocol prio priority filtertype [ filtertype specific parameters ] flowid flow-id tc [ OPTIONS ] filter [ add | change | replace | delete | get ] block BLOCK_INDEX [ handle filter-id ] protocol protocol prio priority filtertype [filtertype specific parameters ] flowid flow-id tc [ OPTIONS ] chain [ add | delete | get ] dev DEV [ parent qdisc-id | root ] filtertype [ filtertype specific parameters ] tc [ OPTIONS ] chain [ add | delete | get ] block BLOCK_INDEX filtertype [ filtertype specific parameters ] tc [ OPTIONS ] [ FORMAT ] qdisc { show | list } [ dev DEV ] [ root | ingress | handle QHANDLE | parent CLASSID ] [ invisible ] tc [ OPTIONS ] [ FORMAT ] class show dev DEV tc [ OPTIONS ] filter show dev DEV tc [ OPTIONS ] filter show block BLOCK_INDEX tc [ OPTIONS ] chain show dev DEV tc [ OPTIONS ] chain show block BLOCK_INDEX tc [ OPTIONS ] monitor [ file FILENAME ]3. 选项OPTIONS := { [ -force ] -b[atch] [ filename ] | [ -n[etns] name ] | [ -N[umeric] ] | [ -nm | -nam[es] ] | [ { -cf | -c[onf] } [ filename ] ] [-t[imestamp] ] | [ -t[short] | [ -o[neline] ] } css Copy code FORMAT := { -s[tatistics] | -d[etails] | -r[aw] | -i[ec] | -g[raph] | -j[json] | -p[retty] | -col[or] }4. 描述tc 用于配置 Linux 内核中的流量控制。流量控制包括以下几个方面：整形（SHAPING）当流量被整形时，其传输速率会受到控制。整形不仅仅是降低可用带宽，它…

ChatGPT 带你学习 iptables
type: item
date: 2023-02-16T15:50:00+08:00
description: 对于 iptables 学习，反复看过 man iptables 命令，但是缺乏归纳总结，不用就忘了。现在好了，直接让 ChatGPT 帮我画一些系统框图辅助记忆。Q:帮我用 Mermaid 画一个系统框图描述 iptables 所有 Chain 的处理顺序，并且描述其生效范围。graph LR INPUT --> PREROUTING PREROUTING --> ROUTING ROUTING --> FORWARD FORWARD --> POSTROUTING POSTROUTING --> OUTPUT 这个图表演示了 iptables 中 5 个 Chain 处理的先后关系，其中：INPUT Chain 用于处理进入本地计算机的网络数据包；PREROUTING Chain 用于处理数据包路由前的操作，例如修改目标 IP 地址；ROUTING Chain 用于处理数据包的路由过程，例如根据路由表进行转发；FORWARD Chain 用于处理转发给其他计算机的网络数据包；POSTROUTING Chain 用于处理数据包路由后的操作，例如修改源 IP 地址；OUTPUT Chain 用于处理从本地计算机发出的网络数据包；Q:再帮我给每一个 Chain 规则生成一个详细的命令。INPUT Chain：允许来自特定 IP 地址的 SSH 连接 iptables -A INPUT -p tcp -s 192.168.1.100 --dport 22 -j ACCEPTPREROUTING Chain：将来自特定 IP 地址的数据包重定向到另一台计算机iptables -t nat -A PREROUTING -s 192.168.1.100 -j DNAT --to-destination 192.168.1.200ROUTING Chain：将来自特定 IP 地址的数据包标记为优先级 1iptables -t mangle -A PREROUTING -s 192.168.1.100 -j MARK --set-mark 1FORWARD Chain：允许从特定网卡转发特定端口的数据包iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 80 -j ACCEPTPOSTROUTING Chain：将来自特定 IP 地址的数据包修改为指定 IP 地址并从指定网卡发出iptables -t nat -A POSTROUTING -s 192.168.1.100 -o eth0 -j SNAT --to-source 10.0.0.1OUTPUT Chain：允许从本地计算机发出到特定 IP 地址和端口的数据包iptables -A OUTPUT -p tcp -d 192.168.1.100 --dport 80 -j ACCEPTQ:再帮我用 Mermaid 描述下 Table 和 Chain 之间的系统关系。graph LR subgraph Table_Chain_Relationships Filter_Table -->|Table| INPUT Filter_Table -->|Table| OUTPUT Filter_Table -->|Table| FORWARD Mangle_Table -->|Table| PREROUTING Mangle_Table -->|Table| INPUT Mangle_Table -->|Table| OUTPUT Mangle_Table -->|Table| FORWARD Mangle_Table -->|Table| POSTROUTING Raw_Table -->|Table| PREROUTING Raw_Table -->|Table| OUTPUT Security_Table -->|Table| INPUT Security_Table -->|Table| OUTPUT Security_Table -->|Table| FORWARD NAT_Table -->|Table| PREROUTING NAT_Table -->|Table| OUTPUT NAT_Table -->|Table| POSTROUTING end

GCC 未使用函数、变量和文件优化策略
type: item
date: 2022-09-15T18:05:00+08:00
description: 目录 [隐藏] 样例探索结论 GCC 优化过于复杂，这里探索 GCC 对未使用的代码和变量以及文件的优化策略。3.10 Options That Control Optimization6.3.3 Reducing Size of Executables with Unused Subprogram/Data Elimination样例如下两个文件。$ tree ├── main.c └── unused.cmain.c 文件内容如下。#include <stdio.h> // __attribute__((used, section(".linker_entry_list"))) int main_extern_unused_var = 0; // __attribute__((used, section(".linker_entry_list"))) static int main_static_unused_var = 0; // __attribute__((used)) static int main_static_unused_func(void) { printf("static unused function.\n"); return 0; } // __attribute__((used)) int main_extern_unused_func(void) { printf("extern unused function.\n"); return 0; } int main(int argc, char* argv[]) { printf("hello world!\n"); return 0; }unused.c#include <stdio.h> // __attribute__((used, section(".linker_entry_list"))) int other_extern_unused_var = 0; // __attribute__((used, section(".linker_entry_list"))) static int other_static_unused_var = 0; // __attribute__((used)) static int other_static_unused_func(void) { printf("static unused function.\n"); return 0; } // __attribute__((used)) int other_extern_unused_func(void) { printf("extern unused function.\n"); return 0; }探索默认编译选项，通过可执行文件确定所有变量和函数都未优化。$ gcc -o main.app main.c unused.c readelf -a main.app |grep unused 37: 0000000000004018 4 OBJECT LOCAL DEFAULT 26 main_static_unused_var 38: 0000000000001149 27 FUNC LOCAL DEFAULT 16 main_static_unused_func 40: 0000000000004020 4 OBJECT LOCAL DEFAULT 26 other_static_unused_var 41: 00000000000011a5 27 FUNC LOCAL DEFAULT 16 other_static_unused_func 57: 0000000000001164 27 FUNC GLOBAL DEFAULT 16 main_extern_unused_func 68: 00000000000011c0 27 FUNC GLOBAL DEFAULT 16 other_extern_unused_func 69: 000000000000401c 4 OBJECT GLOBAL DEFAULT 26 other_extern_unused_var 70: 0000000000004014 4 OBJECT GLOBAL DEFAULT 26 main_extern_unused_var-O1 -O2 -Os 选项，所有static 链接属性的变量和函数被用优化掉。$ gcc -Os -o main.app main.c unused.c $ readelf -a main.app |grep unused 53: 0000000000001169 21 FUNC GLOBAL DEFAULT 16 main_extern_unu…

固件安全之 TF-A 和 SecureBoot
type: item
date: 2022-07-26T22:15:00+08:00
description: 目录 [隐藏] TBBR-CLIENT固件设计BL1BL2BL31BL33证书链 这里详细介绍基于 ARMv8-A AArch64 固件安全相关，包含 TF-A（Trust Firmware A）。以及基于TF-A OEM厂商对 U-Boot 和 Kernel 实现的安全启动流程 SecureBoot。https://trustedfirmware-a.readthedocs.io/en/latestTBBR-CLIENThttps://developer.arm.com/documentation/den0006/latest对于 TF-A，ARMv8-A AArch64 架构需要满足如下设计需求。区分不同的异常等级（Exception Level）；对于不同的安全等级区分了可信的世界（Trust World）和非可信世界（Non-Trusted World）。我们的应用程序，内核都工作它认为不可信世界，所以没有办法直接访问一些资源。权限等级描述实现方EL-0应用权限CPU支持EL-1内核权限CPU支持EL2虚拟权限等级CPU支持EL-3安全权限等级CPU或者内部安全模块支持​不同安全等级下访问不同的硬件资源。例如一些 OTP/eFUSE区域，在 EL0-EL2 异常等级应用程序是没有办法直接访问的。如果需要访问这些资源，通过 SMC 共享内存通过工作更高等级例如 EL3 的程序实现间接访问。有了如上认识，接下来我们梳理 TF-A 约定的在不同 EL下的引导程序。固件设计通常地，对于ARM AArch64 如下开机执行如下引导顺序。提示：对于 AArch32 ，这里 BL31 为 BL32。BL1BL1 作为 ROM Bootloader 工作在最高安全等级 EL3，它拥有独立的 Trusted ROM 和 SRAM 区域。BL1 会在平台指定的基地址载入 BL2，并且传递控制权到 BL2，此时 BL2 工作在SE-L1。BL2BL2 初始化终端 Console；初始化次级引导的存储，用以接下来的加载。使能 MMU 和以及它需要访问的存储空间；保留部分存储用以次级 EL3 的引导；BL31BL2 载入 BL31，移交控制权 EL3 到 BL31。BL31 执行如下架构初始化：初始化其关注的系统寄存器；初始化每个 CPU 的数据架构，提供 Cache 访问，用以提速。该初始化并行在多个 CPU 进行。同时 BL31还会执行如下平台初始化：初始化终端 Console；初始化 MMU；初始化通用中断控制器；BL33BL33 通常就是 U-Boot，此次往后的应用都工作平台不信任的世界。但是此时 BL31 已经常驻内存，如果需要访问安全世界的资源，需要通过 SMC（共享内存） 方式调用BL31接口。证书链如上引导，除了 BL1 是固化在 ROM，其他都是在非可信的外部存储，例如 Flash、EMMC。那么平台又是如何保证其的安全的。如下证书链导出过程指示了多个用以不同固件签名的私钥生成。如上框图指示，厂商会预制一个公钥到硬件，基于该公钥的私钥我们签名了多个证书。Non-Trusted Firmware Updater certificate该证书对应私钥用以非可信固件的签名，公钥用以升级过程的验签。Trusted Boot Firmware certificate该证书对应私钥用以可信固件的签名，公钥用以升级过程的验签。Trusted Key certificate可信秘钥证书对应私钥（OEM Private KEY）又签发了 Trusted Key certificate，包含三个公钥，分别对应：Debug Public Key。Trusted World Public Key。该证书用以 BL2 和 BL31 的认证。Non-Trusted World Public Key。这里用以 BL33，即 U-Boot 的认证。提示：这里有个关键点：对于 Trusted Key certificate 的签发通常芯片厂商会释放工具，相当于开放私钥。之前一直想不明白既然厂商公开了私钥任何人都可以更改后续证书？其实是因为Trusted Key certificate 是烧写在固定地址的 OTP （eFUSE）区域，只可以烧写一次。所以一旦在生产环节烧写了 Trusted Key certificate，那么芯片对应的 OEM Private KEY 也就唯一了。最后我们确认下 BL31 的验签流程。如下图指示，通过厂商预制根公钥 ROTPK 对生产阶段烧写的 Trusted Key Certificate 验签，之后得到可信的 Trusted World Public Key ，用该公钥验证 BL31 Key Certificate，得到 …

Linux capabilities
type: item
date: 2022-06-28T18:04:00+08:00
description: Linux capabilities对于权限细节参考man 7 capabilities；对于-+= eip操作符参考 man 3 cap_from_text；文档中命令setcap、getcap等都可以通过man命令查看；我需要在VS Code 调试NuttX应用，它的Sim应用需要cap_net_raw,cap_net_admin权限，否则就无法正常操作HCI设备。当然网上有一些帖子尝试将VS Code或者GDB运行在root用户，显然这样操作是非常不优雅的。所以这里尝试给需要调试的应用利用linux capabilities直接给可执行文件设置权限。$ sudo setcap 'cap_net_raw,cap_net_admin=ep' nuttx$ getcap nuttx nuttx = cap_net_admin,cap_net_raw+ep此时运行程序，可以通过capsh或者getcaps检查进程确认已经设置成功。$ getpcaps $(pidof nuttx) 283131: = cap_net_admin,cap_net_raw+ep$ cat /proc/283131/status|grep Cap CapInh: 0000000000000000 CapPrm: 0000000000003000 CapEff: 0000000000003000 CapBnd: 000001ffffffffff CapAmb: 0000000000000000 $ capsh --decode=000001ffffffffff WARNING: libcap needs an update (cap=40 should have a name). 0x000001ffffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read,38,39,40此时通过VS Code启动调试后发现其却没有了需要的文件权限。$ getpcaps $(pidof nuttx) 284336: = | | \_ /usr/share/code/code --ms-enable-electron-run-as-node /usr/share/code/resources/app/out/bootstrap-fork --type=ptyHost | | | \_ /usr/bin/bash | | | \_ /usr/bin/bash | | | | \_ /bin/sh /tmp/Microsoft-MIEngine-Cmd-nptpb2ki.pex | | | | \_ /usr/bin/gdb --interpreter=mi --tty=/dev/pts/4 | | | | \_ /home/lijie/my_project/nuttxspace/nuttx/nuttx看起来是父进程/usr/bin/gdb 启动nuttx进程的时候并没有使用其文件文件属性。直接测试了gdb ./nuttx确认和上面现象一致，strace确认其通过ptrace创建进程。ptrace(PTRACE_SETOPTIONS, 285286, NULL, PTRACE_O_TRACESYSGOOD|PTRACE_O_TRACECLONE|PTRACE_O_EXITKILL) = 0怀疑这里是gdb进程没有cap_sys_ptrace权限，添加后再次通过VS Code启用nuttx调试发现其进程已经具有我们需要的权限。$ sudo setcap …

udp发送ip端口发送不可达
type: item
date: 2022-01-12T11:40:00+08:00
description: 众所周知，udp是无连接的，所以忽略udp接收方状态，是否监听对应udp端口以及ip是否存在，直接向udp发送数据，会发生什么？为了搞清楚这个问题，我们尝试在局域网建立收发设备，然后抓包分析。端口不可达从抓包来看，udp数据正常发出。对端设备回复icmp指示端口不可达。ip 不可达当我们把接收端设备关机，此时udp数据正常发出，直到arp连续三次请求失败。此时抓包显示udp包已经不发送了。此时，我们跟踪sytem call 确定，发用户空间的sendto 接口仍然显示成功。sendto(3, "012345679abcdef\0", 16, 0, {sa_family=AF_INET, sin_port=htons(54321), sin_addr=inet_addr("192.168.28.207")}, 16) = 16此时通过查看arp缓存确定ip状态已经标记为INCOMPLETE。$ip neigh show 192.168.28.207 dev wlp0s20f3 INCOMPLETE尝试手动更新arp缓存的mac地址和状态到REACHABLE。$sudo ip neigh change 192.168.28.207 lladdr dc:a6:32:3f:94:36 nud reachable dev wlp0s20f3提示：对于如上命令和状态值详细可以参考man ip-neighbour。此时udp又重新发了出来。值得一提的是，在路由器查看arp缓存，发现不管设备断开多久，状态都不会变更为INCOMPLETE而始终是STALE。$ip neigh show 192.168.28.207 dev br-lan lladdr dc:a6:32:3f:94:36 STALE

vscode 通过数据断点分析segmentation fault
type: item
date: 2020-11-19T20:46:00+08:00
description: vscode 通过数据断点分析segmentation fault通常地，程序异常，我们借助vscode在ubuntu主动调试，程序会自动在异常代码位置停下来，但是异常分析通常不会这么简单，而是一连串连锁反应。这里尝试分析，因为程序异常，非法写入了一段正常内存，从而导致多个链路之后异常发生。而对于此问题，最常使用的调试手段就是添加数据断点。通常直接在某段代码位置添加的代码为函数断点，程序会自动在该位置停下来。同样地，我们可以添加条件断点：当某个判断条件（例如，变量值为真）满足的时候；当某段代码连续执行N次的时候；当某个变量（内存）被读写的时候；如上前两个条件断点，vsocde 里面的c/c++ extension 已经支持，可以在ide里面点击断点（红色小点）直接编辑，但是最后一个为数据断点还不支持。提示：vscode 断点更多信息参考https://code.visualstudio.com/docs/editor/debugging#_advanced-breakpoint-topics。需要借助debug console 键入gdb（gnu debugger）命令，如上操作，成功初始化device_scan_ 成员变量后，程序不再会对变量进行写操作，但是之后该对象的一个成员变量值被异常写入了非法值，当再次用该对象指针打印日志函数时候发生异常。此时通过p命令查看变量并获取变量首地址。-exec p device_scan_ #打印变量 -exec p &device_scan_.data #获取变量地址通过watch命令监控该地址的写操作。-exec watch *0x9ac920 #监控变量写操作提示：如上p、watch命令可以参考gdb手册，https://sourceware.org/gdb/current/onlinedocs/gdb/Set-Watchpoints.html#Set-Watchpoints。同时可以通过awatch监控读写，rwatch监控写操作。之后全速运行，发现程序在另外一个非法访问该变量位置停了下来，并且通过 Old Value和New Value提示了值变化。通过分析上下文就可以定位到引发异常的真正原因。

socat
type: item
date: 2020-11-19T18:09:00+08:00
description: 目录 [隐藏] 地址规范地址关键字socket-connect:\<domain>:\<protocol>:\<remote-address>tcp:\<host>:\<port>tcp-listen:\<port>unix-connect:<fille_name>unix-listen:<fille_name>unix-sendto:<file_name>地址选项forkreuseaddrtype样例远程访问目标机器的unix-domain socket监听unix socket重定向串口 socathttp://www.dest-unreach.org/socat/。提示：如下翻译来自 man 1 socat，未完待续……概述socat 是一个命令行工具，用以建立一个双向字节流交换数据。该字节流又可以被构造成不同地址类型，大量的地址选项也同样可以被作用于该流，因此socat非常强大。filan 是一个打印文件描述符的工具，已经被重构用以调试socat，当然，也可以另做它用。procan 是一个打印进程信息的工具，同样被重构用以调试socat。socat 实例包含如下生命周期。init 阶段解析命令参数，初始化日志打印；open阶段打开第一个地址并且转发到第二个地址字节流，此阶段可能会阻塞，因此类似socks的复杂地址选项，需要在连接请求或认证对话框完成后才会开始下一阶段。transfer阶段通过select 参数观察源地址流的读写操作，当可读或者可写时，socat完成到目的流数据转发。当任意一方流eof，closing阶段开始，socat 主动发送eof操作到对等需要关闭的另外一方尝试优雅的关闭它的写操作的字节流，在运行的时间范围内，socat也可能会继续传输数据到另外一个方向，直到所有的通道被关闭。地址规范命令的地址参数为用户给socat 建立字节流的必要信息。一个地址规范通常包含一个地址类型的关键词，零或者多个地址参数通过":"间隔，零或者多个地址选项通过","间隔。关键词指定地址类型（tcp4、open、exec），而对于一些关键字存在同义词（例如 “-”代表stdio，tcp默认为tcp4），这里的地址类型关键字不区分大小写。对于一些特殊地址类型，关键字可能会被省略，地址关键字socket-connect:\<domain>:\<protocol>:\<remote-address>tcp:\<host>:\<port>通过tcp/ip 4或者6，连接由host、port指定的地址。由地址标准决定ip版本，域名解析。选项组：FD,SOCKET,IP4,IP6,TCP,RETRY有用的选项：crnl, bind, pf, connect-timeout, tos, mtudiscover, mss, nodelay, nonblock, sourceport, retry, readbytestcp-listen:\<port>监听由port 指定的端口，并接收（accept）TCP/IP连接，ip版本为4或者地址选项pf指定，对应选项（socat -4、-6），也可通过环境变量CAT_DEFAULT_LISTEN_IP配置，注意，打开该地址后通常会阻塞进程，直到一个客户端连接。选项组：FD,SOCKET,LISTEN,CHILD,RANGE,IP4,IP6,TCP,RETRY；有用的选项： crnl, fork, bind, range, tcpwrap, pf, max-children, backlog, mss, su, reuseaddr, retry, cool-write；unix-connect:<fille_name>指定地址file_name的unix domain socket，如果未指定地址，或者该地址不是一个unix 域亦或者或者没有进程绑定此地址，则报错。选项组： FD,SOCKET,NAMED,RETRY,UNIX。有用的选项：bind。unix-listen:<fille_name>监听file_name指定地址的unix socket，并且接受（accept）新的连接，同样地，如果指定了地址但不是一个unix domain地址则报错。当然尽管指定了一个unix 域地址，也有可能会因为某个原因（比如前一个连接未unlink）导致绑定（bind）失败。注意，打开该地址后通常会阻塞进程，直到一个客户端连接。从socat 1.4.3 开始，关闭socket后会自动删除对应的文件系统条目（同样地，建议查看unlink-close选项）。选项组：FD,SOCKET,NAMED,LISTEN,CHILD,RETRY,UNIX；有用的选项：UNIX-CONNECT, UNIX-RECVFROM, U…

学习uboot中 U_BOOT_CMD命令参数编程
type: item
date: 2020-07-03T18:14:00+08:00
description: get uboot U_BOOT_CMD usage学习到一个奇淫技能，这里总结如下。方便以后工程实现。在uboot中大量的命令交互，这些命令都对应其参数、help、和命令处理函数。通常做法去解析参数名称后遍历每一个命令名称,选择执行。也就是通常的switch、case做法。uboot给出了不一样的操作。先看uboot怎么做。定义命令处理函数；cmd/version.c#L17static int do_version(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { char buf[DISPLAY_OPTIONS_BANNER_LENGTH]; printf(display_options_get_banner(false, buf, sizeof(buf))); #ifdef CC_VERSION_STRING puts(CC_VERSION_STRING "\n"); #endif #ifdef LD_VERSION_STRING puts(LD_VERSION_STRING "\n"); #endif #ifdef CONFIG_SYS_COREBOOT printf("coreboot-%s (%s)\n", lib_sysinfo.version, lib_sysinfo.build); #endif return 0; }申明该命令；cmd/version.c#L35U_BOOT_CMD( version, 1, 1, do_version, "print monitor, compiler and linker version", "" );之后对于对应console 键入命令version就能够查找到该命令处理函数 do_version 执行。接下来，剖析背后细节。对于do_version通过U_BOOT_CMD完成了函数申明。include/command.h#L368#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \ U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)include/command.h#L325#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \ ll_entry_declare(struct cmd_tbl, _name, cmd) = \ U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \ _usage, _help, _comp);include/linker_lists.h#L70#define ll_entry_declare(_type, _name, _list) \ _type _u_boot_list_2_##_list##_2_##_name __aligned(4) \ __attribute__((unused, \ section(".u_boot_list_2_"#_list"_2_"#_name)))include/command.h#L353#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, \ _help, _comp) \ { #_name, _maxargs, NULL, 0 ? _cmd : NULL, _usage, \ _CMD_HELP(_help) _CMD_COMPLETE(_comp) }include/command.h#L237#ifdef CONFIG_AUTO_COMPLETE # define _CMD_COMPLETE(x) x, #else # define _CMD_COMPLETE(x) #endif #ifdef CONFIG_SYS_LONGHELP # define _CMD_HELP(x) x, #else # define _CMD_HELP(x) #endif最终U_BOOT_CMD申明定义了结构体类型为cmd_tbl 的变量_u_boot_list_2_cmd_2_version 并且完成了该命令的初始化赋值。struct cmd_tbl _u_boot_list_2_cmd_2_version __aligned(4) __attribute__((unused, section(".u_boot_list…

在linux 下通过vscode调试elf可执行文件
type: item
date: 2020-06-30T17:45:00+08:00
description: how to use vscode debug elf ?elf 是linux 下可执行可链接文件（executable and linkable format）。通过gcc/make 我们很容易编译出我们需要的elf文件，借助vscode可以在ubuntu图形化调试该程序，再也不用在gdb命令操作了。如下是elf文件结构，包含文件头（elf header）和代码、数据区索引表（program header table、section header table）和对应代码区、数据区。明白了如上文件结构，还需要具体解答如下疑惑。什么文件可以被调试？通过file命令对比可以知道用以调试的文件包含 with debug_info。$file release_bin release_bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=b057c6d9ce31addd0db181d567845dbc1fe69013, for GNU/Linux 3.2.0, not stripped可以被调试的文件。$file debug_bin debug_bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3c0501fa666e6fb8fdabad385772ed37053fca6f, for GNU/Linux 3.2.0, with debug_info, not strippeddebug 版本额外包含什么信息？$readelf -a debug_bin |grep debug [30] .debug_aranges PROGBITS 0000000000000000 000c1ba4 [31] .debug_info PROGBITS 0000000000000000 000c9e44 [32] .debug_abbrev PROGBITS 0000000000000000 0014b504 [33] .debug_line PROGBITS 0000000000000000 001591d9 [34] .debug_str PROGBITS 0000000000000000 001b50e3 [35] .debug_ranges PROGBITS 0000000000000000 00206cb0 [36] .debug_macro PROGBITS 0000000000000000 0020f540如上可调式的elf文件中增加包含 debug_aranges、debug_info等7个section存储包含数组、文件信息、行数、字符串、宏等调试信息。可以通过 --debug-dump=aranges/info/abbrev/line/str/ranges/macro分别显示对应的 区信息。$readelf debug_bin --debug-dump=info|head -n 20 Contents of the .debug_info section: Compilation Unit @ offset 0x0: Length: 0x1027 (32-bit) Version: 4 Abbrev Offset: 0x0 Pointer Size: 8 <0>: Abbrev Number: 1 (DW_TAG_compile_unit) <c> DW_AT_producer : (indirect string, offset: 0x5537): GNU C99 9.2.1 20191008 -mtune=generic -march=x86-64 -g3 -O0 -std=gnu99 -ffunction-sections -fdata-sections -fcommon -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection <10> DW_AT_language : 12 (ANSI C99) <11> DW_AT_name : (indirect string, offset: 0x3ba4): app_main.c <15> DW_AT_comp_dir : (indir…