summaryrefslogtreecommitdiffstats
path: root/libdwfl
diff options
context:
space:
mode:
authorUlf Hermann <[email protected]>2018-07-13 18:32:53 +0200
committerUlf Hermann <[email protected]>2018-07-13 18:32:53 +0200
commit731aa2b1b0f73b443c8ed7538c134849935d0ba1 (patch)
tree9179c5a58889c4725751856bf75d6a91810d5bf8 /libdwfl
parentd9483eb79086970df1dd875f6914bd0a442e8566 (diff)
parentaa36de0335e3ce12898954985a208f6336731289 (diff)
Merge tag 'elfutils-0.173'
elfutils 0.173 release Change-Id: I83dc56dd15c26fe7acf4ce73c29df65b8b65e757
Diffstat (limited to 'libdwfl')
-rw-r--r--libdwfl/ChangeLog76
-rw-r--r--libdwfl/argp-std.c2
-rw-r--r--libdwfl/cu.c14
-rw-r--r--libdwfl/dwfl_build_id_find_elf.c2
-rw-r--r--libdwfl/dwfl_module.c1
-rw-r--r--libdwfl/dwfl_module_addrsym.c9
-rw-r--r--libdwfl/dwfl_module_getdwarf.c23
-rw-r--r--libdwfl/dwfl_report_elf.c2
-rw-r--r--libdwfl/find-debuginfo.c2
-rw-r--r--libdwfl/frame_unwind.c48
-rw-r--r--libdwfl/libdwflP.h25
-rw-r--r--libdwfl/link_map.c38
-rw-r--r--libdwfl/linux-pid-attach.c86
-rw-r--r--libdwfl/offline.c3
-rw-r--r--libdwfl/relocate.c2
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. */);
}
}