On Thu, 30 May 2013 11:52:55 +0200, Mark Wielaard wrote:
I think it is finished now.
Checked in.
Thanks,
Jan
commit 8ff862960efb648cdff647d7fad1be5acffe9b11
Author: Jan Kratochvil <jan.kratochvil(a)redhat.com>
Date: Thu May 30 13:21:20 2013 +0200
Use DT_DEBUG library search first.
libdwfl/
2013-05-30 Jan Kratochvil <jan.kratochvil(a)redhat.com>
* argp-std.c (parse_opt) <ARGP_KEY_SUCCESS> <opt->core>
<opt->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 <jan.kratochvil(a)redhat.com>
* 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 <jan.kratochvil(a)redhat.com>
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 74ede01..9ee0ab1 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,39 @@
+2013-05-30 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * argp-std.c (parse_opt) <ARGP_KEY_SUCCESS> <opt->core>
<opt->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 <jan.kratochvil(a)redhat.com>
* 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 e54f720..c884390 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 1545ca8..d5e340c 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 660c733..cae007b 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);
@@ -131,6 +140,24 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
}
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 7cf7499..d454ccb 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 37a9dff..69e6e12 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 9f1b867..e752a5d 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -33,6 +33,7 @@
#include <byteswap.h>
#include <endian.h>
+#include <fcntl.h>
/* 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 6df580a..eca60c3 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,13 @@
+2013-05-30 Jan Kratochvil <jan.kratochvil(a)redhat.com>
+
+ * 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 <mjw(a)redhat.com>
* testfilenolines.bz2: New test file.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6327edb..2d819c5 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 9351fb2..8624074 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 9c2b43b..6ede4c7 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 0000000..bb2da88
Binary files /dev/null and b/tests/test-core-lib.so.bz2 differ
diff --git a/tests/test-core.core.bz2 b/tests/test-core.core.bz2
new file mode 100644
index 0000000..4d4346b
Binary files /dev/null and b/tests/test-core.core.bz2 differ
diff --git a/tests/test-core.exec.bz2 b/tests/test-core.exec.bz2
new file mode 100755
index 0000000..49ce551
Binary files /dev/null and b/tests/test-core.exec.bz2 differ