New function to create the process memory object. This allows for a future where different remote process memory objects could be created depending on the way remote memory can be created. Even different local memory objects that access memory without doing any checks. It also allows MemoryRange objects to share one single process memory object and could help if the process memory object caches data. Small changes to MapInfo::CreateMemory to when some errors are detected. - Always check if the map is a device map, instead of only if the name is not empty. - Check if a memory map is readable before creating the memory from process memory. Bug: 23762183 Test: Ran unit tests, unwound on device using the new code. Change-Id: I12a93c2dc19639689a528ec41c67bfac74d431b3
161 lines
3.9 KiB
C++
161 lines
3.9 KiB
C++
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <elf.h>
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
#include <signal.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ptrace.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include <string>
|
|
|
|
#include <unwindstack/Elf.h>
|
|
#include <unwindstack/MapInfo.h>
|
|
#include <unwindstack/Maps.h>
|
|
#include <unwindstack/Memory.h>
|
|
#include <unwindstack/Regs.h>
|
|
|
|
static bool Attach(pid_t pid) {
|
|
if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
|
|
return false;
|
|
}
|
|
|
|
// Allow at least 1 second to attach properly.
|
|
for (size_t i = 0; i < 1000; i++) {
|
|
siginfo_t si;
|
|
if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
|
|
return true;
|
|
}
|
|
usleep(1000);
|
|
}
|
|
printf("%d: Failed to stop.\n", pid);
|
|
return false;
|
|
}
|
|
|
|
static bool Detach(pid_t pid) {
|
|
return ptrace(PTRACE_DETACH, pid, 0, 0) == 0;
|
|
}
|
|
|
|
void DoUnwind(pid_t pid) {
|
|
unwindstack::RemoteMaps remote_maps(pid);
|
|
if (!remote_maps.Parse()) {
|
|
printf("Failed to parse map data.\n");
|
|
return;
|
|
}
|
|
|
|
unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid);
|
|
if (regs == nullptr) {
|
|
printf("Unable to get remote reg data\n");
|
|
return;
|
|
}
|
|
|
|
bool bits32 = true;
|
|
printf("ABI: ");
|
|
switch (regs->MachineType()) {
|
|
case EM_ARM:
|
|
printf("arm");
|
|
break;
|
|
case EM_386:
|
|
printf("x86");
|
|
break;
|
|
case EM_AARCH64:
|
|
printf("arm64");
|
|
bits32 = false;
|
|
break;
|
|
case EM_X86_64:
|
|
printf("x86_64");
|
|
bits32 = false;
|
|
break;
|
|
default:
|
|
printf("unknown\n");
|
|
return;
|
|
}
|
|
printf("\n");
|
|
|
|
auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
|
|
for (size_t frame_num = 0; frame_num < 64; frame_num++) {
|
|
if (regs->pc() == 0) {
|
|
break;
|
|
}
|
|
unwindstack::MapInfo* map_info = remote_maps.Find(regs->pc());
|
|
if (map_info == nullptr) {
|
|
printf("Failed to find map data for the pc\n");
|
|
break;
|
|
}
|
|
|
|
unwindstack::Elf* elf = map_info->GetElf(process_memory, true);
|
|
|
|
uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
|
|
uint64_t adjusted_rel_pc = rel_pc;
|
|
// Don't need to adjust the first frame pc.
|
|
if (frame_num != 0) {
|
|
adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
|
|
}
|
|
|
|
std::string name;
|
|
if (bits32) {
|
|
printf(" #%02zu pc %08" PRIx64, frame_num, adjusted_rel_pc);
|
|
} else {
|
|
printf(" #%02zu pc %016" PRIx64, frame_num, adjusted_rel_pc);
|
|
}
|
|
if (!map_info->name.empty()) {
|
|
printf(" %s", map_info->name.c_str());
|
|
if (map_info->elf_offset != 0) {
|
|
printf(" (offset 0x%" PRIx64 ")", map_info->elf_offset);
|
|
}
|
|
} else {
|
|
printf(" <anonymous:%" PRIx64 ">", map_info->offset);
|
|
}
|
|
uint64_t func_offset;
|
|
if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) {
|
|
printf(" (%s", name.c_str());
|
|
if (func_offset != 0) {
|
|
printf("+%" PRId64, func_offset);
|
|
}
|
|
printf(")");
|
|
}
|
|
printf("\n");
|
|
|
|
if (!elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get())) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc != 2) {
|
|
printf("Usage: unwind <PID>\n");
|
|
return 1;
|
|
}
|
|
|
|
pid_t pid = atoi(argv[1]);
|
|
if (!Attach(pid)) {
|
|
printf("Failed to attach to pid %d: %s\n", pid, strerror(errno));
|
|
return 1;
|
|
}
|
|
|
|
DoUnwind(pid);
|
|
|
|
Detach(pid);
|
|
|
|
return 0;
|
|
}
|