内核中dump_stack的实现原理(2) —— symbol
环境
正文
static __printf(, )
void __check_printsym_format(const char *fmt, ...)
{
} static inline void print_symbol(const char *fmt, unsigned long addr)
{
__check_printsym_format(fmt, "");
__print_symbol(fmt, (unsigned long)
__builtin_extract_return_addr((void *)addr));
}

/* Look up a kernel symbol and print it to the kernel messages. */
void __print_symbol(const char *fmt, unsigned long address)
{
char buffer[KSYM_SYMBOL_LEN]; sprint_symbol(buffer, address); printk(fmt, buffer);
}
/**
* sprint_symbol - Look up a kernel symbol and return it in a text buffer
* @buffer: buffer to be stored
* @address: address to lookup
*
* This function looks up a kernel symbol with @address and stores its name,
* offset, size and module name to @buffer if possible. If no symbol was found,
* just saves its @address as is.
*
* This function returns the number of bytes stored in @buffer.
*/
int sprint_symbol(char *buffer, unsigned long address)
{
return __sprint_symbol(buffer, address, , );
}
/* Look up a kernel symbol and return it in a text buffer. */
static int __sprint_symbol(char *buffer, unsigned long address,
int symbol_offset, int add_offset)
{
char *modname;
const char *name;
unsigned long offset, size;
int len; address += symbol_offset;
name = kallsyms_lookup(address, &size, &offset, &modname, buffer);
if (!name)
return sprintf(buffer, "0x%lx", address - symbol_offset); if (name != buffer)
strcpy(buffer, name);
len = strlen(buffer);
offset -= symbol_offset; if (add_offset)
len += sprintf(buffer + len, "+%#lx/%#lx", offset, size); if (modname)
len += sprintf(buffer + len, " [%s]", modname); return len;
}
上面的第11行的kallsyms_lookup就是根据address获取size,offset,modname
/*
* Lookup an address
* - modname is set to NULL if it's in the kernel.
* - We guarantee that the returned name is valid until we reschedule even if.
* It resides in a module.
* - We also guarantee that modname will be valid until rescheduled.
*/
const char *kallsyms_lookup(unsigned long addr,
unsigned long *symbolsize,
unsigned long *offset,
char **modname, char *namebuf)
{
const char *ret; namebuf[KSYM_NAME_LEN - ] = ;
namebuf[] = ; if (is_ksym_addr(addr)) {
unsigned long pos; pos = get_symbol_pos(addr, symbolsize, offset);
/* Grab name */
kallsyms_expand_symbol(get_symbol_offset(pos),
namebuf, KSYM_NAME_LEN);
if (modname)
*modname = NULL; ret = namebuf;
goto found;
} /* See if it's in a module or a BPF JITed image. */
ret = module_address_lookup(addr, symbolsize, offset,
modname, namebuf);
if (!ret)
ret = bpf_address_lookup(addr, symbolsize,
offset, modname, namebuf); found:
cleanup_symbol_name(namebuf);
return ret;
}






