1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
/*
* ELF-related support code, bitness-dependent (64-bit by default).
*/
/*
* Oracle Linux DTrace.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#include <inttypes.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <elf.h>
#include "Pcontrol.h"
#include "libproc.h"
#ifndef BITS
#define BITS 64
#endif
#include "elfish_impl.h"
#ifndef BITIZE
#define JOIN(pre,post) pre##_elf##post
#define EXJOIN(pre,post) JOIN(pre,post)
#define JOINMID(pre,mid,post) pre##mid##post
#define EXJOINMID(pre,mid,post) JOINMID(pre,mid,post)
#define BITIZE(pre) EXJOIN(pre,BITS)
#define ElfIZE(suffix) EXJOINMID(Elf,BITS,_##suffix)
#define ELFIZE(suffix) EXJOINMID(ELF,BITS,_##suffix)
#endif
/*
* Find the r_debug structure for the base lmid in a running, traced process.
* Return -1 if none, or if the process is not running.
*
* r_debugs for lmids other than LM_ID_BASE require a different method:
* see rtld_db.c:ns_debug_addr().
*/
uintptr_t
BITIZE(r_debug)(struct ps_prochandle *P)
{
uint64_t phaddr = Pgetauxval(P, AT_PHDR);
uint64_t phent = Pgetauxval(P, AT_PHENT);
uint64_t phnum = Pgetauxval(P, AT_PHNUM);
uintptr_t reloc = 0;
uint64_t num_found = 0;
ElfIZE(Phdr) phdr;
ElfIZE(Addr) dynaddr = 0;
ElfIZE(Xword) dynsize = 0;
ElfIZE(Dyn) dyn;
uint64_t i;
if ((phaddr == -1) || (phent == -1) || (phnum == -1)) {
_dprintf("%i: no phaddr, phent or phnum auxvec entry.\n",
P->pid);
return -1;
}
if (P->state == PS_DEAD) {
_dprintf("%i: process is dead.", P->pid);
return -1;
}
if (phent != sizeof(phdr)) {
static int warned = 0;
if (!warned) {
fprintf(stderr, "%i: AT_PHENT is the wrong "
"size: %li bytes versus an expected %li.\n"
"This should never happen.\n", P->pid, phent,
sizeof(phdr));
warned = 1;
}
return -1;
}
/*
* Find the PT_DYNAMIC and PT_PHDR sections.
*/
for (i = 0; i < phnum && num_found < 2; i++, phaddr += sizeof(phdr)) {
ssize_t foo;
if ((foo = Pread(P, &phdr, sizeof(phdr),
(uintptr_t)phaddr)) != sizeof(phdr)) {
_dprintf("short read: phdr end: read %li, sizeof(phdr) %li\n",
foo, sizeof(phdr));
/*
* Short read -> assume end of phdr.
*/
break;
}
if (phdr.p_type == PT_DYNAMIC) {
dynaddr = phdr.p_vaddr;
dynsize = phdr.p_memsz;
num_found++;
} else if (phdr.p_type == PT_PHDR) {
/*
* If this exists, we can use it to figure out the
* relocation, if any, which should be applied to
* find the dynamic section. For PIE executables, this
* can be nonzero.
*/
reloc = phaddr - phdr.p_vaddr;
num_found++;
}
}
if (!dynaddr) {
/*
* No PT_DYNAMIC: probably statically linked.
*
* Look for the symbol by name.
*/
GElf_Sym sym;
P->no_dyn = TRUE;
if (Pxlookup_by_name(P, PR_LMID_EVERY, PR_OBJ_EVERY,
"_r_debug", &sym, NULL) < 0) {
_dprintf("%i: cannot find r_debug: no dynaddr.\n", P->pid);
return 0;
} else
return sym.st_value;
}
/*
* Find the DT_DEBUG dynamic tag.
*/
for (i = 0; i < dynsize; i += sizeof(dyn), dynaddr += sizeof(dyn)) {
if (Pread(P, &dyn, sizeof(dyn),
(uintptr_t)(dynaddr + reloc)) != sizeof(dyn)) {
/*
* Short read -> assume end of dynamic section.
*/
_dprintf("%i: cannot find r_debug: short read in "
"dynamic section.\n", P->pid);
return -1;
}
if (dyn.d_tag == DT_DEBUG)
return dyn.d_un.d_ptr;
}
_dprintf("%i: cannot find r_debug: no DT_DEBUG dynamic tag.\n", P->pid);
return -1;
}
#undef JOIN
#undef EXJOIN
#undef JOINMID
#undef EXJOINMID
#undef BITIZE
#undef ElfIZE
#undef ELFIZE
|