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 31static int 32get_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 41int 42arch_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 203done: 204 lib->arch.hardfp = hardfp; 205 return 0; 206} 207 208void 209arch_elf_destroy(struct ltelf *lte) 210{ 211} 212 213static int 214arch_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 220GElf_Addr 221arch_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 231void * 232sym2addr(struct process *proc, struct library_symbol *sym) 233{ 234 return sym->enter_addr; 235} 236 237int 238arch_library_init(struct library *lib) 239{ 240 return 0; 241} 242 243void 244arch_library_destroy(struct library *lib) 245{ 246} 247 248int 249arch_library_clone(struct library *retp, struct library *lib) 250{ 251 retp->arch = lib->arch; 252 return 0; 253} 254