Loading libbacktrace/UnwindStack.cpp +30 −120 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <ucontext.h> #include <memory> #include <set> #include <string> #if !defined(__ANDROID__) Loading @@ -37,6 +38,8 @@ #include <unwindstack/Regs.h> #include <unwindstack/RegsGetLocal.h> #include <unwindstack/Unwinder.h> #include "BacktraceLog.h" #include "UnwindStack.h" #include "UnwindStackMap.h" Loading @@ -63,135 +66,42 @@ static std::string GetFunctionName(BacktraceMap* back_map, uintptr_t pc, uintptr return name; } static bool IsUnwindLibrary(const std::string& map_name) { const std::string library(basename(map_name.c_str())); return library == "libunwindstack.so" || library == "libbacktrace.so"; } static void SetFrameInfo(unwindstack::Regs* regs, unwindstack::MapInfo* map_info, uint64_t adjusted_rel_pc, backtrace_frame_data_t* frame) { // This will point to the adjusted absolute pc. regs->pc() is // unaltered. frame->pc = map_info->start + adjusted_rel_pc; frame->sp = regs->sp(); frame->rel_pc = adjusted_rel_pc; frame->stack_size = 0; frame->map.start = map_info->start; frame->map.end = map_info->end; frame->map.offset = map_info->offset; frame->map.flags = map_info->flags; frame->map.name = map_info->name; unwindstack::Elf* elf = map_info->elf; frame->map.load_bias = elf->GetLoadBias(); uint64_t func_offset = 0; if (elf->GetFunctionName(adjusted_rel_pc, &frame->func_name, &func_offset)) { frame->func_name = demangle(frame->func_name.c_str()); } else { frame->func_name = ""; } frame->func_offset = func_offset; } static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) { static std::set<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"}; UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map); unwindstack::Maps* maps = stack_map->stack_maps(); bool adjust_rel_pc = false; size_t num_frames = 0; frames->clear(); bool return_address_attempted = false; auto process_memory = stack_map->process_memory(); while (num_frames < MAX_BACKTRACE_FRAMES) { unwindstack::MapInfo* map_info = maps->Find(regs->pc()); bool stepped; bool in_device_map = false; if (map_info == nullptr) { stepped = false; if (num_ignore_frames == 0) { frames->resize(num_frames + 1); backtrace_frame_data_t* frame = &frames->at(num_frames); frame->pc = regs->pc(); frame->sp = regs->sp(); frame->rel_pc = frame->pc; num_frames++; } else { num_ignore_frames--; } } else { unwindstack::Elf* elf = map_info->GetElf(process_memory, true); uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info); unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(), regs, stack_map->process_memory()); unwinder.Unwind(&skip_names); if (frames->size() != 0 || !IsUnwindLibrary(map_info->name)) { if (num_ignore_frames == 0) { uint64_t adjusted_rel_pc = rel_pc; if (adjust_rel_pc) { adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf); if (num_ignore_frames >= unwinder.NumFrames()) { frames->resize(0); return true; } frames->resize(num_frames + 1); backtrace_frame_data_t* frame = &frames->at(num_frames); frame->num = num_frames; SetFrameInfo(regs, map_info, adjusted_rel_pc, frame); frames->resize(unwinder.NumFrames() - num_ignore_frames); auto unwinder_frames = unwinder.frames(); size_t cur_frame = 0; for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, cur_frame++) { auto frame = &unwinder_frames[i]; backtrace_frame_data_t* back_frame = &frames->at(cur_frame); if (num_frames > 0) { // Set the stack size for the previous frame. backtrace_frame_data_t* prev = &frames->at(num_frames - 1); prev->stack_size = frame->sp - prev->sp; } num_frames++; } else { num_ignore_frames--; } } back_frame->num = frame->num; if (map_info->flags & PROT_DEVICE_MAP) { // Do not stop here, fall through in case we are // in the speculative unwind path and need to remove // some of the speculative frames. stepped = false; in_device_map = true; } else { unwindstack::MapInfo* sp_info = maps->Find(regs->sp()); if (sp_info->flags & PROT_DEVICE_MAP) { // Do not stop here, fall through in case we are // in the speculative unwind path and need to remove // some of the speculative frames. stepped = false; in_device_map = true; } else { bool finished; stepped = elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get(), &finished); if (stepped && finished) { break; } } } } adjust_rel_pc = true; back_frame->rel_pc = frame->rel_pc; back_frame->pc = frame->pc; back_frame->sp = frame->sp; if (!stepped) { if (return_address_attempted) { // Remove the speculative frame. if (frames->size() > 0) { frames->pop_back(); } break; } else if (in_device_map) { // Do not attempt any other unwinding, pc or sp is in a device // map. break; } else { // Stepping didn't work, try this secondary method. if (!regs->SetPcFromReturnAddress(process_memory.get())) { break; } return_address_attempted = true; } } else { return_address_attempted = false; } back_frame->func_name = frame->function_name; back_frame->func_offset = frame->function_offset; back_frame->map.name = frame->map_name; back_frame->map.start = frame->map_start; back_frame->map.end = frame->map_end; back_frame->map.offset = frame->map_offset; back_frame->map.load_bias = frame->map_load_bias; back_frame->map.flags = frame->map_flags; } return true; Loading libunwindstack/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,7 @@ cc_test { "tests/DwarfOpTest.cpp", "tests/DwarfSectionTest.cpp", "tests/DwarfSectionImplTest.cpp", "tests/ElfFake.cpp", "tests/ElfInterfaceArmTest.cpp", "tests/ElfInterfaceTest.cpp", "tests/ElfTest.cpp", Loading @@ -125,6 +126,7 @@ cc_test { "tests/RegsTest.cpp", "tests/SymbolsTest.cpp", "tests/UnwindTest.cpp", "tests/UnwinderTest.cpp", ], cflags: [ Loading libunwindstack/Regs.cpp +0 −20 Original line number Diff line number Diff line Loading @@ -33,26 +33,6 @@ namespace unwindstack { template <typename AddressType> bool RegsImpl<AddressType>::GetReturnAddressFromDefault(Memory* memory, uint64_t* value) { switch (return_loc_.type) { case LOCATION_REGISTER: CHECK(return_loc_.value < total_regs_); *value = regs_[return_loc_.value]; return true; case LOCATION_SP_OFFSET: AddressType return_value; if (!memory->Read(sp_ + return_loc_.value, &return_value, sizeof(return_value))) { return false; } *value = return_value; return true; case LOCATION_UNKNOWN: default: return false; } } RegsArm::RegsArm() : RegsImpl<uint32_t>(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {} Loading libunwindstack/Unwinder.cpp +54 −16 Original line number Diff line number Diff line Loading @@ -14,9 +14,11 @@ * limitations under the License. */ #define _GNU_SOURCE 1 #include <elf.h> #include <inttypes.h> #include <stdint.h> #include <string.h> #include <sys/types.h> #include <unistd.h> Loading @@ -28,35 +30,33 @@ namespace unwindstack { void Unwinder::FillInFrame(MapInfo* map_info, uint64_t* rel_pc) { void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, bool adjust_pc) { size_t frame_num = frames_.size(); frames_.resize(frame_num + 1); FrameData* frame = &frames_.at(frame_num); frame->num = frame_num; frame->pc = regs_->pc(); frame->sp = regs_->sp(); frame->rel_pc = frame->pc; frame->rel_pc = rel_pc; if (map_info == nullptr) { return; } Elf* elf = map_info->GetElf(process_memory_, true); *rel_pc = elf->GetRelPc(regs_->pc(), map_info); if (frame_num != 0) { if (adjust_pc) { // Don't adjust the first frame pc. frame->rel_pc = regs_->GetAdjustedPc(*rel_pc, elf); frame->rel_pc = regs_->GetAdjustedPc(rel_pc, elf); // Adjust the original pc. frame->pc -= *rel_pc - frame->rel_pc; } else { frame->rel_pc = *rel_pc; frame->pc -= rel_pc - frame->rel_pc; } frame->map_name = map_info->name; frame->map_offset = map_info->elf_offset; frame->map_start = map_info->start; frame->map_end = map_info->end; frame->map_flags = map_info->flags; frame->map_load_bias = elf->GetLoadBias(); if (!elf->GetFunctionName(frame->rel_pc, &frame->function_name, &frame->function_offset)) { frame->function_name = ""; Loading @@ -64,32 +64,70 @@ void Unwinder::FillInFrame(MapInfo* map_info, uint64_t* rel_pc) { } } void Unwinder::Unwind() { void Unwinder::Unwind(std::set<std::string>* initial_map_names_to_skip) { frames_.clear(); bool return_address_attempt = false; bool adjust_pc = false; for (; frames_.size() < max_frames_;) { MapInfo* map_info = maps_->Find(regs_->pc()); uint64_t rel_pc; FillInFrame(map_info, &rel_pc); Elf* elf; if (map_info == nullptr) { rel_pc = regs_->pc(); } else { elf = map_info->GetElf(process_memory_, true); rel_pc = elf->GetRelPc(regs_->pc(), map_info); } if (map_info == nullptr || initial_map_names_to_skip == nullptr || initial_map_names_to_skip->find(basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) { FillInFrame(map_info, elf, rel_pc, adjust_pc); // Once a frame is added, stop skipping frames. initial_map_names_to_skip = nullptr; } adjust_pc = true; bool stepped; bool in_device_map = false; if (map_info == nullptr) { stepped = false; } else { if (map_info->flags & MAPS_FLAGS_DEVICE_MAP) { // Do not stop here, fall through in case we are // in the speculative unwind path and need to remove // some of the speculative frames. stepped = false; in_device_map = true; } else { MapInfo* sp_info = maps_->Find(regs_->sp()); if (sp_info != nullptr && sp_info->flags & MAPS_FLAGS_DEVICE_MAP) { // Do not stop here, fall through in case we are // in the speculative unwind path and need to remove // some of the speculative frames. stepped = false; in_device_map = true; } else { bool finished; stepped = map_info->elf->Step(rel_pc + map_info->elf_offset, regs_, process_memory_.get(), &finished); stepped = elf->Step(rel_pc + map_info->elf_offset, regs_, process_memory_.get(), &finished); if (stepped && finished) { break; } } } } if (!stepped) { if (return_address_attempt) { // Remove the speculative frame. frames_.pop_back(); break; } else if (in_device_map) { // Do not attempt any other unwinding, pc or sp is in a device // map. break; } else { // Steping didn't work, try this secondary method. if (!regs_->SetPcFromReturnAddress(process_memory_.get())) { Loading libunwindstack/include/unwindstack/Regs.h +0 −4 Original line number Diff line number Diff line Loading @@ -55,8 +55,6 @@ class Regs { virtual uint64_t pc() = 0; virtual uint64_t sp() = 0; virtual bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) = 0; virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0; virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0; Loading Loading @@ -86,8 +84,6 @@ class RegsImpl : public Regs { : Regs(total_regs, sp_reg, return_loc), regs_(total_regs) {} virtual ~RegsImpl() = default; bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) override; uint64_t pc() override { return pc_; } uint64_t sp() override { return sp_; } Loading Loading
libbacktrace/UnwindStack.cpp +30 −120 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <ucontext.h> #include <memory> #include <set> #include <string> #if !defined(__ANDROID__) Loading @@ -37,6 +38,8 @@ #include <unwindstack/Regs.h> #include <unwindstack/RegsGetLocal.h> #include <unwindstack/Unwinder.h> #include "BacktraceLog.h" #include "UnwindStack.h" #include "UnwindStackMap.h" Loading @@ -63,135 +66,42 @@ static std::string GetFunctionName(BacktraceMap* back_map, uintptr_t pc, uintptr return name; } static bool IsUnwindLibrary(const std::string& map_name) { const std::string library(basename(map_name.c_str())); return library == "libunwindstack.so" || library == "libbacktrace.so"; } static void SetFrameInfo(unwindstack::Regs* regs, unwindstack::MapInfo* map_info, uint64_t adjusted_rel_pc, backtrace_frame_data_t* frame) { // This will point to the adjusted absolute pc. regs->pc() is // unaltered. frame->pc = map_info->start + adjusted_rel_pc; frame->sp = regs->sp(); frame->rel_pc = adjusted_rel_pc; frame->stack_size = 0; frame->map.start = map_info->start; frame->map.end = map_info->end; frame->map.offset = map_info->offset; frame->map.flags = map_info->flags; frame->map.name = map_info->name; unwindstack::Elf* elf = map_info->elf; frame->map.load_bias = elf->GetLoadBias(); uint64_t func_offset = 0; if (elf->GetFunctionName(adjusted_rel_pc, &frame->func_name, &func_offset)) { frame->func_name = demangle(frame->func_name.c_str()); } else { frame->func_name = ""; } frame->func_offset = func_offset; } static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) { static std::set<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"}; UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map); unwindstack::Maps* maps = stack_map->stack_maps(); bool adjust_rel_pc = false; size_t num_frames = 0; frames->clear(); bool return_address_attempted = false; auto process_memory = stack_map->process_memory(); while (num_frames < MAX_BACKTRACE_FRAMES) { unwindstack::MapInfo* map_info = maps->Find(regs->pc()); bool stepped; bool in_device_map = false; if (map_info == nullptr) { stepped = false; if (num_ignore_frames == 0) { frames->resize(num_frames + 1); backtrace_frame_data_t* frame = &frames->at(num_frames); frame->pc = regs->pc(); frame->sp = regs->sp(); frame->rel_pc = frame->pc; num_frames++; } else { num_ignore_frames--; } } else { unwindstack::Elf* elf = map_info->GetElf(process_memory, true); uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info); unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(), regs, stack_map->process_memory()); unwinder.Unwind(&skip_names); if (frames->size() != 0 || !IsUnwindLibrary(map_info->name)) { if (num_ignore_frames == 0) { uint64_t adjusted_rel_pc = rel_pc; if (adjust_rel_pc) { adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf); if (num_ignore_frames >= unwinder.NumFrames()) { frames->resize(0); return true; } frames->resize(num_frames + 1); backtrace_frame_data_t* frame = &frames->at(num_frames); frame->num = num_frames; SetFrameInfo(regs, map_info, adjusted_rel_pc, frame); frames->resize(unwinder.NumFrames() - num_ignore_frames); auto unwinder_frames = unwinder.frames(); size_t cur_frame = 0; for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, cur_frame++) { auto frame = &unwinder_frames[i]; backtrace_frame_data_t* back_frame = &frames->at(cur_frame); if (num_frames > 0) { // Set the stack size for the previous frame. backtrace_frame_data_t* prev = &frames->at(num_frames - 1); prev->stack_size = frame->sp - prev->sp; } num_frames++; } else { num_ignore_frames--; } } back_frame->num = frame->num; if (map_info->flags & PROT_DEVICE_MAP) { // Do not stop here, fall through in case we are // in the speculative unwind path and need to remove // some of the speculative frames. stepped = false; in_device_map = true; } else { unwindstack::MapInfo* sp_info = maps->Find(regs->sp()); if (sp_info->flags & PROT_DEVICE_MAP) { // Do not stop here, fall through in case we are // in the speculative unwind path and need to remove // some of the speculative frames. stepped = false; in_device_map = true; } else { bool finished; stepped = elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get(), &finished); if (stepped && finished) { break; } } } } adjust_rel_pc = true; back_frame->rel_pc = frame->rel_pc; back_frame->pc = frame->pc; back_frame->sp = frame->sp; if (!stepped) { if (return_address_attempted) { // Remove the speculative frame. if (frames->size() > 0) { frames->pop_back(); } break; } else if (in_device_map) { // Do not attempt any other unwinding, pc or sp is in a device // map. break; } else { // Stepping didn't work, try this secondary method. if (!regs->SetPcFromReturnAddress(process_memory.get())) { break; } return_address_attempted = true; } } else { return_address_attempted = false; } back_frame->func_name = frame->function_name; back_frame->func_offset = frame->function_offset; back_frame->map.name = frame->map_name; back_frame->map.start = frame->map_start; back_frame->map.end = frame->map_end; back_frame->map.offset = frame->map_offset; back_frame->map.load_bias = frame->map_load_bias; back_frame->map.flags = frame->map_flags; } return true; Loading
libunwindstack/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,7 @@ cc_test { "tests/DwarfOpTest.cpp", "tests/DwarfSectionTest.cpp", "tests/DwarfSectionImplTest.cpp", "tests/ElfFake.cpp", "tests/ElfInterfaceArmTest.cpp", "tests/ElfInterfaceTest.cpp", "tests/ElfTest.cpp", Loading @@ -125,6 +126,7 @@ cc_test { "tests/RegsTest.cpp", "tests/SymbolsTest.cpp", "tests/UnwindTest.cpp", "tests/UnwinderTest.cpp", ], cflags: [ Loading
libunwindstack/Regs.cpp +0 −20 Original line number Diff line number Diff line Loading @@ -33,26 +33,6 @@ namespace unwindstack { template <typename AddressType> bool RegsImpl<AddressType>::GetReturnAddressFromDefault(Memory* memory, uint64_t* value) { switch (return_loc_.type) { case LOCATION_REGISTER: CHECK(return_loc_.value < total_regs_); *value = regs_[return_loc_.value]; return true; case LOCATION_SP_OFFSET: AddressType return_value; if (!memory->Read(sp_ + return_loc_.value, &return_value, sizeof(return_value))) { return false; } *value = return_value; return true; case LOCATION_UNKNOWN: default: return false; } } RegsArm::RegsArm() : RegsImpl<uint32_t>(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {} Loading
libunwindstack/Unwinder.cpp +54 −16 Original line number Diff line number Diff line Loading @@ -14,9 +14,11 @@ * limitations under the License. */ #define _GNU_SOURCE 1 #include <elf.h> #include <inttypes.h> #include <stdint.h> #include <string.h> #include <sys/types.h> #include <unistd.h> Loading @@ -28,35 +30,33 @@ namespace unwindstack { void Unwinder::FillInFrame(MapInfo* map_info, uint64_t* rel_pc) { void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, bool adjust_pc) { size_t frame_num = frames_.size(); frames_.resize(frame_num + 1); FrameData* frame = &frames_.at(frame_num); frame->num = frame_num; frame->pc = regs_->pc(); frame->sp = regs_->sp(); frame->rel_pc = frame->pc; frame->rel_pc = rel_pc; if (map_info == nullptr) { return; } Elf* elf = map_info->GetElf(process_memory_, true); *rel_pc = elf->GetRelPc(regs_->pc(), map_info); if (frame_num != 0) { if (adjust_pc) { // Don't adjust the first frame pc. frame->rel_pc = regs_->GetAdjustedPc(*rel_pc, elf); frame->rel_pc = regs_->GetAdjustedPc(rel_pc, elf); // Adjust the original pc. frame->pc -= *rel_pc - frame->rel_pc; } else { frame->rel_pc = *rel_pc; frame->pc -= rel_pc - frame->rel_pc; } frame->map_name = map_info->name; frame->map_offset = map_info->elf_offset; frame->map_start = map_info->start; frame->map_end = map_info->end; frame->map_flags = map_info->flags; frame->map_load_bias = elf->GetLoadBias(); if (!elf->GetFunctionName(frame->rel_pc, &frame->function_name, &frame->function_offset)) { frame->function_name = ""; Loading @@ -64,32 +64,70 @@ void Unwinder::FillInFrame(MapInfo* map_info, uint64_t* rel_pc) { } } void Unwinder::Unwind() { void Unwinder::Unwind(std::set<std::string>* initial_map_names_to_skip) { frames_.clear(); bool return_address_attempt = false; bool adjust_pc = false; for (; frames_.size() < max_frames_;) { MapInfo* map_info = maps_->Find(regs_->pc()); uint64_t rel_pc; FillInFrame(map_info, &rel_pc); Elf* elf; if (map_info == nullptr) { rel_pc = regs_->pc(); } else { elf = map_info->GetElf(process_memory_, true); rel_pc = elf->GetRelPc(regs_->pc(), map_info); } if (map_info == nullptr || initial_map_names_to_skip == nullptr || initial_map_names_to_skip->find(basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) { FillInFrame(map_info, elf, rel_pc, adjust_pc); // Once a frame is added, stop skipping frames. initial_map_names_to_skip = nullptr; } adjust_pc = true; bool stepped; bool in_device_map = false; if (map_info == nullptr) { stepped = false; } else { if (map_info->flags & MAPS_FLAGS_DEVICE_MAP) { // Do not stop here, fall through in case we are // in the speculative unwind path and need to remove // some of the speculative frames. stepped = false; in_device_map = true; } else { MapInfo* sp_info = maps_->Find(regs_->sp()); if (sp_info != nullptr && sp_info->flags & MAPS_FLAGS_DEVICE_MAP) { // Do not stop here, fall through in case we are // in the speculative unwind path and need to remove // some of the speculative frames. stepped = false; in_device_map = true; } else { bool finished; stepped = map_info->elf->Step(rel_pc + map_info->elf_offset, regs_, process_memory_.get(), &finished); stepped = elf->Step(rel_pc + map_info->elf_offset, regs_, process_memory_.get(), &finished); if (stepped && finished) { break; } } } } if (!stepped) { if (return_address_attempt) { // Remove the speculative frame. frames_.pop_back(); break; } else if (in_device_map) { // Do not attempt any other unwinding, pc or sp is in a device // map. break; } else { // Steping didn't work, try this secondary method. if (!regs_->SetPcFromReturnAddress(process_memory_.get())) { Loading
libunwindstack/include/unwindstack/Regs.h +0 −4 Original line number Diff line number Diff line Loading @@ -55,8 +55,6 @@ class Regs { virtual uint64_t pc() = 0; virtual uint64_t sp() = 0; virtual bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) = 0; virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0; virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0; Loading Loading @@ -86,8 +84,6 @@ class RegsImpl : public Regs { : Regs(total_regs, sp_reg, return_loc), regs_(total_regs) {} virtual ~RegsImpl() = default; bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) override; uint64_t pc() override { return pc_; } uint64_t sp() override { return sp_; } Loading