Home | History | Annotate | Download | only in elfcopy
      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 
     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
    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
    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
    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 
    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 
    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 
    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;
    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 
    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
    405 static int value_visited(unsigned long val __attribute__((unused)))
    406 {
    407     return 0;
    408 }
    409 #endif /*PARANOIA*/
    410 
    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 
    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 
    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 
    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 
    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