static unsigned long get_symbol_pos(unsigned long addr,
unsigned long *symbolsize,
unsigned long *offset)
{
unsigned long symbol_start = , symbol_end = ;
unsigned long i, low, high, mid; /* This kernel should never had been booted. */
if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
BUG_ON(!kallsyms_addresses);
else
BUG_ON(!kallsyms_offsets); /* Do a binary search on the sorted kallsyms_addresses array. */
low = ;
high = kallsyms_num_syms; while (high - low > ) {
mid = low + (high - low) / ;
if (kallsyms_sym_address(mid) <= addr)
low = mid;
else
high = mid;
} /*
* Search for the first aliased symbol. Aliased
* symbols are symbols with the same address.
*/
while (low && kallsyms_sym_address(low-) == kallsyms_sym_address(low))
--low; symbol_start = kallsyms_sym_address(low); /* Search for next non-aliased symbol. */
for (i = low + ; i < kallsyms_num_syms; i++) {
if (kallsyms_sym_address(i) > symbol_start) {
symbol_end = kallsyms_sym_address(i);
break;
}
} /* If we found no next symbol, we use the end of the section. */
if (!symbol_end) {
if (is_kernel_inittext(addr))
symbol_end = (unsigned long)_einittext;
else if (IS_ENABLED(CONFIG_KALLSYMS_ALL))
symbol_end = (unsigned long)_end;
else
symbol_end = (unsigned long)_etext;
} if (symbolsize)
*symbolsize = symbol_end - symbol_start;
if (offset)
*offset = addr - symbol_start; return low;
}
/*
* Find the offset on the compressed stream given and index in the
* kallsyms array.
*/
static unsigned int get_symbol_offset(unsigned long pos)
{
const u8 *name;
int i; /*
* Use the closest marker we have. We have markers every 256 positions,
* so that should be close enough.
*/
name = &kallsyms_names[kallsyms_markers[pos >> ]]; /*
* Sequentially scan all the symbols up to the point we're searching
* for. Every symbol is stored in a [<len>][<len> bytes of data] format,
* so we just need to add the len to the current pointer for every
* symbol we wish to skip.
*/
for (i = ; i < (pos & 0xFF); i++)
name = name + (*name) + ; return name - kallsyms_names;
}
/*
* Expand a compressed symbol data into the resulting uncompressed string,
* if uncompressed string is too long (>= maxlen), it will be truncated,
* given the offset to where the symbol is in the compressed stream.
*/
static unsigned int kallsyms_expand_symbol(unsigned int off,
char *result, size_t maxlen)
{
int len, skipped_first = ;
const u8 *tptr, *data; /* Get the compressed symbol length from the first symbol byte. */
data = &kallsyms_names[off];
len = *data;
data++; /*
* Update the offset to return the offset for the next symbol on
* the compressed stream.
*/
off += len + ; /*
* For every byte on the compressed symbol data, copy the table
* entry for that byte.
*/
while (len) {
tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
data++;
len--; while (*tptr) {
if (skipped_first) {
if (maxlen <= )
goto tail;
*result = *tptr;
result++;
maxlen--;
} else
skipped_first = ;
tptr++;
}
} tail:
if (maxlen)
*result = '\0'; /* Return to offset to the next symbol. */
return off;
}
内核中dump_stack的实现原理(2) —— symbol的更多相关文章
- 内核中dump_stack的实现原理(3) —— 内核函数printk的实现
参考内核文档: Documentation/printk-formats.txt 在内核中使用dump_stack的时候可以看到如下用法: static inline void print_i ...
- 内核中dump_stack的实现原理(1) —— 栈回溯
环境 Aarch64 Qemu aarch64-linux-gnu-gcc linux-4.14 概述 栈回溯的目的是将函数的调用栈打印出来,对于分析函数调用和debug系统异常会很有帮助 ...
- 内核中dump_stack()的实现,并在用户态模拟dump_stack()【转】
转自:https://blog.csdn.net/jasonchen_gbd/article/details/44066815?utm_source=blogxgwz8 版权声明:本文为博主原创文章, ...
- linux内核中打印栈回溯信息 - dump_stack()函数分析【转】
转自:http://blog.csdn.net/jasonchen_gbd/article/details/45585133 版权声明:本文为博主原创文章,转载请附上原博链接. 目录(?)[-] ...
- Openvswitch原理与代码分析(5): 内核中的流表flow table操作
当一个数据包到达网卡的时候,首先要经过内核Openvswitch.ko,流表Flow Table在内核中有一份,通过key查找内核中的flow table,即可以得到action,然后执行acti ...
- Linux 2.6内核中新的锁机制--RCU
转自:http://www.ibm.com/developerworks/cn/linux/l-rcu/ 一. 引言 众所周知,为了保护共享数据,需要一些同步机制,如自旋锁(spinlock),读写锁 ...
- Linux VFS中write系统调用实现原理【转】
转自:http://blog.chinaunix.net/uid-28362602-id-3425881.html 目录 用户空间的write函数在内核里面的服务例程为sys_write Vfs_wr ...
- [php-src]理解Php内核中的函数与INI
内容均以php-5.6.14为例. 一. 函数结构 内核中定义一个php函数使用 PHP_FUNCTION 宏 包装,扩展也不例外,该宏在 ./main/php.h:343 有着一系列类似以 PHP ...
- linux内核中异步通信机制--信号处理机制【转】
转自:http://blog.csdn.net/lu_embedded/article/details/51131663 什么是异步通信?很简单,一旦设备准备好,就主动通知应用程序,这种情况下应用程序 ...
随机推荐
- python3 修改excel 单元格的值(xlsx)
excel code #coding=utf- import os.path import os from openpyxl.reader.excel import load_workbook # e ...
- vue 实现模块上移下移 实现排序
效果图 上移 下移 首先想到的是 数组的相互替换嘛 <template> <div> <div class="box" v-for="(it ...
- Node节点如何加入K8S集群
k8s集群中,有时候发现有些节点状态为 NotReady,如何修复为Ready状态呢? [root@k8s-master~]# kubectl get nodes NAME STATUS ROLES ...
- Web Api 实现删除功能接口
删除数据 [HttpDelete] public ResultModel DeleteDataById(int id) { var result = new ResultModel(); //实例化数 ...
- web-debug-server
web-debug-server 项目来自:https://github.com/itzg/web-debug-server 这位大哥的镜像做的很有意思:一个很小的web debug服务器,访问它可以 ...
- Apache信息头
package org.apache.http; public final class HttpHeaders { public static final String ACCEPT = " ...
- 迭代子(Iterator)模式
迭代子模式又叫做游标模式.迭代子模式可以顺序地访问一个聚集中的元素而必暴露聚集的内部表象. 1. 聚集和Java聚集 多个对象在一起形成的总体形成聚集(Aggregate),聚集对象是能够包容一组对 ...
- 百度前端技术学院task16源代码
欢迎访问我的github:huanshen 做这道题目的时候遇到了很多困难. 1.怎么给空对象添加数据,愣是不知道从哪里下手:遍历对象,一个个输出操作: 2.中英文的正则表达式不知道,赶紧去百度: 3 ...
- PTA 甲级 1139
https://pintia.cn/problem-sets/994805342720868352/problems/994805344776077312 其实这道题目不难,但是有很多坑点! 首先数据 ...
- php 获取当前IP地址
function getIP() { return isset($_SERVER["HTTP_X_FORWARDED_FOR"])?$_SERVER["HTTP_X_FO ...