1 #include <fixdwarf.h>
2 #include <common.h>
3 #include <debug.h>
4 #include <hash.h>
5
6 #include <libelf.h>
7 #include <libebl.h>
8 #include <libebl_arm.h>
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18
19 /* When this macro is set to a nonzero value, we maintain a BST where we store each address once
20 we update the value at that address, and check to make sure that the address has not been
21 visited before we udpate it. This way we make sure that we do not do multiple updates at any
22 any given address. The feature is disabled by default because it is very expensive. It should
23 be enabled as a first step in debugging problems with the DWARF patches that this code makes.
24 */
25
26 #define PARANOIA (0)
27
28 #define _str(name) #name
29 #define _id(a,b) a ## b
30
31 #if PARANOIA
32 #define COLLECT_BACKTRACES (0)
33
34 #if COLLECT_BACKTRACES
35 #include <execinfo.h>
36 #endif
37 #endif/*PARANOIA*/
38
39 #include <dwarf.h>
40
41 int load_debug_section (enum dwarf_section_display_enum debug, void *file);
42 void free_debug_section (enum dwarf_section_display_enum debug);
43
44 static shdr_info_t *s_shdr_info;
45 static int s_shdr_info_len;
46 static int dwarf_to_shdr[max];
47 static shdr_info_t *s_cached_find_section_result = NULL;
48 static int s_num_total_patches = 0;
49 static int s_num_failed_patches = 0;
50
51 static void init_value_free_lists();
52
53 #if PARANOIA
54 typedef struct value_struct {
55 unsigned long key;
56 struct value_struct *left;
57 struct value_struct *right;
58 #if COLLECT_BACKTRACES
59 #define BACKTRACE_DEPTH (10)
60 void *backtrace[BACKTRACE_DEPTH];
61 int backtrace_depth;
62 #endif/*COLLECT_BACKTRACES*/
63 } value_t;
64
65 static value_t *s_visited_values; /* BST of visited values */
66 #endif/*PARANOIA*/
67
68 static void dump_dwarf_section (enum dwarf_section_display_enum dwarf_idx);
69 static void byte_set_little_endian (
70 unsigned char *field, int size, dwarf_vma val);
71 static void byte_set_big_endian (
72 unsigned char *field, int size, dwarf_vma val);
73 static void (*byte_set) (unsigned char *, int, dwarf_vma);
74
update_dwarf_if_necessary(Elf * elf,GElf_Ehdr * ehdr,Elf * newelf,shdr_info_t * shdr_info,int num_shdr_info,int * num_total_patches,int * num_failed_patches)75 void update_dwarf_if_necessary(Elf *elf __attribute__((unused)),
76 GElf_Ehdr *ehdr,
77 Elf *newelf __attribute__((unused)),
78 shdr_info_t *shdr_info, int num_shdr_info,
79 int *num_total_patches, int *num_failed_patches)
80 {
81 /* Find the debug sections */
82
83 int cnt;
84
85 /* Initialize the static variables, which might have been left in
86 nondefault states from a previous call to this function.
87 */
88 s_shdr_info = NULL;
89 s_cached_find_section_result = NULL;
90 s_shdr_info_len = 0;
91 s_num_total_patches = 0;
92 s_num_failed_patches = 0;
93 memset(dwarf_to_shdr, 0, sizeof(dwarf_to_shdr));
94 for(cnt = 0; cnt < max; cnt++)
95 free_debug_section(cnt);
96 #if PARANOIA
97 s_visited_values = NULL;
98 init_value_free_lists();
99 #endif/*PARANOIA*/
100 init_dwarf_variables();
101
102 cnt = 0;
103
104 /* Locate the .debug_<xxx> sections, and save
105 their indices (in shdr_info) in the respective
106 idx_debug_<xxx> variable. If a section is not
107 prwesent in the file, the variable will have
108 a negative value after this loop.
109 */
110
111 #define CHECK_DEBUG_SECTION(sname) \
112 ASSERT(shdr_info[cnt].name != NULL); \
113 if (!strcmp(shdr_info[cnt].name, \
114 ".debug_" _str(sname))) { \
115 FAILIF(dwarf_to_shdr[sname] > 0, \
116 ".debug_" _str(sname) " is already found at index %d!\n", \
117 dwarf_to_shdr[sname]); \
118 INFO("Index of \".debug_" _str(name) " is %d", cnt); \
119 if (shdr_info[cnt].idx > 0) \
120 dwarf_to_shdr[sname] = cnt; \
121 else INFO(", but the section is being removed."); \
122 INFO("\n"); \
123 }
124
125 for(cnt = 1; cnt < num_shdr_info; cnt++) {
126 CHECK_DEBUG_SECTION(aranges);
127 CHECK_DEBUG_SECTION(info);
128 CHECK_DEBUG_SECTION(abbrev);
129 CHECK_DEBUG_SECTION(line);
130 CHECK_DEBUG_SECTION(frame);
131 CHECK_DEBUG_SECTION(loc);
132 CHECK_DEBUG_SECTION(ranges);
133 CHECK_DEBUG_SECTION(pubnames);
134 CHECK_DEBUG_SECTION(str);
135 }
136 #undef CHECK_DEBUG_SECTION
137
138 {
139 is_relocatable = (ehdr->e_type == ET_REL);
140 eh_addr_size = 4;
141
142 if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
143 byte_get = byte_get_little_endian;
144 byte_set = byte_set_little_endian;
145 }
146 else {
147 ASSERT(ehdr->e_ident[EI_DATA] == ELFDATA2MSB);
148 byte_get = byte_get_big_endian;
149 byte_set = byte_set_big_endian;
150 }
151 }
152
153 #define ADJUST_IF_NECESSARY(sname) \
154 do { \
155 if (dwarf_to_shdr[sname] > 0) { \
156 INFO("\nAdjusting for %s.\n", shdr_info[dwarf_to_shdr[sname]].name); \
157 dump_dwarf_section(sname); \
158 } \
159 else { \
160 INFO("\nNot adjusting for %s.\n", shdr_info[dwarf_to_shdr[sname]].name); \
161 } \
162 } while(0)
163
164 s_shdr_info = shdr_info;
165 s_shdr_info_len = num_shdr_info;
166
167 ADJUST_IF_NECESSARY(info);
168 ADJUST_IF_NECESSARY(loc);
169 ADJUST_IF_NECESSARY(aranges);
170 ADJUST_IF_NECESSARY(frame);
171 ADJUST_IF_NECESSARY(ranges);
172 ADJUST_IF_NECESSARY(line);
173 ADJUST_IF_NECESSARY(str);
174 ADJUST_IF_NECESSARY(pubnames);
175 ADJUST_IF_NECESSARY(abbrev);
176
177 #undef ADJUST_IF_NECESSRY
178
179 *num_total_patches = s_num_total_patches;
180 *num_failed_patches = s_num_failed_patches;
181 }
182
183 int
load_debug_section(enum dwarf_section_display_enum debug,void * file)184 load_debug_section (enum dwarf_section_display_enum debug,
185 void *file __attribute__((unused)))
186 {
187 struct dwarf_section *section = &debug_displays [debug].section;
188 int shdr_idx = dwarf_to_shdr[debug];
189 if (!shdr_idx) {
190 INFO("Could not load section %s: it is not in the file.\n",
191 debug_displays[debug].section.name);
192 return 0;
193 }
194 ASSERT(s_shdr_info);
195
196 INFO("Loading DWARF section type %s index %d (type %d)\n",
197 s_shdr_info[shdr_idx].name,
198 s_shdr_info[shdr_idx].idx,
199 debug);
200
201 /* If it is already loaded, do nothing. */
202 if (section->start != NULL) {
203 INFO("\tAlready loaded DWARF section type %s (type %d)\n", s_shdr_info[shdr_idx].name, debug);
204 return 1;
205 }
206
207 ASSERT(s_shdr_info[shdr_idx].newdata);
208
209 section->address = s_shdr_info[shdr_idx].shdr.sh_addr;
210 section->start = s_shdr_info[shdr_idx].newdata->d_buf;
211 section->size = s_shdr_info[shdr_idx].newdata->d_size;
212 ASSERT(s_shdr_info[shdr_idx].newdata->d_off == 0);
213
214 ASSERT(section->size != 0);
215 ASSERT(s_shdr_info[shdr_idx].shdr.sh_size == s_shdr_info[shdr_idx].newdata->d_size);
216 ASSERT(section->start != NULL);
217
218 return 1;
219 }
220
221 void
free_debug_section(enum dwarf_section_display_enum debug)222 free_debug_section (enum dwarf_section_display_enum debug)
223 {
224 struct dwarf_section *section = &debug_displays [debug].section;
225
226 INFO("Unloading DWARF section type %d\n", debug);
227
228 if (section->start == NULL)
229 return;
230
231 section->start = NULL;
232 section->address = 0;
233 section->size = 0;
234 }
235
236 static void
dump_dwarf_section(enum dwarf_section_display_enum dwarf_idx)237 dump_dwarf_section (enum dwarf_section_display_enum dwarf_idx)
238 {
239 int shdr_idx = dwarf_to_shdr[dwarf_idx];
240 ASSERT(shdr_idx);
241 ASSERT(s_shdr_info);
242 ASSERT(s_shdr_info[shdr_idx].idx);
243 ASSERT(s_shdr_info[shdr_idx].name);
244
245 ASSERT(!strcmp (debug_displays[dwarf_idx].section.name, s_shdr_info[shdr_idx].name));
246
247 if (!debug_displays[dwarf_idx].eh_frame) {
248 struct dwarf_section *sec = &debug_displays [dwarf_idx].section;
249
250 if (load_debug_section (dwarf_idx, NULL)) {
251 INFO("Dumping DWARF section [%s] (type %d).\n",
252 s_shdr_info[shdr_idx].name,
253 dwarf_idx);
254 debug_displays[dwarf_idx].display (sec, NULL);
255 if (dwarf_idx != info && dwarf_idx != abbrev)
256 free_debug_section (dwarf_idx);
257 }
258 }
259 }
260
find_section(int value)261 static shdr_info_t *find_section(int value)
262 {
263 ASSERT(s_shdr_info != NULL);
264 ASSERT(s_shdr_info_len > 0);
265
266 #define IN_RANGE(v,s,l) ((s)<=(v) && (v)<((s)+(l)))
267 if (s_cached_find_section_result != NULL &&
268 IN_RANGE((unsigned)value,
269 s_cached_find_section_result->old_shdr.sh_addr,
270 s_cached_find_section_result->old_shdr.sh_size)) {
271 return s_cached_find_section_result;
272 }
273
274 /* Find the section to which the address belongs. */
275 int cnt;
276 for (cnt = 0; cnt < s_shdr_info_len; cnt++) {
277 if (s_shdr_info[cnt].idx > 0 &&
278 (s_shdr_info[cnt].old_shdr.sh_flags & SHF_ALLOC) &&
279 IN_RANGE((unsigned) value,
280 s_shdr_info[cnt].old_shdr.sh_addr,
281 s_shdr_info[cnt].old_shdr.sh_size)) {
282
283 s_cached_find_section_result = s_shdr_info + cnt;
284 return s_cached_find_section_result;
285 }
286 }
287 #undef IN_RANGE
288
289 return NULL;
290 }
291
292 #if PARANOIA
293 static value_t **s_value_free_lists;
294 static int s_num_free_lists;
295 static int s_cur_free_list;
296 static int s_alloc_values; /* number of allocated values in the list */
297 #define LISTS_INCREMENT (10)
298 #define NUM_VALUES_PER_LIST (10000)
299
init_value_free_lists()300 static void init_value_free_lists()
301 {
302 if (s_value_free_lists) {
303 value_t **trav = s_value_free_lists;
304 while(s_cur_free_list) {
305 FREE(*trav++);
306 s_cur_free_list--;
307 }
308 FREE(s_value_free_lists);
309 s_value_free_lists = NULL;
310 }
311 s_num_free_lists = 0;
312 s_alloc_values = 0;
313 }
314
alloc_value()315 static value_t *alloc_value()
316 {
317 if (s_alloc_values == NUM_VALUES_PER_LIST) {
318 s_cur_free_list++;
319 s_alloc_values = 0;
320 }
321
322 if (s_cur_free_list == s_num_free_lists) {
323 s_num_free_lists += LISTS_INCREMENT;
324 s_value_free_lists = REALLOC(s_value_free_lists,
325 s_num_free_lists * sizeof(value_t *));
326 memset(s_value_free_lists + s_cur_free_list,
327 0,
328 (s_num_free_lists - s_cur_free_list) * sizeof(value_t *));
329 }
330
331 if (s_value_free_lists[s_cur_free_list] == NULL) {
332 s_value_free_lists[s_cur_free_list] = MALLOC(NUM_VALUES_PER_LIST*sizeof(value_t));
333 }
334
335 return s_value_free_lists[s_cur_free_list] + s_alloc_values++;
336 }
337
338 static value_t *would_be_parent = NULL;
find_value(unsigned long val)339 static value_t *find_value(unsigned long val)
340 {
341 would_be_parent = NULL;
342 value_t *trav = s_visited_values;
343 while(trav) {
344 would_be_parent = trav;
345 if (val < trav->key)
346 trav = trav->left;
347 else if (val > trav->key)
348 trav = trav->right;
349 else if (val == trav->key) {
350 return trav;
351 }
352 }
353 return NULL;
354 }
355
value_visited(unsigned long val)356 static int value_visited(unsigned long val)
357 {
358 value_t *found = find_value(val);
359 if (found != NULL) {
360 #if COLLECT_BACKTRACES
361 void *new_bt[BACKTRACE_DEPTH];
362 int new_bt_depth = backtrace(new_bt, BACKTRACE_DEPTH);
363 char **symbols = backtrace_symbols(new_bt, new_bt_depth);
364 PRINT("NEW VISIT AT %x\n", val);
365 if (symbols != NULL) {
366 int cnt = 0;
367 while(cnt < new_bt_depth) {
368 PRINT("\t%s\n", symbols[cnt]);
369 cnt++;
370 }
371 }
372 FREE(symbols);
373 PRINT("OLD VISIT AT %x\n", val);
374 symbols = backtrace_symbols(found->backtrace, found->backtrace_depth);
375 if (symbols != NULL) {
376 int cnt = 0;
377 while(cnt < new_bt_depth) {
378 PRINT("\t%s\n", symbols[cnt]);
379 cnt++;
380 }
381 }
382 FREE(symbols);
383 #else
384 ERROR("DWARF: Double update at address 0x%lx!\n", val);
385 #endif/*COLLECT_BACKTRACES*/
386 return 1;
387 }
388 found = alloc_value();
389 found->left = found->right = NULL;
390 found->key = val;
391 #if COLLECT_BACKTRACES
392 found->backtrace_depth = backtrace(found->backtrace, BACKTRACE_DEPTH);
393 #endif/*COLLECT_BACKTRACES*/
394 if (would_be_parent == NULL) {
395 s_visited_values = found;
396 } else {
397 if (val < would_be_parent->key)
398 would_be_parent->left = found;
399 else
400 would_be_parent->right = found;
401 }
402 return 0;
403 }
404 #else
value_visited(unsigned long val)405 static int value_visited(unsigned long val __attribute__((unused)))
406 {
407 return 0;
408 }
409 #endif /*PARANOIA*/
410
value_hook(void * data,int size,int val)411 void value_hook(void *data, int size, int val)
412 {
413 shdr_info_t *shdr = find_section(val);
414 s_num_total_patches++;
415 if(shdr == NULL) {
416 PRINT("DWARF: cannot map address 0x%x to any section!\n", val);
417 s_num_failed_patches++;
418 return;
419 }
420 long delta = shdr->shdr.sh_addr - shdr->old_shdr.sh_addr;
421 if(delta) {
422 if (!value_visited((unsigned long)data)) {
423 INFO("DWARF: adjusting %d-byte value at %p: 0x%x -> 0x%x (delta %d per section %s)\n",
424 size, data,
425 val, (int)(val + delta), (int)delta,
426 shdr->name);
427 byte_set(data, size, val + delta);
428 }
429 }
430 }
431
base_value_pair_hook(void * data,int size,int base,int begin,int end)432 void base_value_pair_hook(void *data, int size,
433 int base, int begin, int end)
434 {
435 shdr_info_t *shdr = find_section(base + begin);
436 s_num_total_patches++;
437
438 if (begin > end) {
439 PRINT("DWARF: start > end in range 0x%x:[0x%x, 0x%x)!\n",
440 base,
441 begin,
442 end);
443 s_num_failed_patches++;
444 return;
445 }
446
447 if(shdr == NULL) {
448 PRINT("DWARF: cannot map range 0x%x:[0x%x, 0x%x) to any section!\n",
449 base,
450 begin,
451 end);
452 s_num_failed_patches++;
453 return;
454 }
455
456 if (unlikely(begin != end)) {
457 shdr_info_t *end_shdr = find_section(base + end - 1);
458 if (shdr != end_shdr) {
459 printf("DWARF: range 0x%x:[%x, %x) maps to different sections: %s and %s!\n",
460 base,
461 begin, end,
462 shdr->name,
463 (end_shdr ? end_shdr->name : "(none)"));
464 s_num_failed_patches++;
465 return;
466 }
467 }
468
469 long delta = shdr->shdr.sh_addr - shdr->old_shdr.sh_addr;
470 if(delta) {
471 if (!value_visited((unsigned long)data)) {
472 INFO("DWARF: adjusting %d-byte value at %p: 0x%x -> 0x%x (delta %d per section %s)\n",
473 size, data,
474 begin, (int)(begin + delta), (int)delta,
475 shdr->name);
476 byte_set(data, size, begin + delta);
477 byte_set(data + size, size, end + delta);
478 }
479 }
480 }
481
signed_value_hook(void * data,int pointer_size,int is_signed,int value)482 void signed_value_hook(
483 void *data,
484 int pointer_size,
485 int is_signed,
486 int value)
487 {
488 INFO("DWARF frame info: initial PC value: %8x (width %d), %ssigned\n",
489 value, pointer_size,
490 (!is_signed ? "un" : ""));
491
492 ASSERT(s_shdr_info != NULL);
493
494 /* Find the section to which the address belongs. */
495 shdr_info_t *shdr = find_section(value);
496 s_num_total_patches++;
497 if(shdr == NULL) {
498 PRINT("DWARF: cannot map address 0x%x to any section!\n", value);
499 s_num_failed_patches++;
500 return;
501 }
502
503 long delta = shdr->shdr.sh_addr - shdr->old_shdr.sh_addr;
504
505 INFO("DWARF frame info: initial PC value: 0x%lx -> 0x%lx (delta %ld per section %s).\n",
506 (long)value,
507 (long)(value + delta),
508 delta,
509 shdr->name);
510
511 if (delta) {
512 if (!value_visited((unsigned long)data)) {
513 value += delta;
514 if (is_signed) {
515 switch (pointer_size) {
516 case 1:
517 value &= 0xFF;
518 value = (value ^ 0x80) - 0x80;
519 break;
520 case 2:
521 value &= 0xFFFF;
522 value = (value ^ 0x8000) - 0x8000;
523 break;
524 case 4:
525 value &= 0xFFFFFFFF;
526 value = (value ^ 0x80000000) - 0x80000000;
527 break;
528 case 8:
529 break;
530 default:
531 FAILIF(1, "Unsupported data size %d!\n", pointer_size);
532 }
533 }
534 byte_set(data, pointer_size, value);
535 }
536 }
537 }
538
byte_set_little_endian(unsigned char * field,int size,dwarf_vma val)539 static void byte_set_little_endian (unsigned char *field, int size, dwarf_vma val)
540 {
541 switch (size) {
542 case 1:
543 FAILIF(val > 0xFF,
544 "Attempting to set value 0x%lx to %d-bit integer!\n",
545 val, size*8);
546 *((uint8_t *)field) = (uint8_t)val;
547 break;
548 case 2:
549 FAILIF(val > 0xFFFF,
550 "Attempting to set value 0x%lx to %d-bit integer!\n",
551 val, size*8);
552 field[1] = (uint8_t)(val >> 8);
553 field[0] = (uint8_t)val;
554 break;
555 case 4:
556 #if 0
557 // this will signal false negatives when running on a 64 bit system.
558 FAILIF(val > 0xFFFFFFFF,
559 "Attempting to set value 0x%lx to %d-bit integer!\n",
560 val, size*8);
561 #endif
562 field[3] = (uint8_t)(val >> 23);
563 field[2] = (uint8_t)(val >> 16);
564 field[1] = (uint8_t)(val >> 8);
565 field[0] = (uint8_t)val;
566 break;
567 default:
568 FAILIF(1, "Unhandled data length: %d\n", size);
569 }
570 }
571
byte_set_big_endian(unsigned char * field,int size,dwarf_vma val)572 static void byte_set_big_endian (unsigned char *field __attribute__((unused)),
573 int size __attribute__((unused)),
574 dwarf_vma val __attribute__((unused)))
575 {
576 FAILIF(1, "Not implemented.\n");
577 }
578