diff options
Diffstat (limited to 'source/Target/Target.cpp')
| -rw-r--r-- | source/Target/Target.cpp | 708 |
1 files changed, 331 insertions, 377 deletions
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp index 3f70741713fb..437f92abdab3 100644 --- a/source/Target/Target.cpp +++ b/source/Target/Target.cpp @@ -7,11 +7,7 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -#include <mutex> -// Other libraries and framework includes -// Project includes +#include "lldb/Target/Target.h" #include "Plugins/ExpressionParser/Clang/ClangASTSource.h" #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" @@ -21,16 +17,17 @@ #include "lldb/Breakpoint/BreakpointResolverFileLine.h" #include "lldb/Breakpoint/BreakpointResolverFileRegex.h" #include "lldb/Breakpoint/BreakpointResolverName.h" +#include "lldb/Breakpoint/BreakpointResolverScripted.h" #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Debugger.h" -#include "lldb/Core/Event.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/SearchFilter.h" #include "lldb/Core/Section.h" #include "lldb/Core/SourceManager.h" -#include "lldb/Core/State.h" #include "lldb/Core/StreamFile.h" +#include "lldb/Core/StructuredDataImpl.h" #include "lldb/Core/ValueObject.h" #include "lldb/Expression/REPL.h" #include "lldb/Expression/UserExpression.h" @@ -52,14 +49,16 @@ #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/SystemRuntime.h" -#include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadSpec.h" +#include "lldb/Utility/Event.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" +#include <mutex> using namespace lldb; using namespace lldb_private; @@ -195,6 +194,8 @@ void Target::DeleteCurrentProcess() { const lldb::ProcessSP &Target::CreateProcess(ListenerSP listener_sp, llvm::StringRef plugin_name, const FileSpec *crash_file) { + if (!listener_sp) + listener_sp = GetDebugger().GetListener(); DeleteCurrentProcess(); m_process_sp = Process::FindPlugin(shared_from_this(), plugin_name, listener_sp, crash_file); @@ -322,7 +323,7 @@ BreakpointSP Target::CreateSourceRegexBreakpoint( BreakpointSP Target::CreateBreakpoint(const FileSpecList *containingModules, const FileSpec &file, uint32_t line_no, - lldb::addr_t offset, + uint32_t column, lldb::addr_t offset, LazyBool check_inlines, LazyBool skip_prologue, bool internal, bool hardware, @@ -366,8 +367,8 @@ BreakpointSP Target::CreateBreakpoint(const FileSpecList *containingModules, move_to_nearest_code = GetMoveToNearestCode() ? eLazyBoolYes : eLazyBoolNo; BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine( - nullptr, remapped_file, line_no, offset, check_inlines, skip_prologue, - !static_cast<bool>(move_to_nearest_code))); + nullptr, remapped_file, line_no, column, offset, check_inlines, + skip_prologue, !static_cast<bool>(move_to_nearest_code))); return CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, true); } @@ -412,12 +413,11 @@ Target::CreateAddressInModuleBreakpoint(lldb::addr_t file_addr, bool internal, false); } -BreakpointSP -Target::CreateBreakpoint(const FileSpecList *containingModules, - const FileSpecList *containingSourceFiles, - const char *func_name, uint32_t func_name_type_mask, - LanguageType language, lldb::addr_t offset, - LazyBool skip_prologue, bool internal, bool hardware) { +BreakpointSP Target::CreateBreakpoint( + const FileSpecList *containingModules, + const FileSpecList *containingSourceFiles, const char *func_name, + FunctionNameType func_name_type_mask, LanguageType language, + lldb::addr_t offset, LazyBool skip_prologue, bool internal, bool hardware) { BreakpointSP bp_sp; if (func_name) { SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList( @@ -440,9 +440,9 @@ lldb::BreakpointSP Target::CreateBreakpoint(const FileSpecList *containingModules, const FileSpecList *containingSourceFiles, const std::vector<std::string> &func_names, - uint32_t func_name_type_mask, LanguageType language, - lldb::addr_t offset, LazyBool skip_prologue, - bool internal, bool hardware) { + FunctionNameType func_name_type_mask, + LanguageType language, lldb::addr_t offset, + LazyBool skip_prologue, bool internal, bool hardware) { BreakpointSP bp_sp; size_t num_names = func_names.size(); if (num_names > 0) { @@ -462,11 +462,13 @@ Target::CreateBreakpoint(const FileSpecList *containingModules, return bp_sp; } -BreakpointSP Target::CreateBreakpoint( - const FileSpecList *containingModules, - const FileSpecList *containingSourceFiles, const char *func_names[], - size_t num_names, uint32_t func_name_type_mask, LanguageType language, - lldb::addr_t offset, LazyBool skip_prologue, bool internal, bool hardware) { +BreakpointSP +Target::CreateBreakpoint(const FileSpecList *containingModules, + const FileSpecList *containingSourceFiles, + const char *func_names[], size_t num_names, + FunctionNameType func_name_type_mask, + LanguageType language, lldb::addr_t offset, + LazyBool skip_prologue, bool internal, bool hardware) { BreakpointSP bp_sp; if (num_names > 0) { SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList( @@ -579,13 +581,56 @@ Target::CreateExceptionBreakpoint(enum lldb::LanguageType language, return exc_bkpt_sp; } +lldb::BreakpointSP +Target::CreateScriptedBreakpoint(const llvm::StringRef class_name, + const FileSpecList *containingModules, + const FileSpecList *containingSourceFiles, + bool internal, + bool request_hardware, + StructuredData::ObjectSP extra_args_sp, + Status *creation_error) +{ + SearchFilterSP filter_sp; + + lldb::SearchDepth depth = lldb::eSearchDepthTarget; + bool has_files = containingSourceFiles && containingSourceFiles->GetSize() > 0; + bool has_modules = containingModules && containingModules->GetSize() > 0; + + if (has_files && has_modules) { + filter_sp = GetSearchFilterForModuleAndCUList( + containingModules, containingSourceFiles); + } else if (has_files) { + filter_sp = GetSearchFilterForModuleAndCUList( + nullptr, containingSourceFiles); + } else if (has_modules) { + filter_sp = GetSearchFilterForModuleList(containingModules); + } else { + filter_sp.reset(new SearchFilterForUnconstrainedSearches(shared_from_this())); + } + + StructuredDataImpl *extra_args_impl = new StructuredDataImpl(); + if (extra_args_sp) + extra_args_impl->SetObjectSP(extra_args_sp); + + BreakpointResolverSP resolver_sp(new + BreakpointResolverScripted(nullptr, class_name, + depth, + extra_args_impl, + *GetDebugger().GetCommandInterpreter() + .GetScriptInterpreter())); + return CreateBreakpoint(filter_sp, resolver_sp, internal, false, true); + +} + + BreakpointSP Target::CreateBreakpoint(SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal, bool request_hardware, bool resolve_indirect_symbols) { BreakpointSP bp_sp; if (filter_sp && resolver_sp) { - bp_sp.reset(new Breakpoint(*this, filter_sp, resolver_sp, request_hardware, + const bool hardware = request_hardware || GetRequireHardwareBreakpoints(); + bp_sp.reset(new Breakpoint(*this, filter_sp, resolver_sp, hardware, resolve_indirect_symbols)); resolver_sp->SetBreakpoint(bp_sp.get()); AddBreakpoint(bp_sp, internal); @@ -719,17 +764,23 @@ void Target::GetBreakpointNames(std::vector<std::string> &names) for (auto bp_name : m_breakpoint_names) { names.push_back(bp_name.first.AsCString()); } - std::sort(names.begin(), names.end()); + llvm::sort(names.begin(), names.end()); } bool Target::ProcessIsValid() { return (m_process_sp && m_process_sp->IsAlive()); } -static bool CheckIfWatchpointsExhausted(Target *target, Status &error) { +static bool CheckIfWatchpointsSupported(Target *target, Status &error) { uint32_t num_supported_hardware_watchpoints; Status rc = target->GetProcessSP()->GetWatchpointSupportInfo( num_supported_hardware_watchpoints); + + // If unable to determine the # of watchpoints available, + // assume they are supported. + if (rc.Fail()) + return true; + if (num_supported_hardware_watchpoints == 0) { error.SetErrorStringWithFormat( "Target supports (%u) hardware watchpoint slots.\n", @@ -768,7 +819,7 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size, error.SetErrorStringWithFormat("invalid watchpoint type: %d", kind); } - if (!CheckIfWatchpointsExhausted(this, error)) + if (!CheckIfWatchpointsSupported(this, error)) return wp_sp; // Currently we only support one watchpoint per address, with total number of @@ -1377,7 +1428,7 @@ void Target::DidExec() { } void Target::SetExecutableModule(ModuleSP &executable_sp, - bool get_dependent_files) { + LoadDependentFiles load_dependent_files) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET)); ClearModules(false); @@ -1401,8 +1452,20 @@ void Target::SetExecutableModule(ModuleSP &executable_sp, FileSpecList dependent_files; ObjectFile *executable_objfile = executable_sp->GetObjectFile(); + bool load_dependents = true; + switch (load_dependent_files) { + case eLoadDependentsDefault: + load_dependents = executable_sp->IsExecutable(); + break; + case eLoadDependentsYes: + load_dependents = true; + break; + case eLoadDependentsNo: + load_dependents = false; + break; + } - if (executable_objfile && get_dependent_files) { + if (executable_objfile && load_dependents) { executable_objfile->GetDependentModules(dependent_files); for (uint32_t i = 0; i < dependent_files.GetSize(); i++) { FileSpec dependent_file_spec( @@ -1426,13 +1489,33 @@ void Target::SetExecutableModule(ModuleSP &executable_sp, } } -bool Target::SetArchitecture(const ArchSpec &arch_spec) { +bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET)); bool missing_local_arch = !m_arch.GetSpec().IsValid(); bool replace_local_arch = true; bool compatible_local_arch = false; ArchSpec other(arch_spec); + // Changing the architecture might mean that the currently selected platform + // isn't compatible. Set the platform correctly if we are asked to do so, + // otherwise assume the user will set the platform manually. + if (set_platform) { + if (other.IsValid()) { + auto platform_sp = GetPlatform(); + if (!platform_sp || + !platform_sp->IsCompatibleArchitecture(other, false, nullptr)) { + ArchSpec platform_arch; + auto arch_platform_sp = + Platform::GetPlatformForArchitecture(other, &platform_arch); + if (arch_platform_sp) { + SetPlatform(arch_platform_sp); + if (platform_arch.IsValid()) + other = platform_arch; + } + } + } + } + if (!missing_local_arch) { if (m_arch.GetSpec().IsCompatibleMatch(arch_spec)) { other.MergeFrom(m_arch.GetSpec()); @@ -1487,7 +1570,7 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec) { nullptr, nullptr); if (!error.Fail() && executable_sp) { - SetExecutableModule(executable_sp, true); + SetExecutableModule(executable_sp, eLoadDependentsYes); return true; } } @@ -1495,11 +1578,18 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec) { } bool Target::MergeArchitecture(const ArchSpec &arch_spec) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET)); if (arch_spec.IsValid()) { if (m_arch.GetSpec().IsCompatibleMatch(arch_spec)) { // The current target arch is compatible with "arch_spec", see if we can // improve our current architecture using bits from "arch_spec" + if (log) + log->Printf("Target::MergeArchitecture target has arch %s, merging with " + "arch %s", + m_arch.GetSpec().GetTriple().getTriple().c_str(), + arch_spec.GetTriple().getTriple().c_str()); + // Merge bits from arch_spec into "merged_arch" and set our architecture ArchSpec merged_arch(m_arch.GetSpec()); merged_arch.MergeFrom(arch_spec); @@ -2057,7 +2147,7 @@ void Target::ImageSearchPathsChanged(const PathMappingList &path_list, Target *target = (Target *)baton; ModuleSP exe_module_sp(target->GetExecutableModule()); if (exe_module_sp) - target->SetExecutableModule(exe_module_sp, true); + target->SetExecutableModule(exe_module_sp, eLoadDependentsYes); } TypeSystem *Target::GetScratchTypeSystemForLanguage(Status *error, @@ -2351,249 +2441,22 @@ lldb::addr_t Target::GetPersistentSymbol(const ConstString &name) { lldb::addr_t Target::GetCallableLoadAddress(lldb::addr_t load_addr, AddressClass addr_class) const { - addr_t code_addr = load_addr; - switch (m_arch.GetSpec().GetMachine()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - switch (addr_class) { - case AddressClass::eData: - case AddressClass::eDebug: - return LLDB_INVALID_ADDRESS; - - case AddressClass::eUnknown: - case AddressClass::eInvalid: - case AddressClass::eCode: - case AddressClass::eCodeAlternateISA: - case AddressClass::eRuntime: - if ((code_addr & 2ull) || (addr_class == AddressClass::eCodeAlternateISA)) - code_addr |= 1ull; - break; - } - break; - - case llvm::Triple::arm: - case llvm::Triple::thumb: - switch (addr_class) { - case AddressClass::eData: - case AddressClass::eDebug: - return LLDB_INVALID_ADDRESS; - - case AddressClass::eUnknown: - case AddressClass::eInvalid: - case AddressClass::eCode: - case AddressClass::eCodeAlternateISA: - case AddressClass::eRuntime: - // Check if bit zero it no set? - if ((code_addr & 1ull) == 0) { - // Bit zero isn't set, check if the address is a multiple of 2? - if (code_addr & 2ull) { - // The address is a multiple of 2 so it must be thumb, set bit zero - code_addr |= 1ull; - } else if (addr_class == AddressClass::eCodeAlternateISA) { - // We checked the address and the address claims to be the alternate - // ISA which means thumb, so set bit zero. - code_addr |= 1ull; - } - } - break; - } - break; - - default: - break; - } - return code_addr; + auto arch_plugin = GetArchitecturePlugin(); + return arch_plugin ? + arch_plugin->GetCallableLoadAddress(load_addr, addr_class) : load_addr; } lldb::addr_t Target::GetOpcodeLoadAddress(lldb::addr_t load_addr, AddressClass addr_class) const { - addr_t opcode_addr = load_addr; - switch (m_arch.GetSpec().GetMachine()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::arm: - case llvm::Triple::thumb: - switch (addr_class) { - case AddressClass::eData: - case AddressClass::eDebug: - return LLDB_INVALID_ADDRESS; - - case AddressClass::eInvalid: - case AddressClass::eUnknown: - case AddressClass::eCode: - case AddressClass::eCodeAlternateISA: - case AddressClass::eRuntime: - opcode_addr &= ~(1ull); - break; - } - break; - - default: - break; - } - return opcode_addr; + auto arch_plugin = GetArchitecturePlugin(); + return arch_plugin ? + arch_plugin->GetOpcodeLoadAddress(load_addr, addr_class) : load_addr; } lldb::addr_t Target::GetBreakableLoadAddress(lldb::addr_t addr) { - addr_t breakable_addr = addr; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - - switch (m_arch.GetSpec().GetMachine()) { - default: - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - addr_t function_start = 0; - addr_t current_offset = 0; - uint32_t loop_count = 0; - Address resolved_addr; - uint32_t arch_flags = m_arch.GetSpec().GetFlags(); - bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16; - bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips; - SectionLoadList §ion_load_list = GetSectionLoadList(); - - if (section_load_list.IsEmpty()) - // No sections are loaded, so we must assume we are not running yet and - // need to operate only on file address. - m_images.ResolveFileAddress(addr, resolved_addr); - else - section_load_list.ResolveLoadAddress(addr, resolved_addr); - - // Get the function boundaries to make sure we don't scan back before the - // beginning of the current function. - ModuleSP temp_addr_module_sp(resolved_addr.GetModule()); - if (temp_addr_module_sp) { - SymbolContext sc; - uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; - temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, - resolve_scope, sc); - Address sym_addr; - if (sc.function) - sym_addr = sc.function->GetAddressRange().GetBaseAddress(); - else if (sc.symbol) - sym_addr = sc.symbol->GetAddress(); - - function_start = sym_addr.GetLoadAddress(this); - if (function_start == LLDB_INVALID_ADDRESS) - function_start = sym_addr.GetFileAddress(); - - if (function_start) - current_offset = addr - function_start; - } - - // If breakpoint address is start of function then we dont have to do - // anything. - if (current_offset == 0) - return breakable_addr; - else - loop_count = current_offset / 2; - - if (loop_count > 3) { - // Scan previous 6 bytes - if (IsMips16 | IsMicromips) - loop_count = 3; - // For mips-only, instructions are always 4 bytes, so scan previous 4 - // bytes only. - else - loop_count = 2; - } - - // Create Disassembler Instance - lldb::DisassemblerSP disasm_sp( - Disassembler::FindPlugin(m_arch.GetSpec(), nullptr, nullptr)); - - ExecutionContext exe_ctx; - CalculateExecutionContext(exe_ctx); - InstructionList instruction_list; - InstructionSP prev_insn; - bool prefer_file_cache = true; // Read from file - uint32_t inst_to_choose = 0; - - for (uint32_t i = 1; i <= loop_count; i++) { - // Adjust the address to read from. - resolved_addr.Slide(-2); - AddressRange range(resolved_addr, i * 2); - uint32_t insn_size = 0; - - disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache); - - uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); - if (num_insns) { - prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0); - insn_size = prev_insn->GetOpcode().GetByteSize(); - if (i == 1 && insn_size == 2) { - // This looks like a valid 2-byte instruction (but it could be a part - // of upper 4 byte instruction). - instruction_list.Append(prev_insn); - inst_to_choose = 1; - } else if (i == 2) { - // Here we may get one 4-byte instruction or two 2-byte instructions. - if (num_insns == 2) { - // Looks like there are two 2-byte instructions above our - // breakpoint target address. Now the upper 2-byte instruction is - // either a valid 2-byte instruction or could be a part of it's - // upper 4-byte instruction. In both cases we don't care because in - // this case lower 2-byte instruction is definitely a valid - // instruction and whatever i=1 iteration has found out is true. - inst_to_choose = 1; - break; - } else if (insn_size == 4) { - // This instruction claims its a valid 4-byte instruction. But it - // could be a part of it's upper 4-byte instruction. Lets try - // scanning upper 2 bytes to verify this. - instruction_list.Append(prev_insn); - inst_to_choose = 2; - } - } else if (i == 3) { - if (insn_size == 4) - // FIXME: We reached here that means instruction at [target - 4] has - // already claimed to be a 4-byte instruction, and now instruction - // at [target - 6] is also claiming that it's a 4-byte instruction. - // This can not be true. In this case we can not decide the valid - // previous instruction so we let lldb set the breakpoint at the - // address given by user. - inst_to_choose = 0; - else - // This is straight-forward - inst_to_choose = 2; - break; - } - } else { - // Decode failed, bytes do not form a valid instruction. So whatever - // previous iteration has found out is true. - if (i > 1) { - inst_to_choose = i - 1; - break; - } - } - } - - // Check if we are able to find any valid instruction. - if (inst_to_choose) { - if (inst_to_choose > instruction_list.GetSize()) - inst_to_choose--; - prev_insn = instruction_list.GetInstructionAtIndex(inst_to_choose - 1); - - if (prev_insn->HasDelaySlot()) { - uint32_t shift_size = prev_insn->GetOpcode().GetByteSize(); - // Adjust the breakable address - breakable_addr = addr - shift_size; - if (log) - log->Printf("Target::%s Breakpoint at 0x%8.8" PRIx64 - " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n", - __FUNCTION__, addr, breakable_addr); - } - } - break; - } - } - return breakable_addr; + auto arch_plugin = GetArchitecturePlugin(); + return arch_plugin ? + arch_plugin->GetBreakableLoadAddress(addr, *this) : addr; } SourceManager &Target::GetSourceManager() { @@ -2971,18 +2834,7 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { PlatformSP platform_sp(GetPlatform()); - // Finalize the file actions, and if none were given, default to opening up a - // pseudo terminal - const bool default_to_use_pty = platform_sp ? platform_sp->IsHost() : false; - if (log) - log->Printf("Target::%s have platform=%s, platform_sp->IsHost()=%s, " - "default_to_use_pty=%s", - __FUNCTION__, platform_sp ? "true" : "false", - platform_sp ? (platform_sp->IsHost() ? "true" : "false") - : "n/a", - default_to_use_pty ? "true" : "false"); - - launch_info.FinalizeFileActions(this, default_to_use_pty); + FinalizeFileActions(launch_info); if (state == eStateConnected) { if (launch_info.GetFlags().Test(eLaunchFlagLaunchInTTY)) { @@ -3003,22 +2855,15 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { log->Printf("Target::%s asking the platform to debug the process", __FUNCTION__); - // Get a weak pointer to the previous process if we have one - ProcessWP process_wp; - if (m_process_sp) - process_wp = m_process_sp; + // If there was a previous process, delete it before we make the new one. + // One subtle point, we delete the process before we release the reference + // to m_process_sp. That way even if we are the last owner, the process + // will get Finalized before it gets destroyed. + DeleteCurrentProcess(); + m_process_sp = GetPlatform()->DebugProcess(launch_info, debugger, this, error); - // Cleanup the old process since someone might still have a strong - // reference to this process and we would like to allow it to cleanup as - // much as it can without the object being destroyed. We try to lock the - // shared pointer and if that works, then someone else still has a strong - // reference to the process. - - ProcessSP old_process_sp(process_wp.lock()); - if (old_process_sp) - old_process_sp->Finalize(); } else { if (log) log->Printf("Target::%s the platform doesn't know how to debug a " @@ -3030,8 +2875,7 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { } else { // Use a Process plugin to construct the process. const char *plugin_name = launch_info.GetProcessPluginName(); - CreateProcess(launch_info.GetListenerForProcess(debugger), plugin_name, - nullptr); + CreateProcess(launch_info.GetListener(), plugin_name, nullptr); } // Since we didn't have a platform launch the process, launch it here. @@ -3206,6 +3050,86 @@ Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { return error; } +void Target::FinalizeFileActions(ProcessLaunchInfo &info) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Finalize the file actions, and if none were given, default to opening up a + // pseudo terminal + PlatformSP platform_sp = GetPlatform(); + const bool default_to_use_pty = + m_platform_sp ? m_platform_sp->IsHost() : false; + LLDB_LOG( + log, + "have platform={0}, platform_sp->IsHost()={1}, default_to_use_pty={2}", + bool(platform_sp), + platform_sp ? (platform_sp->IsHost() ? "true" : "false") : "n/a", + default_to_use_pty); + + // If nothing for stdin or stdout or stderr was specified, then check the + // process for any default settings that were set with "settings set" + if (info.GetFileActionForFD(STDIN_FILENO) == nullptr || + info.GetFileActionForFD(STDOUT_FILENO) == nullptr || + info.GetFileActionForFD(STDERR_FILENO) == nullptr) { + LLDB_LOG(log, "at least one of stdin/stdout/stderr was not set, evaluating " + "default handling"); + + if (info.GetFlags().Test(eLaunchFlagLaunchInTTY)) { + // Do nothing, if we are launching in a remote terminal no file actions + // should be done at all. + return; + } + + if (info.GetFlags().Test(eLaunchFlagDisableSTDIO)) { + LLDB_LOG(log, "eLaunchFlagDisableSTDIO set, adding suppression action " + "for stdin, stdout and stderr"); + info.AppendSuppressFileAction(STDIN_FILENO, true, false); + info.AppendSuppressFileAction(STDOUT_FILENO, false, true); + info.AppendSuppressFileAction(STDERR_FILENO, false, true); + } else { + // Check for any values that might have gotten set with any of: (lldb) + // settings set target.input-path (lldb) settings set target.output-path + // (lldb) settings set target.error-path + FileSpec in_file_spec; + FileSpec out_file_spec; + FileSpec err_file_spec; + // Only override with the target settings if we don't already have an + // action for in, out or error + if (info.GetFileActionForFD(STDIN_FILENO) == nullptr) + in_file_spec = GetStandardInputPath(); + if (info.GetFileActionForFD(STDOUT_FILENO) == nullptr) + out_file_spec = GetStandardOutputPath(); + if (info.GetFileActionForFD(STDERR_FILENO) == nullptr) + err_file_spec = GetStandardErrorPath(); + + LLDB_LOG(log, "target stdin='{0}', target stdout='{1}', stderr='{1}'", + in_file_spec, out_file_spec, err_file_spec); + + if (in_file_spec) { + info.AppendOpenFileAction(STDIN_FILENO, in_file_spec, true, false); + LLDB_LOG(log, "appended stdin open file action for {0}", in_file_spec); + } + + if (out_file_spec) { + info.AppendOpenFileAction(STDOUT_FILENO, out_file_spec, false, true); + LLDB_LOG(log, "appended stdout open file action for {0}", + out_file_spec); + } + + if (err_file_spec) { + info.AppendOpenFileAction(STDERR_FILENO, err_file_spec, false, true); + LLDB_LOG(log, "appended stderr open file action for {0}", + err_file_spec); + } + + if (default_to_use_pty && + (!in_file_spec || !out_file_spec || !err_file_spec)) { + llvm::Error Err = info.SetUpPtyRedirection(); + LLDB_LOG_ERROR(log, std::move(Err), "SetUpPtyRedirection failed: {0}"); + } + } + } +} + //-------------------------------------------------------------- // Target::StopHook //-------------------------------------------------------------- @@ -3275,16 +3199,20 @@ void Target::StopHook::GetDescription(Stream *s, // class TargetProperties //-------------------------------------------------------------- -OptionEnumValueElement lldb_private::g_dynamic_value_types[] = { +// clang-format off +static constexpr OptionEnumValueElement g_dynamic_value_types[] = { {eNoDynamicValues, "no-dynamic-values", "Don't calculate the dynamic type of values"}, {eDynamicCanRunTarget, "run-target", "Calculate the dynamic type of values " "even if you have to run the target."}, {eDynamicDontRunTarget, "no-run-target", - "Calculate the dynamic type of values, but don't run the target."}, - {0, nullptr, nullptr}}; + "Calculate the dynamic type of values, but don't run the target."} }; + +OptionEnumValues lldb_private::GetDynamicValueTypes() { + return OptionEnumValues(g_dynamic_value_types); +} -static OptionEnumValueElement g_inline_breakpoint_enums[] = { +static constexpr OptionEnumValueElement g_inline_breakpoint_enums[] = { {eInlineBreakpointsNever, "never", "Never look for inline breakpoint " "locations (fastest). This setting " "should only be used if you know that " @@ -3295,8 +3223,7 @@ static OptionEnumValueElement g_inline_breakpoint_enums[] = { "files (default)."}, {eInlineBreakpointsAlways, "always", "Always look for inline breakpoint locations when setting file and line " - "breakpoints (slower but most accurate)."}, - {0, nullptr, nullptr}}; + "breakpoints (slower but most accurate)."} }; typedef enum x86DisassemblyFlavor { eX86DisFlavorDefault, @@ -3304,36 +3231,33 @@ typedef enum x86DisassemblyFlavor { eX86DisFlavorATT } x86DisassemblyFlavor; -static OptionEnumValueElement g_x86_dis_flavor_value_types[] = { +static constexpr OptionEnumValueElement g_x86_dis_flavor_value_types[] = { {eX86DisFlavorDefault, "default", "Disassembler default (currently att)."}, {eX86DisFlavorIntel, "intel", "Intel disassembler flavor."}, - {eX86DisFlavorATT, "att", "AT&T disassembler flavor."}, - {0, nullptr, nullptr}}; + {eX86DisFlavorATT, "att", "AT&T disassembler flavor."} }; -static OptionEnumValueElement g_hex_immediate_style_values[] = { +static constexpr OptionEnumValueElement g_hex_immediate_style_values[] = { {Disassembler::eHexStyleC, "c", "C-style (0xffff)."}, - {Disassembler::eHexStyleAsm, "asm", "Asm-style (0ffffh)."}, - {0, nullptr, nullptr}}; + {Disassembler::eHexStyleAsm, "asm", "Asm-style (0ffffh)."} }; -static OptionEnumValueElement g_load_script_from_sym_file_values[] = { +static constexpr OptionEnumValueElement g_load_script_from_sym_file_values[] = { {eLoadScriptFromSymFileTrue, "true", "Load debug scripts inside symbol files"}, {eLoadScriptFromSymFileFalse, "false", "Do not load debug scripts inside symbol files."}, {eLoadScriptFromSymFileWarn, "warn", - "Warn about debug scripts inside symbol files but do not load them."}, - {0, nullptr, nullptr}}; + "Warn about debug scripts inside symbol files but do not load them."} }; -static OptionEnumValueElement g_load_current_working_dir_lldbinit_values[] = { +static constexpr +OptionEnumValueElement g_load_current_working_dir_lldbinit_values[] = { {eLoadCWDlldbinitTrue, "true", "Load .lldbinit files from current directory"}, {eLoadCWDlldbinitFalse, "false", "Do not load .lldbinit files from current directory"}, {eLoadCWDlldbinitWarn, "warn", - "Warn about loading .lldbinit files from current directory"}, - {0, nullptr, nullptr}}; + "Warn about loading .lldbinit files from current directory"} }; -static OptionEnumValueElement g_memory_module_load_level_values[] = { +static constexpr OptionEnumValueElement g_memory_module_load_level_values[] = { {eMemoryModuleLoadLevelMinimal, "minimal", "Load minimal information when loading modules from memory. Currently " "this setting loads sections only."}, @@ -3342,28 +3266,27 @@ static OptionEnumValueElement g_memory_module_load_level_values[] = { "this setting loads sections and function bounds."}, {eMemoryModuleLoadLevelComplete, "complete", "Load complete information when loading modules from memory. Currently " - "this setting loads sections and all symbols."}, - {0, nullptr, nullptr}}; + "this setting loads sections and all symbols."} }; -static PropertyDefinition g_properties[] = { - {"default-arch", OptionValue::eTypeArch, true, 0, nullptr, nullptr, +static constexpr PropertyDefinition g_properties[] = { + {"default-arch", OptionValue::eTypeArch, true, 0, nullptr, {}, "Default architecture to choose, when there's a choice."}, {"move-to-nearest-code", OptionValue::eTypeBoolean, false, true, nullptr, - nullptr, "Move breakpoints to nearest code."}, + {}, "Move breakpoints to nearest code."}, {"language", OptionValue::eTypeLanguage, false, eLanguageTypeUnknown, - nullptr, nullptr, + nullptr, {}, "The language to use when interpreting expressions entered in commands."}, - {"expr-prefix", OptionValue::eTypeFileSpec, false, 0, nullptr, nullptr, + {"expr-prefix", OptionValue::eTypeFileSpec, false, 0, nullptr, {}, "Path to a file containing expressions to be prepended to all " "expressions."}, {"prefer-dynamic-value", OptionValue::eTypeEnum, false, - eDynamicDontRunTarget, nullptr, g_dynamic_value_types, + eDynamicDontRunTarget, nullptr, OptionEnumValues(g_dynamic_value_types), "Should printed values be shown as their dynamic value."}, {"enable-synthetic-value", OptionValue::eTypeBoolean, false, true, nullptr, - nullptr, "Should synthetic values be used by default whenever available."}, - {"skip-prologue", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, + {}, "Should synthetic values be used by default whenever available."}, + {"skip-prologue", OptionValue::eTypeBoolean, false, true, nullptr, {}, "Skip function prologues when setting breakpoints by name."}, - {"source-map", OptionValue::eTypePathMap, false, 0, nullptr, nullptr, + {"source-map", OptionValue::eTypePathMap, false, 0, nullptr, {}, "Source path remappings are used to track the change of location between " "a source file when built, and " "where it exists on the current system. It consists of an array of " @@ -3375,66 +3298,68 @@ static PropertyDefinition g_properties[] = { "Each element of the array is checked in order and the first one that " "results in a match wins."}, {"exec-search-paths", OptionValue::eTypeFileSpecList, false, 0, nullptr, - nullptr, "Executable search paths to use when locating executable files " - "whose paths don't match the local file system."}, + {}, "Executable search paths to use when locating executable files " + "whose paths don't match the local file system."}, {"debug-file-search-paths", OptionValue::eTypeFileSpecList, false, 0, - nullptr, nullptr, - "List of directories to be searched when locating debug symbol files."}, + nullptr, {}, + "List of directories to be searched when locating debug symbol files. " + "See also symbols.enable-external-lookup."}, {"clang-module-search-paths", OptionValue::eTypeFileSpecList, false, 0, - nullptr, nullptr, + nullptr, {}, "List of directories to be searched when locating modules for Clang."}, {"auto-import-clang-modules", OptionValue::eTypeBoolean, false, true, - nullptr, nullptr, + nullptr, {}, "Automatically load Clang modules referred to by the program."}, {"auto-apply-fixits", OptionValue::eTypeBoolean, false, true, nullptr, - nullptr, "Automatically apply fix-it hints to expressions."}, + {}, "Automatically apply fix-it hints to expressions."}, {"notify-about-fixits", OptionValue::eTypeBoolean, false, true, nullptr, - nullptr, "Print the fixed expression text."}, + {}, "Print the fixed expression text."}, {"save-jit-objects", OptionValue::eTypeBoolean, false, false, nullptr, - nullptr, "Save intermediate object files generated by the LLVM JIT"}, + {}, "Save intermediate object files generated by the LLVM JIT"}, {"max-children-count", OptionValue::eTypeSInt64, false, 256, nullptr, - nullptr, "Maximum number of children to expand in any level of depth."}, + {}, "Maximum number of children to expand in any level of depth."}, {"max-string-summary-length", OptionValue::eTypeSInt64, false, 1024, - nullptr, nullptr, + nullptr, {}, "Maximum number of characters to show when using %s in summary strings."}, {"max-memory-read-size", OptionValue::eTypeSInt64, false, 1024, nullptr, - nullptr, "Maximum number of bytes that 'memory read' will fetch before " - "--force must be specified."}, + {}, "Maximum number of bytes that 'memory read' will fetch before " + "--force must be specified."}, {"breakpoints-use-platform-avoid-list", OptionValue::eTypeBoolean, false, - true, nullptr, nullptr, "Consult the platform module avoid list when " - "setting non-module specific breakpoints."}, - {"arg0", OptionValue::eTypeString, false, 0, nullptr, nullptr, + true, nullptr, {}, "Consult the platform module avoid list when " + "setting non-module specific breakpoints."}, + {"arg0", OptionValue::eTypeString, false, 0, nullptr, {}, "The first argument passed to the program in the argument array which can " "be different from the executable itself."}, - {"run-args", OptionValue::eTypeArgs, false, 0, nullptr, nullptr, + {"run-args", OptionValue::eTypeArgs, false, 0, nullptr, {}, "A list containing all the arguments to be passed to the executable when " "it is run. Note that this does NOT include the argv[0] which is in " "target.arg0."}, {"env-vars", OptionValue::eTypeDictionary, false, OptionValue::eTypeString, - nullptr, nullptr, "A list of all the environment variables to be passed " - "to the executable's environment, and their values."}, - {"inherit-env", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, + nullptr, {}, "A list of all the environment variables to be passed " + "to the executable's environment, and their values."}, + {"inherit-env", OptionValue::eTypeBoolean, false, true, nullptr, {}, "Inherit the environment from the process that is running LLDB."}, - {"input-path", OptionValue::eTypeFileSpec, false, 0, nullptr, nullptr, + {"input-path", OptionValue::eTypeFileSpec, false, 0, nullptr, {}, "The file/path to be used by the executable program for reading its " "standard input."}, - {"output-path", OptionValue::eTypeFileSpec, false, 0, nullptr, nullptr, + {"output-path", OptionValue::eTypeFileSpec, false, 0, nullptr, {}, "The file/path to be used by the executable program for writing its " "standard output."}, - {"error-path", OptionValue::eTypeFileSpec, false, 0, nullptr, nullptr, + {"error-path", OptionValue::eTypeFileSpec, false, 0, nullptr, {}, "The file/path to be used by the executable program for writing its " "standard error."}, {"detach-on-error", OptionValue::eTypeBoolean, false, true, nullptr, - nullptr, "debugserver will detach (rather than killing) a process if it " + {}, "debugserver will detach (rather than killing) a process if it " "loses connection with lldb."}, - {"preload-symbols", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, + {"preload-symbols", OptionValue::eTypeBoolean, false, true, nullptr, {}, "Enable loading of symbol tables before they are needed."}, - {"disable-aslr", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, + {"disable-aslr", OptionValue::eTypeBoolean, false, true, nullptr, {}, "Disable Address Space Layout Randomization (ASLR)"}, - {"disable-stdio", OptionValue::eTypeBoolean, false, false, nullptr, nullptr, + {"disable-stdio", OptionValue::eTypeBoolean, false, false, nullptr, {}, "Disable stdin/stdout for process (e.g. for a GUI application)"}, {"inline-breakpoint-strategy", OptionValue::eTypeEnum, false, - eInlineBreakpointsAlways, nullptr, g_inline_breakpoint_enums, + eInlineBreakpointsAlways, nullptr, + OptionEnumValues(g_inline_breakpoint_enums), "The strategy to use when settings breakpoints by file and line. " "Breakpoint locations can end up being inlined by the compiler, so that a " "compile unit 'a.c' might contain an inlined function from another source " @@ -3454,25 +3379,29 @@ static PropertyDefinition g_properties[] = { // FIXME: This is the wrong way to do per-architecture settings, but we // don't have a general per architecture settings system in place yet. {"x86-disassembly-flavor", OptionValue::eTypeEnum, false, - eX86DisFlavorDefault, nullptr, g_x86_dis_flavor_value_types, + eX86DisFlavorDefault, nullptr, + OptionEnumValues(g_x86_dis_flavor_value_types), "The default disassembly flavor to use for x86 or x86-64 targets."}, {"use-hex-immediates", OptionValue::eTypeBoolean, false, true, nullptr, - nullptr, "Show immediates in disassembly as hexadecimal."}, + {}, "Show immediates in disassembly as hexadecimal."}, {"hex-immediate-style", OptionValue::eTypeEnum, false, - Disassembler::eHexStyleC, nullptr, g_hex_immediate_style_values, + Disassembler::eHexStyleC, nullptr, + OptionEnumValues(g_hex_immediate_style_values), "Which style to use for printing hexadecimal disassembly values."}, {"use-fast-stepping", OptionValue::eTypeBoolean, false, true, nullptr, - nullptr, "Use a fast stepping algorithm based on running from branch to " - "branch rather than instruction single-stepping."}, + {}, "Use a fast stepping algorithm based on running from branch to " + "branch rather than instruction single-stepping."}, {"load-script-from-symbol-file", OptionValue::eTypeEnum, false, - eLoadScriptFromSymFileWarn, nullptr, g_load_script_from_sym_file_values, + eLoadScriptFromSymFileWarn, nullptr, + OptionEnumValues(g_load_script_from_sym_file_values), "Allow LLDB to load scripting resources embedded in symbol files when " "available."}, {"load-cwd-lldbinit", OptionValue::eTypeEnum, false, eLoadCWDlldbinitWarn, - nullptr, g_load_current_working_dir_lldbinit_values, + nullptr, OptionEnumValues(g_load_current_working_dir_lldbinit_values), "Allow LLDB to .lldbinit files from the current directory automatically."}, {"memory-module-load-level", OptionValue::eTypeEnum, false, - eMemoryModuleLoadLevelComplete, nullptr, g_memory_module_load_level_values, + eMemoryModuleLoadLevelComplete, nullptr, + OptionEnumValues(g_memory_module_load_level_values), "Loading modules from memory can be slow as reading the symbol tables and " "other data can take a long time depending on your connection to the " "debug target. " @@ -3488,20 +3417,23 @@ static PropertyDefinition g_properties[] = { "symbols, but should rarely be used as stack frames in these memory " "regions will be inaccurate and not provide any context (fastest). "}, {"display-expression-in-crashlogs", OptionValue::eTypeBoolean, false, false, - nullptr, nullptr, "Expressions that crash will show up in crash logs if " - "the host system supports executable specific crash log " - "strings and this setting is set to true."}, + nullptr, {}, "Expressions that crash will show up in crash logs if " + "the host system supports executable specific crash log " + "strings and this setting is set to true."}, {"trap-handler-names", OptionValue::eTypeArray, true, - OptionValue::eTypeString, nullptr, nullptr, + OptionValue::eTypeString, nullptr, {}, "A list of trap handler function names, e.g. a common Unix user process " "one is _sigtramp."}, {"display-runtime-support-values", OptionValue::eTypeBoolean, false, false, - nullptr, nullptr, "If true, LLDB will show variables that are meant to " - "support the operation of a language's runtime " - "support."}, - {"non-stop-mode", OptionValue::eTypeBoolean, false, 0, nullptr, nullptr, + nullptr, {}, "If true, LLDB will show variables that are meant to " + "support the operation of a language's runtime support."}, + {"display-recognized-arguments", OptionValue::eTypeBoolean, false, false, + nullptr, {}, "Show recognized arguments in variable listings by default."}, + {"non-stop-mode", OptionValue::eTypeBoolean, false, 0, nullptr, {}, "Disable lock-step debugging, instead control threads independently."}, - {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}}; + {"require-hardware-breakpoint", OptionValue::eTypeBoolean, false, 0, + nullptr, {}, "Require all breakpoints to be hardware breakpoints."}}; +// clang-format on enum { ePropertyDefaultArch, @@ -3545,8 +3477,10 @@ enum { ePropertyDisplayExpressionsInCrashlogs, ePropertyTrapHandlerNames, ePropertyDisplayRuntimeSupportValues, + ePropertyDisplayRecognizedArguments, ePropertyNonStopModeEnabled, - ePropertyExperimental + ePropertyRequireHardwareBreakpoints, + ePropertyExperimental, }; class TargetOptionValueProperties : public OptionValueProperties { @@ -3623,16 +3557,15 @@ protected: //---------------------------------------------------------------------- // TargetProperties //---------------------------------------------------------------------- -static PropertyDefinition g_experimental_properties[]{ +static constexpr PropertyDefinition g_experimental_properties[]{ {"inject-local-vars", OptionValue::eTypeBoolean, true, true, nullptr, - nullptr, + {}, "If true, inject local variables explicitly into the expression text. " "This will fix symbol resolution when there are name collisions between " "ivars and local variables. " "But it can make expressions run much more slowly."}, {"use-modern-type-lookup", OptionValue::eTypeBoolean, true, false, nullptr, - nullptr, "If true, use Clang's modern type lookup infrastructure."}, - {nullptr, OptionValue::eTypeInvalid, true, 0, nullptr, nullptr, nullptr}}; + {}, "If true, use Clang's modern type lookup infrastructure."}}; enum { ePropertyInjectLocalVars = 0, ePropertyUseModernTypeLookup }; @@ -4104,6 +4037,16 @@ void TargetProperties::SetDisplayRuntimeSupportValues(bool b) { m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } +bool TargetProperties::GetDisplayRecognizedArguments() const { + const uint32_t idx = ePropertyDisplayRecognizedArguments; + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, false); +} + +void TargetProperties::SetDisplayRecognizedArguments(bool b) { + const uint32_t idx = ePropertyDisplayRecognizedArguments; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +} + bool TargetProperties::GetNonStopModeEnabled() const { const uint32_t idx = ePropertyNonStopModeEnabled; return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, false); @@ -4145,6 +4088,17 @@ void TargetProperties::SetProcessLaunchInfo( SetDisableSTDIO(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableSTDIO)); } +bool TargetProperties::GetRequireHardwareBreakpoints() const { + const uint32_t idx = ePropertyRequireHardwareBreakpoints; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); +} + +void TargetProperties::SetRequireHardwareBreakpoints(bool b) { + const uint32_t idx = ePropertyRequireHardwareBreakpoints; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +} + void TargetProperties::Arg0ValueChangedCallback(void *target_property_ptr, OptionValue *) { TargetProperties *this_ = |
