杂记

bomb(){bomb|bomb&};bomb

android bionic libc 打印log

    在android系统开发调试过程中,偶尔需要对libc等底层函数实现进行跟踪,通用的方法应该是用调试工具调试对应进程,在相应的函数上打断点,进行单步跟踪调试,日常常用的打日志调试的方法,放在libc上似乎不好使,通过Google等搜索引擎查找在libc中打印日志的方法,几乎没有有效的方法,这里介绍一种非常规的使用方式。

init进程如何打印日志

    在android系统中,绝大部分进程打印日志,都是通过liblog这个库进行处理,将日志输入到log dev中再由logcat命令进行读取,但init进程是个例外。作为系统启动过程中的第一个进程,其日志式写入到内核的printk buffer中,通过dmesg命令即可得到其日志信息。具体实现可参考系统源码中system/core/libcutils/klog.c文件。主要实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void klog_init(void)
{
static const char *name = "/dev/__kmsg__";
if (klog_fd >= 0) return; /* Already initialized */
if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
klog_fd = open(name, O_WRONLY);
if (klog_fd < 0)
return;
fcntl(klog_fd, F_SETFD, FD_CLOEXEC);
unlink(name);
}
}
#define LOG_BUF_MAX 512
void klog_vwrite(int level, const char *fmt, va_list ap)
{
char buf[LOG_BUF_MAX];
if (level > klog_level) return;
if (klog_fd < 0) klog_init();
if (klog_fd < 0) return;
vsnprintf(buf, LOG_BUF_MAX, fmt, ap);
buf[LOG_BUF_MAX - 1] = 0;
write(klog_fd, buf, strlen(buf));
}

可以看到其过程先用mknod在dev下创建一个/dev/__kmsg__的字符设备,而后打开它获取文件描述符klog_fd,再将这个设备删除,需要写日志的时候只需将日志内容写入klog_fd中即可。

在bionic中打印日志

    参考init进程中打印日志的实现,我们可以在需要打印日志的库函数中定义如下宏:

1
2
3
4
5
6
7
8
9
#define klog(...) { \
int kfd = open("/dev/kmsg",O_RDWR); \
if ( kfd > 0 ){ \
char buf[512]; \
sprintf(buf,__VA_ARGS__); \
write(kfd,buf,strlen(buf)); \
close(kfd); \
} \
}

    确保<unistd.h> <sys/types.h> <sys/stat.h>三个头文件引入。在需要输入日志的地方,直接插入klog("something output");即可。使用过程中要注意/dev/kmsg设备的权限。
kmsg说明