尝试遍历共享库的符号 table 时导致 C 指针分段
C pointer segmentation cause when tries to walk symbol table of shared library
我想知道是否有人能想到一个原因,当指针是:
1. 非空指针。
我想做的是遍历共享库并访问它们的符号 table。当我尝试访问 ELF 哈希 table 以获取符号 table.
中的符号数量时,就会发生分段
这在 x86 平台上没有被注意到。
只有在 MIPS64 平台上执行时才会发生。
代码基于此link:
How to interpret the dynamic symbol table in an ELF executable?
static void
btrace_dl_symtab_walk(struct dl_phdr_info *info,
btrace_dl_lib_t *ctx) {
ElfW(Dyn*) dyn;
ElfW(Sym*) sym = NULL;
ElfW(Word*) hash;
ElfW(Word) sym_cnt = 0;
char* strtab = NULL;
char* sym_name = NULL;
unsigned int i;
int j;
/*
* Make indicator to show all of them acomplished before going forward
*/
for (j = 0; j < info->dlpi_phnum; j++) {
if (info->dlpi_phdr[j].p_type == PT_DYNAMIC) {
dyn = (ElfW(Dyn)*)(info->dlpi_addr + info->dlpi_phdr[j].p_vaddr);
while(dyn->d_tag != DT_NULL) {
if (dyn->d_tag == DT_HASH) {
hash = (ElfW(Word*))dyn->d_un.d_ptr;
if (!hash) {
return;
}
/*
* SEGFAULT happens here
*/
printf("Before Seg Fault\n");
sym_cnt = *(hash + 1); //<=============== This line causes seg fault
printf("Never reached here\n");
} else if(dyn->d_tag == DT_GNU_HASH) {
/*
* Since there is no simply way to find entry count
* in GNU hash table, we have no choice but to
* count by hand
*/
uint32_t *buckets;
uint32_t *hashval;
hash = (ElfW(Word*))dyn->d_un.d_ptr;
buckets = hash + 4 + (hash[2]*sizeof(size_t)/4);
for (i = sym_cnt = 0; i < hash[0]; i++) {
if (buckets[i] > sym_cnt) {
sym_cnt = buckets[i];
}
}
if (sym_cnt) {
sym_cnt -= hash[1];
hashval = buckets + hash[0] + sym_cnt;
do {
sym_cnt++;
} while (!(*hashval++ & 1));
}
sym_cnt += hash[1];
}else if (dyn->d_tag == DT_STRTAB) {
strtab = (char*)dyn->d_un.d_ptr;
} else if (dyn->d_tag == DT_SYMTAB) {
sym = (ElfW(Sym*))dyn->d_un.d_ptr;
break;
}
dyn++;
}
break;
}
}
// Other acitivities
}
欢迎任何指导。谢谢
I was wondering if anyone can think of a reason how a read from a pointer could cause a segmentation when the pointer is: 1. non NULL pointer.
指针不是 NULL
的事实确实 不是 意味着您可以从中读取。它可能由于多种原因而无效,例如
char *p = mmap(...);
munmap(p, ...);
char c = p[0]; // p points into unmapped memory, SIGSEGV likely.
This is not noticed in x86 platform. It happens only when executing on MIPS64 platform.
您是否在两个平台上使用相同版本的 GLIBC?
如果我没记错的话,旧版本的 GLIBC 没有重新定位 DT_HASH
,但新版本会。这也可能是特定于体系结构的。
您需要打印 hash
的值,并将其与 dyn
的值进行比较。如果 hash
很小,您需要将其重新定位 info->dlpi_addr
。
我想知道是否有人能想到一个原因,当指针是: 1. 非空指针。
我想做的是遍历共享库并访问它们的符号 table。当我尝试访问 ELF 哈希 table 以获取符号 table.
中的符号数量时,就会发生分段这在 x86 平台上没有被注意到。 只有在 MIPS64 平台上执行时才会发生。
代码基于此link: How to interpret the dynamic symbol table in an ELF executable?
static void
btrace_dl_symtab_walk(struct dl_phdr_info *info,
btrace_dl_lib_t *ctx) {
ElfW(Dyn*) dyn;
ElfW(Sym*) sym = NULL;
ElfW(Word*) hash;
ElfW(Word) sym_cnt = 0;
char* strtab = NULL;
char* sym_name = NULL;
unsigned int i;
int j;
/*
* Make indicator to show all of them acomplished before going forward
*/
for (j = 0; j < info->dlpi_phnum; j++) {
if (info->dlpi_phdr[j].p_type == PT_DYNAMIC) {
dyn = (ElfW(Dyn)*)(info->dlpi_addr + info->dlpi_phdr[j].p_vaddr);
while(dyn->d_tag != DT_NULL) {
if (dyn->d_tag == DT_HASH) {
hash = (ElfW(Word*))dyn->d_un.d_ptr;
if (!hash) {
return;
}
/*
* SEGFAULT happens here
*/
printf("Before Seg Fault\n");
sym_cnt = *(hash + 1); //<=============== This line causes seg fault
printf("Never reached here\n");
} else if(dyn->d_tag == DT_GNU_HASH) {
/*
* Since there is no simply way to find entry count
* in GNU hash table, we have no choice but to
* count by hand
*/
uint32_t *buckets;
uint32_t *hashval;
hash = (ElfW(Word*))dyn->d_un.d_ptr;
buckets = hash + 4 + (hash[2]*sizeof(size_t)/4);
for (i = sym_cnt = 0; i < hash[0]; i++) {
if (buckets[i] > sym_cnt) {
sym_cnt = buckets[i];
}
}
if (sym_cnt) {
sym_cnt -= hash[1];
hashval = buckets + hash[0] + sym_cnt;
do {
sym_cnt++;
} while (!(*hashval++ & 1));
}
sym_cnt += hash[1];
}else if (dyn->d_tag == DT_STRTAB) {
strtab = (char*)dyn->d_un.d_ptr;
} else if (dyn->d_tag == DT_SYMTAB) {
sym = (ElfW(Sym*))dyn->d_un.d_ptr;
break;
}
dyn++;
}
break;
}
}
// Other acitivities
}
欢迎任何指导。谢谢
I was wondering if anyone can think of a reason how a read from a pointer could cause a segmentation when the pointer is: 1. non NULL pointer.
指针不是 NULL
的事实确实 不是 意味着您可以从中读取。它可能由于多种原因而无效,例如
char *p = mmap(...);
munmap(p, ...);
char c = p[0]; // p points into unmapped memory, SIGSEGV likely.
This is not noticed in x86 platform. It happens only when executing on MIPS64 platform.
您是否在两个平台上使用相同版本的 GLIBC?
如果我没记错的话,旧版本的 GLIBC 没有重新定位 DT_HASH
,但新版本会。这也可能是特定于体系结构的。
您需要打印 hash
的值,并将其与 dyn
的值进行比较。如果 hash
很小,您需要将其重新定位 info->dlpi_addr
。