终于开始进入lab2的内容了。不过在进入内存管理的世界之前,先花点时间完善一下之前的mon_backtrace功能,扩展一下kernel的debug信息,还是很有必要的。
JOS中trace功能是利用stabs实现的。关于stabs的定义格式以及其他信息,可参考:。简言之,通过设置gcc的参数-gstabs(定义于GNUmakefile, Line 73: CFLAGS += -Wall -Wno-format -Wno-unused -Werror -gstabs -m32),编译时将源代码相关信息以stabs格式嵌入目标代码的符号表中,供程序运行时提供调试信息。
在文件kern/kdebug.c中定义了函数debuginfo_eip(). 它搜索结构__STAB_BEGIN__,寻找指定地址所对应的函数和函数内的偏移行数。结构 __STAB_BEGIN__ 定义在链接文件kern/kernel.ld中。其具体实现如下:
1. 初始化变量info,并判断外部变量__STAB_BEGIN__,__STAB_END__,__STABSTR_BEGIN__和 __STABSTR_END__的关系。
2. 通过函数调用 stab_binsearch(stabs, &lfile, &rfile, N_SO, addr); 查找addr所在的文件。
3. 在该文件中查找对应的函数名。当找到时,通过如下语句设置info的值:
if (stabs[lfun].n_strx < stabstr_end - stabstr)
info->eip_fn_name = stabstr + stabs[lfun].n_strx;
其作用为:当找到了函数所对应的stabs(即stabs[lfun])时,判断该stabs的字符串偏移是否在字符串表的范围之内。如果在其范围内,则将代表字符串表起始位置的指针stabstr偏移该偏移值stabs[lfun].n_strx,此时对应的字符串值即为函数名。
如下语句处理地址:
info->eip_fn_addr = stabs[lfun].n_value;
addr -= info->eip_fn_addr;
假设函数起始位置为0x00a0, addr的值为0x00c0, 则info->eip_fn_addr = 0x00a0,addr = (0x00c0 - 0x00a0) = 0x0020,为函数内的偏移位置。
现在,让我们来添加查找函数内addr对应位置所在的行号的功能。
查看文件inc/stab.h,有如下两行:
#define N_SLINE 0x44 // text segment line number
#define N_PSYM 0xa0 // parameter variable
因此,N_SLINE即为我们所要的line的类型,而N_PSYM为参数。
类似于前面的代码,添加如下行:
stab_binsearch(stabs, &lline, &rline, N_SLINE, addr);
if(lline <= rline)
info->eip_line = stabs[lline].n_desc;
添加获得参数数目的代码:
while(lline <= rline){
if(stabs[lline++].n_type == N_PSYM)
info->eip_fn_narg++;
}
在kern/monitor.c中,以eip的值作为参数,通过调用函数debuginfo_eip即可获得eip所在位置处对应的文件名,行号,函数名,以及偏移值。偏移值为:eip-eip_fn_addr。
此外应注意的是,函数名eip_info.eip_fn_name对应的字符串包括了":"和其后的一些与函数名无关的内容,因此必须通过eip_fn_namelen获得函数名真正的长度。
最后,关于函数stab_binsearch(), 其原理为(以下分析可能有误,先记录下来,希望以后能有时间更新):
假设最初时,l=1, r=16, 则从中点位置m=true_m=8处开始往l方向查找。假设当m=5时找到了同类型的,此时比较该stab对应的位置与addr的大小。如果addr=4, 则region_right=m-1=4(为什么是m-1而不是m呢?不明白), 只要在m的左端查找region_left即可; 而如果addr=6, 则region_left=m=5, 此时m的取值区间5-8已经查找过了,因此只要查找剩下的一半即可,故令l=true_m+1=9, 在区间9-16间查找region_right的位置。
(转贴请注明: by: chunchengfh, from: chunchengfh.cublog.cn)
阅读(2806) | 评论(0) | 转发(0) |