This is the mail archive of the
libc-help@sourceware.org
mailing list for the glibc project.
Re: sigsegv dereferencing l_addr in link_map
- From: Adhemerval Zanella <adhemerval dot zanella at linaro dot org>
- To: libc-help at sourceware dot org
- Date: Mon, 13 Jun 2016 09:40:30 -0300
- Subject: Re: sigsegv dereferencing l_addr in link_map
- Authentication-results: sourceware.org; auth=none
- References: <faa187fe19781ef6d0e67c582ab908e3 at carlo-kok dot com>
On 11/06/2016 19:12, Carlo Kok wrote:
> On some (ubuntu 14.04.4, libc 2.19-0ubuntu6.9) systems I'm getting a sigsegv when casting the link_map's l_addr to Elf64_Ehdr. This is something libgc does and works fine on most linux systems, but not all.
>
> What am I missing here, and if this isn't guaranteed to work, how else can I get all the loaded data segments.
Because _DYNAMIC is not an Elf64_Ehdr on all architectures. It is defined as:
elf/link.h
28 /* We use this macro to refer to ELF types independent of the native wordsize.
29 `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */
30 #define ElfW(type) _ElfW (Elf, __ELF_NATIVE_CLASS, type)
31 #define _ElfW(e,w,t) _ElfW_1 (e, w, _##t)
32 #define _ElfW_1(e,w,t) e##w##t
[...]
76 extern ElfW(Dyn) _DYNAMIC[];
bits/elfclass.h
11 #define __ELF_NATIVE_CLASS __WORDSIZE
So you need to use:
# pragma weak _DYNAMIC
extern ElfW(Dyn) _Dynamic[]
Such as:
--
#include <link.h>
#include <stdio.h>
#pragma weak _DYNAMIC
extern ElfW(Dyn) _DYNAMIC[];
int
main ()
{
int tag;
ElfW(Dyn) *dp;
struct link_map *cachedResult;
for (dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++)
{
if (tag == DT_DEBUG)
{
struct link_map *lm = ((struct r_debug *) (dp->d_un.d_ptr))->r_map;
if (lm != 0)
cachedResult = lm->l_next; /* might be NULL */
break;
}
}
printf ("%p cached result; %p dyn \n", (void*)cachedResult, (void*)dp->d_un.d_ptr);
while (cachedResult)
{
printf ("%p %p %s\n", (void*)cachedResult->l_addr, cachedResult->l_ld,
cachedResult->l_name);
ElfW(Ehdr) *e = (ElfW(Ehdr)*) cachedResult->l_addr;
printf ("machine: %d\n", e->e_machine); // CRASH here, first iteration.
cachedResult = cachedResult->l_next;
}
return 0;
}
--
$ gcc -Wall test.c -m32 -o test-m32
$ ./test-m32
0xf77a0c08 cached result; 0xf77a0904 dyn
0xf777b000 0xf777b2bc
machine: 3
0xf759c000 0xf774ddb0 /lib/i386-linux-gnu/libc.so.6
machine: 3
0xf777c000 0xf779ff3c /lib/ld-linux.so.2
machine: 3
$ gcc -Wall test.c -m64 -o test-m64
$ ./test-m64
0x7fc40653e700 cached result; 0x7fc40653e140 dyn
0x7ffd2409c000 0x7ffd2409c360
machine: 62
0x7fc405f4e000 0x7fc406310ba0 /lib/x86_64-linux-gnu/libc.so.6
machine: 62
0x7fc406317000 0x7fc40653ce70 /lib64/ld-linux-x86-64.so.2
machine: 62
> Code like this shows it:
>
> #include <link.h>
> #include <stdio.h>
>
> # pragma weak _DYNAMIC
> extern Elf64_Dyn _DYNAMIC[];
>
> int main() {
> int tag;
> Elf64_Dyn* dp;
> struct link_map* cachedResult;
> for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
> if( tag == DT_DEBUG ) {
> struct link_map *lm = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
> if( lm != 0 ) cachedResult = lm->l_next; /* might be NULL */
> break;
> }
> }
> printf("%p cached result; %p dyn \n", cachedResult, dp->d_un.d_ptr);
> while(cachedResult) {
> printf("%p %p %s\n", cachedResult->l_addr, cachedResult->l_ld, cachedResult->l_name);
> Elf64_Ehdr* e = (Elf64_Ehdr *)cachedResult->l_addr;
> printf("machine: %d\n", e->e_machine); // CRASH here, first iteration.
>
> cachedResult = cachedResult->l_next;
> }
> return 0;
> }
>