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