File: elfish_64.c

package info (click to toggle)
dtrace 2.0.5-1
  • links: PTS
  • area: main
  • in suites: sid
  • size: 24,408 kB
  • sloc: ansic: 61,247; sh: 17,997; asm: 1,717; lex: 947; awk: 754; yacc: 695; perl: 37; sed: 17; makefile: 15
file content (162 lines) | stat: -rw-r--r-- 3,747 bytes parent folder | download
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