bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) { if (context == nullptr) { BACK_LOGW("The context is needed for offline backtracing."); return false; } context_ = context; unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0); unw_cursor_t cursor; int ret = unw_init_remote(&cursor, addr_space, this); if (ret != 0) { BACK_LOGW("unw_init_remote failed %d", ret); unw_destroy_addr_space(addr_space); return false; } size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } if (num_ignore_frames == 0) { frames_.resize(num_frames + 1); backtrace_frame_data_t* frame = &frames_[num_frames]; frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; if (num_frames > 0) { backtrace_frame_data_t* prev = &frames_[num_frames - 1]; prev->stack_size = frame->sp - prev->sp; } frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); FillInMap(frame->pc, &frame->map); num_frames++; } else { num_ignore_frames--; } ret = unw_step(&cursor); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); unw_destroy_addr_space(addr_space); context_ = nullptr; return true; }
bool BacktraceOffline::FindProcInfo(unw_addr_space_t addr_space, uint64_t ip, unw_proc_info_t* proc_info, int need_unwind_info) { backtrace_map_t map; FillInMap(ip, &map); if (!BacktraceMap::IsValid(map)) { return false; } const std::string& filename = map.name; DebugFrameInfo* debug_frame = GetDebugFrameInFile(filename); if (debug_frame == nullptr) { return false; } if (debug_frame->is_eh_frame) { uint64_t ip_offset = ip - map.start + map.offset; uint64_t ip_vaddr; // vaddr in the elf file. bool result = FileOffsetToVaddr(debug_frame->eh_frame.program_headers, ip_offset, &ip_vaddr); if (!result) { return false; } // Calculate the addresses where .eh_frame_hdr and .eh_frame stay when the process was running. eh_frame_hdr_space_.start = (ip - ip_vaddr) + debug_frame->eh_frame.eh_frame_hdr_vaddr; eh_frame_hdr_space_.end = eh_frame_hdr_space_.start + debug_frame->eh_frame.eh_frame_hdr_data.size(); eh_frame_hdr_space_.data = debug_frame->eh_frame.eh_frame_hdr_data.data(); eh_frame_space_.start = (ip - ip_vaddr) + debug_frame->eh_frame.eh_frame_vaddr; eh_frame_space_.end = eh_frame_space_.start + debug_frame->eh_frame.eh_frame_data.size(); eh_frame_space_.data = debug_frame->eh_frame.eh_frame_data.data(); unw_dyn_info di; memset(&di, '\0', sizeof(di)); di.start_ip = map.start; di.end_ip = map.end; di.format = UNW_INFO_FORMAT_REMOTE_TABLE; di.u.rti.name_ptr = 0; di.u.rti.segbase = eh_frame_hdr_space_.start; di.u.rti.table_data = eh_frame_hdr_space_.start + debug_frame->eh_frame.fde_table_offset_in_eh_frame_hdr; di.u.rti.table_len = (eh_frame_hdr_space_.end - di.u.rti.table_data) / sizeof(unw_word_t); int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this); return ret == 0; } eh_frame_hdr_space_.Clear(); eh_frame_space_.Clear(); unw_dyn_info_t di; unw_word_t segbase = map.start - map.offset; int found = dwarf_find_debug_frame(0, &di, ip, segbase, filename.c_str(), map.start, map.end); if (found == 1) { int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this); return ret == 0; } return false; }
void CAAUMIDIMapManager::ReplaceAllMaps (AUParameterMIDIMapping* inMappings, UInt32 inNumMaps, AUBase &That) { mParameterMaps.clear(); for (unsigned int i = 0; i < inNumMaps; ++i) { CAAUMIDIMap mapping(inMappings[i]); FillInMap (mapping, That); mParameterMaps.push_back (mapping); } std::sort(mParameterMaps.begin(),mParameterMaps.end(), CompareMIDIMap()); }
size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) { #if defined(__APPLE__) BACK_LOGW("MacOS does not support reading from another pid."); return 0; #else backtrace_map_t map; FillInMap(addr, &map); if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { return 0; } bytes = MIN(map.end - addr, bytes); size_t bytes_read = 0; word_t data_word; size_t align_bytes = addr & (sizeof(word_t) - 1); if (align_bytes != 0) { if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) { return 0; } align_bytes = sizeof(word_t) - align_bytes; memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + sizeof(word_t) - align_bytes, align_bytes); addr += align_bytes; buffer += align_bytes; bytes -= align_bytes; bytes_read += align_bytes; } size_t num_words = bytes / sizeof(word_t); for (size_t i = 0; i < num_words; i++) { if (!PtraceRead(Tid(), addr, &data_word)) { return bytes_read; } memcpy(buffer, &data_word, sizeof(word_t)); buffer += sizeof(word_t); addr += sizeof(word_t); bytes_read += sizeof(word_t); } size_t left_over = bytes & (sizeof(word_t) - 1); if (left_over) { if (!PtraceRead(Tid(), addr, &data_word)) { return bytes_read; } memcpy(buffer, &data_word, left_over); bytes_read += left_over; } return bytes_read; #endif }
bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) { #if defined(__APPLE__) BACK_LOGW("MacOS does not support reading from another pid."); return false; #else if (!VerifyReadWordArgs(ptr, out_value)) { return false; } backtrace_map_t map; FillInMap(ptr, &map); if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) { return false; } return PtraceRead(Tid(), ptr, out_value); #endif }
OSStatus CAAUMIDIMapManager::SortedInsertToParamaterMaps (AUParameterMIDIMapping *maps, UInt32 inNumMaps, AUBase &That) { for (unsigned int i = 0; i < inNumMaps; ++i) { CAAUMIDIMap map(maps[i]); FillInMap (map, That); int idx = FindParameterIndex (maps[i]); if (idx > -1) mParameterMaps.erase(mParameterMaps.begin() + idx); // least disruptive place to put this is at the end mParameterMaps.push_back(map); } std::sort(mParameterMaps.begin(), mParameterMaps.end(), CompareMIDIMap()); return noErr; }
bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) { if (ucontext == nullptr) { int ret = unw_getcontext(&context_); if (ret < 0) { BACK_LOGW("unw_getcontext failed %d", ret); return false; } } else { GetUnwContextFromUcontext(ucontext); } // The cursor structure is pretty large, do not put it on the stack. std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t); int ret = unw_init_local(cursor.get(), &context_); if (ret < 0) { BACK_LOGW("unw_init_local failed %d", ret); return false; } size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } frames_.resize(num_frames+1); backtrace_frame_data_t* frame = &frames_.at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; FillInMap(frame->pc, &frame->map); // Check to see if we should skip this frame because it's coming // from within the library, and we are doing a local unwind. if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) { if (num_ignore_frames == 0) { // GetFunctionName is an expensive call, only do it if we are // keeping the frame. frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); 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--; } } ret = unw_step (cursor.get()); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); return true; }
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { if (GetMap() == nullptr) { // Without a map object, we can't do anything. error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING; return false; } error_ = BACKTRACE_UNWIND_NO_ERROR; if (ucontext) { BACK_LOGW("Unwinding from a specified context not supported yet."); error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION; return false; } if (!Init()) { return false; } unw_cursor_t cursor; int ret = unw_init_remote(&cursor, addr_space_, upt_info_); if (ret < 0) { BACK_LOGW("unw_init_remote failed %d", ret); error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; return false; } size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } if (num_ignore_frames == 0) { frames_.resize(num_frames+1); backtrace_frame_data_t* frame = &frames_.at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; if (num_frames > 0) { backtrace_frame_data_t* prev = &frames_.at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } FillInMap(frame->pc, &frame->map); if (BacktraceMap::IsValid(frame->map)) { frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias; } else { frame->rel_pc = frame->pc; } frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map); num_frames++; // If the pc is in a device map, then don't try to step. if (frame->map.flags & PROT_DEVICE_MAP) { break; } } else { // If the pc is in a device map, then don't try to step. backtrace_map_t map; FillInMap(pc, &map); if (map.flags & PROT_DEVICE_MAP) { break; } num_ignore_frames--; } // Verify the sp is not in a device map. backtrace_map_t map; FillInMap(sp, &map); if (map.flags & PROT_DEVICE_MAP) { break; } ret = unw_step (&cursor); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); return true; }
bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) { if (ucontext == nullptr) { int ret = unw_getcontext(&context_); if (ret < 0) { BACK_LOGW("unw_getcontext failed %d", ret); error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; return false; } } else { GetUnwContextFromUcontext(ucontext); } // The cursor structure is pretty large, do not put it on the stack. std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t); int ret = unw_init_local(cursor.get(), &context_); if (ret < 0) { BACK_LOGW("unw_init_local failed %d", ret); error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; return false; } initialized_ = true; size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } frames_.resize(num_frames+1); backtrace_frame_data_t* frame = &frames_.at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; FillInMap(frame->pc, &frame->map); // Check to see if we should skip this frame because it's coming // from within the library, and we are doing a local unwind. if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) { if (num_ignore_frames == 0) { // GetFunctionName is an expensive call, only do it if we are // keeping the frame. frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map); 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; } if (BacktraceMap::IsValid(frame->map)) { frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias; } else { frame->rel_pc = frame->pc; } num_frames++; } else { num_ignore_frames--; // Set the number of frames to zero to remove the frame added // above. By definition, if we still have frames to ignore // there should only be one frame in the vector. CHECK(num_frames == 0); frames_.resize(0); } } // If the pc is in a device map, then don't try to step. if (frame->map.flags & PROT_DEVICE_MAP) { break; } // Verify the sp is not in a device map too. backtrace_map_t map; FillInMap(frame->sp, &map); if (map.flags & PROT_DEVICE_MAP) { break; } ret = unw_step (cursor.get()); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); return true; }
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { if (GetMap() == nullptr) { // Without a map object, we can't do anything. return false; } if (ucontext) { BACK_LOGW("Unwinding from a specified context not supported yet."); return false; } addr_space_ = unw_create_addr_space(&_UPT_accessors, 0); if (!addr_space_) { BACK_LOGW("unw_create_addr_space failed."); return false; } UnwindMap* map = static_cast<UnwindMap*>(GetMap()); unw_map_set(addr_space_, map->GetMapCursor()); upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid())); if (!upt_info_) { BACK_LOGW("Failed to create upt info."); return false; } unw_cursor_t cursor; int ret = unw_init_remote(&cursor, addr_space_, upt_info_); if (ret < 0) { BACK_LOGW("unw_init_remote failed %d", ret); return false; } size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } if (num_ignore_frames == 0) { frames_.resize(num_frames+1); backtrace_frame_data_t* frame = &frames_.at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; if (num_frames > 0) { backtrace_frame_data_t* prev = &frames_.at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); FillInMap(frame->pc, &frame->map); num_frames++; } else { num_ignore_frames--; } ret = unw_step (&cursor); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); return true; }