- 博客(77)
- 资源 (7)
- 收藏
- 关注
原创 使用bcc/memleak定位C/C++应用的内存泄露问题
但在实际的内存泄露问题定位过程中,我们只能通过这种调试方式得知内存分配的调用栈回溯,具体问题的解决还要根据这一栈信息确定遗忘释放内存的相关代码;依笔者的经验,有时需要多次修改才能确定内存不再泄露,因为同一处申请的内存,在应用代码中可能有多个地方泄露掉。命令将增长的内存(即对应着泄露的内存数据)导出到文件,之后根据文件中的内存数据,结合代码推测出可能出现内存泄露的代码。在笔者的那篇文章后面也提到,这种方法对泄露的内存数据很敏感,数据的“质量”直接决定了能否定位到存在缺陷的C/C++代码;
2024-11-23 22:32:40
1244
原创 基于USDT的日志优化
尽管安卓系统的日志管理系统是原生的,但这么大的日志生成量确实给设备带来比较大的负载(尤其当日志需要保存到文件中时)。这固然与嵌入式软件研发管理脱不开关系,但我们仍然需要寻找相应的解决办法——尤其对于一个没有研发管理权限的开发人员(如笔者),不可能限制其他的开发人员不在代码中加入过量的、循环的日志信息。一种方案是,通过编译时的宏定义来控制这些日志信息是否会生成,但这也造成了一问题:用于生产的嵌入式应用很可能因编译时的宏定义,不会生成这些冗余的调试信息,而一些软件异常只能在实际应用中发生。
2024-03-09 20:32:22
1004
原创 为raspberrypi编译bpftrace调试工具
例如,树苺派的Linux内核版本为6.1,那么确认该版本内核的(初始)发布日期(是2023年初发布的),然后选择时间上相近的。系统,二者的Linux内核版本大致相同,均为6.1版本。之后,我们需要在debian安装其他依赖库(而不编译所有的依赖库,否则耗时太久了)。工具的过程,按照这些操作,笔者为工作中的嵌入式设备也制作了可用的。然而工作中,笔者因使用的嵌入式设备比较老,使用的版本为。的正常运行,可能还需要访问内核的头文件,这就需要使能。然后,笔者为树莓派的内核使能了相关的内核选项,详见。
2024-03-03 20:19:02
1537
1
原创 在Ubuntu-12.04环境下使用新的Rust开发工具
这种修改、替换应用使用的动态链接器(从而间接指定使用的glibc动态库)的方法,可以方便地为老系统安装一些新的应用。在一些工作环境受限的条件下(如不能安装新的系统作为开发环境),能够让我们不受过多的限制,不影响我们对开发工具的选择。
2024-02-17 21:45:25
1167
1
原创 RISCV汇编与Linux内核传参
这种方法生成的可执行文件是静态链接的,不依赖动态链接器也不能调用标准C语言库提供的功能。第二种方法是可以连接到标准C语言库的,而且是动态链接的。的C语方库的这一过程整合到全志D1设备上运行,就可以直接在汇编代码中引用柡准C语言库提供的变量及函数。这一点可以参考上面帖出的Linux内核源码:因在riscv平台上,C语言函数栈是向下生长的,内核在栈上构造这些信息时,参数的写入恰好与。而该设备上也缺少整套的。需要说明的是,在使用C语言库编写汇编应用时,需要严格地遵守。的应用层汇编的开发,有了一个可行的方法。
2023-11-26 19:09:19
640
原创 获取系统中各应用的运行时间
因为笔者的树莓派内核的配置选项为该值。但在其他嵌入式设备上运行结果是正确的(感兴趣的可以尝试一下)——该方案通常只适用于嵌入式设备,而不适合在。由此可判定各个应用进程的开始运行时的系统启动时间,其与当前系统已运行的时间之差,就是应用进程已持续运行的时间。另一种可行的方案是,增加一个动态库,当动态库被加载时会自动执行一个函数,记录应用开始运行时的系统时间。不过该方案的缺陷是需要修改各个应用的代码,并增加进程间通信的机制(通过上面的。这也是笔者在该分享前部分说的,相比之下,另两种方案的可取之处。
2023-05-14 16:26:45
777
原创 Rust下的JSON动态反序列化
Rust下的结构体反序列化在之前的一篇文章中,笔者介绍了在Rust编程语言中,使用serde_json包对结构体的序列化和反序列化的基本操作;重点是在定义结构体时,继承源于serde包的 Deserialize及Serialize特性:use serde_json;use serde::{Deserialize, Serialize};#[derive(Serilize, Deserialize, Debug)]struct rust_struct { member_0: String,
2022-05-21 15:18:32
1637
原创 为嵌入式设备编译paho.mqtt.rust应用
为嵌入式MIPS准备rust开发环境在此前的一篇文章中,笔者对Rust的交叉编译开发环境的安装作了说明,演示了简单Hello World应用的交叉编译。笔者在该文章中记录了较为复杂的rust应用(paho.mqtt.rust)的编译过程,目柡设备为运行openwrt系统的MT7628设备。此处简要重复笔者安装嵌入式MIPS的rust交叉编译工具链的过程。首先,以根用户权限安装rust编译器:curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs
2022-05-01 13:30:57
940
原创 PLY:嵌入式Linux环境下的内核探测工具
简单Linux系统环境下的内核探测在笔者之前的文章中提到,基于内核eBPF探针的常用工具主要bpftrace、bcc,二者复杂的依赖库使得其在嵌入式Linux系统环境下常常是不可用的。截止目前,一些嵌入式SDK(例如buildroot及openwrt等)未提供这两个性能分析工具的自动化构建功能。一种可行的方案是参考Linux内核源码samples/bpf下的示例编写基于eBPF的C代码,并编译生成BTF目柡文件和可执行应用,用于嵌入式设备上的性能分析。这种方案可行但实施的效率较低。幸运的是,同属于iovi
2022-04-17 08:45:19
1202
原创 虚拟动态共享库VDSO的实现机制
失落的strace在《BPF Performance Tools》一书中,作者评批strace用于监测系统应用的创建execve时写道:The current implementation of strace(1) uses breakpoints that can greatly slow the target (over 100x), making it dangerous for production use. ...Also, this example traces the exec() sy
2022-04-05 20:44:22
1848
原创 为Evince-PDF添加灰色背景
Ubuntu系统的默认PDF阅读软件ubuntu操作系统自带了Evince-PDF阅读器,其优点是简单便捷,不过与其他常用的PDF阅读器相比,缺少很多定制化的选项,例如为避免眼睛疲劳的替换阅读界面背景颜色的功能。使用GNU/Linux操作系统的一个优势是,可以获取从内核至应用各个层面的软件源码,并加以修改后重新编译,可以方便地实现所需的新功能。笔者在该文章中记录了为Evince阅读器添加灰色背景的操作过程。作为对比,在添加该功能之前,笔者打开SystemTap教程文档的背景如下:修改之后,在Evinc
2022-03-20 12:08:35
1221
原创 基于Linux内核的应用探测: uprobe
基于Linux内核的应用性能分析技术Linux内核有良好的分层设计,但了解并实时跟踪内核的行为并不容易。为此,Linux内核开发者实现了跟踪点(tracepoint)、性能监测(perf_event)、函数跟踪(ftrace)等功能,用于Linux的调试和性能分析。最近几年已经成熟的eBPF内核子系统带来了内核性能分析技术的飞跃,常用的主要有bcc、bpftrace;二者同属于github的iovisor用户,直译出来即为“输入输出监测”,即性能监测。这些工具同样可用于应用层的性能分析,这是笔者关注的功能
2022-03-13 20:31:28
4515
原创 SystemTap应用跟踪探测的使用
用户静态定义探测点USDTusdt(User-Statically-Defined-Tracepoint)是一种向应用插入跟踪点的技术方案,其特点是跟踪点的插入是静态的,通常需要修改应用的源码并再次编译。该技术方案源于DTrace,不过usdt应用跟踪的功能在Systemtap和bcc等内核跟踪调试工具中已有良好的支持。Systemtap开源工具提供了sys/sdt.h头文件,该头文件没有相应用C代码实现,仅仅提供了多个STAP_PROBExxx和DTRACE_PROBExxx宏定义。这些宏定义通过GCC
2021-11-07 23:23:41
862
原创 嵌入式设备上SystemTap调试工具使用
SystemTap调试工具简介SystemTap调试器常用于Linux内核的动态调试,不过该工具集也可用于应用的跟踪调试。随着Linux内核及其应用程序的复杂度不断加深,使用一些在功能上区别于传统的GDB调试工具就变得越来越重要了。这类调试工具具有低延时(Low Latency),高性能,动态调试的特点。嵌入式Linux设备的系统软件通常不需从头开发,这些调试工具可以帮助开发者快速理解Linux内核、系统层软件,同时定位、解决一些软件上的缺陷。SystemTap的工作机制比较特殊,它会将开发者编写的Sy
2021-10-31 21:54:43
1346
原创 BPF示例在64位ARM上的调试
eBPF调试工具eBPF作为Linux内核中调试功能强大的子系统,相应的应用层调试工具有很多,例如bpftool/bpftrace,以及提供了Lua和Python调试接口的bcc;内核信息收集、性能分析的开源工具SystemTap也用到了内核的eBPF功能。不过笔者希望在嵌入式设备上使用eBPF提供的调试功能,一种方法是使用开源的SDK(例如yocto,笔者未尝试过)自动化构建这些调试工具(否则就需要手动交叉编译);另一种方法是将某个支持arm64架构的Linux发行版(例如运行debian系统的树莓派)
2021-10-24 22:18:05
4314
5
原创 BPF内核调试开发坏境的搭建
BPF的内核调试方法一直以来,笔者对BPF功能的认知一直停留在与tcpdump工具进行网络抓包相关;最近几年BPF已成为内核的顶级子系统,从网络抓包的内核支持模块演进成为内核调试、性能跟踪的复杂模块。其对内核的调试(也可用于应用的调试)是动态的;不过该动态调试过程并不需要编译内核模块并加载之,而是将调试应用编译成为eBPF字节码,并通过bpf系统调用将该字节码加载到内核中的BPF虚拟机中解析执行,或由内核中的BPF Jit编译为机器码后运行。这一调试机制使得其与传统的GDB调试方法相比,具有更低的延时和更
2021-10-17 22:41:15
3945
3
原创 GDB内存调试初探八
Linux/amd64的调用规则为了方便调试,笔者在PC机上直接调试简单的内存相关的应用;这需要了解x86_64的ABI,该文档对函数调用制定了一些限定规则,其中重要的有两点,第一点是参数的传参(非浮点参数):User-level applications use as integer registersfor passing the sequence: %rdi, %rsi, %rdx, %rcx, %r8 and %r9.The kernel interface uses %rdi, %rsi,
2021-10-10 22:37:36
1135
原创 GDB内存调试初探七
非main_arena的内存分配在初探六中提到,正常情况下创建一个新的线程时,会为新线程创建独立的arena,其类型为struct malloc_state。当一个线程退出时,其动态分配的堆内存不会被释放,而是通过malloc_state结构体中的next_free指针链接保存起来(那么当再次创建新线程时可复用):/* malloc/malloc.c */struct malloc_state { ... struct malloc_state * next; struct m
2021-10-03 21:44:39
1353
原创 应用OOM及子进程的创建
Linux应用内存分配失败的问题大型的嵌入式应用常占用巨量的内存。一些“杂揉、拼凑”而成的应用,常在一个应用中包含多个功能模块,例如音视频处理模块,系统控制模块等。这样的应用设计会带来一系列的内存问题,最主要的一个是音视频的应用会占用大量的内存空间,从而影响应用的运行性能。笔者根据以往的经验,列出一种与子进程创建相关的内存分配失败问题。当某个应用向Linux内核申请内存但内核无法满足时,内核会根据配置,选择性地杀掉该进程;该功能与OOM-Killer相关(注意,区别于安卓内核中的lowmemory-kil
2021-09-25 22:35:02
1099
原创 ARMv7-a的多寄存器Load/Store
多寄存器的加载与存储ARMv7-a架构的芯片提供了高效的寄存器数据加载与存储指令,一条指令可以从内存中加载多个寄存器,也可以将多个寄存器的数据存储至内存中。读写的内存必须是连续的;虽然数据量不大,但基于这些指令可以实现高效的数据拷贝、(软)中断的上下文保存、恢复,以及内核的任务切换、应用层的协程实现。Arm Architecture Reference Manual对这些指令做了详尽的说明:编写多寄存器的加载和存储示例ARMv7芯片提供了以上多种指令,原因是这些指令在加载、存储数据时,具体功能实现有
2021-09-19 23:02:38
644
原创 GDB内存调试初探六
内存访问越界的定位去年笔者分享了两篇内存访问越界的定位方法,第一种方法用到了mprotect系统调用设置内存属性,第二种方法则未用到该系统调用。两种方法对于调试用的简单应用都有效,不过笔者编写的调试应用是单线程的。在具体的工作实践中,只用到过第一种方法;因此不确定第二种方法效果如何。笔者认为这两种方法有一些缺点,某些情况下甚至可能会失效,例如系统调用产生的内存访问越界:read(fd, buf, buflen + overflowsize)。此外,第二种方法需要知晓具体的内存分配的数据结构,笔者希望通过本
2021-09-12 22:31:35
1297
原创 U-Boot的重定位实现机制
获取当前芯片平台的相关信息为了深入了解ARM 64位芯片架构,笔者为u-boot添加了archinfo命令,以获取CPU当前的工作状态等信息。不过在增加完整的64位ARM架构信息查看功能之前,笔者首先增加了简单的获取当前PC指针及栈指针的函数:diff --git a/arch/arm/lib/arch-info.c b/arch/arm/lib/arch-info.cnew file mode 100644index 00000000..b9bc9fd0--- /dev/null+++ b/a
2021-09-05 22:05:13
2406
1
原创 U-Boot启动Linux内核的简单实现
64位ARM Linux内核启动的环境要求在64位ARM处理器上,Linux内核启动前,对设备的环境要求主要有以下几点:内存(DDR)已初始化完成,禁用MMU,关闭数据缓存(dcache);蔽屏CPU中断,关闭指令缓存(icache);禁用驱动的DMA操作,防止Linux内核在启动过程中内存被IO设备访问;除此之外, Linux内核对64位ARM处理器的状态(例如异常级别,Exception Level)有一些细致的要求,这里不再探究,详细的说明请参考官方文档。U-Boot启动
2021-08-29 22:51:06
923
原创 GNU Makefile -- 规则依赖执行顺序和双冒号规则
Make的规则依赖执行顺序GNU Make的规则依赖有两种类型:普通依赖(normal prerequisites)和顺序依赖(order-only prerequisites)。对于普通依赖,其出现的顺序指定了依赖被更新的顺序。这一特性可以在一定程度上(非并行调用Make)隐含各依赖项之间的依赖关系,但不具备稳定性。笔者编写了简单的测试脚本:.PHONY: all foo bar cleanifeq ($(REORDER),yes)all: bar foo | orderedelseall:
2021-08-22 23:23:12
4833
原创 Rust对异步编程的支持
线程池与异步执行作为一名嵌入式底层开发人员,工作中很少遇到线程池和异步执行的概念。在Lua脚本语言中有一个协程的概念,与线程池的异步执行有一些相似,但仍存在很多区别。用户态应用创建一个线程,绝大部分时间处于阻塞的状态(如果不是这样,这个线程占用的CPU时间会很高);线程会占用一定的系统资源。当一个多线程的应用的大部分线程都处于一个阻塞的状态,那就会浪费很多的系统资源。此外,对于一些高并发的事件处理,若采用创建新的任务线程的方案,那么某些情况下创建的线程数量可能达到上百个甚至上千个。这两点都会浪费操作系统的
2021-08-15 23:18:40
1063
原创 Rust结构体的JSON序列化和反序列化
一个JSON的序列化问题与人聊天时偶然问到一个问题:“给定任意一个(C/C++)结构体,如何实现其JSON的序列化和反序列化,而不用专门编写相应的序列化、反序列化实现代码?”我摇摇头,表示不知如何实现这一功能;现在我也认为,这一功能对于C/C++,是不可能自动化实现的。不过对于其他的静态编译型编程语言,如Golang/Rust等,这一功能则相对容易实现。与Golang的反射机制(Reflection)不同,Rust使用到了trait机制。Rust的JSON序列化库serde提供了通用的序列化功能,诸多
2021-08-08 23:05:02
3936
原创 GNU Makefile--C/C++头文件依赖规则的生成
使用GCC编译器生成头文件依赖复杂的C/C++工程中的头文件比较多,在编写GNU Makefile时,手动指出其源代码文件的头文件依赖关系是不可行的,需要通过编译工具自动生成头文件的依赖关系。GNU GCC的-MXX命令行选项用于生成某个代码文件的依赖关系,通常使用的命令行选项为:-MT object.o -MP -MMD -MF object.d其中,-MT用于指定与源文件对应的目标文件名(此处为object.o);-MP指示GCC编译器为依赖的头文件增加伪目标规则;-MMD不会隐含增加-E编译选
2021-08-01 22:33:35
1182
原创 u-boot的自拷贝(重定位)
u-boot的加载地址早期的通用启动器(Universal Bootloader, u-boot)没有图形界面配置的功能,为某个设备修改配置的操作比较繁琐。较新版本的u-boot提供了图形化配置界面,可以在以下配置界面下修改u-boot的加载基地址(对应的配置项为CONFIG_SYS_TEXT_BASE):-> Boot options -> Boot images -> Text Base该地址指定了u-boot在内存中存放的起始地址,通常由SoC厂商的内置B
2021-07-25 21:41:53
1620
2
LuaARM.tar.xz
2020-08-09
LinuxARM.tar.xz
2020-04-12
c++-mprotect.tar.gz
2019-10-27
rootfs.ext2.xz
2019-08-04
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人