1 /*- 2 * Copyright (c) 2010 Kai Wang 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include "_libdwarf.h" 28 29 ELFTC_VCSID("$Id: libdwarf_reloc.c 3149 2015-02-15 19:00:06Z emaste $"); 30 31 Dwarf_Unsigned 32 _dwarf_get_reloc_type(Dwarf_P_Debug dbg, int is64) 33 { 34 35 assert(dbg != NULL); 36 37 switch (dbg->dbgp_isa) { 38 case DW_ISA_AARCH64: 39 return (is64 ? R_AARCH64_ABS64 : R_AARCH64_ABS32); 40 case DW_ISA_X86: 41 return (R_386_32); 42 case DW_ISA_X86_64: 43 return (is64 ? R_X86_64_64 : R_X86_64_32); 44 case DW_ISA_SPARC: 45 return (is64 ? R_SPARC_UA64 : R_SPARC_UA32); 46 case DW_ISA_PPC: 47 return (R_PPC_ADDR32); 48 case DW_ISA_ARM: 49 return (R_ARM_ABS32); 50 case DW_ISA_MIPS: 51 return (is64 ? R_MIPS_64 : R_MIPS_32); 52 case DW_ISA_IA64: 53 return (is64 ? R_IA_64_DIR64LSB : R_IA_64_DIR32LSB); 54 default: 55 break; 56 } 57 return (0); /* NOT REACHED */ 58 } 59 60 int 61 _dwarf_get_reloc_size(Dwarf_Debug dbg, Dwarf_Unsigned rel_type) 62 { 63 64 switch (dbg->dbg_machine) { 65 case EM_NONE: 66 break; 67 case EM_AARCH64: 68 if (rel_type == R_AARCH64_ABS32) 69 return (4); 70 else if (rel_type == R_AARCH64_ABS64) 71 return (8); 72 break; 73 case EM_ARM: 74 if (rel_type == R_ARM_ABS32) 75 return (4); 76 break; 77 case EM_386: 78 if (rel_type == R_386_32) 79 return (4); 80 break; 81 case EM_X86_64: 82 if (rel_type == R_X86_64_32) 83 return (4); 84 else if (rel_type == R_X86_64_64) 85 return (8); 86 break; 87 case EM_SPARC: 88 if (rel_type == R_SPARC_UA32) 89 return (4); 90 else if (rel_type == R_SPARC_UA64) 91 return (8); 92 break; 93 case EM_PPC: 94 if (rel_type == R_PPC_ADDR32) 95 return (4); 96 break; 97 case EM_MIPS: 98 if (rel_type == R_MIPS_32) 99 return (4); 100 else if (rel_type == R_MIPS_64) 101 return (8); 102 break; 103 case EM_IA_64: 104 if (rel_type == R_IA_64_SECREL32LSB) 105 return (4); 106 else if (rel_type == R_IA_64_DIR64LSB) 107 return (8); 108 break; 109 default: 110 break; 111 } 112 113 /* unknown relocation. */ 114 return (0); 115 } 116 117 int 118 _dwarf_reloc_section_init(Dwarf_P_Debug dbg, Dwarf_Rel_Section *drsp, 119 Dwarf_P_Section ref, Dwarf_Error *error) 120 { 121 Dwarf_Rel_Section drs; 122 char name[128]; 123 int pseudo; 124 125 assert(dbg != NULL && drsp != NULL && ref != NULL); 126 127 if ((drs = calloc(1, sizeof(struct _Dwarf_Rel_Section))) == NULL) { 128 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 129 return (DW_DLE_MEMORY); 130 } 131 132 drs->drs_ref = ref; 133 134 /* 135 * FIXME The logic here is most likely wrong. It should 136 * be the ISA that determines relocation type. 137 */ 138 if (dbg->dbgp_flags & DW_DLC_SIZE_64) 139 drs->drs_addend = 1; 140 else 141 drs->drs_addend = 0; 142 143 if (dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS) 144 pseudo = 1; 145 else 146 pseudo = 0; 147 148 snprintf(name, sizeof(name), "%s%s", 149 drs->drs_addend ? ".rela" : ".rel", ref->ds_name); 150 if (_dwarf_section_init(dbg, &drs->drs_ds, name, pseudo, error) != 151 DW_DLE_NONE) { 152 free(drs); 153 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 154 return (DW_DLE_MEMORY); 155 } 156 157 STAILQ_INIT(&drs->drs_dre); 158 STAILQ_INSERT_TAIL(&dbg->dbgp_drslist, drs, drs_next); 159 dbg->dbgp_drscnt++; 160 *drsp = drs; 161 162 return (DW_DLE_NONE); 163 } 164 165 void 166 _dwarf_reloc_section_free(Dwarf_P_Debug dbg, Dwarf_Rel_Section *drsp) 167 { 168 Dwarf_Rel_Section drs, tdrs; 169 Dwarf_Rel_Entry dre, tdre; 170 171 assert(dbg != NULL && drsp != NULL); 172 173 if (*drsp == NULL) 174 return; 175 176 STAILQ_FOREACH_SAFE(drs, &dbg->dbgp_drslist, drs_next, tdrs) { 177 if (drs != *drsp) 178 continue; 179 STAILQ_REMOVE(&dbg->dbgp_drslist, drs, _Dwarf_Rel_Section, 180 drs_next); 181 STAILQ_FOREACH_SAFE(dre, &drs->drs_dre, dre_next, tdre) { 182 STAILQ_REMOVE(&drs->drs_dre, dre, _Dwarf_Rel_Entry, 183 dre_next); 184 free(dre); 185 } 186 if ((dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS) == 0) 187 _dwarf_section_free(dbg, &drs->drs_ds); 188 else { 189 if (drs->drs_ds->ds_name) 190 free(drs->drs_ds->ds_name); 191 free(drs->drs_ds); 192 } 193 free(drs); 194 *drsp = NULL; 195 dbg->dbgp_drscnt--; 196 break; 197 } 198 } 199 200 int 201 _dwarf_reloc_entry_add(Dwarf_P_Debug dbg, Dwarf_Rel_Section drs, 202 Dwarf_P_Section ds, unsigned char type, unsigned char length, 203 Dwarf_Unsigned offset, Dwarf_Unsigned symndx, Dwarf_Unsigned addend, 204 const char *secname, Dwarf_Error *error) 205 { 206 Dwarf_Rel_Entry dre; 207 Dwarf_Unsigned reloff; 208 int ret; 209 210 assert(drs != NULL); 211 assert(offset <= ds->ds_size); 212 reloff = offset; 213 214 /* 215 * If the DW_DLC_SYMBOLIC_RELOCATIONS flag is set or ElfXX_Rel 216 * is used instead of ELfXX_Rela, we need to write the addend 217 * in the storage unit to be relocated. Otherwise write 0 in the 218 * storage unit and the addend will be written into relocation 219 * section later. 220 */ 221 if ((dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS) || 222 drs->drs_addend == 0) 223 ret = dbg->write_alloc(&ds->ds_data, &ds->ds_cap, &offset, 224 addend, length, error); 225 else 226 ret = dbg->write_alloc(&ds->ds_data, &ds->ds_cap, &offset, 227 0, length, error); 228 if (ret != DW_DLE_NONE) 229 return (ret); 230 if (offset > ds->ds_size) 231 ds->ds_size = offset; 232 233 if ((dre = calloc(1, sizeof(struct _Dwarf_Rel_Entry))) == NULL) { 234 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 235 return (DW_DLE_MEMORY); 236 } 237 STAILQ_INSERT_TAIL(&drs->drs_dre, dre, dre_next); 238 dre->dre_type = type; 239 dre->dre_length = length; 240 dre->dre_offset = reloff; 241 dre->dre_symndx = symndx; 242 dre->dre_addend = addend; 243 dre->dre_secname = secname; 244 drs->drs_drecnt++; 245 246 return (DW_DLE_NONE); 247 } 248 249 int 250 _dwarf_reloc_entry_add_pair(Dwarf_P_Debug dbg, Dwarf_Rel_Section drs, 251 Dwarf_P_Section ds, unsigned char length, Dwarf_Unsigned offset, 252 Dwarf_Unsigned symndx, Dwarf_Unsigned esymndx, Dwarf_Unsigned symoff, 253 Dwarf_Unsigned esymoff, Dwarf_Error *error) 254 { 255 Dwarf_Rel_Entry dre; 256 Dwarf_Unsigned reloff; 257 int ret; 258 259 assert(drs != NULL); 260 assert(offset <= ds->ds_size); 261 assert(dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS); 262 reloff = offset; 263 264 /* Write net offset into section stream. */ 265 ret = dbg->write_alloc(&ds->ds_data, &ds->ds_cap, &offset, 266 esymoff - symoff, length, error); 267 if (ret != DW_DLE_NONE) 268 return (ret); 269 if (offset > ds->ds_size) 270 ds->ds_size = offset; 271 272 if ((dre = calloc(2, sizeof(struct _Dwarf_Rel_Entry))) == NULL) { 273 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 274 return (DW_DLE_MEMORY); 275 } 276 STAILQ_INSERT_TAIL(&drs->drs_dre, &dre[0], dre_next); 277 STAILQ_INSERT_TAIL(&drs->drs_dre, &dre[1], dre_next); 278 dre[0].dre_type = dwarf_drt_first_of_length_pair; 279 dre[0].dre_length = length; 280 dre[0].dre_offset = reloff; 281 dre[0].dre_symndx = symndx; 282 dre[0].dre_addend = 0; 283 dre[0].dre_secname = NULL; 284 dre[1].dre_type = dwarf_drt_second_of_length_pair; 285 dre[1].dre_length = length; 286 dre[1].dre_offset = reloff; 287 dre[1].dre_symndx = esymndx; 288 dre[1].dre_addend = 0; 289 dre[1].dre_secname = NULL; 290 drs->drs_drecnt += 2; 291 292 return (DW_DLE_NONE); 293 } 294 295 int 296 _dwarf_reloc_section_finalize(Dwarf_P_Debug dbg, Dwarf_Rel_Section drs, 297 Dwarf_Error *error) 298 { 299 Dwarf_P_Section ds; 300 Dwarf_Unsigned unit; 301 int ret, size; 302 303 assert(dbg != NULL && drs != NULL && drs->drs_ds != NULL && 304 drs->drs_ref != NULL); 305 306 ds = drs->drs_ds; 307 308 /* 309 * Calculate the size (in bytes) of the relocation section. 310 */ 311 if (dbg->dbgp_flags & DW_DLC_SIZE_64) 312 unit = drs->drs_addend ? sizeof(Elf64_Rela) : sizeof(Elf64_Rel); 313 else 314 unit = drs->drs_addend ? sizeof(Elf32_Rela) : sizeof(Elf32_Rel); 315 assert(ds->ds_size == 0); 316 size = drs->drs_drecnt * unit; 317 318 /* 319 * Discard this relocation section if there is no entry in it. 320 */ 321 if (size == 0) { 322 _dwarf_reloc_section_free(dbg, &drs); 323 return (DW_DLE_NONE); 324 } 325 326 /* 327 * If we are under stream mode, realloc the section data block to 328 * this size. 329 */ 330 if ((dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS) == 0) { 331 ds->ds_cap = size; 332 if ((ds->ds_data = realloc(ds->ds_data, (size_t) ds->ds_cap)) == 333 NULL) { 334 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 335 return (DW_DLE_MEMORY); 336 } 337 } 338 339 /* 340 * Notify the application the creation of this relocation section. 341 * Note that the section link here should point to the .symtab 342 * section, we set it to 0 since we have no way to know .symtab 343 * section index. 344 */ 345 ret = _dwarf_pro_callback(dbg, ds->ds_name, size, 346 drs->drs_addend ? SHT_RELA : SHT_REL, 0, 0, drs->drs_ref->ds_ndx, 347 &ds->ds_symndx, NULL); 348 if (ret < 0) { 349 DWARF_SET_ERROR(dbg, error, DW_DLE_ELF_SECT_ERR); 350 return (DW_DLE_ELF_SECT_ERR); 351 } 352 ds->ds_ndx = ret; 353 354 return (DW_DLE_NONE); 355 } 356 357 int 358 _dwarf_reloc_section_gen(Dwarf_P_Debug dbg, Dwarf_Rel_Section drs, 359 Dwarf_Error *error) 360 { 361 Dwarf_Rel_Entry dre; 362 Dwarf_P_Section ds; 363 Dwarf_Unsigned type; 364 int ret; 365 366 assert((dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS) == 0); 367 assert(drs->drs_ds != NULL && drs->drs_ds->ds_size == 0); 368 assert(!STAILQ_EMPTY(&drs->drs_dre)); 369 ds = drs->drs_ds; 370 371 STAILQ_FOREACH(dre, &drs->drs_dre, dre_next) { 372 assert(dre->dre_length == 4 || dre->dre_length == 8); 373 type = _dwarf_get_reloc_type(dbg, dre->dre_length == 8); 374 if (dbg->dbgp_flags & DW_DLC_SIZE_64) { 375 /* Write r_offset (8 bytes) */ 376 ret = dbg->write_alloc(&ds->ds_data, &ds->ds_cap, 377 &ds->ds_size, dre->dre_offset, 8, error); 378 if (ret != DW_DLE_NONE) 379 return (ret); 380 /* Write r_info (8 bytes) */ 381 ret = dbg->write_alloc(&ds->ds_data, &ds->ds_cap, 382 &ds->ds_size, ELF64_R_INFO(dre->dre_symndx, type), 383 8, error); 384 if (ret != DW_DLE_NONE) 385 return (ret); 386 /* Write r_addend (8 bytes) */ 387 if (drs->drs_addend) { 388 ret = dbg->write_alloc(&ds->ds_data, 389 &ds->ds_cap, &ds->ds_size, dre->dre_addend, 390 8, error); 391 if (ret != DW_DLE_NONE) 392 return (ret); 393 } 394 } else { 395 /* Write r_offset (4 bytes) */ 396 ret = dbg->write_alloc(&ds->ds_data, &ds->ds_cap, 397 &ds->ds_size, dre->dre_offset, 4, error); 398 if (ret != DW_DLE_NONE) 399 return (ret); 400 /* Write r_info (4 bytes) */ 401 ret = dbg->write_alloc(&ds->ds_data, &ds->ds_cap, 402 &ds->ds_size, ELF32_R_INFO(dre->dre_symndx, type), 403 4, error); 404 if (ret != DW_DLE_NONE) 405 return (ret); 406 /* Write r_addend (4 bytes) */ 407 if (drs->drs_addend) { 408 ret = dbg->write_alloc(&ds->ds_data, 409 &ds->ds_cap, &ds->ds_size, dre->dre_addend, 410 4, error); 411 if (ret != DW_DLE_NONE) 412 return (ret); 413 } 414 } 415 } 416 assert(ds->ds_size == ds->ds_cap); 417 418 return (DW_DLE_NONE); 419 } 420 421 int 422 _dwarf_reloc_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) 423 { 424 Dwarf_Rel_Section drs; 425 Dwarf_Rel_Entry dre; 426 Dwarf_P_Section ds; 427 int ret; 428 429 STAILQ_FOREACH(drs, &dbg->dbgp_drslist, drs_next) { 430 /* 431 * Update relocation entries: translate any section name 432 * reference to section symbol index. 433 */ 434 STAILQ_FOREACH(dre, &drs->drs_dre, dre_next) { 435 if (dre->dre_secname == NULL) 436 continue; 437 ds = _dwarf_pro_find_section(dbg, dre->dre_secname); 438 assert(ds != NULL && ds->ds_symndx != 0); 439 dre->dre_symndx = ds->ds_symndx; 440 } 441 442 /* 443 * Generate ELF relocation section if we are under stream 444 * mode. 445 */ 446 if ((dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS) == 0) { 447 ret = _dwarf_reloc_section_gen(dbg, drs, error); 448 if (ret != DW_DLE_NONE) 449 return (ret); 450 } 451 } 452 453 return (DW_DLE_NONE); 454 } 455 456 void 457 _dwarf_reloc_cleanup(Dwarf_P_Debug dbg) 458 { 459 Dwarf_Rel_Section drs, tdrs; 460 Dwarf_Rel_Entry dre, tdre; 461 462 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); 463 464 STAILQ_FOREACH_SAFE(drs, &dbg->dbgp_drslist, drs_next, tdrs) { 465 STAILQ_REMOVE(&dbg->dbgp_drslist, drs, _Dwarf_Rel_Section, 466 drs_next); 467 free(drs->drs_drd); 468 STAILQ_FOREACH_SAFE(dre, &drs->drs_dre, dre_next, tdre) { 469 STAILQ_REMOVE(&drs->drs_dre, dre, _Dwarf_Rel_Entry, 470 dre_next); 471 free(dre); 472 } 473 if (dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS) { 474 if (drs->drs_ds) { 475 if (drs->drs_ds->ds_name) 476 free(drs->drs_ds->ds_name); 477 free(drs->drs_ds); 478 } 479 } 480 free(drs); 481 } 482 dbg->dbgp_drscnt = 0; 483 dbg->dbgp_drspos = NULL; 484 } 485