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