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