plt.c revision 4e2073f64f9db2974d89064dcdc49b2ed7aa9006
1#include <gelf.h>
2#include <sys/ptrace.h>
3#include <errno.h>
4#include <error.h>
5#include <inttypes.h>
6#include <assert.h>
7
8#include "proc.h"
9#include "common.h"
10#include "library.h"
11
12#define PPC_PLT_STUB_SIZE 16
13
14static inline int
15host_powerpc64()
16{
17#ifdef __powerpc64__
18	return 1;
19#else
20	return 0;
21#endif
22}
23
24GElf_Addr
25arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
26{
27	if (lte->ehdr.e_machine == EM_PPC && lte->arch.secure_plt) {
28		assert(lte->arch.plt_stub_vma != 0);
29		return lte->arch.plt_stub_vma + PPC_PLT_STUB_SIZE * ndx;
30
31	} else if (lte->ehdr.e_machine == EM_PPC) {
32		return rela->r_offset;
33
34	} else {
35		assert(lte->ehdr.e_machine == EM_PPC64);
36		fprintf(stderr, "PPC64\n");
37		abort();
38		return rela->r_offset;
39	}
40}
41
42int
43arch_translate_address(struct Process *proc,
44		       target_address_t addr, target_address_t *ret)
45{
46	if (host_powerpc64() && proc->e_machine == EM_PPC64) {
47		long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
48		fprintf(stderr, "arch_translate_address %p->%#lx\n",
49			addr, l);
50		if (l == -1 && errno) {
51			error(0, errno, ".opd translation of %p", addr);
52			return -1;
53		}
54		*ret = (target_address_t)l;
55		return 0;
56	}
57
58	*ret = addr;
59	return 0;
60}
61
62/* XXX Apparently PPC64 doesn't support PLT breakpoints.  */
63void *
64sym2addr(Process *proc, struct library_symbol *sym) {
65	void *addr = sym->enter_addr;
66	long pt_ret;
67
68	debug(3, 0);
69
70	if (sym->plt_type != LS_TOPLT_POINT) {
71		return addr;
72	}
73
74	if (proc->pid == 0) {
75		return 0;
76	}
77
78	if (options.debug >= 3) {
79		xinfdump(proc->pid, (void *)(((long)addr-32)&0xfffffff0),
80			 sizeof(void*)*8);
81	}
82
83	// On a PowerPC-64 system, a plt is three 64-bit words: the first is the
84	// 64-bit address of the routine.  Before the PLT has been initialized,
85	// this will be 0x0. In fact, the symbol table won't have the plt's
86	// address even.  Ater the PLT has been initialized, but before it has
87	// been resolved, the first word will be the address of the function in
88	// the dynamic linker that will reslove the PLT.  After the PLT is
89	// resolved, this will will be the address of the routine whose symbol
90	// is in the symbol table.
91
92	// On a PowerPC-32 system, there are two types of PLTs: secure (new) and
93	// non-secure (old).  For the secure case, the PLT is simply a pointer
94	// and we can treat it much as we do for the PowerPC-64 case.  For the
95	// non-secure case, the PLT is executable code and we can put the
96	// break-point right in the PLT.
97
98	pt_ret = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
99
100#if SIZEOF_LONG == 8
101	if (proc->mask_32bit) {
102		// Assume big-endian.
103		addr = (void *)((pt_ret >> 32) & 0xffffffff);
104	} else {
105		addr = (void *)pt_ret;
106	}
107#else
108	/* XXX Um, so where exactly are we dealing with the non-secure
109	   PLT thing?  */
110	addr = (void *)pt_ret;
111#endif
112
113	return addr;
114}
115
116static GElf_Addr
117get_glink_vma(struct ltelf *lte, GElf_Addr ppcgot, Elf_Data *plt_data)
118{
119	Elf_Scn *ppcgot_sec = NULL;
120	GElf_Shdr ppcgot_shdr;
121	if (ppcgot != 0
122	    && elf_get_section_covering(lte, ppcgot,
123					&ppcgot_sec, &ppcgot_shdr) < 0)
124		// xxx should be the log out
125		fprintf(stderr,
126			"DT_PPC_GOT=%#" PRIx64 ", but no such section found.\n",
127			ppcgot);
128
129	if (ppcgot_sec != NULL) {
130		Elf_Data *data = elf_loaddata(ppcgot_sec, &ppcgot_shdr);
131		if (data == NULL || data->d_size < 8 ) {
132			fprintf(stderr, "Couldn't read GOT data.\n");
133		} else {
134			// where PPCGOT begins in .got
135			size_t offset = ppcgot - ppcgot_shdr.sh_addr;
136			assert(offset % 4 == 0);
137			uint32_t glink_vma;
138			if (elf_read_u32(data, offset + 4, &glink_vma) < 0) {
139				fprintf(stderr,
140					"Couldn't read glink VMA address"
141					" at %zd@GOT\n", offset);
142				return 0;
143			}
144			if (glink_vma != 0) {
145				debug(1, "PPC GOT glink_vma address: %#" PRIx32,
146				      glink_vma);
147				fprintf(stderr, "PPC GOT glink_vma "
148					"address: %#"PRIx32"\n", glink_vma);
149				return (GElf_Addr)glink_vma;
150			}
151		}
152	}
153
154	if (plt_data != NULL) {
155		uint32_t glink_vma;
156		if (elf_read_u32(plt_data, 0, &glink_vma) < 0) {
157			fprintf(stderr,
158				"Couldn't read glink VMA address at 0@.plt\n");
159			return 0;
160		}
161		debug(1, ".plt glink_vma address: %#" PRIx32, glink_vma);
162		fprintf(stderr, ".plt glink_vma address: "
163			"%#"PRIx32"\n", glink_vma);
164		return (GElf_Addr)glink_vma;
165	}
166
167	return 0;
168}
169
170int
171arch_elf_dynamic_tag(struct ltelf *lte, GElf_Dyn dyn)
172{
173	if (dyn.d_tag == DT_PPC_GOT) {
174		lte->arch.ppcgot = dyn.d_un.d_val;
175		debug(1, "ppcgot %#" PRIx64, lte->arch.ppcgot);
176	}
177	return 0;
178}
179
180int
181arch_elf_init(struct ltelf *lte)
182{
183	lte->arch.secure_plt = !(lte->lte_flags & LTE_PLT_EXECUTABLE);
184	if (lte->ehdr.e_machine == EM_PPC && lte->arch.secure_plt) {
185		GElf_Addr glink_vma
186			= get_glink_vma(lte, lte->arch.ppcgot, lte->plt_data);
187
188		assert (lte->relplt_size % 12 == 0);
189		size_t count = lte->relplt_size / 12; // size of RELA entry
190		lte->arch.plt_stub_vma = glink_vma
191			- (GElf_Addr)count * PPC_PLT_STUB_SIZE;
192		debug(1, "stub_vma is %#" PRIx64, lte->arch.plt_stub_vma);
193	}
194
195	/* Override the value that we gleaned from flags on the .plt
196	 * section.  The PLT entries are in fact executable, they are
197	 * just not in .plt.  */
198	lte->lte_flags |= LTE_PLT_EXECUTABLE;
199	return 0;
200}
201