Home | History | Annotate | Download | only in arm
      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
     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
     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
    209 arch_elf_destroy(struct ltelf *lte)
    210 {
    211 }
    212 
    213 static int
    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
    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 *
    232 sym2addr(struct process *proc, struct library_symbol *sym)
    233 {
    234 	return sym->enter_addr;
    235 }
    236 
    237 int
    238 arch_library_init(struct library *lib)
    239 {
    240 	return 0;
    241 }
    242 
    243 void
    244 arch_library_destroy(struct library *lib)
    245 {
    246 }
    247 
    248 int
    249 arch_library_clone(struct library *retp, struct library *lib)
    250 {
    251 	retp->arch = lib->arch;
    252 	return 0;
    253 }
    254