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