bool CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result) { Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); if (target == NULL) { result.AppendError ("invalid target, create a debug target using the 'target create' command"); result.SetStatus (eReturnStatusFailed); return false; } if (!m_options.arch.IsValid()) m_options.arch = target->GetArchitecture(); if (!m_options.arch.IsValid()) { result.AppendError ("use the --arch option or set the target architecure to disassemble"); result.SetStatus (eReturnStatusFailed); return false; } const char *plugin_name = m_options.GetPluginName (); const char *flavor_string = m_options.GetFlavorString(); DisassemblerSP disassembler = Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name); if (!disassembler) { if (plugin_name) { result.AppendErrorWithFormat ("Unable to find Disassembler plug-in named '%s' that supports the '%s' architecture.\n", plugin_name, m_options.arch.GetArchitectureName()); } else result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for the '%s' architecture.\n", m_options.arch.GetArchitectureName()); result.SetStatus (eReturnStatusFailed); return false; } else if (flavor_string != NULL && !disassembler->FlavorValidForArchSpec(m_options.arch, flavor_string)) result.AppendWarningWithFormat("invalid disassembler flavor \"%s\", using default.\n", flavor_string); result.SetStatus (eReturnStatusSuccessFinishResult); if (command.GetArgumentCount() != 0) { result.AppendErrorWithFormat ("\"disassemble\" arguments are specified as options.\n"); GetOptions()->GenerateOptionUsage (result.GetErrorStream(), this); result.SetStatus (eReturnStatusFailed); return false; } if (m_options.show_mixed && m_options.num_lines_context == 0) m_options.num_lines_context = 1; // Always show the PC in the disassembly uint32_t options = Disassembler::eOptionMarkPCAddress; // Mark the source line for the current PC only if we are doing mixed source and assembly if (m_options.show_mixed) options |= Disassembler::eOptionMarkPCSourceLine; if (m_options.show_bytes) options |= Disassembler::eOptionShowBytes; if (m_options.raw) options |= Disassembler::eOptionRawOuput; if (!m_options.func_name.empty()) { ConstString name(m_options.func_name.c_str()); if (Disassembler::Disassemble (m_interpreter.GetDebugger(), m_options.arch, plugin_name, flavor_string, m_exe_ctx, name, NULL, // Module * m_options.num_instructions, m_options.show_mixed ? m_options.num_lines_context : 0, options, result.GetOutputStream())) { result.SetStatus (eReturnStatusSuccessFinishResult); } else { result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString()); result.SetStatus (eReturnStatusFailed); } } else { std::vector<AddressRange> ranges; AddressRange range; StackFrame *frame = m_exe_ctx.GetFramePtr(); if (m_options.frame_line) { if (frame == NULL) { result.AppendError ("Cannot disassemble around the current line without a selected frame.\n"); result.SetStatus (eReturnStatusFailed); return false; } LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry); if (pc_line_entry.IsValid()) { range = pc_line_entry.range; } else { m_options.at_pc = true; // No line entry, so just disassemble around the current pc m_options.show_mixed = false; } } else if (m_options.current_function) { if (frame == NULL) { result.AppendError ("Cannot disassemble around the current function without a selected frame.\n"); result.SetStatus (eReturnStatusFailed); return false; } Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol; if (symbol) { range.GetBaseAddress() = symbol->GetAddress(); range.SetByteSize(symbol->GetByteSize()); } } // Did the "m_options.frame_line" find a valid range already? If so // skip the rest... if (range.GetByteSize() == 0) { if (m_options.at_pc) { if (frame == NULL) { result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n"); result.SetStatus (eReturnStatusFailed); return false; } range.GetBaseAddress() = frame->GetFrameCodeAddress(); if (m_options.num_instructions == 0) { // Disassembling at the PC always disassembles some number of instructions (not the whole function). m_options.num_instructions = DEFAULT_DISASM_NUM_INS; } ranges.push_back(range); } else { range.GetBaseAddress().SetOffset (m_options.start_addr); if (range.GetBaseAddress().IsValid()) { if (m_options.end_addr != LLDB_INVALID_ADDRESS) { if (m_options.end_addr <= m_options.start_addr) { result.AppendErrorWithFormat ("End address before start address.\n"); result.SetStatus (eReturnStatusFailed); return false; } range.SetByteSize (m_options.end_addr - m_options.start_addr); } ranges.push_back(range); } else { if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS && target) { if (!target->GetSectionLoadList().IsEmpty()) { bool failed = false; Address symbol_containing_address; if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address)) { ModuleSP module_sp (symbol_containing_address.GetModule()); SymbolContext sc; bool resolve_tail_call_address = true; // PC can be one past the address range of the function. module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc, resolve_tail_call_address); if (sc.function || sc.symbol) { sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range); } else { failed = true; } } else { failed = true; } if (failed) { result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr); result.SetStatus (eReturnStatusFailed); return false; } ranges.push_back(range); } else { for (lldb::ModuleSP module_sp : target->GetImages().Modules()) { lldb::addr_t file_addr = m_options.symbol_containing_addr; Address file_address; if (module_sp->ResolveFileAddress(file_addr, file_address)) { SymbolContext sc; bool resolve_tail_call_address = true; // PC can be one past the address range of the function. module_sp->ResolveSymbolContextForAddress (file_address, eSymbolContextEverything, sc, resolve_tail_call_address); if (sc.function || sc.symbol) { sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range); ranges.push_back(range); } } } } } } } } else ranges.push_back(range); if (m_options.num_instructions != 0) { if (ranges.size() == 0) { // The default action is to disassemble the current frame function. if (frame) { SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); if (sc.function) range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress(); else if (sc.symbol && sc.symbol->ValueIsAddress()) range.GetBaseAddress() = sc.symbol->GetAddress(); else range.GetBaseAddress() = frame->GetFrameCodeAddress(); } if (!range.GetBaseAddress().IsValid()) { result.AppendError ("invalid frame"); result.SetStatus (eReturnStatusFailed); return false; } } bool print_sc_header = ranges.size() > 1; for (AddressRange cur_range : ranges) { if (Disassembler::Disassemble (m_interpreter.GetDebugger(), m_options.arch, plugin_name, flavor_string, m_exe_ctx, cur_range.GetBaseAddress(), m_options.num_instructions, m_options.show_mixed ? m_options.num_lines_context : 0, options, result.GetOutputStream())) { result.SetStatus (eReturnStatusSuccessFinishResult); } else { if (m_options.start_addr != LLDB_INVALID_ADDRESS) result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr); else if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) result.AppendErrorWithFormat ("Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n", m_options.symbol_containing_addr); result.SetStatus (eReturnStatusFailed); } } if (print_sc_header) result.AppendMessage("\n"); } else { if (ranges.size() == 0) { // The default action is to disassemble the current frame function. if (frame) { SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); if (sc.function) range = sc.function->GetAddressRange(); else if (sc.symbol && sc.symbol->ValueIsAddress()) { range.GetBaseAddress() = sc.symbol->GetAddress(); range.SetByteSize (sc.symbol->GetByteSize()); } else range.GetBaseAddress() = frame->GetFrameCodeAddress(); } else { result.AppendError ("invalid frame"); result.SetStatus (eReturnStatusFailed); return false; } ranges.push_back(range); } bool print_sc_header = ranges.size() > 1; for (AddressRange cur_range : ranges) { if (cur_range.GetByteSize() == 0) cur_range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE); if (Disassembler::Disassemble (m_interpreter.GetDebugger(), m_options.arch, plugin_name, flavor_string, m_exe_ctx, cur_range, m_options.num_instructions, m_options.show_mixed ? m_options.num_lines_context : 0, options, result.GetOutputStream())) { result.SetStatus (eReturnStatusSuccessFinishResult); } else { result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr); result.SetStatus (eReturnStatusFailed); } if (print_sc_header) result.AppendMessage("\n"); } } } return result.Succeeded(); }
AddressClass ObjectFile::GetAddressClass (addr_t file_addr) { Symtab *symtab = GetSymtab(ObjectFile::eSymtabFromUnifiedSectionList); if (symtab) { Symbol *symbol = symtab->FindSymbolContainingFileAddress(file_addr); if (symbol) { if (symbol->ValueIsAddress()) { const SectionSP section_sp (symbol->GetAddress().GetSection()); if (section_sp) { const SectionType section_type = section_sp->GetType(); switch (section_type) { case eSectionTypeInvalid: return eAddressClassUnknown; case eSectionTypeCode: return eAddressClassCode; case eSectionTypeContainer: return eAddressClassUnknown; case eSectionTypeData: case eSectionTypeDataCString: case eSectionTypeDataCStringPointers: case eSectionTypeDataSymbolAddress: case eSectionTypeData4: case eSectionTypeData8: case eSectionTypeData16: case eSectionTypeDataPointers: case eSectionTypeZeroFill: case eSectionTypeDataObjCMessageRefs: case eSectionTypeDataObjCCFStrings: return eAddressClassData; case eSectionTypeDebug: case eSectionTypeDWARFDebugAbbrev: case eSectionTypeDWARFDebugAranges: case eSectionTypeDWARFDebugFrame: case eSectionTypeDWARFDebugInfo: case eSectionTypeDWARFDebugLine: case eSectionTypeDWARFDebugLoc: case eSectionTypeDWARFDebugMacInfo: case eSectionTypeDWARFDebugPubNames: case eSectionTypeDWARFDebugPubTypes: case eSectionTypeDWARFDebugRanges: case eSectionTypeDWARFDebugStr: case eSectionTypeDWARFAppleNames: case eSectionTypeDWARFAppleTypes: case eSectionTypeDWARFAppleNamespaces: case eSectionTypeDWARFAppleObjC: return eAddressClassDebug; case eSectionTypeEHFrame: return eAddressClassRuntime; case eSectionTypeELFSymbolTable: case eSectionTypeELFDynamicSymbols: case eSectionTypeELFRelocationEntries: case eSectionTypeELFDynamicLinkInfo: case eSectionTypeOther: return eAddressClassUnknown; } } } const SymbolType symbol_type = symbol->GetType(); switch (symbol_type) { case eSymbolTypeAny: return eAddressClassUnknown; case eSymbolTypeAbsolute: return eAddressClassUnknown; case eSymbolTypeCode: return eAddressClassCode; case eSymbolTypeTrampoline: return eAddressClassCode; case eSymbolTypeResolver: return eAddressClassCode; case eSymbolTypeData: return eAddressClassData; case eSymbolTypeRuntime: return eAddressClassRuntime; case eSymbolTypeException: return eAddressClassRuntime; case eSymbolTypeSourceFile: return eAddressClassDebug; case eSymbolTypeHeaderFile: return eAddressClassDebug; case eSymbolTypeObjectFile: return eAddressClassDebug; case eSymbolTypeCommonBlock: return eAddressClassDebug; case eSymbolTypeBlock: return eAddressClassDebug; case eSymbolTypeLocal: return eAddressClassData; case eSymbolTypeParam: return eAddressClassData; case eSymbolTypeVariable: return eAddressClassData; case eSymbolTypeVariableType: return eAddressClassDebug; case eSymbolTypeLineEntry: return eAddressClassDebug; case eSymbolTypeLineHeader: return eAddressClassDebug; case eSymbolTypeScopeBegin: return eAddressClassDebug; case eSymbolTypeScopeEnd: return eAddressClassDebug; case eSymbolTypeAdditional: return eAddressClassUnknown; case eSymbolTypeCompiler: return eAddressClassDebug; case eSymbolTypeInstrumentation:return eAddressClassDebug; case eSymbolTypeUndefined: return eAddressClassUnknown; case eSymbolTypeObjCClass: return eAddressClassRuntime; case eSymbolTypeObjCMetaClass: return eAddressClassRuntime; case eSymbolTypeObjCIVar: return eAddressClassRuntime; } } } return eAddressClassUnknown; }
bool Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style, uint32_t addr_size) const { // If the section was NULL, only load address is going to work unless we are // trying to deref a pointer SectionSP section_sp (GetSection()); if (!section_sp && style != DumpStyleResolvedPointerDescription) style = DumpStyleLoadAddress; ExecutionContext exe_ctx (exe_scope); Target *target = exe_ctx.GetTargetPtr(); // If addr_byte_size is UINT32_MAX, then determine the correct address // byte size for the process or default to the size of addr_t if (addr_size == UINT32_MAX) { if (target) addr_size = target->GetArchitecture().GetAddressByteSize (); else addr_size = sizeof(addr_t); } Address so_addr; switch (style) { case DumpStyleInvalid: return false; case DumpStyleSectionNameOffset: if (section_sp) { section_sp->DumpName(s); s->Printf (" + %" PRIu64, m_offset.load()); } else { s->Address(m_offset, addr_size); } break; case DumpStyleSectionPointerOffset: s->Printf("(Section *)%p + ", static_cast<void*>(section_sp.get())); s->Address(m_offset, addr_size); break; case DumpStyleModuleWithFileAddress: if (section_sp) { s->Printf("%s[", section_sp->GetModule()->GetFileSpec().GetFilename().AsCString("<Unknown>")); } // Fall through case DumpStyleFileAddress: { addr_t file_addr = GetFileAddress(); if (file_addr == LLDB_INVALID_ADDRESS) { if (fallback_style != DumpStyleInvalid) return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); return false; } s->Address (file_addr, addr_size); if (style == DumpStyleModuleWithFileAddress && section_sp) s->PutChar(']'); } break; case DumpStyleLoadAddress: { addr_t load_addr = GetLoadAddress (target); if (load_addr == LLDB_INVALID_ADDRESS) { if (fallback_style != DumpStyleInvalid) return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); return false; } s->Address (load_addr, addr_size); } break; case DumpStyleResolvedDescription: case DumpStyleResolvedDescriptionNoModule: case DumpStyleResolvedDescriptionNoFunctionArguments: if (IsSectionOffset()) { uint32_t pointer_size = 4; ModuleSP module_sp (GetModule()); if (target) pointer_size = target->GetArchitecture().GetAddressByteSize(); else if (module_sp) pointer_size = module_sp->GetArchitecture().GetAddressByteSize(); bool showed_info = false; if (section_sp) { SectionType sect_type = section_sp->GetType(); switch (sect_type) { case eSectionTypeData: if (module_sp) { SymbolVendor *sym_vendor = module_sp->GetSymbolVendor(); if (sym_vendor) { Symtab *symtab = sym_vendor->GetSymtab(); if (symtab) { const addr_t file_Addr = GetFileAddress(); Symbol *symbol = symtab->FindSymbolContainingFileAddress (file_Addr); if (symbol) { const char *symbol_name = symbol->GetName().AsCString(); if (symbol_name) { s->PutCString(symbol_name); addr_t delta = file_Addr - symbol->GetAddress().GetFileAddress(); if (delta) s->Printf(" + %" PRIu64, delta); showed_info = true; } } } } } break; case eSectionTypeDataCString: // Read the C string from memory and display it showed_info = true; ReadCStringFromMemory (exe_scope, *this, s); break; case eSectionTypeDataCStringPointers: { if (ReadAddress (exe_scope, *this, pointer_size, so_addr)) { #if VERBOSE_OUTPUT s->PutCString("(char *)"); so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress); s->PutCString(": "); #endif showed_info = true; ReadCStringFromMemory (exe_scope, so_addr, s); } } break; case eSectionTypeDataObjCMessageRefs: { if (ReadAddress (exe_scope, *this, pointer_size, so_addr)) { if (target && so_addr.IsSectionOffset()) { SymbolContext func_sc; target->GetImages().ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, func_sc); if (func_sc.function || func_sc.symbol) { showed_info = true; #if VERBOSE_OUTPUT s->PutCString ("(objc_msgref *) -> { (func*)"); so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress); #else s->PutCString ("{ "); #endif Address cstr_addr(*this); cstr_addr.SetOffset(cstr_addr.GetOffset() + pointer_size); func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false, true); if (ReadAddress (exe_scope, cstr_addr, pointer_size, so_addr)) { #if VERBOSE_OUTPUT s->PutCString("), (char *)"); so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress); s->PutCString(" ("); #else s->PutCString(", "); #endif ReadCStringFromMemory (exe_scope, so_addr, s); } #if VERBOSE_OUTPUT s->PutCString(") }"); #else s->PutCString(" }"); #endif } } } } break; case eSectionTypeDataObjCCFStrings: { Address cfstring_data_addr(*this); cfstring_data_addr.SetOffset(cfstring_data_addr.GetOffset() + (2 * pointer_size)); if (ReadAddress (exe_scope, cfstring_data_addr, pointer_size, so_addr)) { #if VERBOSE_OUTPUT s->PutCString("(CFString *) "); cfstring_data_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress); s->PutCString(" -> @"); #else s->PutChar('@'); #endif if (so_addr.Dump(s, exe_scope, DumpStyleResolvedDescription)) showed_info = true; } } break; case eSectionTypeData4: // Read the 4 byte data and display it showed_info = true; s->PutCString("(uint32_t) "); DumpUInt (exe_scope, *this, 4, s); break; case eSectionTypeData8: // Read the 8 byte data and display it showed_info = true; s->PutCString("(uint64_t) "); DumpUInt (exe_scope, *this, 8, s); break; case eSectionTypeData16: // Read the 16 byte data and display it showed_info = true; s->PutCString("(uint128_t) "); DumpUInt (exe_scope, *this, 16, s); break; case eSectionTypeDataPointers: // Read the pointer data and display it { if (ReadAddress (exe_scope, *this, pointer_size, so_addr)) { s->PutCString ("(void *)"); so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress); showed_info = true; if (so_addr.IsSectionOffset()) { SymbolContext pointer_sc; if (target) { target->GetImages().ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, pointer_sc); if (pointer_sc.function || pointer_sc.symbol) { s->PutCString(": "); pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false, true); } } } } } break; default: break; } } if (!showed_info) { if (module_sp) { SymbolContext sc; module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc); if (sc.function || sc.symbol) { bool show_stop_context = true; const bool show_module = (style == DumpStyleResolvedDescription); const bool show_fullpaths = false; const bool show_inlined_frames = true; const bool show_function_arguments = (style != DumpStyleResolvedDescriptionNoFunctionArguments); if (sc.function == NULL && sc.symbol != NULL) { // If we have just a symbol make sure it is in the right section if (sc.symbol->ValueIsAddress()) { if (sc.symbol->GetAddress().GetSection() != GetSection()) { // don't show the module if the symbol is a trampoline symbol show_stop_context = false; } } } if (show_stop_context) { // We have a function or a symbol from the same // sections as this address. sc.DumpStopContext (s, exe_scope, *this, show_fullpaths, show_module, show_inlined_frames, show_function_arguments); } else { // We found a symbol but it was in a different // section so it isn't the symbol we should be // showing, just show the section name + offset Dump (s, exe_scope, DumpStyleSectionNameOffset); } } } } } else { if (fallback_style != DumpStyleInvalid) return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); return false; } break; case DumpStyleDetailedSymbolContext: if (IsSectionOffset()) { ModuleSP module_sp (GetModule()); if (module_sp) { SymbolContext sc; module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc); if (sc.symbol) { // If we have just a symbol make sure it is in the same section // as our address. If it isn't, then we might have just found // the last symbol that came before the address that we are // looking up that has nothing to do with our address lookup. if (sc.symbol->ValueIsAddress() && sc.symbol->GetAddress().GetSection() != GetSection()) sc.symbol = NULL; } sc.GetDescription(s, eDescriptionLevelBrief, target); if (sc.block) { bool can_create = true; bool get_parent_variables = true; bool stop_if_block_is_inlined_function = false; VariableList variable_list; sc.block->AppendVariables (can_create, get_parent_variables, stop_if_block_is_inlined_function, &variable_list); const size_t num_variables = variable_list.GetSize(); for (size_t var_idx = 0; var_idx < num_variables; ++var_idx) { Variable *var = variable_list.GetVariableAtIndex (var_idx).get(); if (var && var->LocationIsValidForAddress (*this)) { s->Indent(); s->Printf (" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\", type= \"%s\", location =", var->GetID(), var->GetName().GetCString(), var->GetType()->GetName().GetCString()); var->DumpLocationForAddress(s, *this); s->PutCString(", decl = "); var->GetDeclaration().DumpStopContext(s, false); s->EOL(); } } } } } else { if (fallback_style != DumpStyleInvalid) return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); return false; } break; case DumpStyleResolvedPointerDescription: { Process *process = exe_ctx.GetProcessPtr(); if (process) { addr_t load_addr = GetLoadAddress (target); if (load_addr != LLDB_INVALID_ADDRESS) { Error memory_error; addr_t dereferenced_load_addr = process->ReadPointerFromMemory(load_addr, memory_error); if (dereferenced_load_addr != LLDB_INVALID_ADDRESS) { Address dereferenced_addr; if (dereferenced_addr.SetLoadAddress(dereferenced_load_addr, target)) { StreamString strm; if (dereferenced_addr.Dump (&strm, exe_scope, DumpStyleResolvedDescription, DumpStyleInvalid, addr_size)) { s->Address (dereferenced_load_addr, addr_size, " -> ", " "); s->Write(strm.GetData(), strm.GetSize()); return true; } } } } } if (fallback_style != DumpStyleInvalid) return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); return false; } break; } return true; }