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