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