//===-- MacOSXLibunwindCallbacks.cpp ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef liblldb_MacOSXLibunwindCallbacks_cpp_ #define liblldb_MacOSXLibunwindCallbacks_cpp_ #if defined(__cplusplus) #include "lldb/Core/DataExtractor.h" #include "lldb/Core/FileSpec.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb-enumerations.h" #include "libunwind.h" #include "llvm-c/EnhancedDisassembly.h" using namespace lldb; namespace lldb_private { /* Don't implement (libunwind does not use) find_proc_info put_unwind_info get_dyn_info_list_addr access_mem resume */ /* Should implement (not needed yet) access_fpreg access_vecreg proc_is_sigtramp proc_is_inferior_function_call access_reg_inf_func_call */ static int access_reg (lldb_private::unw_addr_space_t as, lldb_private::unw_regnum_t regnum, lldb_private::unw_word_t *valp, int write, void *arg) { if (arg == 0) return -1; Thread *th = (Thread *) arg; /* FIXME Only support reading for now. */ if (write == 1) return -1; if (th->GetRegisterContext()->GetRegisterInfoAtIndex(regnum) == NULL) return -1; DataExtractor de; if (!th->GetRegisterContext()->ReadRegisterBytes (regnum, de)) return -1; memcpy (valp, de.GetDataStart(), de.GetByteSize()); return UNW_ESUCCESS; } static int get_proc_name (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t ip, char *bufp, size_t buf_len, lldb_private::unw_word_t *offp, void *arg) { if (arg == 0) return -1; Thread *th = (Thread *) arg; Address addr; if (!th->GetProcess().ResolveLoadAddress(ip, addr)) return -1; SymbolContext sc; if (!th->GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (addr, eSymbolContextFunction, sc)) return -1; if (!sc.symbol) return -1; strlcpy (bufp, sc.symbol->GetMangled().GetMangledName().AsCString(""), buf_len); if (offp) *offp = addr.GetLoadAddress(&th->GetProcess()) - sc.symbol->GetValue().GetLoadAddress(&th->GetProcess()); return UNW_ESUCCESS; } static int find_image_info (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t load_addr, lldb_private::unw_word_t *mh, lldb_private::unw_word_t *text_start, lldb_private::unw_word_t *text_end, lldb_private::unw_word_t *eh_frame, lldb_private::unw_word_t *eh_frame_len, lldb_private::unw_word_t *compact_unwind_start, lldb_private::unw_word_t *compact_unwind_len, void *arg) { if (arg == 0) return -1; Thread *th = (Thread *) arg; Address addr; if (!th->GetProcess().ResolveLoadAddress(load_addr, addr)) return -1; SymbolContext sc; if (!th->GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (addr, eSymbolContextModule, sc)) return -1; SectionList *sl = sc.module_sp->GetObjectFile()->GetSectionList(); static ConstString g_segment_name_TEXT("__TEXT"); SectionSP text_segment_sp(sl->FindSectionByName(g_segment_name_TEXT)); if (!text_segment_sp) return -1; *mh = text_segment_sp->GetLoadBaseAddress (&th->GetProcess()); *text_start = text_segment_sp->GetLoadBaseAddress (&th->GetProcess()); *text_end = *text_start + text_segment_sp->GetByteSize(); static ConstString g_section_name_eh_frame ("__eh_frame"); SectionSP eh_frame_section_sp = text_segment_sp->GetChildren().FindSectionByName(g_section_name_eh_frame); if (eh_frame_section_sp.get()) { *eh_frame = eh_frame_section_sp->GetLoadBaseAddress (&th->GetProcess()); *eh_frame_len = eh_frame_section_sp->GetByteSize(); } else { *eh_frame = 0; *eh_frame_len = 0; } static ConstString g_section_name_unwind_info ("__unwind_info"); SectionSP unwind_info_section_sp = text_segment_sp->GetChildren().FindSectionByName(g_section_name_unwind_info); if (unwind_info_section_sp.get()) { *compact_unwind_start = unwind_info_section_sp->GetLoadBaseAddress (&th->GetProcess()); *compact_unwind_len = unwind_info_section_sp->GetByteSize(); } else { *compact_unwind_start = 0; *compact_unwind_len = 0; } return UNW_ESUCCESS; } static int get_proc_bounds (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t ip, lldb_private::unw_word_t *low, lldb_private::unw_word_t *high, void *arg) { if (arg == 0) return -1; Thread *th = (Thread *) arg; Address addr; if (!th->GetProcess().ResolveLoadAddress(ip, addr)) return -1; SymbolContext sc; if (!th->GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (addr, eSymbolContextFunction | eSymbolContextSymbol, sc)) return -1; if (sc.function) { lldb::addr_t start, len; start = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(&th->GetProcess()); len = sc.function->GetAddressRange().GetByteSize(); if (start == LLDB_INVALID_ADDRESS || len == LLDB_INVALID_ADDRESS) return -1; *low = start; *high = start + len; return UNW_ESUCCESS; } if (sc.symbol) { lldb::addr_t start, len; start = sc.symbol->GetAddressRangeRef().GetBaseAddress().GetLoadAddress(&th->GetProcess()); len = sc.symbol->GetAddressRangeRef().GetByteSize(); if (start == LLDB_INVALID_ADDRESS) return -1; *low = start; if (len != LLDB_INVALID_ADDRESS) *high = start + len; else *high = 0; return UNW_ESUCCESS; } return -1; } static int access_raw (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t addr, lldb_private::unw_word_t extent, uint8_t *valp, int write, void *arg) { if (arg == 0) return -1; Thread *th = (Thread *) arg; /* FIXME Only support reading for now. */ if (write == 1) return -1; Error error; if (th->GetProcess().ReadMemory (addr, valp, extent, error) != extent) return -1; return UNW_ESUCCESS; } static int reg_info (lldb_private::unw_addr_space_t as, lldb_private::unw_regnum_t regnum, lldb_private::unw_regtype_t *type, char *buf, size_t buflen, void *arg) { if (arg == 0) return -1; Thread *th = (Thread *) arg; RegisterContext *regc = th->GetRegisterContext(); if (regnum > regc->GetRegisterCount()) { *type = UNW_NOT_A_REG; return UNW_ESUCCESS; } const char *name = regc->GetRegisterName (regnum); if (name == NULL) { *type = UNW_NOT_A_REG; return UNW_ESUCCESS; } strlcpy (buf, name, buflen); const lldb::RegisterInfo *reginfo = regc->GetRegisterInfoAtIndex (regnum); if (reginfo == NULL || reginfo->encoding == eEncodingInvalid) { *type = UNW_NOT_A_REG; return UNW_ESUCCESS; } if (reginfo->encoding == eEncodingUint || reginfo->encoding == eEncodingSint) *type = UNW_INTEGER_REG; if (reginfo->encoding == eEncodingIEEE754) *type = UNW_FLOATING_POINT_REG; if (reginfo->encoding == eEncodingVector) *type = UNW_VECTOR_REG; return UNW_ESUCCESS; } static int read_byte_for_edis (uint8_t *buf, uint64_t addr, void *arg) { if (arg == 0) return -1; Thread *th = (Thread *) arg; DataBufferHeap onebyte(1, 0); Error error; if (th->GetProcess().ReadMemory (addr, onebyte.GetBytes(), onebyte.GetByteSize(), error) != 1) return -1; *buf = onebyte.GetBytes()[0]; return UNW_ESUCCESS; } static int instruction_length (lldb_private::unw_addr_space_t as, lldb_private::unw_word_t addr, int *length, void *arg) { EDDisassemblerRef disasm; EDInstRef cur_insn; if (arg == 0) return -1; Thread *th = (Thread *) arg; const ArchSpec target_arch (th->GetProcess().GetTarget().GetArchitecture ()); if (target_arch.GetCPUType() == CPU_TYPE_I386) { if (EDGetDisassembler (&disasm, "i386-apple-darwin", kEDAssemblySyntaxX86ATT) != 0) return -1; } else if (target_arch.GetCPUType() == CPU_TYPE_X86_64) { if (EDGetDisassembler (&disasm, "x86_64-apple-darwin", kEDAssemblySyntaxX86ATT) != 0) return -1; } else { return -1; } if (EDCreateInsts (&cur_insn, 1, disasm, read_byte_for_edis, addr, arg) != 1) return -1; *length = EDInstByteSize (cur_insn); EDReleaseInst (cur_insn); return UNW_ESUCCESS; } lldb_private::unw_accessors_t get_macosx_libunwind_callbacks () { lldb_private::unw_accessors_t ap; bzero (&ap, sizeof (lldb_private::unw_accessors_t)); ap.find_proc_info = NULL; ap.put_unwind_info = NULL; ap.get_dyn_info_list_addr = NULL; ap.find_image_info = find_image_info; ap.access_mem = NULL; ap.access_reg = access_reg; ap.access_fpreg = NULL; ap.access_vecreg = NULL; ap.resume = NULL; ap.get_proc_name = get_proc_name; ap.get_proc_bounds = get_proc_bounds; ap.access_raw = access_raw; ap.reg_info = reg_info; ap.proc_is_sigtramp = NULL; ap.proc_is_inferior_function_call = NULL; ap.access_reg_inf_func_call = NULL; ap.instruction_length = instruction_length; return ap; } } // namespace lldb_private #endif // #if defined(__cplusplus) #endif // #ifndef liblldb_MacOSXLibunwindCallbacks_cpp_