diff options
| author | Ulf Hermann <[email protected]> | 2018-07-13 18:32:53 +0200 |
|---|---|---|
| committer | Ulf Hermann <[email protected]> | 2018-07-13 18:32:53 +0200 |
| commit | 731aa2b1b0f73b443c8ed7538c134849935d0ba1 (patch) | |
| tree | 9179c5a58889c4725751856bf75d6a91810d5bf8 /libdwfl | |
| parent | d9483eb79086970df1dd875f6914bd0a442e8566 (diff) | |
| parent | aa36de0335e3ce12898954985a208f6336731289 (diff) | |
Merge tag 'elfutils-0.173'
elfutils 0.173 release
Change-Id: I83dc56dd15c26fe7acf4ce73c29df65b8b65e757
Diffstat (limited to 'libdwfl')
| -rw-r--r-- | libdwfl/ChangeLog | 76 | ||||
| -rw-r--r-- | libdwfl/argp-std.c | 2 | ||||
| -rw-r--r-- | libdwfl/cu.c | 14 | ||||
| -rw-r--r-- | libdwfl/dwfl_build_id_find_elf.c | 2 | ||||
| -rw-r--r-- | libdwfl/dwfl_module.c | 1 | ||||
| -rw-r--r-- | libdwfl/dwfl_module_addrsym.c | 9 | ||||
| -rw-r--r-- | libdwfl/dwfl_module_getdwarf.c | 23 | ||||
| -rw-r--r-- | libdwfl/dwfl_report_elf.c | 2 | ||||
| -rw-r--r-- | libdwfl/find-debuginfo.c | 2 | ||||
| -rw-r--r-- | libdwfl/frame_unwind.c | 48 | ||||
| -rw-r--r-- | libdwfl/libdwflP.h | 25 | ||||
| -rw-r--r-- | libdwfl/link_map.c | 38 | ||||
| -rw-r--r-- | libdwfl/linux-pid-attach.c | 86 | ||||
| -rw-r--r-- | libdwfl/offline.c | 3 | ||||
| -rw-r--r-- | libdwfl/relocate.c | 2 |
15 files changed, 260 insertions, 73 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index e4bfa71a..d03268b6 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -35,6 +35,82 @@ * dwfl_error.c: If we don't have a strerror_r returning a char*, output a less useful message in case of a system error. +2018-06-04 Mark Wielaard <[email protected]> + + * libdwflP.h (__libdwfl_addrsym): Remove function declaration. + * dwfl_module_addrsym.c (__libdwfl_addrsym): Make a static function. + +2018-05-27 Mark Wielaard <[email protected]> + + * relocate.c (__libdwfl_relocate): Always call relocate_section with + partial true. + +2018-05-17 Mark Wielaard <[email protected]> + + * dwfl_module (__libdwfl_module_free): Free elfdir. + * dwfl_module_getdwarf.c (load_dw): Close file descriptors after + dwarf_begin_elf call. Set Dwarf debugdir if it is NULL, this is the + main module file and we recorded the elfdir. + * libdwflP.h (struct Dwfl_Module): Add elfdir field. + * offline.c (process_elf): Record the elfdir before we close the + main ELF file descriptor. + +2018-04-10 Mark Wielaard <[email protected]> + + * frame_unwind.c (unwind): If __libdwfl_frame_reg_get fails for + the return address either set an error or mark the pc undefined. + +2018-03-17 Mark Wielaard <[email protected]> + + * libdwflP.h (struct __libdwfl_remote_mem_cache): New. + (struct __libdwfl_pid_arg): Add mem_cache field. + * linux-pid-attach.c (read_cached_memory): New function. + (clear_cached_memory): Likewise. + (pid_memory_read): Call read_cached_memory. + (pid_detach): Free mem_cache. + (pid_thread_detach): Call clear_cached_memory. + (dwfl_linux_proc_attach): Initialize mem_cache to NULL. + +2018-03-05 Mark Wielaard <[email protected]> + + * dwfl_build_id_find_elf.c (__libdwfl_open_by_build_id): Use + realpath (name, NULL) instead of canonicalize_file_name (name). + * find-debuginfo.c (dwfl_standard_find_debuginfo): Likewise. + +2018-01-29 Mark Wielaard <[email protected]> + + * cu.c (cudie_offset): Use __libdw_first_die_off_from_cu instead of + DIE_OFFSET_FROM_CU_OFFSET. + (intern_cu): Simply use a copy of the given die CU as key instead of + trying to construct a dummy one by hand. + +2018-02-15 Mark Wielaard <[email protected]> + + * linux-pid-attach.c: Include sys/wait.h after sys/ptrace.h. + +2018-02-09 Joshua Watt <[email protected]> + + * dwfl_report_elf.c (__libdwfl_elf_address_range): Use FALLTHROUGH + macro instead of comment. + * frame_unwind.c (expr_eval): Likewise. + +2017-11-20 Mark Wielaard <[email protected]> + + * link_map.c (do_check64): Take a char * and calculate type and val + offsets before reading, possibly unaligned, values. + (do_check32): Likewise. + (check64): Remove define. + (check32): Likewise. + (auxv_format_probe): Call do_check32 and do_check64 directly with + a, possibly unaligned, auxv entry pointer. + (dwfl_link_map_report): Redefine AUXV_SCAN to not dereference a + possibly unaligned auxv entry pointer. + +2017-10-16 Mark Wielaard <[email protected]> + + * argp-std.c (parse_opt): For -k call argp_failure not failure to + keep dwfl around. + 2017-07-26 Yunlian Jiang <[email protected]> * argp-std.c (failure): Move to file scope. diff --git a/libdwfl/argp-std.c b/libdwfl/argp-std.c index e03614c2..fbdbb231 100644 --- a/libdwfl/argp-std.c +++ b/libdwfl/argp-std.c @@ -238,7 +238,7 @@ parse_opt (int key, char *arg, struct argp_state *state) result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl); if (result != 0) /* Non-fatal to have no modules since we do have the kernel. */ - failure (dwfl, result, _("cannot find kernel modules"), state); + argp_failure (state, 0, result, _("cannot find kernel modules")); opt->dwfl = dwfl; } else diff --git a/libdwfl/cu.c b/libdwfl/cu.c index 7aa23b50..94bfad8d 100644 --- a/libdwfl/cu.c +++ b/libdwfl/cu.c @@ -1,5 +1,5 @@ /* Keeping track of DWARF compilation units in libdwfl. - Copyright (C) 2005-2010, 2015 Red Hat, Inc. + Copyright (C) 2005-2010, 2015, 2016, 2017 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -155,12 +155,7 @@ less_lazy (Dwfl_Module *mod) static inline Dwarf_Off cudie_offset (const struct dwfl_cu *cu) { - /* These are real CUs, so there never is a type_sig8. Note - initialization of dwkey.start and offset_size in intern_cu () - to see why this calculates the same value for both key and - die.cu search items. */ - return DIE_OFFSET_FROM_CU_OFFSET (cu->die.cu->start, cu->die.cu->offset_size, - 0); + return __libdw_first_die_off_from_cu (cu->die.cu); } static int @@ -198,11 +193,8 @@ intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result) if (die == NULL) return DWFL_E_LIBDW; - struct Dwarf_CU dwkey; struct dwfl_cu key; - key.die.cu = &dwkey; - dwkey.offset_size = 0; - dwkey.start = cuoff - (3 * 0 - 4 + 3); + key.die.cu = die->cu; struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey); if (unlikely (found == NULL)) return DWFL_E_NOMEM; diff --git a/libdwfl/dwfl_build_id_find_elf.c b/libdwfl/dwfl_build_id_find_elf.c index cf2a0f15..1cf2751c 100644 --- a/libdwfl/dwfl_build_id_find_elf.c +++ b/libdwfl/dwfl_build_id_find_elf.c @@ -100,7 +100,7 @@ __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name, { if (*file_name != NULL) free (*file_name); - *file_name = canonicalize_file_name (name); + *file_name = realpath (name, NULL); if (*file_name == NULL) { *file_name = name; diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c index 510bd691..e7dfdace 100644 --- a/libdwfl/dwfl_module.c +++ b/libdwfl/dwfl_module.c @@ -120,6 +120,7 @@ __libdwfl_module_free (Dwfl_Module *mod) free (mod->reloc_info); free (mod->name); + free (mod->elfdir); free (mod); } diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c index db302e63..2336b602 100644 --- a/libdwfl/dwfl_module_addrsym.c +++ b/libdwfl/dwfl_module_addrsym.c @@ -235,9 +235,12 @@ search_table (struct search_state *state, int start, int end) } /* Returns the name of the symbol "closest" to ADDR. - Never returns symbols at addresses above ADDR. */ -const char * -internal_function + Never returns symbols at addresses above ADDR. + + Wrapper for old dwfl_module_addrsym and new dwfl_module_addrinfo. + adjust_st_value set to true returns adjusted SYM st_value, set to false + it will not adjust SYM at all, but does match against resolved values. */ +static const char * __libdwfl_addrsym (Dwfl_Module *_mod, GElf_Addr _addr, GElf_Off *off, GElf_Sym *_closest_sym, GElf_Word *shndxp, Elf **elfp, Dwarf_Addr *biasp, bool _adjust_st_value) diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index f6380934..095a853f 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -1335,7 +1335,18 @@ load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile) result = __libdwfl_relocate (mod, debugfile->elf, true); if (result != DWFL_E_NOERROR) return result; + } + + mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL); + if (mod->dw == NULL) + { + int err = INTUSE(dwarf_errno) (); + return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err); + } + /* Do this after dwarf_begin_elf has a chance to process the fd. */ + if (mod->e_type == ET_REL && !debugfile->relocated) + { /* Don't keep the file descriptors around. */ if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0) { @@ -1349,12 +1360,12 @@ load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile) } } - mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL); - if (mod->dw == NULL) - { - int err = INTUSE(dwarf_errno) (); - return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err); - } + /* We might have already closed the fd when we asked dwarf_begin_elf to + create an Dwarf. Help out a little in case we need to find an alt or + dwo file later. */ + if (mod->dw->debugdir == NULL && mod->elfdir != NULL + && debugfile == &mod->main) + mod->dw->debugdir = strdup (mod->elfdir); /* Until we have iterated through all CU's, we might do lazy lookups. */ mod->lazycu = 1; diff --git a/libdwfl/dwfl_report_elf.c b/libdwfl/dwfl_report_elf.c index d4d3feb9..57f58538 100644 --- a/libdwfl/dwfl_report_elf.c +++ b/libdwfl/dwfl_report_elf.c @@ -174,7 +174,7 @@ __libdwfl_elf_address_range (Elf *elf, GElf_Addr base, bool add_p_vaddr, /* An assigned base address is meaningless for these. */ base = 0; add_p_vaddr = true; - /* Fallthrough. */ + FALLTHROUGH; case ET_DYN: default:; size_t phnum; diff --git a/libdwfl/find-debuginfo.c b/libdwfl/find-debuginfo.c index 3a65eda0..96f98cac 100644 --- a/libdwfl/find-debuginfo.c +++ b/libdwfl/find-debuginfo.c @@ -404,7 +404,7 @@ dwfl_standard_find_debuginfo (Dwfl_Module *mod, /* If FILE_NAME is a symlink, the debug file might be associated with the symlink target name instead. */ - char *canon = canonicalize_file_name (file_name); + char *canon = realpath (file_name, NULL); if (canon != NULL && strcmp (file_name, canon)) fd = find_debuginfo_in_path (mod, canon, debuglink_file, debuglink_crc, diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c index 4dc9c432..8da691ee 100644 --- a/libdwfl/frame_unwind.c +++ b/libdwfl/frame_unwind.c @@ -442,7 +442,7 @@ expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops, } if (val1 == 0) break; - /* FALLTHRU */ + FALLTHROUGH; case DW_OP_skip:; Dwarf_Word offset = op->offset + 1 + 2 + (int16_t) op->number; const Dwarf_Op *found = bsearch ((void *) (uintptr_t) offset, ops, nops, @@ -632,24 +632,38 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias) ra_set = true; } } - if (unwound->pc_state == DWFL_FRAME_STATE_ERROR - && __libdwfl_frame_reg_get (unwound, - frame->fde->cie->return_address_register, - &unwound->pc)) + if (unwound->pc_state == DWFL_FRAME_STATE_ERROR) { - /* PPC32 __libc_start_main properly CFI-unwinds PC as zero. Currently - none of the archs supported for unwinding have zero as a valid PC. */ - if (unwound->pc == 0) - unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; + if (__libdwfl_frame_reg_get (unwound, + frame->fde->cie->return_address_register, + &unwound->pc)) + { + /* PPC32 __libc_start_main properly CFI-unwinds PC as zero. + Currently none of the archs supported for unwinding have + zero as a valid PC. */ + if (unwound->pc == 0) + unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; + else + { + unwound->pc_state = DWFL_FRAME_STATE_PC_SET; + /* In SPARC the return address register actually contains + the address of the call instruction instead of the return + address. Therefore we add here an offset defined by the + backend. Most likely 0. */ + unwound->pc += ebl_ra_offset (ebl); + } + } else - { - unwound->pc_state = DWFL_FRAME_STATE_PC_SET; - /* In SPARC the return address register actually contains - the address of the call instruction instead of the return - address. Therefore we add here an offset defined by the - backend. Most likely 0. */ - unwound->pc += ebl_ra_offset (ebl); - } + { + /* We couldn't set the return register, either it was bogus, + or the return pc is undefined, maybe end of call stack. */ + unsigned pcreg = frame->fde->cie->return_address_register; + if (! ebl_dwarf_to_regno (ebl, &pcreg) + || pcreg >= ebl_frame_nregs (ebl)) + __libdwfl_seterrno (DWFL_E_INVALID_REGISTER); + else + unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; + } } free (frame); } diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index fbd1a647..dcdb332c 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -1,5 +1,5 @@ /* Internal definitions for libdwfl. - Copyright (C) 2005-2015 Red Hat, Inc. + Copyright (C) 2005-2015, 2018 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -190,6 +190,8 @@ struct Dwfl_Module Elf_Data *symxndxdata; /* Data in the extended section index table. */ Elf_Data *aux_symxndxdata; /* Data in the extended auxiliary table. */ + char *elfdir; /* The dir where we found the main Elf. */ + Dwarf *dw; /* libdw handle for its debugging info. */ Dwarf *alt; /* Dwarf used for dwarf_setalt, or NULL. */ int alt_fd; /* descriptor, only valid when alt != NULL. */ @@ -401,6 +403,14 @@ struct dwfl_arange size_t arange; /* Index in Dwarf_Aranges. */ }; +#define __LIBDWFL_REMOTE_MEM_CACHE_SIZE 4096 +/* Structure for caching remote memory reads as used by __libdwfl_pid_arg. */ +struct __libdwfl_remote_mem_cache +{ + Dwarf_Addr addr; /* Remote address. */ + Dwarf_Off len; /* Zero if cleared, otherwise likely 4K. */ + unsigned char buf[__LIBDWFL_REMOTE_MEM_CACHE_SIZE]; /* The actual cache. */ +}; /* Structure used for keeping track of ptrace attaching a thread. Shared by linux-pid-attach and linux-proc-maps. If it has been setup @@ -411,6 +421,10 @@ struct __libdwfl_pid_arg DIR *dir; /* Elf for /proc/PID/exe. Set to NULL if it couldn't be opened. */ Elf *elf; + /* Remote memory cache, NULL if there is no memory cached. + Should be cleared on detachment (because that makes the thread + runnable and the cache invalid). */ + struct __libdwfl_remote_mem_cache *mem_cache; /* fd for /proc/PID/exe. Set to -1 if it couldn't be opened. */ int elf_fd; /* It is 0 if not used. */ @@ -449,15 +463,6 @@ extern const char *__libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, bool *resolved, bool adjust_st_value) internal_function; -/* Internal wrapper for old dwfl_module_addrsym and new dwfl_module_addrinfo. - adjust_st_value set to true returns adjusted SYM st_value, set to false - it will not adjust SYM at all, but does match against resolved values. */ -extern const char *__libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, - GElf_Off *off, GElf_Sym *sym, - GElf_Word *shndxp, Elf **elfp, - Dwarf_Addr *bias, - bool adjust_st_value) internal_function; - extern void __libdwfl_module_free (Dwfl_Module *mod) internal_function; /* Find the main ELF file, update MOD->elferr and/or MOD->main.elf. */ diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c index 4a50c441..937cc1a0 100644 --- a/libdwfl/link_map.c +++ b/libdwfl/link_map.c @@ -43,13 +43,14 @@ static inline bool -do_check64 (size_t i, const Elf64_auxv_t (*a64)[], uint_fast8_t *elfdata) +do_check64 (const char *a64, uint_fast8_t *elfdata) { /* The AUXV pointer might not even be naturally aligned for 64-bit data, because note payloads in a core file are not aligned. */ - - uint64_t type = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_type); - uint64_t val = read_8ubyte_unaligned_noncvt (&(*a64)[i].a_un.a_val); + const char *typep = a64 + offsetof (Elf64_auxv_t, a_type); + uint64_t type = read_8ubyte_unaligned_noncvt (typep); + const char *valp = a64 + offsetof (Elf64_auxv_t, a_un.a_val); + uint64_t val = read_8ubyte_unaligned_noncvt (valp); if (type == BE64 (PROBE_TYPE) && val == BE64 (PROBE_VAL64)) @@ -68,16 +69,15 @@ do_check64 (size_t i, const Elf64_auxv_t (*a64)[], uint_fast8_t *elfdata) return false; } -#define check64(n) do_check64 (n, a64, elfdata) - static inline bool -do_check32 (size_t i, const Elf32_auxv_t (*a32)[], uint_fast8_t *elfdata) +do_check32 (const char *a32, uint_fast8_t *elfdata) { /* The AUXV pointer might not even be naturally aligned for 32-bit data, because note payloads in a core file are not aligned. */ - - uint32_t type = read_4ubyte_unaligned_noncvt (&(*a32)[i].a_type); - uint32_t val = read_4ubyte_unaligned_noncvt (&(*a32)[i].a_un.a_val); + const char *typep = a32 + offsetof (Elf32_auxv_t, a_type); + uint32_t type = read_4ubyte_unaligned_noncvt (typep); + const char *valp = a32 + offsetof (Elf32_auxv_t, a_un.a_val); + uint32_t val = read_4ubyte_unaligned_noncvt (valp); if (type == BE32 (PROBE_TYPE) && val == BE32 (PROBE_VAL32)) @@ -96,26 +96,22 @@ do_check32 (size_t i, const Elf32_auxv_t (*a32)[], uint_fast8_t *elfdata) return false; } -#define check32(n) do_check32 (n, a32, elfdata) - /* Examine an auxv data block and determine its format. Return true iff we figured it out. */ static bool auxv_format_probe (const void *auxv, size_t size, uint_fast8_t *elfclass, uint_fast8_t *elfdata) { - const Elf32_auxv_t (*a32)[size / sizeof (Elf32_auxv_t)] = (void *) auxv; - const Elf64_auxv_t (*a64)[size / sizeof (Elf64_auxv_t)] = (void *) auxv; - for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i) { - if (check64 (i)) + if (do_check64 (auxv + i * sizeof (Elf64_auxv_t), elfdata)) { *elfclass = ELFCLASS64; return true; } - if (check32 (i * 2) || check32 (i * 2 + 1)) + if (do_check32 (auxv + (i * 2) * sizeof (Elf32_auxv_t), elfdata) + || do_check32 (auxv + (i * 2 + 1) * sizeof (Elf32_auxv_t), elfdata)) { *elfclass = ELFCLASS32; return true; @@ -717,8 +713,12 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, const Elf##NN##_auxv_t *av = auxv; \ for (size_t i = 0; i < auxv_size / sizeof av[0]; ++i) \ { \ - uint##NN##_t type = READ_AUXV##NN (&av[i].a_type); \ - uint##NN##_t val = BL##NN (READ_AUXV##NN (&av[i].a_un.a_val)); \ + const char *typep = auxv + i * sizeof (Elf##NN##_auxv_t); \ + typep += offsetof (Elf##NN##_auxv_t, a_type); \ + uint##NN##_t type = READ_AUXV##NN (typep); \ + const char *valp = auxv + i * sizeof (Elf##NN##_auxv_t); \ + valp += offsetof (Elf##NN##_auxv_t, a_un.a_val); \ + uint##NN##_t val = BL##NN (READ_AUXV##NN (valp)); \ if (type == BL##NN (AT_ENTRY)) \ entry = val; \ else if (type == BL##NN (AT_PHDR)) \ diff --git a/libdwfl/linux-pid-attach.c b/libdwfl/linux-pid-attach.c index 1def7f16..7e0ff466 100644 --- a/libdwfl/linux-pid-attach.c +++ b/libdwfl/linux-pid-attach.c @@ -1,5 +1,5 @@ /* Get Dwarf Frame state for target live PID process. - Copyright (C) 2013, 2014, 2015 Red Hat, Inc. + Copyright (C) 2013, 2014, 2015, 2018 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -34,8 +34,8 @@ #include "libdwflP.h" #include <sys/types.h> #include <sys/stat.h> +#include <sys/uio.h> #include <fcntl.h> -#include <sys/wait.h> #include <dirent.h> #include <unistd.h> @@ -43,6 +43,7 @@ #include <sys/ptrace.h> #include <sys/syscall.h> +#include <sys/wait.h> static bool linux_proc_pid_is_stopped (pid_t pid) @@ -115,12 +116,90 @@ __libdwfl_ptrace_attach (pid_t tid, bool *tid_was_stoppedp) return true; } +#ifdef HAVE_PROCESS_VM_READV +/* Note that the result word size depends on the architecture word size. + That is sizeof long. */ +static bool +read_cached_memory (struct __libdwfl_pid_arg *pid_arg, + Dwarf_Addr addr, Dwarf_Word *result) +{ + /* Let the ptrace fallback deal with the corner case of the address + possibly crossing a page boundery. */ + if ((addr & ((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1)) + > (Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - sizeof (unsigned long)) + return false; + + struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache; + if (mem_cache == NULL) + { + size_t mem_cache_size = sizeof (struct __libdwfl_remote_mem_cache); + mem_cache = (struct __libdwfl_remote_mem_cache *) malloc (mem_cache_size); + if (mem_cache == NULL) + return false; + + mem_cache->addr = 0; + mem_cache->len = 0; + pid_arg->mem_cache = mem_cache; + } + + unsigned char *d; + if (addr >= mem_cache->addr && addr - mem_cache->addr < mem_cache->len) + { + d = &mem_cache->buf[addr - mem_cache->addr]; + if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0) + *result = *(unsigned long *) d; + else + memcpy (result, d, sizeof (unsigned long)); + return true; + } + + struct iovec local, remote; + mem_cache->addr = addr & ~((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1); + local.iov_base = mem_cache->buf; + local.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE; + remote.iov_base = (void *) (uintptr_t) mem_cache->addr; + remote.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE; + + ssize_t res = process_vm_readv (pid_arg->tid_attached, + &local, 1, &remote, 1, 0); + if (res != __LIBDWFL_REMOTE_MEM_CACHE_SIZE) + { + mem_cache->len = 0; + return false; + } + + mem_cache->len = res; + d = &mem_cache->buf[addr - mem_cache->addr]; + if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0) + *result = *(unsigned long *) d; + else + memcpy (result, d, sizeof (unsigned long)); + return true; +} +#endif /* HAVE_PROCESS_VM_READV */ + +static void +clear_cached_memory (struct __libdwfl_pid_arg *pid_arg) +{ + struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache; + if (mem_cache != NULL) + mem_cache->len = 0; +} + +/* Note that the result word size depends on the architecture word size. + That is sizeof long. */ static bool pid_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg) { struct __libdwfl_pid_arg *pid_arg = arg; pid_t tid = pid_arg->tid_attached; assert (tid > 0); + +#ifdef HAVE_PROCESS_VM_READV + if (read_cached_memory (pid_arg, addr, result)) + return true; +#endif + Dwfl_Process *process = dwfl->process; if (ebl_get_elfclass (process->ebl) == ELFCLASS64) { @@ -253,6 +332,7 @@ pid_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg) { struct __libdwfl_pid_arg *pid_arg = dwfl_arg; elf_end (pid_arg->elf); + free (pid_arg->mem_cache); close (pid_arg->elf_fd); closedir (pid_arg->dir); free (pid_arg); @@ -278,6 +358,7 @@ pid_thread_detach (Dwfl_Thread *thread, void *thread_arg) pid_t tid = INTUSE(dwfl_thread_tid) (thread); assert (pid_arg->tid_attached == tid); pid_arg->tid_attached = 0; + clear_cached_memory (pid_arg); if (! pid_arg->assume_ptrace_stopped) __libdwfl_ptrace_detach (tid, pid_arg->tid_was_stopped); } @@ -379,6 +460,7 @@ dwfl_linux_proc_attach (Dwfl *dwfl, pid_t pid, bool assume_ptrace_stopped) pid_arg->dir = dir; pid_arg->elf = elf; pid_arg->elf_fd = elf_fd; + pid_arg->mem_cache = NULL; pid_arg->tid_attached = 0; pid_arg->assume_ptrace_stopped = assume_ptrace_stopped; if (! INTUSE(dwfl_attach_state) (dwfl, elf, pid, &pid_thread_callbacks, diff --git a/libdwfl/offline.c b/libdwfl/offline.c index 7666358f..be34a63f 100644 --- a/libdwfl/offline.c +++ b/libdwfl/offline.c @@ -150,6 +150,9 @@ process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd, /* Don't keep the file descriptor around. */ if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0) { + /* Grab the dir path in case we want to report this file as + Dwarf later. */ + mod->elfdir = __libdw_debugdir (mod->main.fd); close (mod->main.fd); mod->main.fd = -1; } diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c index 17682433..9afcdebe 100644 --- a/libdwfl/relocate.c +++ b/libdwfl/relocate.c @@ -751,7 +751,7 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug) else result = relocate_section (mod, debugfile, ehdr, d_shstrndx, &reloc_symtab, scn, shdr, tscn, - debug, !debug); + debug, true /* partial always OK. */); } } |
