1 /*
2 * This file is part of ltrace.
3 * Copyright (C) 2013 Petr Machata, Red Hat Inc.
4 * Copyright (C) 2010 Zach Welch, CodeSourcery
5 * Copyright (C) 2004,2008,2009 Juan Cespedes
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 */
22
23 #include <gelf.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "proc.h"
28 #include "library.h"
29 #include "ltrace-elf.h"
30
31 static int
get_hardfp(uint64_t abi_vfp_args)32 get_hardfp(uint64_t abi_vfp_args)
33 {
34 if (abi_vfp_args == 2)
35 fprintf(stderr,
36 "Tag_ABI_VFP_args value 2 (tool chain-specific "
37 "conventions) not supported.\n");
38 return abi_vfp_args == 1;
39 }
40
41 int
arch_elf_init(struct ltelf * lte,struct library * lib)42 arch_elf_init(struct ltelf *lte, struct library *lib)
43 {
44 GElf_Addr jmprel_addr;
45 Elf_Scn *jmprel_sec;
46 GElf_Shdr jmprel_shdr;
47 if (elf_load_dynamic_entry(lte, DT_JMPREL, &jmprel_addr) < 0
48 || elf_get_section_covering(lte, jmprel_addr,
49 &jmprel_sec, &jmprel_shdr) < 0
50 || jmprel_sec == NULL)
51 return -1;
52
53 lte->arch.jmprel_data = elf_loaddata(jmprel_sec, &jmprel_shdr);
54 if (lte->arch.jmprel_data == NULL)
55 return -1;
56
57 /* Nothing in this section is strictly critical. It's not
58 * that much of a deal if we fail to guess right whether the
59 * ABI is softfp or hardfp. */
60 unsigned hardfp = 0;
61
62 Elf_Scn *scn;
63 Elf_Data *data;
64 GElf_Shdr shdr;
65 if (elf_get_section_type(lte, SHT_ARM_ATTRIBUTES, &scn, &shdr) < 0
66 || (scn != NULL && (data = elf_loaddata(scn, &shdr)) == NULL)) {
67 fprintf(stderr,
68 "Error when obtaining ARM attribute section: %s\n",
69 elf_errmsg(-1));
70 goto done;
71
72 } else if (scn != NULL && data != NULL) {
73 GElf_Xword offset = 0;
74 uint8_t version;
75 if (elf_read_next_u8(data, &offset, &version) < 0) {
76 goto done;
77 } else if (version != 'A') {
78 fprintf(stderr, "Unsupported ARM attribute section "
79 "version %d ('%c').\n", version, version);
80 goto done;
81 }
82
83 do {
84 const char signature[] = "aeabi";
85 /* N.B. LEN is including the length field
86 * itself. */
87 uint32_t sec_len;
88 if (elf_read_u32(data, offset, &sec_len) < 0
89 || !elf_can_read_next(data, offset, sec_len)) {
90 goto done;
91 }
92 const GElf_Xword next_offset = offset + sec_len;
93 offset += 4;
94
95 if (sec_len < 4 + sizeof signature
96 || strcmp(signature, data->d_buf + offset) != 0)
97 goto skip;
98 offset += sizeof signature;
99
100 const GElf_Xword offset0 = offset;
101 uint64_t tag;
102 uint32_t sub_len;
103 if (elf_read_next_uleb128(data, &offset, &tag) < 0
104 || elf_read_next_u32(data, &offset, &sub_len) < 0
105 || !elf_can_read_next(data, offset0, sub_len))
106 goto done;
107
108 if (tag != 1)
109 /* IHI0045D_ABI_addenda: "section and
110 * symbol attributes are deprecated
111 * [...] consumers are permitted to
112 * ignore them." */
113 goto skip;
114
115 while (offset < offset0 + sub_len) {
116 if (elf_read_next_uleb128(data,
117 &offset, &tag) < 0)
118 goto done;
119
120 switch (tag) {
121 uint64_t v;
122 case 6: /* Tag_CPU_arch */
123 case 7: /* Tag_CPU_arch_profile */
124 case 8: /* Tag_ARM_ISA_use */
125 case 9: /* Tag_THUMB_ISA_use */
126 case 10: /* Tag_FP_arch */
127 case 11: /* Tag_WMMX_arch */
128 case 12: /* Tag_Advanced_SIMD_arch */
129 case 13: /* Tag_PCS_config */
130 case 14: /* Tag_ABI_PCS_R9_use */
131 case 15: /* Tag_ABI_PCS_RW_data */
132 case 16: /* Tag_ABI_PCS_RO_data */
133 case 17: /* Tag_ABI_PCS_GOT_use */
134 case 18: /* Tag_ABI_PCS_wchar_t */
135 case 19: /* Tag_ABI_FP_rounding */
136 case 20: /* Tag_ABI_FP_denormal */
137 case 21: /* Tag_ABI_FP_exceptions */
138 case 22: /* Tag_ABI_FP_user_exceptions */
139 case 23: /* Tag_ABI_FP_number_model */
140 case 24: /* Tag_ABI_align_needed */
141 case 25: /* Tag_ABI_align_preserved */
142 case 26: /* Tag_ABI_enum_size */
143 case 27: /* Tag_ABI_HardFP_use */
144 case 28: /* Tag_ABI_VFP_args */
145 case 29: /* Tag_ABI_WMMX_args */
146 case 30: /* Tag_ABI_optimization_goals */
147 case 31: /* Tag_ABI_FP_optimization_goals */
148 case 32: /* Tag_compatibility */
149 case 34: /* Tag_CPU_unaligned_access */
150 case 36: /* Tag_FP_HP_extension */
151 case 38: /* Tag_ABI_FP_16bit_format */
152 case 42: /* Tag_MPextension_use */
153 case 70: /* Tag_MPextension_use as well */
154 case 44: /* Tag_DIV_use */
155 case 64: /* Tag_nodefaults */
156 case 66: /* Tag_T2EE_use */
157 case 68: /* Tag_Virtualization_use */
158 uleb128:
159 if (elf_read_next_uleb128
160 (data, &offset, &v) < 0)
161 goto done;
162 if (tag == 28)
163 hardfp = get_hardfp(v);
164 if (tag != 32)
165 continue;
166
167 /* Tag 32 has two arguments,
168 * fall through. */
169
170 case 4: /* Tag_CPU_raw_name */
171 case 5: /* Tag_CPU_name */
172 case 65: /* Tag_also_compatible_with */
173 case 67: /* Tag_conformance */
174 ntbs:
175 offset += strlen(data->d_buf
176 + offset) + 1;
177 continue;
178 }
179
180 /* Handle unknown tags in a generic
181 * manner, if possible. */
182 if (tag <= 32) {
183 fprintf(stderr,
184 "Unknown tag %lld "
185 "at offset %#llx "
186 "of ARM attribute section.",
187 tag, offset);
188 goto skip;
189 } else if (tag % 2 == 0) {
190 goto uleb128;
191 } else {
192 goto ntbs;
193 }
194 }
195
196 skip:
197 offset = next_offset;
198
199 } while (elf_can_read_next(data, offset, 1));
200
201 }
202
203 done:
204 lib->arch.hardfp = hardfp;
205 return 0;
206 }
207
208 void
arch_elf_destroy(struct ltelf * lte)209 arch_elf_destroy(struct ltelf *lte)
210 {
211 }
212
213 static int
arch_plt_entry_has_stub(struct ltelf * lte,size_t off)214 arch_plt_entry_has_stub(struct ltelf *lte, size_t off) {
215 char *buf = (char *) lte->arch.jmprel_data->d_buf;
216 uint16_t op = *(uint16_t *) (buf + off);
217 return op == 0x4778;
218 }
219
220 GElf_Addr
arch_plt_sym_val(struct ltelf * lte,size_t ndx,GElf_Rela * rela)221 arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
222 size_t start = lte->arch.jmprel_data->d_size + 12;
223 size_t off = start + 20, i;
224 for (i = 0; i < ndx; i++)
225 off += arch_plt_entry_has_stub(lte, off) ? 16 : 12;
226 if (arch_plt_entry_has_stub(lte, off))
227 off += 4;
228 return lte->plt_addr + off - start;
229 }
230
231 void *
sym2addr(struct process * proc,struct library_symbol * sym)232 sym2addr(struct process *proc, struct library_symbol *sym)
233 {
234 return sym->enter_addr;
235 }
236
237 int
arch_library_init(struct library * lib)238 arch_library_init(struct library *lib)
239 {
240 return 0;
241 }
242
243 void
arch_library_destroy(struct library * lib)244 arch_library_destroy(struct library *lib)
245 {
246 }
247
248 int
arch_library_clone(struct library * retp,struct library * lib)249 arch_library_clone(struct library *retp, struct library *lib)
250 {
251 retp->arch = lib->arch;
252 return 0;
253 }
254