From 8ff862960efb648cdff647d7fad1be5acffe9b11 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Thu, 30 May 2013 13:21:20 +0200 Subject: [PATCH] Use DT_DEBUG library search first. libdwfl/ 2013-05-30 Jan Kratochvil * argp-std.c (parse_opt) core> e>: Set executable_for_core before calling dwfl_core_file_report. * core-file.c (clear_r_debug_info): New function. (dwfl_core_file_report): Move raw segments reporting lower. New variable r_debug_info, pass it to dwfl_segment_report_module. Call clear_r_debug_info in the end. Return sum of LISTED and SNIFFED. * dwfl_module_build_id.c (check_notes): Move into __libdwfl_find_elf_build_id. (__libdwfl_find_build_id): Rename to ... (__libdwfl_find_elf_build_id): ... here. Add parameters build_id_bits, build_id_elfaddr and build_id_len. Verify MOD vs. ELF. (__libdwfl_find_elf_build_id) (check_notes): Remove parameters mod and set, rename data_vaddr to data_elfaddr. Do not call found_build_id. (__libdwfl_find_elf_build_id): Update the check_notes caller, do not adjust its data_elfaddr parameter. (__libdwfl_find_build_id): New wrapper of __libdwfl_find_elf_build_id. * dwfl_segment_report_module.c (dwfl_segment_report_module): New parameter r_debug_info. New variable name_is_final. Adjust addresses according to R_DEBUG_INFO->MODULE. Check conflicts against DWFL. Do not overwrite NAME by SONAME if NAME_IS_FINAL. * libdwflP.h (__libdwfl_find_elf_build_id): New declaration. (struct r_debug_info_module, struct r_debug_info): New definitions. (dwfl_segment_report_module, dwfl_link_map_report): Add parameter r_debug_info. * link_map.c: Include fcntl.h. (report_r_debug): Add parameter r_debug_info, describe it in the function comment. Delete dwfl_addrmodule call and its dependent code. Verify build-id before calling dwfl_report_elf, also supply executable_for_core to it. Store r_debug_info->module info when appropriate. (dwfl_link_map_report): Add parameter r_debug_info. New variable in_ok. Try to read IN from EXECUTABLE_FOR_CORE. Update report_r_debug caller parameters. tests/ 2013-05-30 Jan Kratochvil * Makefile.am (EXTRA_DIST): Add test-core-lib.so.bz2, test-core.core.bz2 and test-core.exec.bz2. * run-addrname-test.sh: New test for these files. * run-unstrip-n.sh: Update expected output. New test for these files. * test-core-lib.so.bz2: New file. * test-core.core.bz2: New file. * test-core.exec.bz2: New file. Signed-off-by: Jan Kratochvil --- libdwfl/ChangeLog | 36 ++++++ libdwfl/argp-std.c | 6 +- libdwfl/core-file.c | 71 +++++++---- libdwfl/dwfl_module_build_id.c | 85 ++++++++----- libdwfl/dwfl_segment_report_module.c | 46 ++++++- libdwfl/libdwflP.h | 34 +++++- libdwfl/link_map.c | 172 +++++++++++++++++++++------ tests/ChangeLog | 10 ++ tests/Makefile.am | 3 +- tests/run-addrname-test.sh | 6 + tests/run-unstrip-n.sh | 33 +++-- tests/test-core-lib.so.bz2 | Bin 0 -> 2028 bytes tests/test-core.core.bz2 | Bin 0 -> 14165 bytes tests/test-core.exec.bz2 | Bin 0 -> 2565 bytes 14 files changed, 397 insertions(+), 105 deletions(-) create mode 100755 tests/test-core-lib.so.bz2 create mode 100644 tests/test-core.core.bz2 create mode 100755 tests/test-core.exec.bz2 diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index 74ede01dc..9ee0ab16d 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,39 @@ +2013-05-30 Jan Kratochvil + + * argp-std.c (parse_opt) core> e>: Set + executable_for_core before calling dwfl_core_file_report. + * core-file.c (clear_r_debug_info): New function. + (dwfl_core_file_report): Move raw segments reporting lower. New + variable r_debug_info, pass it to dwfl_segment_report_module. Call + clear_r_debug_info in the end. Return sum of LISTED and SNIFFED. + * dwfl_module_build_id.c (check_notes): Move into + __libdwfl_find_elf_build_id. + (__libdwfl_find_build_id): Rename to ... + (__libdwfl_find_elf_build_id): ... here. Add parameters build_id_bits, + build_id_elfaddr and build_id_len. Verify MOD vs. ELF. + (__libdwfl_find_elf_build_id) (check_notes): Remove parameters mod and + set, rename data_vaddr to data_elfaddr. Do not call found_build_id. + (__libdwfl_find_elf_build_id): Update the check_notes caller, do not + adjust its data_elfaddr parameter. + (__libdwfl_find_build_id): New wrapper of __libdwfl_find_elf_build_id. + * dwfl_segment_report_module.c (dwfl_segment_report_module): New + parameter r_debug_info. New variable name_is_final. Adjust addresses + according to R_DEBUG_INFO->MODULE. Check conflicts against DWFL. + Do not overwrite NAME by SONAME if NAME_IS_FINAL. + * libdwflP.h (__libdwfl_find_elf_build_id): New declaration. + (struct r_debug_info_module, struct r_debug_info): New definitions. + (dwfl_segment_report_module, dwfl_link_map_report): Add parameter + r_debug_info. + * link_map.c: Include fcntl.h. + (report_r_debug): Add parameter r_debug_info, describe it in the + function comment. Delete dwfl_addrmodule call and its dependent code. + Verify build-id before calling dwfl_report_elf, also supply + executable_for_core to it. Store r_debug_info->module info when + appropriate. + (dwfl_link_map_report): Add parameter r_debug_info. New variable + in_ok. Try to read IN from EXECUTABLE_FOR_CORE. Update report_r_debug + caller parameters. + 2013-04-30 Jan Kratochvil * dwfl_report_elf.c (__libdwfl_report_elf): Add parameter add_p_vaddr. diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c index e54f720c4..c8843909a 100644 --- a/libdwfl/argp-std.c +++ b/libdwfl/argp-std.c @@ -295,6 +295,9 @@ parse_opt (int key, char *arg, struct argp_state *state) if (opt->core) { + if (opt->e) + dwfl->executable_for_core = strdup (opt->e); + int fd = open64 (opt->core, O_RDONLY); if (fd < 0) { @@ -330,9 +333,6 @@ parse_opt (int key, char *arg, struct argp_state *state) _("No modules recognized in core file")); return ENOENT; } - - if (opt->e) - dwfl->executable_for_core = strdup (opt->e); } else if (opt->e) { diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c index 1545ca869..d5e340cbe 100644 --- a/libdwfl/core-file.c +++ b/libdwfl/core-file.c @@ -381,6 +381,19 @@ dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx, return true; } +/* Free the contents of R_DEBUG_INFO without the R_DEBUG_INFO memory itself. */ + +static void +clear_r_debug_info (struct r_debug_info *r_debug_info) +{ + while (r_debug_info->module != NULL) + { + struct r_debug_info_module *module = r_debug_info->module; + r_debug_info->module = module->next; + free (module); + } +} + int dwfl_core_file_report (Dwfl *dwfl, Elf *elf) { @@ -397,26 +410,6 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf) if (unlikely (ndx <= 0)) return ndx; - /* Now sniff segment contents for modules. */ - int sniffed = 0; - ndx = 0; - do - { - int seg = dwfl_segment_report_module (dwfl, ndx, NULL, - &dwfl_elf_phdr_memory_callback, elf, - core_file_read_eagerly, elf); - if (unlikely (seg < 0)) - return seg; - if (seg > ndx) - { - ndx = seg; - ++sniffed; - } - else - ++ndx; - } - while (ndx < (int) phnum); - /* Next, we should follow the chain from DT_DEBUG. */ const void *auxv = NULL; @@ -451,13 +444,43 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf) /* Now we have NT_AUXV contents. From here on this processing could be used for a live process with auxv read from /proc. */ + struct r_debug_info r_debug_info; + memset (&r_debug_info, 0, sizeof r_debug_info); int listed = dwfl_link_map_report (dwfl, auxv, auxv_size, - dwfl_elf_phdr_memory_callback, elf); + dwfl_elf_phdr_memory_callback, elf, + &r_debug_info); + + /* Now sniff segment contents for modules hinted by information gathered + from DT_DEBUG. */ + + int sniffed = 0; + ndx = 0; + do + { + int seg = dwfl_segment_report_module (dwfl, ndx, NULL, + &dwfl_elf_phdr_memory_callback, elf, + core_file_read_eagerly, elf, + &r_debug_info); + if (unlikely (seg < 0)) + { + clear_r_debug_info (&r_debug_info); + return seg; + } + if (seg > ndx) + { + ndx = seg; + ++sniffed; + } + else + ++ndx; + } + while (ndx < (int) phnum); + + clear_r_debug_info (&r_debug_info); /* We return the number of modules we found if we found any. If we found none, we return -1 instead of 0 if there was an - error rather than just nothing found. If link_map handling - failed, we still have the sniffed modules. */ - return sniffed == 0 || listed > sniffed ? listed : sniffed; + error rather than just nothing found. */ + return sniffed || listed >= 0 ? listed + sniffed : listed; } INTDEF (dwfl_core_file_report) diff --git a/libdwfl/dwfl_module_build_id.c b/libdwfl/dwfl_module_build_id.c index 660c733f0..cae007b48 100644 --- a/libdwfl/dwfl_module_build_id.c +++ b/libdwfl/dwfl_module_build_id.c @@ -54,28 +54,41 @@ found_build_id (Dwfl_Module *mod, bool set, #define NO_VADDR ((GElf_Addr) -1l) -static int -check_notes (Dwfl_Module *mod, bool set, Elf_Data *data, GElf_Addr data_vaddr) -{ - size_t pos = 0; - GElf_Nhdr nhdr; - size_t name_pos; - size_t desc_pos; - while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, &desc_pos)) > 0) - if (nhdr.n_type == NT_GNU_BUILD_ID - && nhdr.n_namesz == sizeof "GNU" && !memcmp (data->d_buf + name_pos, - "GNU", sizeof "GNU")) - return found_build_id (mod, set, - data->d_buf + desc_pos, nhdr.n_descsz, - data_vaddr == NO_VADDR ? 0 - : data_vaddr + desc_pos); - return 0; -} - int internal_function -__libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf) +__libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf, + const void **build_id_bits, + GElf_Addr *build_id_elfaddr, int *build_id_len) { + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (unlikely (ehdr == NULL)) + { + __libdwfl_seterrno (DWFL_E_LIBELF); + return -1; + } + // MOD->E_TYPE is zero here. + assert (ehdr->e_type != ET_REL || mod != NULL); + + int check_notes (Elf_Data *data, GElf_Addr data_elfaddr) + { + size_t pos = 0; + GElf_Nhdr nhdr; + size_t name_pos; + size_t desc_pos; + while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, &desc_pos)) > 0) + if (nhdr.n_type == NT_GNU_BUILD_ID + && nhdr.n_namesz == sizeof "GNU" && !memcmp (data->d_buf + name_pos, + "GNU", sizeof "GNU")) + { + *build_id_bits = data->d_buf + desc_pos; + *build_id_elfaddr = (data_elfaddr == NO_VADDR + ? 0 : data_elfaddr + desc_pos); + *build_id_len = nhdr.n_descsz; + return 1; + } + return 0; + } + size_t shstrndx = SHN_UNDEF; int result = 0; @@ -84,11 +97,8 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf) if (scn == NULL) { /* No sections, have to look for phdrs. */ - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); size_t phnum; - if (unlikely (ehdr == NULL) - || unlikely (elf_getphdrnum (elf, &phnum) != 0)) + if (unlikely (elf_getphdrnum (elf, &phnum) != 0)) { __libdwfl_seterrno (DWFL_E_LIBELF); return -1; @@ -98,12 +108,11 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf) GElf_Phdr phdr_mem; GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); if (likely (phdr != NULL) && phdr->p_type == PT_NOTE) - result = check_notes (mod, set, - elf_getdata_rawchunk (elf, + result = check_notes (elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR), - dwfl_adjusted_address (mod, phdr->p_vaddr)); + phdr->p_vaddr); } } else @@ -117,12 +126,12 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf) GElf_Addr vaddr = 0; if (!(shdr->sh_flags & SHF_ALLOC)) vaddr = NO_VADDR; - else if (mod->e_type != ET_REL) - vaddr = dwfl_adjusted_address (mod, shdr->sh_addr); + else if (mod == NULL || ehdr->e_type != ET_REL) + vaddr = shdr->sh_addr; else if (__libdwfl_relocate_value (mod, elf, &shstrndx, elf_ndxscn (scn), &vaddr)) vaddr = NO_VADDR; - result = check_notes (mod, set, elf_getdata (scn, NULL), vaddr); + result = check_notes (elf_getdata (scn, NULL), vaddr); } } while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL); @@ -130,6 +139,24 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf) return result; } +int +internal_function +__libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf) +{ + const void *build_id_bits; + GElf_Addr build_id_elfaddr; + int build_id_len; + + int result = __libdwfl_find_elf_build_id (mod, elf, &build_id_bits, + &build_id_elfaddr, &build_id_len); + if (result <= 0) + return result; + + GElf_Addr build_id_vaddr = build_id_elfaddr + (build_id_elfaddr != 0 + ? mod->main_bias : 0); + return found_build_id (mod, set, build_id_bits, build_id_len, build_id_vaddr); +} + int dwfl_module_build_id (Dwfl_Module *mod, const unsigned char **bits, GElf_Addr *vaddr) diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c index 7cf74994e..d454ccb50 100644 --- a/libdwfl/dwfl_segment_report_module.c +++ b/libdwfl/dwfl_segment_report_module.c @@ -83,7 +83,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, Dwfl_Memory_Callback *memory_callback, void *memory_callback_arg, Dwfl_Module_Callback *read_eagerly, - void *read_eagerly_arg) + void *read_eagerly_arg, + const struct r_debug_info *r_debug_info) { size_t segment = ndx; @@ -433,6 +434,47 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, dyn_vaddr += bias; + /* NAME found from link map has precedence over DT_SONAME possibly read + below. */ + bool name_is_final = false; + + /* Try to match up DYN_VADDR against L_LD as found in link map. + Segments sniffing may guess invalid address as the first read-only memory + mapping may not be dumped to the core file (if ELF headers are not dumped) + and the ELF header is dumped first with the read/write mapping of the same + file at higher addresses. */ + if (r_debug_info != NULL) + for (const struct r_debug_info_module *module = r_debug_info->module; + module != NULL; module = module->next) + if (module_start <= module->l_ld && module->l_ld < module_end) + { + /* L_LD read from link map must be right while DYN_VADDR is unsafe. + Therefore subtract DYN_VADDR and add L_LD to get a possibly + corrective displacement for all addresses computed so far. */ + GElf_Addr fixup = module->l_ld - dyn_vaddr; + if ((fixup & (dwfl->segment_align - 1)) == 0 + && module_start + fixup <= module->l_ld + && module->l_ld < module_end + fixup) + { + module_start += fixup; + module_end += fixup; + dyn_vaddr += fixup; + bias += fixup; + if (module->name[0] != '\0') + { + name = module->name; + name_is_final = true; + } + break; + } + } + + /* Ignore this found module if it would conflict in address space with any + already existing module of DWFL. */ + for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next) + if (module_end > mod->low_addr && module_start < mod->high_addr) + return finish (); + /* Our return value now says to skip the segments contained within the module. */ ndx = addr_segndx (dwfl, segment, module_end, true); @@ -518,7 +560,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, void *soname = NULL; size_t soname_size = 0; - if (dynstrsz != 0 && dynstr_vaddr != 0) + if (! name_is_final && dynstrsz != 0 && dynstr_vaddr != 0) { /* We know the bounds of the .dynstr section. diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index 37a9dff4e..69e6e12a5 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -362,6 +362,16 @@ extern Dwfl_Error __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, extern Dwfl_Error __libdwfl_cu_getsrclines (struct dwfl_cu *cu) internal_function; +/* Look in ELF for an NT_GNU_BUILD_ID note. Store it to BUILD_ID_BITS, + its vaddr in ELF to BUILD_ID_VADDR (it is unrelocated, even if MOD is not + NULL) and store length to BUILD_ID_LEN. Returns -1 for errors, 1 if it was + stored and 0 if no note is found. MOD may be NULL, MOD must be non-NULL + only if ELF is ET_REL. */ +extern int __libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf, + const void **build_id_bits, + GElf_Addr *build_id_elfaddr, + int *build_id_len); + /* Look in ELF for an NT_GNU_BUILD_ID note. If SET is true, store it in MOD and return its length. If SET is false, instead compare it to that stored in MOD and return 2 if they match, 1 if they do not. @@ -439,13 +449,29 @@ typedef bool Dwfl_Module_Callback (Dwfl_Module *mod, void **userdata, GElf_Off whole, GElf_Off contiguous, void *arg, Elf **elfp); +/* One shared library (or executable) info from DT_DEBUG link map. */ +struct r_debug_info_module +{ + struct r_debug_info_module *next; + GElf_Addr l_ld; + char name[0]; +}; + +/* Information gathered from DT_DEBUG by dwfl_link_map_report hinted to + dwfl_segment_report_module. */ +struct r_debug_info +{ + struct r_debug_info_module *module; +}; + /* ... */ extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, Dwfl_Memory_Callback *memory_callback, void *memory_callback_arg, Dwfl_Module_Callback *read_eagerly, - void *read_eagerly_arg); + void *read_eagerly_arg, + const struct r_debug_info *r_debug_info); /* Report a module for entry in the dynamic linker's struct link_map list. For each link_map entry, if an existing module resides at its address, @@ -459,10 +485,14 @@ extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, only find where to begin if the correct executable file was previously reported and preloaded as with dwfl_report_elf. + Fill in R_DEBUG_INFO if it is not NULL. It should be cleared by the + caller, this function does not touch fields it does not need to modify. + Returns the number of modules found, or -1 for errors. */ extern int dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, Dwfl_Memory_Callback *memory_callback, - void *memory_callback_arg); + void *memory_callback_arg, + struct r_debug_info *r_debug_info); /* Avoid PLT entries. */ diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c index 9f1b867e3..e752a5dbf 100644 --- a/libdwfl/link_map.c +++ b/libdwfl/link_map.c @@ -33,6 +33,7 @@ #include #include +#include /* This element is always provided and always has a constant value. This makes it an easy thing to scan for to discern the format. */ @@ -222,7 +223,8 @@ addrsize (uint_fast8_t elfclass) } /* Report a module for each struct link_map in the linked list at r_map - in the struct r_debug at R_DEBUG_VADDR. + in the struct r_debug at R_DEBUG_VADDR. For r_debug_info description + see dwfl_link_map_report in libdwflP.h. For each link_map entry, if an existing module resides at its address, this just modifies that module's name and suggested file name. If @@ -234,7 +236,8 @@ static int report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, Dwfl *dwfl, GElf_Addr r_debug_vaddr, Dwfl_Memory_Callback *memory_callback, - void *memory_callback_arg) + void *memory_callback_arg, + struct r_debug_info *r_debug_info) { /* Skip r_version, to aligned r_map field. */ GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass); @@ -349,42 +352,83 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, if (name != NULL && name[0] == '\0') name = NULL; - /* If content-sniffing already reported a module covering - the same area, find that existing module to adjust. - The l_ld address is the only one we know for sure - to be within the module's own segments (its .dynamic). */ - Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (dwfl, l_ld); - if (mod != NULL) + if (iterations == 1 && dwfl->executable_for_core != NULL) + name = dwfl->executable_for_core; + + Dwfl_Module *mod = NULL; + if (name != NULL) { - /* We have a module. We can give it a better name from l_name. */ - if (name != NULL && mod->name[0] == '[') + /* This code is mostly inlined dwfl_report_elf. */ + // XXX hook for sysroot + int fd = open64 (name, O_RDONLY); + if (fd >= 0) { - char *newname = strdup (basename (name)); - if (newname != NULL) + Elf *elf; + Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false); + if (error == DWFL_E_NOERROR) { - free (mod->name); - mod->name = newname; + const void *build_id_bits; + GElf_Addr build_id_elfaddr; + int build_id_len; + bool valid = true; + + /* FIXME: Bias L_ADDR should be computed from the prelink + state in memory (when the file got loaded), not against + the current on-disk file state as is computed below. + + This verification gives false positive if in-core ELF had + build-id but on-disk ELF does not have any. But we cannot + reliably find ELF header and/or the ELF build id just from + the link map (and checking core segments is also not + reliable). */ + + if (__libdwfl_find_elf_build_id (NULL, elf, &build_id_bits, + &build_id_elfaddr, + &build_id_len) > 0 + && build_id_elfaddr != 0) + { + GElf_Addr build_id_vaddr = build_id_elfaddr + l_addr; + release_buffer (0); + int segndx = INTUSE(dwfl_addrsegment) (dwfl, + build_id_vaddr, + NULL); + if (! (*memory_callback) (dwfl, segndx, + &buffer, &buffer_available, + build_id_vaddr, build_id_len, + memory_callback_arg) + || memcmp (build_id_bits, buffer, build_id_len) != 0) + { + /* File has valid build-id which cannot be verified + in memory. */ + valid = false; + } + } + + if (valid) + // XXX hook for sysroot + mod = __libdwfl_report_elf (dwfl, basename (name), name, + fd, elf, l_addr, true, true); + if (mod == NULL) + { + elf_end (elf); + close (fd); + } } } - - if (name == NULL && mod->name[0] == '/') - name = mod->name; - - /* If we don't have a file for it already, we can pre-install - the full file name from l_name. Opening the file by this - name will be the fallback when no build ID match is found. - XXX hook for sysroot */ - if (name != NULL && mod->main.name == NULL) - mod->main.name = strdup (name); } - else if (name != NULL) + if (r_debug_info != NULL && mod == NULL) { - /* We have to find the file's phdrs to compute along with l_addr - what its runtime address boundaries are. */ - - // XXX hook for sysroot - mod = INTUSE(dwfl_report_elf) (dwfl, basename (name), - name, -1, l_addr, true); + /* Save link map information about valid shared library (or + executable) which has not been found on disk. */ + const char *base = name == NULL ? "" : basename (name); + struct r_debug_info_module *module; + module = malloc (sizeof (*module) + strlen (base) + 1); + if (module == NULL) + return release_buffer (result); + module->l_ld = l_ld; + strcpy (module->name, base); + module->next = r_debug_info->module; + r_debug_info->module = module; } if (mod != NULL) @@ -601,7 +645,8 @@ find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry, int dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, Dwfl_Memory_Callback *memory_callback, - void *memory_callback_arg) + void *memory_callback_arg, + struct r_debug_info *r_debug_info) { GElf_Addr r_debug_vaddr = 0; @@ -699,8 +744,65 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, .d_size = phnum * phent, .d_buf = NULL }; - if ((*memory_callback) (dwfl, phdr_segndx, &in.d_buf, &in.d_size, - phdr, phnum * phent, memory_callback_arg)) + bool in_ok = (*memory_callback) (dwfl, phdr_segndx, &in.d_buf, + &in.d_size, phdr, phnum * phent, + memory_callback_arg); + if (! in_ok && dwfl->executable_for_core != NULL) + { + /* AUXV -> PHDR -> DYNAMIC + Both AUXV and DYNAMIC should be always present in a core file. + PHDR may be missing in core file, try to read it from + EXECUTABLE_FOR_CORE to find where DYNAMIC is located in the + core file. */ + + int fd = open (dwfl->executable_for_core, O_RDONLY); + Elf *elf; + Dwfl_Error error = DWFL_E_ERRNO; + if (fd != -1) + error = __libdw_open_file (&fd, &elf, true, false); + if (error != DWFL_E_NOERROR) + { + __libdwfl_seterrno (error); + return false; + } + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + elf_end (elf); + close (fd); + __libdwfl_seterrno (DWFL_E_LIBELF); + return false; + } + if (ehdr->e_phnum != phnum || ehdr->e_phentsize != phent) + { + elf_end (elf); + close (fd); + __libdwfl_seterrno (DWFL_E_BADELF); + return false; + } + off_t off = ehdr->e_phoff; + assert (in.d_buf == NULL); + assert (in.d_size == phnum * phent); + in.d_buf = malloc (in.d_size); + if (unlikely (in.d_buf == NULL)) + { + elf_end (elf); + close (fd); + __libdwfl_seterrno (DWFL_E_NOMEM); + return false; + } + ssize_t nread = pread_retry (fd, in.d_buf, in.d_size, off); + elf_end (elf); + close (fd); + if (nread != (ssize_t) in.d_size) + { + free (in.d_buf); + __libdwfl_seterrno (DWFL_E_ERRNO); + return false; + } + in_ok = true; + } + if (in_ok) { union { @@ -862,6 +964,6 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, /* Now we can follow the dynamic linker's library list. */ return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr, - &integrated_memory_callback, &mcb); + &integrated_memory_callback, &mcb, r_debug_info); } INTDEF (dwfl_link_map_report) diff --git a/tests/ChangeLog b/tests/ChangeLog index 6df580a7f..eca60c39e 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,13 @@ +2013-05-30 Jan Kratochvil + + * Makefile.am (EXTRA_DIST): Add test-core-lib.so.bz2, + test-core.core.bz2 and test-core.exec.bz2. + * run-addrname-test.sh: New test for these files. + * run-unstrip-n.sh: Update expected output. New test for these files. + * test-core-lib.so.bz2: New file. + * test-core.core.bz2: New file. + * test-core.exec.bz2: New file. + 2013-05-03 Mark Wielaard * testfilenolines.bz2: New test file. diff --git a/tests/Makefile.am b/tests/Makefile.am index 6327edbb1..2d819c5b3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -199,7 +199,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ testfile70.core.bz2 testfile70.exec.bz2 \ run-dwfllines.sh run-dwfl-report-elf-align.sh \ testfile-dwfl-report-elf-align-shlib.so.bz2 \ - testfilenolines + testfilenolines test-core-lib.so.bz2 test-core.core.bz2 \ + test-core.exec.bz2 if USE_VALGRIND valgrind_cmd='valgrind -q --trace-children=yes --error-exitcode=1 --run-libc-freeres=no' diff --git a/tests/run-addrname-test.sh b/tests/run-addrname-test.sh index 9351fb2a0..8624074fa 100755 --- a/tests/run-addrname-test.sh +++ b/tests/run-addrname-test.sh @@ -316,4 +316,10 @@ main+0x9 ??:0 EOF +testfiles test-core-lib.so test-core.core test-core.exec +testrun_compare ${abs_top_builddir}/src/addr2line -S -e test-core.exec --core=test-core.core 0x7f67f2aaf619 <<\EOF +libfunc+0x9 +??:0 +EOF + exit 0 diff --git a/tests/run-unstrip-n.sh b/tests/run-unstrip-n.sh index 9c2b43b3c..6ede4c7e6 100755 --- a/tests/run-unstrip-n.sh +++ b/tests/run-unstrip-n.sh @@ -35,20 +35,35 @@ testfiles testcore-rtlib testcore-rtlib-ppc testrun_compare ${abs_top_builddir}/src/unstrip -n --core=testcore-rtlib <<\EOF 0x8048000+0x2000 f1c600bc36cb91bf01f9a63a634ecb79aa4c3199@0x8048178 . - [exe] +0xf75e9000+0x1a000 29a103420abe341e92072fb14274e250e4072148@0xf75e9164 - - libpthread.so.0 +0xf7603000+0x1b0000 0b9bf374699e141e5dfc14757ff42b8c2373b4de@0xf7603184 - - libc.so.6 +0xf77b3000+0x9000 c6c5b5e35ab9589d4762ac85b4bd56b1b2720e37@0xf77b3164 - - librt.so.1 0xf77d6000+0x1000 676560b1b765cde9c2e53f134f4ee354ea894747@0xf77d6210 . - linux-gate.so.1 -0xf77b3000+0x9000 c6c5b5e35ab9589d4762ac85b4bd56b1b2720e37@0xf77b3164 /lib/librt.so.1 - librt.so.1 -0xf7603000+0x1b0000 0b9bf374699e141e5dfc14757ff42b8c2373b4de@0xf7603184 /lib/libc.so.6 - libc.so.6 -0xf75e9000+0x1a000 29a103420abe341e92072fb14274e250e4072148@0xf75e9164 /lib/libpthread.so.0 - libpthread.so.0 -0xf77d7000+0x21000 6d2cb32650054f1c176d01d48713a4a5e5e84c1a@0xf77d7124 /lib/ld-linux.so.2 - ld-linux.so.2 +0xf77d7000+0x21000 6d2cb32650054f1c176d01d48713a4a5e5e84c1a@0xf77d7124 - - ld-linux.so.2 EOF testrun_compare ${abs_top_builddir}/src/unstrip -n --core=testcore-rtlib-ppc <<\EOF -0x10000000+0x20000 979b7a26747cc09bd84a42b311b5288c704baea5@0x10000174 . - [exe] 0x100000+0x10000 708b900b05176964512a6b0fe90c2a0c9d73d726@0x100334 . - linux-vdso32.so.1 -0xfd50000+0x30000 3f7d21508470322d2f47acddc20ab10516edba99@0xfd50164 /lib/librt.so.1 - librt.so.1 -0xfdf0000+0x1c0000 edf3dd232e09d01b90683889bd16b9406c52d4de@0xfdf0184 /lib/libc.so.6 - libc.so.6 -0xfdb0000+0x40000 f6ee91d4c629bc7dacc10534cb30056914e7e0b5@0xfdb0164 /lib/libpthread.so.0 - libpthread.so.0 -0xffb0000+0x50000 edec437a85026a1cf8cda94003706202733130c1@0xffb0124 /lib/ld.so.1 - ld.so.1 +0xfd50000+0x30000 3f7d21508470322d2f47acddc20ab10516edba99@0xfd50164 . - librt.so.1 +0xfdb0000+0x40000 f6ee91d4c629bc7dacc10534cb30056914e7e0b5@0xfdb0164 - - libpthread.so.0 +0xfdf0000+0x1c0000 edf3dd232e09d01b90683889bd16b9406c52d4de@0xfdf0184 - - libc.so.6 +0xffb0000+0x50000 edec437a85026a1cf8cda94003706202733130c1@0xffb0124 - - ld.so.1 +0x10000000+0x20000 979b7a26747cc09bd84a42b311b5288c704baea5@0x10000174 . - [exe] +EOF + +# FAIL was 0x7f67f2caf000 for test-core-lib.so . +# /lib64/libc.so.6 and /lib64/ld-linux-x86-64.so.2 from link map +# do not have ELF header stored in the core file. +# ELF headers in the core file: +# Offset VirtAddr +# 0x014000 0x00007f67f2caf000 ./test-core-lib.so +# 0x03a000 0x00007fff1596c000 linux-vdso.so.1 +testfiles test-core.core test-core.exec +rm -f test-core-lib.so +testrun_compare ${abs_top_builddir}/src/unstrip -n -e test-core.exec --core=test-core.core <<\EOF +0x400000+0x202038 - test-core.exec - test-core.exec +0x7f67f2aaf000+0x202000 - . - test-core-lib.so +0x7fff1596c000+0x1000 a9cf37f53897b5468ee018655760be61b8633d3c@0x7fff1596c340 . - linux-vdso.so.1 EOF test_cleanup diff --git a/tests/test-core-lib.so.bz2 b/tests/test-core-lib.so.bz2 new file mode 100755 index 0000000000000000000000000000000000000000..bb2da888ca3f566cc4695acaa11fcd304b1bbf72 GIT binary patch literal 2028 zc-jH%2NU>0T4*^jL0KkKS>=cdPXGt7|NsC0|NPhYfB*mY{_g+(|Nigm(0Ia(M0kCG zdO_NJ|M}ns)~@Eh3(e{3_SU_7h5&Z0000q27wbuk+mL~CQKmmfCE90XaE2-00000X@~#-01X2`01W^Esicvh z!cCxhiRdN(OaK!BGGG7zm;o>V6951LU;tP5Mcnw$Y?Y)!VD7= zL7)bJ0AQL136NnL42GIvGGYK|5+s2FU=+fQr1CUPG6q1<8Vv!onrJljGH3y&O#lD@ z4Kx4%G5{F>17a_Boc1hY9%shw@^)}<`^B~6s#)muO%2`LM5rK(|VqFpzxv}+OtT8;Rw zjK18)OC~{4lf?|6ZfW%D6~-e`ChVga0x6T2?;3!k>B{0 zrA&$}FT$wcEAKhi4w*nif(8Zt0r5~UN+1BB{4!c4$SB15p%Q6bS~gfs&SOa+fKmv% zz4BptXm0L#k)g1IV-(p~6SJcxyI=l}xpm?Fe71yh6O#9Ep?GGCo} z%U*BbT_{W>Or~hqu8rHW=4&FwX;WI6CA#S#1Q`rTBsK_3N;H*BW9i02V@bBgHZ_*e zbE%+GV(D64yn@`4BQ_Ei7O7$hG$9S7k{bltMc9F`Pe5i;kqi`yq|}h4N)Q8J>VQ!Y zfN>PGDM`S#hNOa1LQw;C5Hc9^)(j280Td#uK(i0b!J?`>drsY|Zmmc5f*IPF7SH4G>1S!OQ4CM-%4*Fxop@kgGP7<(raZ6K8*))t9J17n~V7N?ER8Suuyf+JUNHu+QSCn~1h3T7AcpjAFe zoK}7=63a&9_ma=MYLkFq$VM@dBM34dasd*&-C=9n)&hB|?FjVh(AAnm#{F_i7j|FPFW8WWC@wd$HW#im0i!pbPaokIpJSS!k7 zYZYL~sRP`h4Bt}7p$!NdIE88uXE-9Npje@uW;fFB=l#s)SP zUH6|RC*vnE*%XO_ArZn5bS){e;PVv#7(7A0g= zR6op{SAm(btopWf?Ze1M!QdB8i0v>^+-Z1H4aT+ytgT5gTSbRkDNP3`+ac@?)nj8` zfLufnk*{&ey+T2PHxR-SJ~XYW0f$Du9cwbPh#yuEz_EhSQbqy+!*UckA_*MW!MKQ% zgymh3(_*w3s_&75uW!_?JK-jjGSP?lUC>V__)WwTV zMw@}QGV9fUCM@p>gKvZ6Ep8dSV6U~0A`h|m4J`&{1tgJ52S9-s=K(^%PgbyE)DUM| zSVsseCnX0BWE#*;^gWLDl7Bv~qpM7ycSaqG#Uq<^R^0n1i_~@ZxbLnpgRQb2rb^bh zI~ezXz+P?PWgxxQOR$Z5i`Y~++?u88sl@dKvlS<>{U8kW#^^K_vSMusjH^_PM|SXp zsmTFDV1OcMGA6>u4s?No1Ky%p?JI0Smr^w5_bO&;Aev}8{i-u65kN=}r?h}ZaJqep zCzN=-_t0qk)+`oS?;ZgDp0d!-#6(Lo8g+Vt&yZF2K3pG zcHW&YsvvaEQ@*ZQAmU7`wCZmc2W)EiZ;It`cW#9N6&q~@IY?kw3`zrMIViAMn3c{A z>5R%tiySJPs(3E6Oc~iX&0|iGlFPAC1@TrIkvk^?0@0aOo3TBe1=YQMa?=|wvk};3 z;R0Zx6k|DwrgLXoTSi=0@sg^cx{e4GqLO>IIB}YT72x4rR2B*YZcb_O$^!Gu$SV;< z)u66oV9he}PSyAKREd#r)Wbs_Bsvq-JIv!=7Pq zy>SgD!;Suz8zu>mGp2H>o5=mkVx^C<0d3seY)&y%(#Xa>HxnQwEcXZl6e3ISw3Bp_ zfXR^(LIT|3g|O5`{_$DZw65q9VF1}OEoqR81Rw;1A)6gJt02m$y1Waz-CxQ_{9VZu K;X*@}ASpbkCV6%M literal 0 Hc-jL100001 diff --git a/tests/test-core.core.bz2 b/tests/test-core.core.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..4d4346b9cf7e2ffb995ca80b1549ee28a39d4d4f GIT binary patch literal 14165 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 literal 0 Hc-jL100001 diff --git a/tests/test-core.exec.bz2 b/tests/test-core.exec.bz2 new file mode 100755 index 0000000000000000000000000000000000000000..49ce5519c68c629bb87acf811c837d249bfb8293 GIT binary patch literal 2565 zc-jF43i|azT4*^jL0KkKS=VeH@Bj&P|NsC0|Ns8?|NH;{{_p?y|NZ;#)?-{+R{Hn@G(^ zwFt~mJx@^mDW=qVjE$scs(P9lZ8V-x&}pZr+McF>^$h@eG=_uJ405kvq0iXesKr#WK0001J00000(0YOfOql@5kN|0d8UWA$ z28JP~fMfsxpc)24Kr{fz4FgRWgGPV=4FCb4X`v8Ilhi5dc~59lYI>X0YI>fa(@m(v zVKfaiGypUj0qP9{5t9>4BSt{N10WutXaS=@(?HRaA)*FMnE=U<0BM360MGyih9Rba zWB>u68U{l^GyupA15Fr%Mt}ef00E##l4ufSVl-+|?18E3n-kSPBr=#0p@j7sdWKA% zp@MBpn4Ta20v@I&BOnGtCQS?`fD8tSiGZ1l%*TzHZT92W*2}0MzjC#-I5evDjEqVW zKtH$8p@=96V+1xgf+;Wt*J`tLt1`{B@!ZYG3S@3BoGg`7jf|O+h>fIc#)L??&jDB& z#bbpjZzrcR&8CR}!JDFBI@Pw7ksIvN&bp{e5>KS9NCzk-O|?K|&5D6I0@$eVGGI|C zaOE+TIEX8Ug<>FJRs~^@XlBQIACil0Lu}>@YV6HJaGne5_IvE1??WnNVw6U(-CVR z4JYOCJ#J2i-T3;PKRZ`tU@j(5%iwh!u4QiWP$DAe$|kmTcv{Z}r=+1^fpIkGy`$20 z^17SL5=d3gw(c+Aw5SJH4<#gjouLw|=)yS4Ghe5AX(hb7en|j$&&psLQ}I8Ckw4k_ ze+S~vnU9u^?82^TGaEVQ4mH%c>1@GNrb}21Y*h?nf}QLRI}6e}ZR%G!2K}KQceI3% zEsF#p6Bye=7|LM~8jN2JIvou)(h&_C_8{F15+uYObSMK(AOUa&kv1hJ6f}}eqzQE_ zh9XTvLCiG`HX;0;UhAWvoCs1P0BjIN;gWDjATof71u7KIPysPSZutu`098N=rAnz% ztAwKpS_K$Xu&PQc<037IklPl(ARdhV-;2|3(TlXXU#rAm$;o#W&dOk?c=tsc!7a&| zn3BnI*ucFtlY+GufdH~JT6eQbK{0?p!fUKkg6IXCda1}bfb-?Co>Fv%tU|F6Y)G?M z%PguKkw_}>ki-zA8^Gb8ER+-i^-T=u3DyvASdm5z0$z;0 z*d3b;1upgYlz$nog+N0MNF3#Y6ZqL&x<5y+o4m@MFZ9pza`;?~94y%-r5%N0h=!QR z6AXc0>wD$ z*7VyDLo>U(?qDsBHZq`j?JcuLBQtCQkdPb-VT?B){sg?Hk~uT^)0MuV1>}O%S_Dww zfn0(>5teC{m5Vbzn?;L}qL{4;14A2&j;UXkOO|2C@TKA1V=nx_f>I%n&3*V`7NyFI zhj}7-K~8~BK8(O(MnHNM+m z)&&enaqL84fI^h;jf8;=5f^j*AuRCDg}$cKpPj04e7f;Uy?2-FQ4wqArg53Okd8di zqI54qWwCTlV`1@lh!9sZbHAW3Q5tN|`3SQhuR><&O}lfIUcj;>SS1__QYctOz>guV zi?QcJhRHen%?;-9b=Q^oLX%LUfkJUbZSQko!!rxEgBFxR0uc(#%BN#$K*-6%tiBKH zp+i(d)2so9kSD0r3A%Krg55?J-(-0FV zP*lnWu1^7yA-KOv<{1kx42nvsRk6Rwt6^UM80u422*=Csnrqd7qPIo+)VZ)Lz!f(2|U1?rUkP)|av5-mk9{x|MTJX=}K`vD&nSVTst8 z@M>TUiDrHW?z+Pp*^>m?q%b-3@wHaW0sgAm(_s@or4JpSCZ^+o5?uH+`#Ir7!H1!e zuNm1}eBGWqnr{T5@J&s@e&IeYc@c8QJy})Ry;u(c8rp~!;o)cHirA4jTy=Z%o8^8F zXo|E4U(V7Hkaa>as)Fbf85;iJ(VhNzw^Lo6U!9H zAVp=Y#fD*N1}0Ty16O_mpsMOdU>JBx?%pVq#jAcRybNRPP1asczh9Sag@DRL&1Slh zA4xj1APlXB3`TJ^GUQ=N5{GF_z{4_ni}rXdZ`HVD zXyVed6#Z~fL%NT`HrP?AiM86$0ZX+bjC}O&|j*xA%HnQhn zzqhx?&t!il0Fb*P5-g2Ooj5lENQxR(I5l%kI7;W?ubDfdexK>5vncbg|76r~lmLW! zVJ(>~2sCeQmLe1s2r{w6(QtfC)YAK4U(^RW;YCK&l7fkl8ioWR@N@!qO;M<^6CFsf b(54wp(eS0i{<<6QGyfNIML1B9*K8i}OChCW literal 0 Hc-jL100001 -- 2.47.2