Home | History | Annotate | Download | only in tools
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <elf.h>
     18 #include <errno.h>
     19 #include <fcntl.h>
     20 #include <inttypes.h>
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <sys/mman.h>
     25 #include <sys/stat.h>
     26 #include <sys/types.h>
     27 #include <unistd.h>
     28 
     29 #include <unwindstack/DwarfLocation.h>
     30 #include <unwindstack/DwarfMemory.h>
     31 #include <unwindstack/DwarfSection.h>
     32 #include <unwindstack/DwarfStructs.h>
     33 #include <unwindstack/Elf.h>
     34 #include <unwindstack/ElfInterface.h>
     35 #include <unwindstack/Log.h>
     36 
     37 #include "DwarfOp.h"
     38 
     39 namespace unwindstack {
     40 
     41 void PrintSignedValue(int64_t value) {
     42   if (value < 0) {
     43     printf("- %" PRId64, -value);
     44   } else if (value > 0) {
     45     printf("+ %" PRId64, value);
     46   }
     47 }
     48 
     49 void PrintExpression(Memory* memory, uint8_t class_type, uint64_t end, uint64_t length) {
     50   std::vector<std::string> lines;
     51   DwarfMemory dwarf_memory(memory);
     52   if (class_type == ELFCLASS32) {
     53     DwarfOp<uint32_t> op(&dwarf_memory, nullptr);
     54     op.GetLogInfo(end - length, end, &lines);
     55   } else {
     56     DwarfOp<uint64_t> op(&dwarf_memory, nullptr);
     57     op.GetLogInfo(end - length, end, &lines);
     58   }
     59   for (auto& line : lines) {
     60     printf("    %s\n", line.c_str());
     61   }
     62 }
     63 
     64 void PrintRegInformation(DwarfSection* section, Memory* memory, uint64_t pc, uint8_t class_type) {
     65   const DwarfFde* fde = section->GetFdeFromPc(pc);
     66   if (fde == nullptr) {
     67     printf("  No fde found.\n");
     68     return;
     69   }
     70 
     71   dwarf_loc_regs_t regs;
     72   if (!section->GetCfaLocationInfo(pc, fde, &regs)) {
     73     printf("  Cannot get location information.\n");
     74     return;
     75   }
     76 
     77   std::vector<std::pair<uint32_t, DwarfLocation>> loc_regs;
     78   for (auto& loc : regs) {
     79     loc_regs.push_back(loc);
     80   }
     81   std::sort(loc_regs.begin(), loc_regs.end(), [](auto a, auto b) {
     82     if (a.first == CFA_REG) {
     83       return true;
     84     } else if (b.first == CFA_REG) {
     85       return false;
     86     }
     87     return a.first < b.first;
     88   });
     89 
     90   for (auto& entry : loc_regs) {
     91     const DwarfLocation* loc = &entry.second;
     92     if (entry.first == CFA_REG) {
     93       printf("  cfa = ");
     94     } else {
     95       printf("  r%d = ", entry.first);
     96     }
     97     switch (loc->type) {
     98       case DWARF_LOCATION_OFFSET:
     99         printf("[cfa ");
    100         PrintSignedValue(loc->values[0]);
    101         printf("]\n");
    102         break;
    103 
    104       case DWARF_LOCATION_VAL_OFFSET:
    105         printf("cfa ");
    106         PrintSignedValue(loc->values[0]);
    107         printf("\n");
    108         break;
    109 
    110       case DWARF_LOCATION_REGISTER:
    111         printf("r%" PRId64 " ", loc->values[0]);
    112         PrintSignedValue(loc->values[1]);
    113         printf("\n");
    114         break;
    115 
    116       case DWARF_LOCATION_EXPRESSION: {
    117         printf("EXPRESSION\n");
    118         PrintExpression(memory, class_type, loc->values[1], loc->values[0]);
    119         break;
    120       }
    121 
    122       case DWARF_LOCATION_VAL_EXPRESSION: {
    123         printf("VAL EXPRESSION\n");
    124         PrintExpression(memory, class_type, loc->values[1], loc->values[0]);
    125         break;
    126       }
    127 
    128       case DWARF_LOCATION_UNDEFINED:
    129         printf("undefine\n");
    130         break;
    131 
    132       case DWARF_LOCATION_INVALID:
    133         printf("INVALID\n");
    134         break;
    135     }
    136   }
    137 }
    138 
    139 int GetInfo(const char* file, uint64_t pc) {
    140   MemoryFileAtOffset* memory = new MemoryFileAtOffset;
    141   if (!memory->Init(file, 0)) {
    142     // Initializatation failed.
    143     printf("Failed to init\n");
    144     return 1;
    145   }
    146 
    147   Elf elf(memory);
    148   if (!elf.Init(true) || !elf.valid()) {
    149     printf("%s is not a valid elf file.\n", file);
    150     return 1;
    151   }
    152 
    153   ElfInterface* interface = elf.interface();
    154   uint64_t load_bias = elf.GetLoadBias();
    155   if (pc < load_bias) {
    156     printf("PC is less than load bias.\n");
    157     return 1;
    158   }
    159 
    160   std::string soname;
    161   if (elf.GetSoname(&soname)) {
    162     printf("Soname: %s\n\n", soname.c_str());
    163   }
    164 
    165   printf("PC 0x%" PRIx64 ":\n", pc);
    166 
    167   DwarfSection* section = interface->eh_frame();
    168   if (section != nullptr) {
    169     printf("\neh_frame:\n");
    170     PrintRegInformation(section, memory, pc - load_bias, elf.class_type());
    171   } else {
    172     printf("\nno eh_frame information\n");
    173   }
    174 
    175   section = interface->debug_frame();
    176   if (section != nullptr) {
    177     printf("\ndebug_frame:\n");
    178     PrintRegInformation(section, memory, pc - load_bias, elf.class_type());
    179     printf("\n");
    180   } else {
    181     printf("\nno debug_frame information\n");
    182   }
    183 
    184   // If there is a gnu_debugdata interface, dump the information for that.
    185   ElfInterface* gnu_debugdata_interface = elf.gnu_debugdata_interface();
    186   if (gnu_debugdata_interface != nullptr) {
    187     section = gnu_debugdata_interface->eh_frame();
    188     if (section != nullptr) {
    189       printf("\ngnu_debugdata (eh_frame):\n");
    190       PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type());
    191       printf("\n");
    192     } else {
    193       printf("\nno gnu_debugdata (eh_frame)\n");
    194     }
    195 
    196     section = gnu_debugdata_interface->debug_frame();
    197     if (section != nullptr) {
    198       printf("\ngnu_debugdata (debug_frame):\n");
    199       PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type());
    200       printf("\n");
    201     } else {
    202       printf("\nno gnu_debugdata (debug_frame)\n");
    203     }
    204   } else {
    205     printf("\nno valid gnu_debugdata information\n");
    206   }
    207 
    208   return 0;
    209 }
    210 
    211 }  // namespace unwindstack
    212 
    213 int main(int argc, char** argv) {
    214   if (argc != 3) {
    215     printf("Usage: unwind_reg_info ELF_FILE PC\n");
    216     printf("  ELF_FILE\n");
    217     printf("    The path to an elf file.\n");
    218     printf("  PC\n");
    219     printf("    The pc for which the register information should be obtained.\n");
    220     return 1;
    221   }
    222 
    223   struct stat st;
    224   if (stat(argv[1], &st) == -1) {
    225     printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
    226     return 1;
    227   }
    228   if (!S_ISREG(st.st_mode)) {
    229     printf("%s is not a regular file.\n", argv[1]);
    230     return 1;
    231   }
    232 
    233   uint64_t pc = 0;
    234   char* end;
    235   pc = strtoull(argv[2], &end, 16);
    236   if (*end != '\0') {
    237     printf("Malformed OFFSET value: %s\n", argv[2]);
    238     return 1;
    239   }
    240 
    241   return unwindstack::GetInfo(argv[1], pc);
    242 }
    243