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
_dwarf_get_reloc_type(Dwarf_P_Debug dbg,int is64)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
_dwarf_get_reloc_size(Dwarf_Debug dbg,Dwarf_Unsigned rel_type)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
_dwarf_reloc_section_init(Dwarf_P_Debug dbg,Dwarf_Rel_Section * drsp,Dwarf_P_Section ref,Dwarf_Error * error)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
_dwarf_reloc_section_free(Dwarf_P_Debug dbg,Dwarf_Rel_Section * drsp)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
_dwarf_reloc_entry_add(Dwarf_P_Debug dbg,Dwarf_Rel_Section drs,Dwarf_P_Section ds,unsigned char type,unsigned char length,Dwarf_Unsigned offset,Dwarf_Unsigned symndx,Dwarf_Unsigned addend,const char * secname,Dwarf_Error * error)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
_dwarf_reloc_entry_add_pair(Dwarf_P_Debug dbg,Dwarf_Rel_Section drs,Dwarf_P_Section ds,unsigned char length,Dwarf_Unsigned offset,Dwarf_Unsigned symndx,Dwarf_Unsigned esymndx,Dwarf_Unsigned symoff,Dwarf_Unsigned esymoff,Dwarf_Error * error)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
_dwarf_reloc_section_finalize(Dwarf_P_Debug dbg,Dwarf_Rel_Section drs,Dwarf_Error * error)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
_dwarf_reloc_section_gen(Dwarf_P_Debug dbg,Dwarf_Rel_Section drs,Dwarf_Error * error)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
_dwarf_reloc_gen(Dwarf_P_Debug dbg,Dwarf_Error * error)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
_dwarf_reloc_cleanup(Dwarf_P_Debug dbg)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