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