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