1 /*
2 * This file is part of ltrace.
3 * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
4 * Copyright (C) 2012 Edgar E. Iglesias, Axis Communications
5 * Copyright (C) 2008,2009 Juan Cespedes
6 * Copyright (C) 2006 Eric Vaitl, Cisco Systems, Inc.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 */
23
24 #include <string.h>
25 #include <errno.h>
26 #include <gelf.h>
27 #include <sys/ptrace.h>
28
29 #include "common.h"
30 #include "debug.h"
31 #include "proc.h"
32 #include "library.h"
33 #include "breakpoint.h"
34 #include "backend.h"
35
36 /**
37 \addtogroup mips
38 @{
39 */
40
41 /* Are we in pure CPIC mode (the non-PIC ABI extension)? */
42 static inline int
mips_elf_is_cpic(unsigned int elf_flags)43 mips_elf_is_cpic(unsigned int elf_flags)
44 {
45 return (elf_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC;
46 }
47
48 /**
49 \param lte Structure containing link table entry information
50 \param ndx Index into .dynsym
51 \param rela Not used.
52 \return Address of GOT table entry
53
54 MIPS ABI Supplement:
55
56 DT_PLTGOT This member holds the address of the .got section.
57
58 DT_MIPS_SYMTABNO This member holds the number of entries in the
59 .dynsym section.
60
61 DT_MIPS_LOCAL_GOTNO This member holds the number of local global
62 offset table entries.
63
64 DT_MIPS_GOTSYM This member holds the index of the first dyamic
65 symbol table entry that corresponds to an entry in the gobal offset
66 table.
67
68 Called by read_elf when building the symbol table.
69
70 */
71 GElf_Addr
arch_plt_sym_val(struct ltelf * lte,size_t ndx,GElf_Rela * rela)72 arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
73 {
74 debug(1,"plt_addr %zx ndx %#zx",lte->arch.pltgot_addr, ndx);
75
76 if (mips_elf_is_cpic(lte->ehdr.e_flags)) {
77 /* Return a pointer into the PLT. */
78 return lte->plt_addr + 16 * 2 + (ndx * 16);
79 }
80
81 /* Return a pointer to a GOT entry. */
82 return lte->arch.pltgot_addr +
83 sizeof(void *) * (lte->arch.mips_local_gotno
84 + (ndx - lte->arch.mips_gotsym));
85 }
86 /**
87 \param proc The process to work on.
88 \param sym The library symbol.
89 \return What is at the got table address
90
91 The return value should be the address to put the breakpoint at.
92
93 On the mips the library_symbol.enter_addr is the .got addr for the
94 symbol and the breakpoint.addr is the actual breakpoint address.
95
96 Other processors use a plt, the mips is "special" in that is uses
97 the .got for both function and data relocations. Prior to program
98 startup, return 0.
99
100 \warning MIPS relocations are lazy. This means that the breakpoint
101 may move after the first call. Ltrace dictionary routines don't
102 have a delete and symbol is one to one with breakpoint, so if the
103 breakpoint changes I just add a new breakpoint for the new address.
104 */
105 void *
sym2addr(struct process * proc,struct library_symbol * sym)106 sym2addr(struct process *proc, struct library_symbol *sym)
107 {
108 long ret;
109
110 if (sym->arch.pltalways
111 || (!sym->arch.gotonly && sym->plt_type == LS_TOPLT_NONE)) {
112 return sym->enter_addr;
113 }
114
115 if(!proc->pid){
116 return 0;
117 }
118 ret=ptrace(PTRACE_PEEKTEXT, proc->pid, sym->enter_addr, 0);
119 if(ret==-1){
120 ret =0;
121 }
122 return (void *)ret;;
123 }
124
125 /* Address of run time loader map, used for debugging. */
126 #define DT_MIPS_RLD_MAP 0x70000016
127 int
arch_find_dl_debug(struct process * proc,arch_addr_t dyn_addr,arch_addr_t * ret)128 arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr,
129 arch_addr_t *ret)
130 {
131 arch_addr_t rld_addr;
132 int r;
133
134 /* MIPS puts the address of the r_debug structure into the
135 * DT_MIPS_RLD_MAP entry instead of into the DT_DEBUG entry. */
136 r = proc_find_dynamic_entry_addr(proc, dyn_addr,
137 DT_MIPS_RLD_MAP, &rld_addr);
138 if (r == 0) {
139 if (umovebytes(proc, rld_addr,
140 ret, sizeof *ret) != sizeof *ret) {
141 r = -1;
142 }
143 }
144 return r;
145 }
146
147
148 /*
149 * MIPS doesn't have traditional got.plt entries with corresponding
150 * relocations.
151 *
152 * sym_index is an offset into the external GOT entries. Filter out
153 * stuff that are not functions.
154 */
155 int
arch_get_sym_info(struct ltelf * lte,const char * filename,size_t sym_index,GElf_Rela * rela,GElf_Sym * sym)156 arch_get_sym_info(struct ltelf *lte, const char *filename,
157 size_t sym_index, GElf_Rela *rela, GElf_Sym *sym)
158 {
159 if (mips_elf_is_cpic(lte->ehdr.e_flags)) {
160 return gelf_getsym(lte->dynsym, ELF64_R_SYM(rela->r_info),
161 sym) != NULL ? 0 : -1;
162 }
163
164 /* Fixup the offset. */
165 sym_index += lte->arch.mips_gotsym;
166
167 if (gelf_getsym(lte->dynsym, sym_index, sym) == NULL)
168 return -1;
169
170 if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) {
171 const char *name = lte->dynstr + sym->st_name;
172 debug(2, "sym %s not a function", name);
173 return 1;
174 }
175
176 return 0;
177 }
178
179 /**
180 MIPS ABI Supplement:
181
182 DT_PLTGOT This member holds the address of the .got section.
183
184 DT_MIPS_SYMTABNO This member holds the number of entries in the
185 .dynsym section.
186
187 DT_MIPS_LOCAL_GOTNO This member holds the number of local global
188 offset table entries.
189
190 DT_MIPS_GOTSYM This member holds the index of the first dyamic
191 symbol table entry that corresponds to an entry in the gobal offset
192 table.
193
194 */
195 int
arch_elf_init(struct ltelf * lte,struct library * lib)196 arch_elf_init(struct ltelf *lte, struct library *lib)
197 {
198 Elf_Scn *scn;
199 GElf_Shdr shdr;
200
201 /* FIXME: for CPIC we should really scan both GOT tables
202 * to pick up relocations to external functions. Right now
203 * function pointers from the main binary to external functions
204 * can't be traced in CPIC mode. */
205 if (mips_elf_is_cpic(lte->ehdr.e_flags)) {
206 return 0; /* We are already done. */
207 }
208
209 if (elf_get_section_type(lte, SHT_DYNAMIC, &scn, &shdr) < 0
210 || scn == NULL) {
211 fail:
212 fprintf(stderr, "Couldn't get SHT_DYNAMIC: %s",
213 elf_errmsg(-1));
214 return -1;
215 }
216
217 Elf_Data *data = elf_loaddata(scn, &shdr);
218 if (data == NULL)
219 goto fail;
220
221 size_t j;
222 for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
223 GElf_Dyn dyn;
224 if (gelf_getdyn(data, j, &dyn) == NULL)
225 goto fail;
226
227 if(dyn.d_tag == DT_PLTGOT) {
228 lte->arch.pltgot_addr = dyn.d_un.d_ptr;
229 }
230 if(dyn.d_tag == DT_MIPS_LOCAL_GOTNO){
231 lte->arch.mips_local_gotno = dyn.d_un.d_val;
232 }
233 if(dyn.d_tag == DT_MIPS_GOTSYM){
234 lte->arch.mips_gotsym = dyn.d_un.d_val;
235 }
236 }
237
238 /* Tell the generic code how many dynamic trace:able symbols
239 * we've got. */
240 /* BEGIN android-changed */
241 /* TODO(mkayyash): Investigate a fix for missing relplt_count. */
242 /* lte->relplt_count = lte->dynsym_count - lte->arch.mips_gotsym; */
243 /* END android-changed */
244 return 0;
245 }
246
247 void
arch_elf_destroy(struct ltelf * lte)248 arch_elf_destroy(struct ltelf *lte)
249 {
250 }
251
252 /* When functions return we check if the symbol needs an updated
253 breakpoint with the resolved address. */
arch_symbol_ret(struct process * proc,struct library_symbol * libsym)254 void arch_symbol_ret(struct process *proc, struct library_symbol *libsym)
255 {
256 struct breakpoint *bp;
257 arch_addr_t resolved_addr;
258 struct process *leader = proc->leader;
259
260 /* Only deal with unresolved symbols. */
261 if (libsym->arch.type != MIPS_PLT_UNRESOLVED)
262 return;
263
264 /* Get out if we are always using the PLT. */
265 if (libsym->arch.pltalways)
266 return;
267
268 resolved_addr = sym2addr(proc, libsym);
269 libsym->arch.resolved_addr = (uintptr_t) resolved_addr;
270 libsym->arch.type = MIPS_PLT_RESOLVED;
271
272 if (libsym->arch.stub_addr == libsym->arch.resolved_addr) {
273 /* Prelinked symbol. No need to add new breakpoint. */
274 return;
275 }
276
277 bp = malloc(sizeof (*bp));
278 if (bp == NULL) {
279 fprintf(stderr, "Failed to allocate bp for %s\n",
280 libsym->name);
281 return;
282 }
283
284 if (breakpoint_init(bp, leader, resolved_addr, libsym) < 0)
285 goto err;
286
287 if (proc_add_breakpoint(leader, bp) < 0) {
288 breakpoint_destroy(bp);
289 goto err;
290 }
291
292 if (breakpoint_turn_on(bp, leader) < 0) {
293 proc_remove_breakpoint(leader, bp);
294 breakpoint_destroy(bp);
295 goto err;
296 }
297 return;
298 err:
299 free(bp);
300 }
301
302 static enum callback_status
cb_enable_breakpoint_sym(struct library_symbol * libsym,void * data)303 cb_enable_breakpoint_sym(struct library_symbol *libsym, void *data)
304 {
305 struct process *proc = data;
306 arch_addr_t bp_addr;
307
308 if (!libsym->arch.gotonly)
309 return CBS_CONT;
310
311 /* Update state. */
312 bp_addr = sym2addr(proc, libsym);
313 /* XXX The cast to uintptr_t should be removed when
314 * arch_addr_t becomes integral type. keywords: double cast. */
315 libsym->arch.resolved_addr = (uintptr_t) bp_addr;
316
317 if (libsym->arch.resolved_addr == 0)
318 /* FIXME: What does this mean? */
319 return CBS_CONT;
320
321 libsym->arch.type = MIPS_PLT_RESOLVED;
322
323 /* Now, activate the symbol causing a breakpoint to be added. */
324 if (proc_activate_delayed_symbol(proc, libsym) < 0) {
325 fprintf(stderr, "Failed to activate delayed sym %s\n",
326 libsym->name);
327 }
328 return CBS_CONT;
329 }
330
331 static enum callback_status
cb_enable_breakpoint_lib(struct process * proc,struct library * lib,void * data)332 cb_enable_breakpoint_lib(struct process *proc, struct library *lib, void *data)
333 {
334 library_each_symbol(lib, NULL, cb_enable_breakpoint_sym, proc);
335 return CBS_CONT;
336 }
337
arch_dynlink_done(struct process * proc)338 void arch_dynlink_done(struct process *proc)
339 {
340 proc_each_library(proc->leader, NULL, cb_enable_breakpoint_lib, NULL);
341 }
342
343 enum plt_status
arch_elf_add_plt_entry(struct process * proc,struct ltelf * lte,const char * a_name,GElf_Rela * rela,size_t ndx,struct library_symbol ** ret)344 arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
345 const char *a_name, GElf_Rela *rela, size_t ndx,
346 struct library_symbol **ret)
347 {
348 char *name = NULL;
349 int sym_index = ndx + lte->arch.mips_gotsym;
350
351 struct library_symbol *libsym = malloc(sizeof(*libsym));
352 if (libsym == NULL)
353 return PLT_FAIL;
354
355 GElf_Addr addr = arch_plt_sym_val(lte, sym_index, 0);
356
357 name = strdup(a_name);
358 if (name == NULL) {
359 fprintf(stderr, "%s: failed %s(%#llx): %s\n", __func__,
360 name, addr, strerror(errno));
361 goto fail;
362 }
363
364 /* XXX The double cast should be removed when
365 * arch_addr_t becomes integral type. */
366 if (library_symbol_init(libsym,
367 (arch_addr_t) (uintptr_t) addr,
368 name, 1, LS_TOPLT_EXEC) < 0) {
369 fprintf(stderr, "%s: failed %s : %llx\n", __func__, name, addr);
370 goto fail;
371 }
372
373 arch_addr_t bp_addr = sym2addr(proc, libsym);
374 /* XXX This cast should be removed when
375 * arch_addr_t becomes integral type. keywords: double cast. */
376 libsym->arch.stub_addr = (uintptr_t) bp_addr;
377
378 if (bp_addr == 0) {
379 /* Function pointers without PLT entries. */
380 libsym->plt_type = LS_TOPLT_NONE;
381 libsym->arch.gotonly = 1;
382 libsym->arch.type = MIPS_PLT_UNRESOLVED;
383
384 /* Delay breakpoint activation until the symbol gets
385 * resolved. */
386 libsym->delayed = 1;
387 } else if (mips_elf_is_cpic(lte->ehdr.e_flags)) {
388 libsym->arch.pltalways = 1;
389 }
390
391 *ret = libsym;
392 return PLT_OK;
393
394 fail:
395 free(name);
396 free(libsym);
397 return PLT_FAIL;
398 }
399
400 int
arch_library_symbol_init(struct library_symbol * libsym)401 arch_library_symbol_init(struct library_symbol *libsym)
402 {
403 libsym->arch.pltalways = 0;
404 libsym->arch.gotonly = 0;
405 libsym->arch.type = MIPS_PLT_UNRESOLVED;
406 if (libsym->plt_type == LS_TOPLT_NONE) {
407 libsym->arch.type = MIPS_PLT_RESOLVED;
408 }
409 return 0;
410 }
411
412 void
arch_library_symbol_destroy(struct library_symbol * libsym)413 arch_library_symbol_destroy(struct library_symbol *libsym)
414 {
415 }
416
417 int
arch_library_symbol_clone(struct library_symbol * retp,struct library_symbol * libsym)418 arch_library_symbol_clone(struct library_symbol *retp,
419 struct library_symbol *libsym)
420 {
421 retp->arch = libsym->arch;
422 return 0;
423 }
424
425 /**@}*/
426