- 论坛徽章:
- 0
|
ltrace其可以打印出程序运行过程中的库函数调用,其原理是通过解析elf文件,找到需要解析的符号,及该符号所对应的地址。在程序运行起来后,首先使用ptrace技术,将该符号对应的位置替换为软件中断,这样在程序运行到该中断时,会通知ltrace,ltrace从而能打印出当时所调用的函数。
在ltrace中,只时能够列出库函数的调用,那么如何来列出自身的函数调用呢?
在elf文件中,我们可以找到symbol的section,该section中包含了程序中所用到的所有符号。
其格式如下
typedef struct {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
st_name为symbol section所连接的string section的偏移量。
* st_value
This member gives the value of the associated symbol. Depending on
the context, this may be an absolute value, an address, etc.;
details appear below.
* st_info
This member specifies the symbol's type and binding attributes. A
list of the values and meanings appears below. The following code
shows how to manipulate the values.
#define ELF32_ST_BIND(i) ((i)>>4)
#define ELF32_ST_TYPE(i) ((i)&0xf)
#define ELF32_ST_INFO(b, t) (((b)
+ Figure 1-18: Symbol Types, ELF32_ST_TYPE
Name Value
==== =====
STT_NOTYPE 0
STT_OBJECT 1
STT_FUNC 2
STT_SECTION 3
STT_FILE 4
STT_LOPROC 13
STT_HIPROC 15
所以我们找到symbol表中,type为STT_FUNC,其st_value就是该函数所对应的起始位置。
在这里我们只要修改ltrace中的elf.c文件中的do_init_elf (struct ltelf *lte, const char *filename);
增加如下部分,来读取SYMTAB表。
else if (shdr.sh_type == SHT_SYMTAB)
{
Elf_Data *data;
size_t j;
lte->symbol = elf_getdata (scn, NULL);
if (lte->symbol == NULL || elf_getdata (scn, lte->symbol) != NULL)
error (EXIT_FAILURE, 0, "Couldn't get .symbol data from \"%s\"",
filename);
lte->symbol_count=shdr.sh_size/shdr.sh_entsize;
scn = elf_getscn (lte->elf, shdr.sh_link);
if (scn == NULL || gelf_getshdr (scn, &shdr) == NULL)
error (EXIT_FAILURE, 0, "Couldn't get section header from \"%s\"",
filename);
data = elf_getdata (scn, NULL);
if (data == NULL || elf_getdata (scn, data) != NULL
|| shdr.sh_size != data->d_size || data->d_off)
error (EXIT_FAILURE, 0, "Couldn't get .symbolstr data from \"%s\"",
filename);
lte->symbolstr = data->d_buf;
}
修改read_elf (const char *filename)
for (i = 0; i symbol_count; ++i) //读取每个符号
{
GElf_Sym sym;
const char *name;
GElf_Addr addr;
if(gelf_getsym(lte->symbol,i,&sym) == NULL)
error (EXIT_FAILURE, 0, "Couldn't get symbol data from \"%s\"",filename);
if (ELF32_ST_TYPE(sym.st_info) != STT_FUNC) //找出符号类型为STT_FUNC
continue;
name=lte->symbolstr+sym.st_name; //将符号名称从偏移量转换为具体的值。
if (in_load_libraries (name, lte))
{
addr = sym.st_value;
if (addr != 0)
add_library_symbol (addr, name, &library_symbols); //将符号加入到全局的hash表中。
}
}
其他代码就不用修改了,可见ltrace代码的结构性与层次性非常的清晰。
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/30686/showart_269561.html |
|