bool ThreadPlanStepRange::InRange () { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); bool ret_value = false; lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC(); size_t num_ranges = m_address_ranges.size(); for (size_t i = 0; i < num_ranges; i++) { ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, m_thread.CalculateTarget().get()); if (ret_value) break; } if (!ret_value && !m_given_ranges_only) { // See if we've just stepped to another part of the same line number... StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get(); SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything)); if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid()) { if (m_addr_context.line_entry.original_file == new_context.line_entry.original_file) { if (m_addr_context.line_entry.line == new_context.line_entry.line) { m_addr_context = new_context; AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange()); ret_value = true; if (log) { StreamString s; m_addr_context.line_entry.Dump (&s, m_thread.CalculateTarget().get(), true, Address::DumpStyleLoadAddress, Address::DumpStyleLoadAddress, true); log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData()); } } else if (new_context.line_entry.line == 0) { new_context.line_entry.line = m_addr_context.line_entry.line; m_addr_context = new_context; AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange()); ret_value = true; if (log) { StreamString s; m_addr_context.line_entry.Dump (&s, m_thread.CalculateTarget().get(), true, Address::DumpStyleLoadAddress, Address::DumpStyleLoadAddress, true); log->Printf ("Step range plan stepped to a range at linenumber 0 stepping through that range: %s", s.GetData()); } } else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(m_thread.CalculateTarget().get()) != pc_load_addr) { // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another // line. So far I mostly see this due to bugs in the debug information. // But we probably don't want to be in the middle of a line range, so in that case reset the stepping // range to the line we've stepped into the middle of and continue. m_addr_context = new_context; m_address_ranges.clear(); AddRange(m_addr_context.line_entry.range); ret_value = true; if (log) { StreamString s; m_addr_context.line_entry.Dump (&s, m_thread.CalculateTarget().get(), true, Address::DumpStyleLoadAddress, Address::DumpStyleLoadAddress, true); log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.", new_context.line_entry.line, s.GetData()); } } } } } if (!ret_value && log) log->Printf ("Step range plan out of range to 0x%" PRIx64, pc_load_addr); return ret_value; }
SBValue SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueType use_dynamic) { Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); SBValue sb_value; if (name == NULL || name[0] == '\0') { if (log) log->Printf ("SBFrame::FindValue called with empty name."); return sb_value; } ValueObjectSP value_sp; Mutex::Locker api_locker; ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker); StackFrame *frame = NULL; Target *target = exe_ctx.GetTargetPtr(); Process *process = exe_ctx.GetProcessPtr(); if (target && process) { Process::StopLocker stop_locker; if (stop_locker.TryLock(&process->GetRunLock())) { frame = exe_ctx.GetFramePtr(); if (frame) { switch (value_type) { case eValueTypeVariableGlobal: // global variable case eValueTypeVariableStatic: // static variable case eValueTypeVariableArgument: // function argument variables case eValueTypeVariableLocal: // function local variables { VariableList *variable_list = frame->GetVariableList(true); SymbolContext sc (frame->GetSymbolContext (eSymbolContextBlock)); const bool can_create = true; const bool get_parent_variables = true; const bool stop_if_block_is_inlined_function = true; if (sc.block && sc.block->AppendVariables (can_create, get_parent_variables, stop_if_block_is_inlined_function, variable_list)) { ConstString const_name(name); const uint32_t num_variables = variable_list->GetSize(); for (uint32_t i = 0; i < num_variables; ++i) { VariableSP variable_sp (variable_list->GetVariableAtIndex(i)); if (variable_sp && variable_sp->GetScope() == value_type && variable_sp->GetName() == const_name) { value_sp = frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues); sb_value.SetSP (value_sp, use_dynamic); break; } } } } break; case eValueTypeRegister: // stack frame register value { RegisterContextSP reg_ctx (frame->GetRegisterContext()); if (reg_ctx) { const uint32_t num_regs = reg_ctx->GetRegisterCount(); for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_idx); if (reg_info && ((reg_info->name && strcasecmp (reg_info->name, name) == 0) || (reg_info->alt_name && strcasecmp (reg_info->alt_name, name) == 0))) { value_sp = ValueObjectRegister::Create (frame, reg_ctx, reg_idx); sb_value.SetSP (value_sp); break; } } } } break; case eValueTypeRegisterSet: // A collection of stack frame register values { RegisterContextSP reg_ctx (frame->GetRegisterContext()); if (reg_ctx) { const uint32_t num_sets = reg_ctx->GetRegisterSetCount(); for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx) { const RegisterSet *reg_set = reg_ctx->GetRegisterSet (set_idx); if (reg_set && ((reg_set->name && strcasecmp (reg_set->name, name) == 0) || (reg_set->short_name && strcasecmp (reg_set->short_name, name) == 0))) { value_sp = ValueObjectRegisterSet::Create (frame, reg_ctx, set_idx); sb_value.SetSP (value_sp); break; } } } } break; case eValueTypeConstResult: // constant result variables { ConstString const_name(name); ClangExpressionVariableSP expr_var_sp (target->GetPersistentVariables().GetVariable (const_name)); if (expr_var_sp) { value_sp = expr_var_sp->GetValueObject(); sb_value.SetSP (value_sp, use_dynamic); } } break; default: break; } } else { if (log) log->Printf ("SBFrame::FindValue () => error: could not reconstruct frame object for this SBFrame."); } } else { if (log) log->Printf ("SBFrame::FindValue () => error: process is running"); } } if (log) log->Printf ("SBFrame(%p)::FindVariableInScope (name=\"%s\", value_type=%i) => SBValue(%p)", frame, name, value_type, value_sp.get()); return sb_value; }
bool CommandObjectDisassemble::DoExecute(Args &command, CommandReturnObject &result) { Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); if (target == nullptr) { 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 architecture 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 != nullptr && !disassembler->FlavorValidForArchSpec(m_options.arch, flavor_string)) result.AppendWarningWithFormat( "invalid disassembler flavor \"%s\", using default.\n", flavor_string); result.SetStatus(eReturnStatusSuccessFinishResult); if (!command.empty()) { result.AppendErrorWithFormat( "\"disassemble\" arguments are specified as options.\n"); const int terminal_width = GetCommandInterpreter().GetDebugger().GetTerminalWidth(); GetOptions()->GenerateOptionUsage(result.GetErrorStream(), this, terminal_width); result.SetStatus(eReturnStatusFailed); return false; } if (m_options.show_mixed && m_options.num_lines_context == 0) m_options.num_lines_context = 2; // 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, nullptr, // Module * m_options.num_instructions, m_options.show_mixed, 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 == nullptr) { 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 == nullptr) { 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 == nullptr) { 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.empty()) { // 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.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.empty()) { // 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.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(); }
SBValue SBFrame::FindVariable (const char *name, lldb::DynamicValueType use_dynamic) { Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); VariableSP var_sp; SBValue sb_value; if (name == NULL || name[0] == '\0') { if (log) log->Printf ("SBFrame::FindVariable called with empty name"); return sb_value; } ValueObjectSP value_sp; Mutex::Locker api_locker; ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker); StackFrame *frame = NULL; Target *target = exe_ctx.GetTargetPtr(); Process *process = exe_ctx.GetProcessPtr(); if (target && process) { Process::StopLocker stop_locker; if (stop_locker.TryLock(&process->GetRunLock())) { frame = exe_ctx.GetFramePtr(); if (frame) { VariableList variable_list; SymbolContext sc (frame->GetSymbolContext (eSymbolContextBlock)); if (sc.block) { const bool can_create = true; const bool get_parent_variables = true; const bool stop_if_block_is_inlined_function = true; if (sc.block->AppendVariables (can_create, get_parent_variables, stop_if_block_is_inlined_function, &variable_list)) { var_sp = variable_list.FindVariable (ConstString(name)); } } if (var_sp) { value_sp = frame->GetValueObjectForFrameVariable(var_sp, eNoDynamicValues); sb_value.SetSP(value_sp, use_dynamic); } } else { if (log) log->Printf ("SBFrame::FindVariable () => error: could not reconstruct frame object for this SBFrame."); } } else { if (log) log->Printf ("SBFrame::FindVariable () => error: process is running"); } } if (log) log->Printf ("SBFrame(%p)::FindVariable (name=\"%s\") => SBValue(%p)", frame, name, value_sp.get()); return sb_value; }
void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); if (log) log->Printf("ClangUserExpression::ScanContext()"); m_target = exe_ctx.GetTargetPtr(); if (!(m_allow_cxx || m_allow_objc)) { if (log) log->Printf(" [CUE::SC] Settings inhibit C++ and Objective-C"); return; } StackFrame *frame = exe_ctx.GetFramePtr(); if (frame == NULL) { if (log) log->Printf(" [CUE::SC] Null stack frame"); return; } SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction | lldb::eSymbolContextBlock); if (!sym_ctx.function) { if (log) log->Printf(" [CUE::SC] Null function"); return; } // Find the block that defines the function represented by "sym_ctx" Block *function_block = sym_ctx.GetFunctionBlock(); if (!function_block) { if (log) log->Printf(" [CUE::SC] Null function block"); return; } CompilerDeclContext decl_context = function_block->GetDeclContext(); if (!decl_context) { if (log) log->Printf(" [CUE::SC] Null decl context"); return; } if (clang::CXXMethodDecl *method_decl = ClangASTContext::DeclContextGetAsCXXMethodDecl(decl_context)) { if (m_allow_cxx && method_decl->isInstance()) { if (m_enforce_valid_object) { lldb::VariableListSP variable_list_sp( function_block->GetBlockVariableList(true)); const char *thisErrorString = "Stopped in a C++ method, but 'this' " "isn't available; pretending we are in a " "generic context"; if (!variable_list_sp) { err.SetErrorString(thisErrorString); return; } lldb::VariableSP this_var_sp( variable_list_sp->FindVariable(ConstString("this"))); if (!this_var_sp || !this_var_sp->IsInScope(frame) || !this_var_sp->LocationIsValidForFrame(frame)) { err.SetErrorString(thisErrorString); return; } } m_in_cplusplus_method = true; m_needs_object_ptr = true; } } else if (clang::ObjCMethodDecl *method_decl = ClangASTContext::DeclContextGetAsObjCMethodDecl( decl_context)) { if (m_allow_objc) { if (m_enforce_valid_object) { lldb::VariableListSP variable_list_sp( function_block->GetBlockVariableList(true)); const char *selfErrorString = "Stopped in an Objective-C method, but " "'self' isn't available; pretending we " "are in a generic context"; if (!variable_list_sp) { err.SetErrorString(selfErrorString); return; } lldb::VariableSP self_variable_sp = variable_list_sp->FindVariable(ConstString("self")); if (!self_variable_sp || !self_variable_sp->IsInScope(frame) || !self_variable_sp->LocationIsValidForFrame(frame)) { err.SetErrorString(selfErrorString); return; } } m_in_objectivec_method = true; m_needs_object_ptr = true; if (!method_decl->isInstanceMethod()) m_in_static_method = true; } } else if (clang::FunctionDecl *function_decl = ClangASTContext::DeclContextGetAsFunctionDecl(decl_context)) { // We might also have a function that said in the debug information that it // captured an object pointer. The best way to deal with getting to the // ivars at present is by pretending that this is a method of a class in // whatever runtime the debug info says the object pointer belongs to. Do // that here. ClangASTMetadata *metadata = ClangASTContext::DeclContextGetMetaData(decl_context, function_decl); if (metadata && metadata->HasObjectPtr()) { lldb::LanguageType language = metadata->GetObjectPtrLanguage(); if (language == lldb::eLanguageTypeC_plus_plus) { if (m_enforce_valid_object) { lldb::VariableListSP variable_list_sp( function_block->GetBlockVariableList(true)); const char *thisErrorString = "Stopped in a context claiming to " "capture a C++ object pointer, but " "'this' isn't available; pretending we " "are in a generic context"; if (!variable_list_sp) { err.SetErrorString(thisErrorString); return; } lldb::VariableSP this_var_sp( variable_list_sp->FindVariable(ConstString("this"))); if (!this_var_sp || !this_var_sp->IsInScope(frame) || !this_var_sp->LocationIsValidForFrame(frame)) { err.SetErrorString(thisErrorString); return; } } m_in_cplusplus_method = true; m_needs_object_ptr = true; } else if (language == lldb::eLanguageTypeObjC) { if (m_enforce_valid_object) { lldb::VariableListSP variable_list_sp( function_block->GetBlockVariableList(true)); const char *selfErrorString = "Stopped in a context claiming to capture an Objective-C object " "pointer, but 'self' isn't available; pretending we are in a " "generic context"; if (!variable_list_sp) { err.SetErrorString(selfErrorString); return; } lldb::VariableSP self_variable_sp = variable_list_sp->FindVariable(ConstString("self")); if (!self_variable_sp || !self_variable_sp->IsInScope(frame) || !self_variable_sp->LocationIsValidForFrame(frame)) { err.SetErrorString(selfErrorString); return; } Type *self_type = self_variable_sp->GetType(); if (!self_type) { err.SetErrorString(selfErrorString); return; } CompilerType self_clang_type = self_type->GetForwardCompilerType(); if (!self_clang_type) { err.SetErrorString(selfErrorString); return; } if (ClangASTContext::IsObjCClassType(self_clang_type)) { return; } else if (ClangASTContext::IsObjCObjectPointerType( self_clang_type)) { m_in_objectivec_method = true; m_needs_object_ptr = true; } else { err.SetErrorString(selfErrorString); return; } } else { m_in_objectivec_method = true; m_needs_object_ptr = true; } } } } }