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