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 <signal.h>
     21 #include <stdint.h>
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 #include <string.h>
     25 #include <sys/ptrace.h>
     26 #include <sys/types.h>
     27 #include <unistd.h>
     28 
     29 #include <string>
     30 
     31 #include <unwindstack/Elf.h>
     32 #include <unwindstack/MapInfo.h>
     33 #include <unwindstack/Maps.h>
     34 #include <unwindstack/Memory.h>
     35 #include <unwindstack/Regs.h>
     36 
     37 static bool Attach(pid_t pid) {
     38   if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
     39     return false;
     40   }
     41 
     42   // Allow at least 1 second to attach properly.
     43   for (size_t i = 0; i < 1000; i++) {
     44     siginfo_t si;
     45     if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
     46       return true;
     47     }
     48     usleep(1000);
     49   }
     50   printf("%d: Failed to stop.\n", pid);
     51   return false;
     52 }
     53 
     54 static bool Detach(pid_t pid) {
     55   return ptrace(PTRACE_DETACH, pid, 0, 0) == 0;
     56 }
     57 
     58 void DoUnwind(pid_t pid) {
     59   unwindstack::RemoteMaps remote_maps(pid);
     60   if (!remote_maps.Parse()) {
     61     printf("Failed to parse map data.\n");
     62     return;
     63   }
     64 
     65   uint32_t machine_type;
     66   unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid, &machine_type);
     67   if (regs == nullptr) {
     68     printf("Unable to get remote reg data\n");
     69     return;
     70   }
     71 
     72   bool bits32 = true;
     73   printf("ABI: ");
     74   switch (machine_type) {
     75     case EM_ARM:
     76       printf("arm");
     77       break;
     78     case EM_386:
     79       printf("x86");
     80       break;
     81     case EM_AARCH64:
     82       printf("arm64");
     83       bits32 = false;
     84       break;
     85     case EM_X86_64:
     86       printf("x86_64");
     87       bits32 = false;
     88       break;
     89     default:
     90       printf("unknown\n");
     91       return;
     92   }
     93   printf("\n");
     94 
     95   unwindstack::MemoryRemote remote_memory(pid);
     96   for (size_t frame_num = 0; frame_num < 64; frame_num++) {
     97     if (regs->pc() == 0) {
     98       break;
     99     }
    100     unwindstack::MapInfo* map_info = remote_maps.Find(regs->pc());
    101     if (map_info == nullptr) {
    102       printf("Failed to find map data for the pc\n");
    103       break;
    104     }
    105 
    106     unwindstack::Elf* elf = map_info->GetElf(pid, true);
    107 
    108     uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
    109     uint64_t adjusted_rel_pc = rel_pc;
    110     // Don't need to adjust the first frame pc.
    111     if (frame_num != 0) {
    112       adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
    113     }
    114 
    115     std::string name;
    116     if (bits32) {
    117       printf("  #%02zu pc %08" PRIx64, frame_num, adjusted_rel_pc);
    118     } else {
    119       printf("  #%02zu pc %016" PRIx64, frame_num, adjusted_rel_pc);
    120     }
    121     if (!map_info->name.empty()) {
    122       printf("  %s", map_info->name.c_str());
    123       if (map_info->elf_offset != 0) {
    124         printf(" (offset 0x%" PRIx64 ")", map_info->elf_offset);
    125       }
    126     } else {
    127       printf("  <anonymous:%" PRIx64 ">", map_info->offset);
    128     }
    129     uint64_t func_offset;
    130     if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) {
    131       printf(" (%s", name.c_str());
    132       if (func_offset != 0) {
    133         printf("+%" PRId64, func_offset);
    134       }
    135       printf(")");
    136     }
    137     printf("\n");
    138 
    139     if (!elf->Step(rel_pc + map_info->elf_offset, regs, &remote_memory)) {
    140       break;
    141     }
    142   }
    143 }
    144 
    145 int main(int argc, char** argv) {
    146   if (argc != 2) {
    147     printf("Usage: unwind <PID>\n");
    148     return 1;
    149   }
    150 
    151   pid_t pid = atoi(argv[1]);
    152   if (!Attach(pid)) {
    153     printf("Failed to attach to pid %d: %s\n", pid, strerror(errno));
    154     return 1;
    155   }
    156 
    157   DoUnwind(pid);
    158 
    159   Detach(pid);
    160 
    161   return 0;
    162 }
    163