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 37static 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 54static bool Detach(pid_t pid) { 55 return ptrace(PTRACE_DETACH, pid, 0, 0) == 0; 56} 57 58void 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 145int 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