2 * Copyright (c) 2010 Kai Wang
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include "_libdwarf.h"
29 ELFTC_VCSID("$Id: libdwarf_reloc.c 3198 2015-05-14 18:36:19Z emaste $");
32 _dwarf_get_reloc_type(Dwarf_P_Debug dbg, int is64)
37 switch (dbg->dbgp_isa) {
39 return (is64 ? R_AARCH64_ABS64 : R_AARCH64_ABS32);
43 return (is64 ? R_X86_64_64 : R_X86_64_32);
45 return (is64 ? R_SPARC_UA64 : R_SPARC_UA32);
47 return (R_PPC_ADDR32);
51 return (is64 ? R_MIPS_64 : R_MIPS_32);
53 return (is64 ? R_IA_64_DIR64LSB : R_IA_64_DIR32LSB);
57 return (0); /* NOT REACHED */
61 _dwarf_get_reloc_size(Dwarf_Debug dbg, Dwarf_Unsigned rel_type)
64 switch (dbg->dbg_machine) {
68 if (rel_type == R_AARCH64_ABS32)
70 else if (rel_type == R_AARCH64_ABS64)
74 if (rel_type == R_ARM_ABS32)
79 if (rel_type == R_386_32)
83 if (rel_type == R_X86_64_32)
85 else if (rel_type == R_X86_64_64)
89 if (rel_type == R_SPARC_UA32)
91 else if (rel_type == R_SPARC_UA64)
95 if (rel_type == R_PPC_ADDR32)
99 if (rel_type == R_MIPS_32)
101 else if (rel_type == R_MIPS_64)
105 if (rel_type == R_IA_64_SECREL32LSB)
107 else if (rel_type == R_IA_64_DIR64LSB)
114 /* unknown relocation. */
119 _dwarf_reloc_section_init(Dwarf_P_Debug dbg, Dwarf_Rel_Section *drsp,
120 Dwarf_P_Section ref, Dwarf_Error *error)
122 Dwarf_Rel_Section drs;
126 assert(dbg != NULL && drsp != NULL && ref != NULL);
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);
136 * FIXME The logic here is most likely wrong. It should
137 * be the ISA that determines relocation type.
139 if (dbg->dbgp_flags & DW_DLC_SIZE_64)
144 if (dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS)
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) !=
154 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
155 return (DW_DLE_MEMORY);
158 STAILQ_INIT(&drs->drs_dre);
159 STAILQ_INSERT_TAIL(&dbg->dbgp_drslist, drs, drs_next);
163 return (DW_DLE_NONE);
167 _dwarf_reloc_section_free(Dwarf_P_Debug dbg, Dwarf_Rel_Section *drsp)
169 Dwarf_Rel_Section drs, tdrs;
170 Dwarf_Rel_Entry dre, tdre;
172 assert(dbg != NULL && drsp != NULL);
177 STAILQ_FOREACH_SAFE(drs, &dbg->dbgp_drslist, drs_next, tdrs) {
180 STAILQ_REMOVE(&dbg->dbgp_drslist, drs, _Dwarf_Rel_Section,
182 STAILQ_FOREACH_SAFE(dre, &drs->drs_dre, dre_next, tdre) {
183 STAILQ_REMOVE(&drs->drs_dre, dre, _Dwarf_Rel_Entry,
187 if ((dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS) == 0)
188 _dwarf_section_free(dbg, &drs->drs_ds);
190 if (drs->drs_ds->ds_name)
191 free(drs->drs_ds->ds_name);
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)
208 Dwarf_Unsigned reloff;
212 assert(offset <= ds->ds_size);
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
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);
227 ret = dbg->write_alloc(&ds->ds_data, &ds->ds_cap, &offset,
229 if (ret != DW_DLE_NONE)
231 if (offset > ds->ds_size)
232 ds->ds_size = offset;
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);
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;
247 return (DW_DLE_NONE);
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)
257 Dwarf_Unsigned reloff;
261 assert(offset <= ds->ds_size);
262 assert(dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS);
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)
270 if (offset > ds->ds_size)
271 ds->ds_size = offset;
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);
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;
293 return (DW_DLE_NONE);
297 _dwarf_reloc_section_finalize(Dwarf_P_Debug dbg, Dwarf_Rel_Section drs,
304 assert(dbg != NULL && drs != NULL && drs->drs_ds != NULL &&
305 drs->drs_ref != NULL);
310 * Calculate the size (in bytes) of the relocation section.
312 if (dbg->dbgp_flags & DW_DLC_SIZE_64)
313 unit = drs->drs_addend ? sizeof(Elf64_Rela) : sizeof(Elf64_Rel);
315 unit = drs->drs_addend ? sizeof(Elf32_Rela) : sizeof(Elf32_Rel);
316 assert(ds->ds_size == 0);
317 size = drs->drs_drecnt * unit;
320 * Discard this relocation section if there is no entry in it.
323 _dwarf_reloc_section_free(dbg, &drs);
324 return (DW_DLE_NONE);
328 * If we are under stream mode, realloc the section data block to
331 if ((dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS) == 0) {
333 if ((ds->ds_data = realloc(ds->ds_data, (size_t) ds->ds_cap)) ==
335 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
336 return (DW_DLE_MEMORY);
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
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);
350 DWARF_SET_ERROR(dbg, error, DW_DLE_ELF_SECT_ERR);
351 return (DW_DLE_ELF_SECT_ERR);
355 return (DW_DLE_NONE);
359 _dwarf_reloc_section_gen(Dwarf_P_Debug dbg, Dwarf_Rel_Section drs,
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));
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)
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),
385 if (ret != DW_DLE_NONE)
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,
392 if (ret != DW_DLE_NONE)
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)
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),
405 if (ret != DW_DLE_NONE)
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,
412 if (ret != DW_DLE_NONE)
417 assert(ds->ds_size == ds->ds_cap);
419 return (DW_DLE_NONE);
423 _dwarf_reloc_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
425 Dwarf_Rel_Section drs;
430 STAILQ_FOREACH(drs, &dbg->dbgp_drslist, drs_next) {
432 * Update relocation entries: translate any section name
433 * reference to section symbol index.
435 STAILQ_FOREACH(dre, &drs->drs_dre, dre_next) {
436 if (dre->dre_secname == NULL)
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;
444 * Generate ELF relocation section if we are under stream
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)
454 return (DW_DLE_NONE);
458 _dwarf_reloc_cleanup(Dwarf_P_Debug dbg)
460 Dwarf_Rel_Section drs, tdrs;
461 Dwarf_Rel_Entry dre, tdre;
463 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
465 STAILQ_FOREACH_SAFE(drs, &dbg->dbgp_drslist, drs_next, tdrs) {
466 STAILQ_REMOVE(&dbg->dbgp_drslist, drs, _Dwarf_Rel_Section,
469 STAILQ_FOREACH_SAFE(dre, &drs->drs_dre, dre_next, tdre) {
470 STAILQ_REMOVE(&drs->drs_dre, dre, _Dwarf_Rel_Entry,
474 if (dbg->dbgp_flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
476 if (drs->drs_ds->ds_name)
477 free(drs->drs_ds->ds_name);
483 dbg->dbgp_drscnt = 0;
484 dbg->dbgp_drspos = NULL;