Home | History | Annotate | Download | only in tools
      1 /*
      2  * Copyright (C) 2016 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 <inttypes.h>
     20 #include <stdio.h>
     21 #include <string.h>
     22 #include <sys/stat.h>
     23 #include <sys/types.h>
     24 #include <unistd.h>
     25 
     26 #include <unwindstack/Elf.h>
     27 #include <unwindstack/Log.h>
     28 #include <unwindstack/Memory.h>
     29 
     30 int main(int argc, char** argv) {
     31   if (argc != 2 && argc != 3) {
     32     printf("Usage: unwind_symbols <ELF_FILE> [<FUNC_ADDRESS>]\n");
     33     printf("  Dump all function symbols in ELF_FILE. If FUNC_ADDRESS is\n");
     34     printf("  specified, then get the function at that address.\n");
     35     printf("  FUNC_ADDRESS must be a hex number.\n");
     36     return 1;
     37   }
     38 
     39   struct stat st;
     40   if (stat(argv[1], &st) == -1) {
     41     printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
     42     return 1;
     43   }
     44   if (!S_ISREG(st.st_mode)) {
     45     printf("%s is not a regular file.\n", argv[1]);
     46     return 1;
     47   }
     48 
     49   uint64_t func_addr;
     50   if (argc == 3) {
     51     char* name;
     52     func_addr = strtoull(argv[2], &name, 16);
     53     if (*name != '\0') {
     54       printf("%s is not a hex number.\n", argv[2]);
     55       return 1;
     56     }
     57   }
     58 
     59   // Send all log messages to stdout.
     60   unwindstack::log_to_stdout(true);
     61 
     62   unwindstack::MemoryFileAtOffset* memory = new unwindstack::MemoryFileAtOffset;
     63   if (!memory->Init(argv[1], 0)) {
     64     printf("Failed to init\n");
     65     return 1;
     66   }
     67 
     68   unwindstack::Elf elf(memory);
     69   if (!elf.Init(true) || !elf.valid()) {
     70     printf("%s is not a valid elf file.\n", argv[1]);
     71     return 1;
     72   }
     73 
     74   std::string soname;
     75   if (elf.GetSoname(&soname)) {
     76     printf("Soname: %s\n\n", soname.c_str());
     77   }
     78 
     79   switch (elf.machine_type()) {
     80     case EM_ARM:
     81       printf("ABI: arm\n");
     82       break;
     83     case EM_AARCH64:
     84       printf("ABI: arm64\n");
     85       break;
     86     case EM_386:
     87       printf("ABI: x86\n");
     88       break;
     89     case EM_X86_64:
     90       printf("ABI: x86_64\n");
     91       break;
     92     default:
     93       printf("ABI: unknown\n");
     94       return 1;
     95   }
     96 
     97   std::string name;
     98   uint64_t load_bias = elf.GetLoadBias();
     99   if (argc == 3) {
    100     std::string cur_name;
    101     uint64_t func_offset;
    102     if (!elf.GetFunctionName(func_addr, &cur_name, &func_offset)) {
    103       printf("No known function at 0x%" PRIx64 "\n", func_addr);
    104       return 1;
    105     }
    106     printf("<0x%" PRIx64 ">", func_addr - func_offset);
    107     if (func_offset != 0) {
    108       printf("+%" PRId64, func_offset);
    109     }
    110     printf(": %s\n", cur_name.c_str());
    111     return 0;
    112   }
    113 
    114   // This is a crude way to get the symbols in order.
    115   for (const auto& entry : elf.interface()->pt_loads()) {
    116     uint64_t start = entry.second.offset + load_bias;
    117     uint64_t end = entry.second.table_size + load_bias;
    118     for (uint64_t addr = start; addr < end; addr += 4) {
    119       std::string cur_name;
    120       uint64_t func_offset;
    121       if (elf.GetFunctionName(addr, &cur_name, &func_offset)) {
    122         if (cur_name != name) {
    123           printf("<0x%" PRIx64 "> Function: %s\n", addr - func_offset, cur_name.c_str());
    124         }
    125         name = cur_name;
    126       }
    127     }
    128   }
    129 
    130   return 0;
    131 }
    132