diff options
Diffstat (limited to 'lldb/source/Core')
23 files changed, 800 insertions, 559 deletions
diff --git a/lldb/source/Core/Communication.cpp b/lldb/source/Core/Communication.cpp index b358e70b1a91..b50cd0ecab5c 100644 --- a/lldb/source/Core/Communication.cpp +++ b/lldb/source/Core/Communication.cpp @@ -199,9 +199,8 @@ bool Communication::StartReadThread(Status *error_ptr) { LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION), "{0} Communication::StartReadThread ()", this); - char thread_name[1024]; - snprintf(thread_name, sizeof(thread_name), "<lldb.comm.%s>", - GetBroadcasterName().AsCString()); + const std::string thread_name = + llvm::formatv("<lldb.comm.{0}>", GetBroadcasterName()); m_read_thread_enabled = true; m_read_thread_did_exit = false; @@ -340,7 +339,7 @@ lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) { } if (error.Fail()) LLDB_LOG(log, "error: {0}, status = {1}", error, - Communication::ConnectionStatusAsCString(status)); + Communication::ConnectionStatusAsString(status)); break; case eConnectionStatusInterrupted: // Synchronization signal from // SynchronizeWithReadThread() @@ -356,7 +355,7 @@ lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) { case eConnectionStatusTimedOut: // Request timed out if (error.Fail()) LLDB_LOG(log, "error: {0}, status = {1}", error, - Communication::ConnectionStatusAsCString(status)); + Communication::ConnectionStatusAsString(status)); break; } } @@ -417,8 +416,8 @@ void Communication::SetConnection(std::unique_ptr<Connection> connection) { m_connection_sp = std::move(connection); } -const char * -Communication::ConnectionStatusAsCString(lldb::ConnectionStatus status) { +std::string +Communication::ConnectionStatusAsString(lldb::ConnectionStatus status) { switch (status) { case eConnectionStatusSuccess: return "success"; @@ -436,8 +435,5 @@ Communication::ConnectionStatusAsCString(lldb::ConnectionStatus status) { return "interrupted"; } - static char unknown_state_string[64]; - snprintf(unknown_state_string, sizeof(unknown_state_string), - "ConnectionStatus = %i", status); - return unknown_state_string; + return "@" + std::to_string(status); } diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td index b04738175f34..96f67801553b 100644 --- a/lldb/source/Core/CoreProperties.td +++ b/lldb/source/Core/CoreProperties.td @@ -131,4 +131,8 @@ let Definition = "debugger" in { Global, DefaultStringValue<"frame #${frame.index}: ${ansi.fg.yellow}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-without-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}{${function.is-optimized} [opt]}{${frame.is-artificial} [artificial]}\\\\n">, Desc<"The default frame format string to use when displaying stack frameinformation for threads from thread backtrace unique.">; + def ShowAutosuggestion: Property<"show-autosuggestion", "Boolean">, + Global, + DefaultFalse, + Desc<"If true, LLDB will show suggestions to complete the command the user typed.">; } diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 5f4f1e266d81..b16ce68c2fd2 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -346,6 +346,12 @@ bool Debugger::SetUseColor(bool b) { return ret; } +bool Debugger::GetUseAutosuggestion() const { + const uint32_t idx = ePropertyShowAutosuggestion; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); +} + bool Debugger::GetUseSourceCache() const { const uint32_t idx = ePropertyUseSourceCache; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -666,9 +672,7 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) m_event_handler_thread(), m_io_handler_thread(), m_sync_broadcaster(nullptr, "lldb.debugger.sync"), m_forward_listener_sp(), m_clear_once() { - char instance_cstr[256]; - snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID()); - m_instance_name.SetCString(instance_cstr); + m_instance_name.SetString(llvm::formatv("debugger_{0}", GetID()).str()); if (log_callback) m_log_callback_stream_sp = std::make_shared<StreamCallback>(log_callback, baton); @@ -678,7 +682,16 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) assert(default_platform_sp); m_platform_list.Append(default_platform_sp, true); - m_dummy_target_sp = m_target_list.GetDummyTarget(*this); + // Create the dummy target. + { + ArchSpec arch(Target::GetDefaultArchitecture()); + if (!arch.IsValid()) + arch = HostInfo::GetArchitecture(); + assert(arch.IsValid() && "No valid default or host archspec"); + const bool is_dummy_target = true; + m_dummy_target_sp.reset( + new Target(*this, arch, default_platform_sp, is_dummy_target)); + } assert(m_dummy_target_sp.get() && "Couldn't construct dummy target?"); m_collection_sp->Initialize(g_debugger_properties); @@ -778,7 +791,7 @@ repro::DataRecorder *Debugger::GetInputRecorder() { return m_input_recorder; } void Debugger::SetInputFile(FileSP file_sp, repro::DataRecorder *recorder) { assert(file_sp && file_sp->IsValid()); m_input_recorder = recorder; - m_input_file_sp = file_sp; + m_input_file_sp = std::move(file_sp); // Save away the terminal state if that is relevant, so that we can restore // it in RestoreInputState. SaveInputTerminalState(); @@ -1160,11 +1173,11 @@ bool Debugger::EnableLog(llvm::StringRef channel, flags |= File::eOpenOptionAppend; else flags |= File::eOpenOptionTruncate; - auto file = FileSystem::Instance().Open( + llvm::Expected<FileUP> file = FileSystem::Instance().Open( FileSpec(log_file), flags, lldb::eFilePermissionsFileDefault, false); if (!file) { - // FIXME: This gets garbled when called from the log command. - error_stream << "Unable to open log file: " << log_file; + error_stream << "Unable to open log file '" << log_file + << "': " << llvm::toString(file.takeError()) << "\n"; return false; } @@ -1565,14 +1578,11 @@ void Debugger::JoinIOHandlerThread() { } } -Target *Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) { - Target *target = nullptr; +Target &Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) { if (!prefer_dummy) { - target = m_target_list.GetSelectedTarget().get(); - if (target) - return target; + if (TargetSP target = m_target_list.GetSelectedTarget()) + return *target; } - return GetDummyTarget(); } diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp index 4da823c7a243..3a975d9296f4 100644 --- a/lldb/source/Core/Disassembler.cpp +++ b/lldb/source/Core/Disassembler.cpp @@ -58,9 +58,7 @@ using namespace lldb_private; DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch, const char *flavor, const char *plugin_name) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "Disassembler::FindPlugin (arch = %s, plugin_name = %s)", + LLDB_SCOPED_TIMERF("Disassembler::FindPlugin (arch = %s, plugin_name = %s)", arch.GetArchitectureName(), plugin_name); DisassemblerCreateInstance create_callback = nullptr; @@ -540,34 +538,29 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch, } bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch, - const char *plugin_name, const char *flavor, - const ExecutionContext &exe_ctx, - uint32_t num_instructions, - bool mixed_source_and_assembly, - uint32_t num_mixed_context_lines, - uint32_t options, Stream &strm) { + StackFrame &frame, Stream &strm) { AddressRange range; - StackFrame *frame = exe_ctx.GetFramePtr(); - 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->GetAddressRef(); - range.SetByteSize(sc.symbol->GetByteSize()); - } else { - range.GetBaseAddress() = frame->GetFrameCodeAddress(); - } + SymbolContext sc( + frame.GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); + if (sc.function) { + range = sc.function->GetAddressRange(); + } else if (sc.symbol && sc.symbol->ValueIsAddress()) { + range.GetBaseAddress() = sc.symbol->GetAddressRef(); + range.SetByteSize(sc.symbol->GetByteSize()); + } else { + range.GetBaseAddress() = frame.GetFrameCodeAddress(); + } if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0) range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE); - } - return Disassemble( - debugger, arch, plugin_name, flavor, exe_ctx, range.GetBaseAddress(), - {Limit::Instructions, num_instructions}, mixed_source_and_assembly, - num_mixed_context_lines, options, strm); + Disassembler::Limit limit = {Disassembler::Limit::Bytes, + range.GetByteSize()}; + if (limit.value == 0) + limit.value = DEFAULT_DISASM_BYTE_SIZE; + + return Disassemble(debugger, arch, nullptr, nullptr, frame, + range.GetBaseAddress(), limit, false, 0, 0, strm); } Instruction::Instruction(const Address &address, AddressClass addr_class) @@ -957,6 +950,13 @@ InstructionSP InstructionList::GetInstructionAtIndex(size_t idx) const { return inst_sp; } +InstructionSP InstructionList::GetInstructionAtAddress(const Address &address) { + uint32_t index = GetIndexOfInstructionAtAddress(address); + if (index != UINT32_MAX) + return GetInstructionAtIndex(index); + return nullptr; +} + void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes, const ExecutionContext *exe_ctx) { const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize(); @@ -990,17 +990,15 @@ void InstructionList::Append(lldb::InstructionSP &inst_sp) { uint32_t InstructionList::GetIndexOfNextBranchInstruction(uint32_t start, - Target &target, bool ignore_calls, bool *found_calls) const { size_t num_instructions = m_instructions.size(); uint32_t next_branch = UINT32_MAX; - size_t i; if (found_calls) *found_calls = false; - for (i = start; i < num_instructions; i++) { + for (size_t i = start; i < num_instructions; i++) { if (m_instructions[i]->DoesBranch()) { if (ignore_calls && m_instructions[i]->IsCall()) { if (found_calls) @@ -1012,42 +1010,6 @@ InstructionList::GetIndexOfNextBranchInstruction(uint32_t start, } } - // Hexagon needs the first instruction of the packet with the branch. Go - // backwards until we find an instruction marked end-of-packet, or until we - // hit start. - if (target.GetArchitecture().GetTriple().getArch() == llvm::Triple::hexagon) { - // If we didn't find a branch, find the last packet start. - if (next_branch == UINT32_MAX) { - i = num_instructions - 1; - } - - while (i > start) { - --i; - - Status error; - uint32_t inst_bytes; - bool prefer_file_cache = false; // Read from process if process is running - lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; - target.ReadMemory(m_instructions[i]->GetAddress(), prefer_file_cache, - &inst_bytes, sizeof(inst_bytes), error, &load_addr); - // If we have an error reading memory, return start - if (!error.Success()) - return start; - // check if this is the last instruction in a packet bits 15:14 will be - // 11b or 00b for a duplex - if (((inst_bytes & 0xC000) == 0xC000) || - ((inst_bytes & 0xC000) == 0x0000)) { - // instruction after this should be the start of next packet - next_branch = i + 1; - break; - } - } - - if (next_branch == UINT32_MAX) { - // We couldn't find the previous packet, so return start - next_branch = start; - } - } return next_branch; } diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp index ceccbe437e1d..22cb9f18147a 100644 --- a/lldb/source/Core/DynamicLoader.cpp +++ b/lldb/source/Core/DynamicLoader.cpp @@ -60,8 +60,6 @@ DynamicLoader *DynamicLoader::FindPlugin(Process *process, DynamicLoader::DynamicLoader(Process *process) : m_process(process) {} -DynamicLoader::~DynamicLoader() = default; - // Accessosors to the global setting as to whether to stop at image (shared // library) loading/unloading. diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp index 6cf09aaa7f9d..8c654d9d8a98 100644 --- a/lldb/source/Core/IOHandler.cpp +++ b/lldb/source/Core/IOHandler.cpp @@ -18,6 +18,7 @@ #include "lldb/Host/Config.h" #include "lldb/Host/File.h" #include "lldb/Utility/Predicate.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringList.h" @@ -102,11 +103,11 @@ FILE *IOHandler::GetErrorFILE() { return (m_error_sp ? m_error_sp->GetFile().GetStream() : nullptr); } -FileSP &IOHandler::GetInputFileSP() { return m_input_sp; } +FileSP IOHandler::GetInputFileSP() { return m_input_sp; } -StreamFileSP &IOHandler::GetOutputStreamFileSP() { return m_output_sp; } +StreamFileSP IOHandler::GetOutputStreamFileSP() { return m_output_sp; } -StreamFileSP &IOHandler::GetErrorStreamFileSP() { return m_error_sp; } +StreamFileSP IOHandler::GetErrorStreamFileSP() { return m_error_sp; } bool IOHandler::GetIsInteractive() { return GetInputFileSP() ? GetInputFileSP()->GetIsInteractive() : false; @@ -195,6 +196,14 @@ void IOHandlerConfirm::IOHandlerInputComplete(IOHandler &io_handler, } } +llvm::Optional<std::string> +IOHandlerDelegate::IOHandlerSuggestion(IOHandler &io_handler, + llvm::StringRef line) { + return io_handler.GetDebugger() + .GetCommandInterpreter() + .GetAutoSuggestionForCommand(line); +} + void IOHandlerDelegate::IOHandlerComplete(IOHandler &io_handler, CompletionRequest &request) { switch (m_completion) { @@ -258,6 +267,8 @@ IOHandlerEditline::IOHandlerEditline( m_color_prompts); m_editline_up->SetIsInputCompleteCallback(IsInputCompleteCallback, this); m_editline_up->SetAutoCompleteCallback(AutoCompleteCallback, this); + if (debugger.GetUseAutosuggestion() && debugger.GetUseColor()) + m_editline_up->SetSuggestionCallback(SuggestionCallback, this); // See if the delegate supports fixing indentation const char *indent_chars = delegate.IOHandlerGetFixIndentationCharacters(); if (indent_chars) { @@ -430,6 +441,16 @@ int IOHandlerEditline::FixIndentationCallback(Editline *editline, *editline_reader, lines, cursor_position); } +llvm::Optional<std::string> +IOHandlerEditline::SuggestionCallback(llvm::StringRef line, void *baton) { + IOHandlerEditline *editline_reader = static_cast<IOHandlerEditline *>(baton); + if (editline_reader) + return editline_reader->m_delegate.IOHandlerSuggestion(*editline_reader, + line); + + return llvm::None; +} + void IOHandlerEditline::AutoCompleteCallback(CompletionRequest &request, void *baton) { IOHandlerEditline *editline_reader = (IOHandlerEditline *)baton; diff --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp index f8fc91772198..19066e6be623 100644 --- a/lldb/source/Core/IOHandlerCursesGUI.cpp +++ b/lldb/source/Core/IOHandlerCursesGUI.cpp @@ -10,9 +10,14 @@ #include "lldb/Host/Config.h" #if LLDB_ENABLE_CURSES +#if CURSES_HAVE_NCURSES_CURSES_H +#include <ncurses/curses.h> +#include <ncurses/panel.h> +#else #include <curses.h> #include <panel.h> #endif +#endif #if defined(__APPLE__) #include <deque> @@ -268,6 +273,32 @@ struct KeyHelp { const char *description; }; +// COLOR_PAIR index names +enum { + // First 16 colors are 8 black background and 8 blue background colors, + // needed by OutputColoredStringTruncated(). + BlackOnBlack = 1, + RedOnBlack, + GreenOnBlack, + YellowOnBlack, + BlueOnBlack, + MagentaOnBlack, + CyanOnBlack, + WhiteOnBlack, + BlackOnBlue, + RedOnBlue, + GreenOnBlue, + YellowOnBlue, + BlueOnBlue, + MagentaOnBlue, + CyanOnBlue, + WhiteOnBlue, + // Other colors, as needed. + BlackOnWhite, + MagentaOnWhite, + LastColorPairIndex = MagentaOnWhite +}; + class WindowDelegate { public: virtual ~WindowDelegate() = default; @@ -362,23 +393,23 @@ public: } void Clear() { ::wclear(m_window); } void Erase() { ::werase(m_window); } - Rect GetBounds() { + Rect GetBounds() const { return Rect(GetParentOrigin(), GetSize()); } // Get the rectangle in our parent window int GetChar() { return ::wgetch(m_window); } - int GetCursorX() { return getcurx(m_window); } - int GetCursorY() { return getcury(m_window); } - Rect GetFrame() { + int GetCursorX() const { return getcurx(m_window); } + int GetCursorY() const { return getcury(m_window); } + Rect GetFrame() const { return Rect(Point(), GetSize()); } // Get our rectangle in our own coordinate system - Point GetParentOrigin() { return Point(GetParentX(), GetParentY()); } - Size GetSize() { return Size(GetWidth(), GetHeight()); } - int GetParentX() { return getparx(m_window); } - int GetParentY() { return getpary(m_window); } - int GetMaxX() { return getmaxx(m_window); } - int GetMaxY() { return getmaxy(m_window); } - int GetWidth() { return GetMaxX(); } - int GetHeight() { return GetMaxY(); } + Point GetParentOrigin() const { return Point(GetParentX(), GetParentY()); } + Size GetSize() const { return Size(GetWidth(), GetHeight()); } + int GetParentX() const { return getparx(m_window); } + int GetParentY() const { return getpary(m_window); } + int GetMaxX() const { return getmaxx(m_window); } + int GetMaxY() const { return getmaxy(m_window); } + int GetWidth() const { return GetMaxX(); } + int GetHeight() const { return GetMaxY(); } void MoveCursor(int x, int y) { ::wmove(m_window, y, x); } void MoveWindow(int x, int y) { MoveWindow(Point(x, y)); } void Resize(int w, int h) { ::wresize(m_window, h, w); } @@ -391,11 +422,11 @@ public: ::wbkgd(m_window, COLOR_PAIR(color_pair_idx)); } - void PutCStringTruncated(const char *s, int right_pad) { + void PutCStringTruncated(int right_pad, const char *s, int len = -1) { int bytes_left = GetWidth() - GetCursorX(); if (bytes_left > right_pad) { bytes_left -= right_pad; - ::waddnstr(m_window, s, bytes_left); + ::waddnstr(m_window, s, len < 0 ? bytes_left : std::min(bytes_left, len)); } } @@ -433,6 +464,93 @@ public: va_end(args); } + void PrintfTruncated(int right_pad, const char *format, ...) + __attribute__((format(printf, 3, 4))) { + va_list args; + va_start(args, format); + StreamString strm; + strm.PrintfVarArg(format, args); + va_end(args); + PutCStringTruncated(right_pad, strm.GetData()); + } + + size_t LimitLengthToRestOfLine(size_t length) const { + return std::min<size_t>(length, std::max(0, GetWidth() - GetCursorX() - 1)); + } + + // Curses doesn't allow direct output of color escape sequences, but that's + // how we get source lines from the Highligher class. Read the line and + // convert color escape sequences to curses color attributes. Use + // first_skip_count to skip leading visible characters. Returns false if all + // visible characters were skipped due to first_skip_count. + bool OutputColoredStringTruncated(int right_pad, StringRef string, + size_t skip_first_count, + bool use_blue_background) { + attr_t saved_attr; + short saved_pair; + bool result = false; + wattr_get(m_window, &saved_attr, &saved_pair, nullptr); + if (use_blue_background) + ::wattron(m_window, COLOR_PAIR(WhiteOnBlue)); + while (!string.empty()) { + size_t esc_pos = string.find('\x1b'); + if (esc_pos == StringRef::npos) { + string = string.substr(skip_first_count); + if (!string.empty()) { + PutCStringTruncated(right_pad, string.data(), string.size()); + result = true; + } + break; + } + if (esc_pos > 0) { + if (skip_first_count > 0) { + int skip = std::min(esc_pos, skip_first_count); + string = string.substr(skip); + skip_first_count -= skip; + esc_pos -= skip; + } + if (esc_pos > 0) { + PutCStringTruncated(right_pad, string.data(), esc_pos); + result = true; + string = string.drop_front(esc_pos); + } + } + bool consumed = string.consume_front("\x1b"); + assert(consumed); + UNUSED_IF_ASSERT_DISABLED(consumed); + // This is written to match our Highlighter classes, which seem to + // generate only foreground color escape sequences. If necessary, this + // will need to be extended. + if (!string.consume_front("[")) { + llvm::errs() << "Missing '[' in color escape sequence.\n"; + continue; + } + // Only 8 basic foreground colors and reset, our Highlighter doesn't use + // anything else. + int value; + if (!!string.consumeInteger(10, value) || // Returns false on success. + !(value == 0 || (value >= 30 && value <= 37))) { + llvm::errs() << "No valid color code in color escape sequence.\n"; + continue; + } + if (!string.consume_front("m")) { + llvm::errs() << "Missing 'm' in color escape sequence.\n"; + continue; + } + if (value == 0) { // Reset. + wattr_set(m_window, saved_attr, saved_pair, nullptr); + if (use_blue_background) + ::wattron(m_window, COLOR_PAIR(WhiteOnBlue)); + } else { + // Mapped directly to first 16 color pairs (black/blue background). + ::wattron(m_window, + COLOR_PAIR(value - 30 + 1 + (use_blue_background ? 8 : 0))); + } + } + wattr_set(m_window, saved_attr, saved_pair, nullptr); + return result; + } + void Touch() { ::touchwin(m_window); if (m_parent) @@ -521,7 +639,7 @@ public: void DrawTitleBox(const char *title, const char *bottom_message = nullptr) { attr_t attr = 0; if (IsActive()) - attr = A_BOLD | COLOR_PAIR(2); + attr = A_BOLD | COLOR_PAIR(BlackOnWhite); else attr = 0; if (attr) @@ -548,7 +666,7 @@ public: } else { MoveCursor(1, GetHeight() - 1); PutChar('['); - PutCStringTruncated(bottom_message, 1); + PutCStringTruncated(1, bottom_message); } } if (attr) @@ -687,42 +805,44 @@ public: void SelectNextWindowAsActive() { // Move active focus to next window - const size_t num_subwindows = m_subwindows.size(); - if (m_curr_active_window_idx == UINT32_MAX) { - uint32_t idx = 0; - for (auto subwindow_sp : m_subwindows) { - if (subwindow_sp->GetCanBeActive()) { - m_curr_active_window_idx = idx; - break; - } - ++idx; - } - } else if (m_curr_active_window_idx + 1 < num_subwindows) { - bool handled = false; + const int num_subwindows = m_subwindows.size(); + int start_idx = 0; + if (m_curr_active_window_idx != UINT32_MAX) { m_prev_active_window_idx = m_curr_active_window_idx; - for (size_t idx = m_curr_active_window_idx + 1; idx < num_subwindows; - ++idx) { - if (m_subwindows[idx]->GetCanBeActive()) { - m_curr_active_window_idx = idx; - handled = true; - break; - } + start_idx = m_curr_active_window_idx + 1; + } + for (int idx = start_idx; idx < num_subwindows; ++idx) { + if (m_subwindows[idx]->GetCanBeActive()) { + m_curr_active_window_idx = idx; + return; } - if (!handled) { - for (size_t idx = 0; idx <= m_prev_active_window_idx; ++idx) { - if (m_subwindows[idx]->GetCanBeActive()) { - m_curr_active_window_idx = idx; - break; - } - } + } + for (int idx = 0; idx < start_idx; ++idx) { + if (m_subwindows[idx]->GetCanBeActive()) { + m_curr_active_window_idx = idx; + break; } - } else { + } + } + + void SelectPreviousWindowAsActive() { + // Move active focus to previous window + const int num_subwindows = m_subwindows.size(); + int start_idx = num_subwindows - 1; + if (m_curr_active_window_idx != UINT32_MAX) { m_prev_active_window_idx = m_curr_active_window_idx; - for (size_t idx = 0; idx < num_subwindows; ++idx) { - if (m_subwindows[idx]->GetCanBeActive()) { - m_curr_active_window_idx = idx; - break; - } + start_idx = m_curr_active_window_idx - 1; + } + for (int idx = start_idx; idx >= 0; --idx) { + if (m_subwindows[idx]->GetCanBeActive()) { + m_curr_active_window_idx = idx; + return; + } + } + for (int idx = num_subwindows - 1; idx > start_idx; --idx) { + if (m_subwindows[idx]->GetCanBeActive()) { + m_curr_active_window_idx = idx; + break; } } } @@ -916,9 +1036,9 @@ void Menu::DrawMenuTitle(Window &window, bool highlight) { } else { const int shortcut_key = m_key_value; bool underlined_shortcut = false; - const attr_t hilgight_attr = A_REVERSE; + const attr_t highlight_attr = A_REVERSE; if (highlight) - window.AttributeOn(hilgight_attr); + window.AttributeOn(highlight_attr); if (llvm::isPrint(shortcut_key)) { size_t lower_pos = m_name.find(tolower(shortcut_key)); size_t upper_pos = m_name.find(toupper(shortcut_key)); @@ -945,18 +1065,18 @@ void Menu::DrawMenuTitle(Window &window, bool highlight) { } if (highlight) - window.AttributeOff(hilgight_attr); + window.AttributeOff(highlight_attr); if (m_key_name.empty()) { if (!underlined_shortcut && llvm::isPrint(m_key_value)) { - window.AttributeOn(COLOR_PAIR(3)); + window.AttributeOn(COLOR_PAIR(MagentaOnWhite)); window.Printf(" (%c)", m_key_value); - window.AttributeOff(COLOR_PAIR(3)); + window.AttributeOff(COLOR_PAIR(MagentaOnWhite)); } } else { - window.AttributeOn(COLOR_PAIR(3)); + window.AttributeOn(COLOR_PAIR(MagentaOnWhite)); window.Printf(" (%s)", m_key_name.c_str()); - window.AttributeOff(COLOR_PAIR(3)); + window.AttributeOff(COLOR_PAIR(MagentaOnWhite)); } } } @@ -968,7 +1088,7 @@ bool Menu::WindowDelegateDraw(Window &window, bool force) { Menu::Type menu_type = GetType(); switch (menu_type) { case Menu::Type::Bar: { - window.SetBackground(2); + window.SetBackground(BlackOnWhite); window.MoveCursor(0, 0); for (size_t i = 0; i < num_submenus; ++i) { Menu *menu = submenus[i].get(); @@ -988,7 +1108,7 @@ bool Menu::WindowDelegateDraw(Window &window, bool force) { int cursor_x = 0; int cursor_y = 0; window.Erase(); - window.SetBackground(2); + window.SetBackground(BlackOnWhite); window.Box(); for (size_t i = 0; i < num_submenus; ++i) { const bool is_selected = (i == static_cast<size_t>(selected_idx)); @@ -1189,18 +1309,16 @@ public: ListenerSP listener_sp( Listener::MakeListener("lldb.IOHandler.curses.Application")); - ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass()); ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass()); - ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass()); debugger.EnableForwardEvents(listener_sp); - bool update = true; + m_update_screen = true; #if defined(__APPLE__) std::deque<int> escape_chars; #endif while (!done) { - if (update) { + if (m_update_screen) { m_window_sp->Draw(false); // All windows should be calling Window::DeferredRefresh() instead of // Window::Refresh() so we can do a single update and avoid any screen @@ -1212,7 +1330,7 @@ public: m_window_sp->MoveCursor(0, 0); doupdate(); - update = false; + m_update_screen = false; } #if defined(__APPLE__) @@ -1274,7 +1392,7 @@ public: if (broadcaster_class == broadcaster_class_process) { debugger.GetCommandInterpreter().UpdateExecutionContext( nullptr); - update = true; + m_update_screen = true; continue; // Don't get any key, just update our view } } @@ -1286,9 +1404,13 @@ public: switch (key_result) { case eKeyHandled: debugger.GetCommandInterpreter().UpdateExecutionContext(nullptr); - update = true; + m_update_screen = true; break; case eKeyNotHandled: + if (ch == 12) { // Ctrl+L, force full redraw + redrawwin(m_window_sp->get()); + m_update_screen = true; + } break; case eQuitApplication: done = true; @@ -1306,12 +1428,65 @@ public: return m_window_sp; } + void TerminalSizeChanged() { + ::endwin(); + ::refresh(); + Rect content_bounds = m_window_sp->GetFrame(); + m_window_sp->SetBounds(content_bounds); + if (WindowSP menubar_window_sp = m_window_sp->FindSubWindow("Menubar")) + menubar_window_sp->SetBounds(content_bounds.MakeMenuBar()); + if (WindowSP status_window_sp = m_window_sp->FindSubWindow("Status")) + status_window_sp->SetBounds(content_bounds.MakeStatusBar()); + + WindowSP source_window_sp = m_window_sp->FindSubWindow("Source"); + WindowSP variables_window_sp = m_window_sp->FindSubWindow("Variables"); + WindowSP registers_window_sp = m_window_sp->FindSubWindow("Registers"); + WindowSP threads_window_sp = m_window_sp->FindSubWindow("Threads"); + + Rect threads_bounds; + Rect source_variables_bounds; + content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds, + threads_bounds); + if (threads_window_sp) + threads_window_sp->SetBounds(threads_bounds); + else + source_variables_bounds = content_bounds; + + Rect source_bounds; + Rect variables_registers_bounds; + source_variables_bounds.HorizontalSplitPercentage( + 0.70, source_bounds, variables_registers_bounds); + if (variables_window_sp || registers_window_sp) { + if (variables_window_sp && registers_window_sp) { + Rect variables_bounds; + Rect registers_bounds; + variables_registers_bounds.VerticalSplitPercentage( + 0.50, variables_bounds, registers_bounds); + variables_window_sp->SetBounds(variables_bounds); + registers_window_sp->SetBounds(registers_bounds); + } else if (variables_window_sp) { + variables_window_sp->SetBounds(variables_registers_bounds); + } else { + registers_window_sp->SetBounds(variables_registers_bounds); + } + } else { + source_bounds = source_variables_bounds; + } + + source_window_sp->SetBounds(source_bounds); + + touchwin(stdscr); + redrawwin(m_window_sp->get()); + m_update_screen = true; + } + protected: WindowSP m_window_sp; WindowDelegates m_window_delegates; SCREEN *m_screen; FILE *m_in; FILE *m_out; + bool m_update_screen = false; }; } // namespace curses @@ -1322,19 +1497,18 @@ struct Row { ValueObjectManager value; Row *parent; // The process stop ID when the children were calculated. - uint32_t children_stop_id; - int row_idx; - int x; - int y; + uint32_t children_stop_id = 0; + int row_idx = 0; + int x = 1; + int y = 1; bool might_have_children; - bool expanded; - bool calculated_children; + bool expanded = false; + bool calculated_children = false; std::vector<Row> children; Row(const ValueObjectSP &v, Row *p) - : value(v, lldb::eDynamicDontRunTarget, true), parent(p), row_idx(0), - x(1), y(1), might_have_children(v ? v->MightHaveChildren() : false), - expanded(false), calculated_children(false), children() {} + : value(v, lldb::eDynamicDontRunTarget, true), parent(p), + might_have_children(v ? v->MightHaveChildren() : false) {} size_t GetDepth() const { if (parent) @@ -1849,7 +2023,7 @@ public: if (FormatEntity::Format(m_format, strm, &sc, &exe_ctx, nullptr, nullptr, false, false)) { int right_pad = 1; - window.PutCStringTruncated(strm.GetString().str().c_str(), right_pad); + window.PutCStringTruncated(right_pad, strm.GetString().str().c_str()); } } } @@ -1908,7 +2082,7 @@ public: if (FormatEntity::Format(m_format, strm, nullptr, &exe_ctx, nullptr, nullptr, false, false)) { int right_pad = 1; - window.PutCStringTruncated(strm.GetString().str().c_str(), right_pad); + window.PutCStringTruncated(right_pad, strm.GetString().str().c_str()); } } } @@ -1998,7 +2172,7 @@ public: if (FormatEntity::Format(m_format, strm, nullptr, &exe_ctx, nullptr, nullptr, false, false)) { int right_pad = 1; - window.PutCStringTruncated(strm.GetString().str().c_str(), right_pad); + window.PutCStringTruncated(right_pad, strm.GetString().str().c_str()); } } } @@ -2301,29 +2475,29 @@ protected: window.AttributeOn(A_REVERSE); if (type_name && type_name[0]) - window.Printf("(%s) ", type_name); + window.PrintfTruncated(1, "(%s) ", type_name); if (name && name[0]) - window.PutCString(name); + window.PutCStringTruncated(1, name); attr_t changd_attr = 0; if (valobj->GetValueDidChange()) - changd_attr = COLOR_PAIR(5) | A_BOLD; + changd_attr = COLOR_PAIR(RedOnBlack) | A_BOLD; if (value && value[0]) { - window.PutCString(" = "); + window.PutCStringTruncated(1, " = "); if (changd_attr) window.AttributeOn(changd_attr); - window.PutCString(value); + window.PutCStringTruncated(1, value); if (changd_attr) window.AttributeOff(changd_attr); } if (summary && summary[0]) { - window.PutChar(' '); + window.PutCStringTruncated(1, " "); if (changd_attr) window.AttributeOn(changd_attr); - window.PutCString(summary); + window.PutCStringTruncated(1, summary); if (changd_attr) window.AttributeOff(changd_attr); } @@ -2761,7 +2935,7 @@ bool HelpDialogDelegate::WindowDelegateDraw(Window &window, bool force) { while (y <= max_y) { window.MoveCursor(x, y); window.PutCStringTruncated( - m_text.GetStringAtIndex(m_first_visible_line + y - min_y), 1); + 1, m_text.GetStringAtIndex(m_first_visible_line + y - min_y)); ++y; } return true; @@ -2831,7 +3005,8 @@ public: eMenuID_Process, eMenuID_ProcessAttach, - eMenuID_ProcessDetach, + eMenuID_ProcessDetachResume, + eMenuID_ProcessDetachSuspended, eMenuID_ProcessLaunch, eMenuID_ProcessContinue, eMenuID_ProcessHalt, @@ -2867,6 +3042,10 @@ public: window.SelectNextWindowAsActive(); return eKeyHandled; + case KEY_BTAB: + window.SelectPreviousWindowAsActive(); + return eKeyHandled; + case 'h': window.CreateHelpSubwindow(); return eKeyHandled; @@ -2891,6 +3070,7 @@ public: KeyHelp *WindowDelegateGetKeyHelp() override { static curses::KeyHelp g_source_view_key_help[] = { {'\t', "Select next view"}, + {KEY_BTAB, "Select previous view"}, {'h', "Show help dialog with view specific key bindings"}, {',', "Page up"}, {'.', "Page down"}, @@ -2976,13 +3156,15 @@ public: } return MenuActionResult::Handled; - case eMenuID_ProcessDetach: { + case eMenuID_ProcessDetachResume: + case eMenuID_ProcessDetachSuspended: { ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); if (exe_ctx.HasProcessScope()) { Process *process = exe_ctx.GetProcessPtr(); if (process && process->IsAlive()) - process->Detach(false); + process->Detach(menu.GetIdentifier() == + eMenuID_ProcessDetachSuspended); } } return MenuActionResult::Handled; @@ -3072,7 +3254,7 @@ public: new_registers_rect); registers_window_sp->SetBounds(new_registers_rect); } else { - // No variables window, grab the bottom part of the source window + // No registers window, grab the bottom part of the source window Rect new_source_rect; source_bounds.HorizontalSplitPercentage(0.70, new_source_rect, new_variables_rect); @@ -3123,7 +3305,7 @@ public: new_regs_rect); variables_window_sp->SetBounds(new_vars_rect); } else { - // No registers window, grab the bottom part of the source window + // No variables window, grab the bottom part of the source window Rect new_source_rect; source_bounds.HorizontalSplitPercentage(0.70, new_source_rect, new_regs_rect); @@ -3169,7 +3351,7 @@ public: Thread *thread = exe_ctx.GetThreadPtr(); StackFrame *frame = exe_ctx.GetFramePtr(); window.Erase(); - window.SetBackground(2); + window.SetBackground(BlackOnWhite); window.MoveCursor(0, 0); if (process) { const StateType state = process->GetState(); @@ -3181,7 +3363,7 @@ public: if (thread && FormatEntity::Format(m_format, strm, nullptr, &exe_ctx, nullptr, nullptr, false, false)) { window.MoveCursor(40, 0); - window.PutCStringTruncated(strm.GetString().str().c_str(), 1); + window.PutCStringTruncated(1, strm.GetString().str().c_str()); } window.MoveCursor(60, 0); @@ -3214,7 +3396,8 @@ public: m_disassembly_scope(nullptr), m_disassembly_sp(), m_disassembly_range(), m_title(), m_line_width(4), m_selected_line(0), m_pc_line(0), m_stop_id(0), m_frame_idx(UINT32_MAX), m_first_visible_line(0), - m_min_x(0), m_min_y(0), m_max_x(0), m_max_y(0) {} + m_first_visible_column(0), m_min_x(0), m_min_y(0), m_max_x(0), + m_max_y(0) {} ~SourceFileWindowDelegate() override = default; @@ -3231,19 +3414,21 @@ public: {KEY_RETURN, "Run to selected line with one shot breakpoint"}, {KEY_UP, "Select previous source line"}, {KEY_DOWN, "Select next source line"}, + {KEY_LEFT, "Scroll to the left"}, + {KEY_RIGHT, "Scroll to the right"}, {KEY_PPAGE, "Page up"}, {KEY_NPAGE, "Page down"}, {'b', "Set breakpoint on selected source/disassembly line"}, {'c', "Continue process"}, - {'d', "Detach and resume process"}, {'D', "Detach with process suspended"}, {'h', "Show help dialog"}, - {'k', "Kill process"}, {'n', "Step over (source line)"}, {'N', "Step over (single instruction)"}, - {'o', "Step out"}, + {'f', "Step out (finish)"}, {'s', "Step in (source line)"}, {'S', "Step in (single instruction)"}, + {'u', "Frame up"}, + {'d', "Frame down"}, {',', "Page up"}, {'.', "Page down"}, {'\0', nullptr}}; @@ -3407,7 +3592,7 @@ public: window.AttributeOn(A_REVERSE); window.MoveCursor(1, 1); window.PutChar(' '); - window.PutCStringTruncated(m_title.GetString().str().c_str(), 1); + window.PutCStringTruncated(1, m_title.GetString().str().c_str()); int x = window.GetCursorX(); if (x < window_width - 1) { window.Printf("%*s", window_width - x - 1, ""); @@ -3441,7 +3626,7 @@ public: } const attr_t selected_highlight_attr = A_REVERSE; - const attr_t pc_highlight_attr = COLOR_PAIR(1); + const attr_t pc_highlight_attr = COLOR_PAIR(BlackOnBlue); for (size_t i = 0; i < num_visible_lines; ++i) { const uint32_t curr_line = m_first_visible_line + i; @@ -3460,7 +3645,7 @@ public: highlight_attr = selected_highlight_attr; if (bp_lines.find(curr_line + 1) != bp_lines.end()) - bp_attr = COLOR_PAIR(2); + bp_attr = COLOR_PAIR(BlackOnWhite); if (bp_attr) window.AttributeOn(bp_attr); @@ -3479,10 +3664,21 @@ public: if (highlight_attr) window.AttributeOn(highlight_attr); - const uint32_t line_len = - m_file_sp->GetLineLength(curr_line + 1, false); - if (line_len > 0) - window.PutCString(m_file_sp->PeekLineData(curr_line + 1), line_len); + + StreamString lineStream; + m_file_sp->DisplaySourceLines(curr_line + 1, {}, 0, 0, &lineStream); + StringRef line = lineStream.GetString(); + if (line.endswith("\n")) + line = line.drop_back(); + bool wasWritten = window.OutputColoredStringTruncated( + 1, line, m_first_visible_column, line_is_selected); + if (line_is_selected && !wasWritten) { + // Draw an empty space to show the selected line if empty, + // or draw '<' if nothing is visible because of scrolling too much + // to the right. + window.PutCStringTruncated( + 1, line.empty() && m_first_visible_column == 0 ? " " : "<"); + } if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0) { @@ -3494,11 +3690,15 @@ public: if (stop_description && stop_description[0]) { size_t stop_description_len = strlen(stop_description); int desc_x = window_width - stop_description_len - 16; - window.Printf("%*s", desc_x - window.GetCursorX(), ""); - // window.MoveCursor(window_width - stop_description_len - 15, - // line_y); - window.Printf("<<< Thread %u: %s ", thread->GetIndexID(), - stop_description); + if (desc_x - window.GetCursorX() > 0) + window.Printf("%*s", desc_x - window.GetCursorX(), ""); + window.MoveCursor(window_width - stop_description_len - 16, + line_y); + const attr_t stop_reason_attr = COLOR_PAIR(WhiteOnBlue); + window.AttributeOn(stop_reason_attr); + window.PrintfTruncated(1, " <<< Thread %u: %s ", + thread->GetIndexID(), stop_description); + window.AttributeOff(stop_reason_attr); } } else { window.Printf("%*s", window_width - window.GetCursorX() - 1, ""); @@ -3538,7 +3738,7 @@ public: } const attr_t selected_highlight_attr = A_REVERSE; - const attr_t pc_highlight_attr = COLOR_PAIR(1); + const attr_t pc_highlight_attr = COLOR_PAIR(WhiteOnBlue); StreamString strm; @@ -3586,7 +3786,7 @@ public: if (bp_file_addrs.find(inst->GetAddress().GetFileAddress()) != bp_file_addrs.end()) - bp_attr = COLOR_PAIR(2); + bp_attr = COLOR_PAIR(BlackOnWhite); if (bp_attr) window.AttributeOn(bp_attr); @@ -3629,7 +3829,9 @@ public: strm.Printf("%s", mnemonic); int right_pad = 1; - window.PutCStringTruncated(strm.GetData(), right_pad); + window.PutCStringTruncated( + right_pad, + strm.GetString().substr(m_first_visible_column).data()); if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0) { @@ -3641,11 +3843,12 @@ public: if (stop_description && stop_description[0]) { size_t stop_description_len = strlen(stop_description); int desc_x = window_width - stop_description_len - 16; - window.Printf("%*s", desc_x - window.GetCursorX(), ""); - // window.MoveCursor(window_width - stop_description_len - 15, - // line_y); - window.Printf("<<< Thread %u: %s ", thread->GetIndexID(), - stop_description); + if (desc_x - window.GetCursorX() > 0) + window.Printf("%*s", desc_x - window.GetCursorX(), ""); + window.MoveCursor(window_width - stop_description_len - 15, + line_y); + window.PrintfTruncated(1, "<<< Thread %u: %s ", + thread->GetIndexID(), stop_description); } } else { window.Printf("%*s", window_width - window.GetCursorX() - 1, ""); @@ -3723,6 +3926,15 @@ public: } return eKeyHandled; + case KEY_LEFT: + if (m_first_visible_column > 0) + --m_first_visible_column; + return eKeyHandled; + + case KEY_RIGHT: + ++m_first_visible_column; + return eKeyHandled; + case '\r': case '\n': case KEY_ENTER: @@ -3767,59 +3979,18 @@ public: return eKeyHandled; case 'b': // 'b' == toggle breakpoint on currently selected line - if (m_selected_line < GetNumSourceLines()) { - ExecutionContext exe_ctx = - m_debugger.GetCommandInterpreter().GetExecutionContext(); - if (exe_ctx.HasTargetScope()) { - BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint( - nullptr, // Don't limit the breakpoint to certain modules - m_file_sp->GetFileSpec(), // Source file - m_selected_line + - 1, // Source line number (m_selected_line is zero based) - 0, // No column specified. - 0, // No offset - eLazyBoolCalculate, // Check inlines using global setting - eLazyBoolCalculate, // Skip prologue using global setting, - false, // internal - false, // request_hardware - eLazyBoolCalculate); // move_to_nearest_code - } - } else if (m_selected_line < GetNumDisassemblyLines()) { - const Instruction *inst = m_disassembly_sp->GetInstructionList() - .GetInstructionAtIndex(m_selected_line) - .get(); - ExecutionContext exe_ctx = - m_debugger.GetCommandInterpreter().GetExecutionContext(); - if (exe_ctx.HasTargetScope()) { - Address addr = inst->GetAddress(); - BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint( - addr, // lldb_private::Address - false, // internal - false); // request_hardware - } - } + ToggleBreakpointOnSelectedLine(); return eKeyHandled; - case 'd': // 'd' == detach and let run case 'D': // 'D' == detach and keep stopped { ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); if (exe_ctx.HasProcessScope()) - exe_ctx.GetProcessRef().Detach(c == 'D'); + exe_ctx.GetProcessRef().Detach(true); } return eKeyHandled; - case 'k': - // 'k' == kill - { - ExecutionContext exe_ctx = - m_debugger.GetCommandInterpreter().GetExecutionContext(); - if (exe_ctx.HasProcessScope()) - exe_ctx.GetProcessRef().Destroy(false); - } - return eKeyHandled; - case 'c': // 'c' == continue { @@ -3830,8 +4001,8 @@ public: } return eKeyHandled; - case 'o': - // 'o' == step out + case 'f': + // 'f' == step out (finish) { ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); @@ -3868,6 +4039,26 @@ public: } return eKeyHandled; + case 'u': // 'u' == frame up + case 'd': // 'd' == frame down + { + ExecutionContext exe_ctx = + m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasThreadScope()) { + Thread *thread = exe_ctx.GetThreadPtr(); + uint32_t frame_idx = thread->GetSelectedFrameIndex(); + if (frame_idx == UINT32_MAX) + frame_idx = 0; + if (c == 'u' && frame_idx + 1 < thread->GetStackFrameCount()) + ++frame_idx; + else if (c == 'd' && frame_idx > 0) + --frame_idx; + if (thread->SetSelectedFrameByIndex(frame_idx, true)) + exe_ctx.SetFrameSP(thread->GetSelectedFrame()); + } + } + return eKeyHandled; + case 'h': window.CreateHelpSubwindow(); return eKeyHandled; @@ -3878,6 +4069,85 @@ public: return eKeyNotHandled; } + void ToggleBreakpointOnSelectedLine() { + ExecutionContext exe_ctx = + m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (!exe_ctx.HasTargetScope()) + return; + if (GetNumSourceLines() > 0) { + // Source file breakpoint. + BreakpointList &bp_list = exe_ctx.GetTargetRef().GetBreakpointList(); + const size_t num_bps = bp_list.GetSize(); + for (size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) { + BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx); + const size_t num_bps_locs = bp_sp->GetNumLocations(); + for (size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) { + BreakpointLocationSP bp_loc_sp = + bp_sp->GetLocationAtIndex(bp_loc_idx); + LineEntry bp_loc_line_entry; + if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry( + bp_loc_line_entry)) { + if (m_file_sp->GetFileSpec() == bp_loc_line_entry.file && + m_selected_line + 1 == bp_loc_line_entry.line) { + bool removed = + exe_ctx.GetTargetRef().RemoveBreakpointByID(bp_sp->GetID()); + assert(removed); + UNUSED_IF_ASSERT_DISABLED(removed); + return; // Existing breakpoint removed. + } + } + } + } + // No breakpoint found on the location, add it. + BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint( + nullptr, // Don't limit the breakpoint to certain modules + m_file_sp->GetFileSpec(), // Source file + m_selected_line + + 1, // Source line number (m_selected_line is zero based) + 0, // No column specified. + 0, // No offset + eLazyBoolCalculate, // Check inlines using global setting + eLazyBoolCalculate, // Skip prologue using global setting, + false, // internal + false, // request_hardware + eLazyBoolCalculate); // move_to_nearest_code + } else { + // Disassembly breakpoint. + assert(GetNumDisassemblyLines() > 0); + assert(m_selected_line < GetNumDisassemblyLines()); + const Instruction *inst = m_disassembly_sp->GetInstructionList() + .GetInstructionAtIndex(m_selected_line) + .get(); + Address addr = inst->GetAddress(); + // Try to find it. + BreakpointList &bp_list = exe_ctx.GetTargetRef().GetBreakpointList(); + const size_t num_bps = bp_list.GetSize(); + for (size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) { + BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx); + const size_t num_bps_locs = bp_sp->GetNumLocations(); + for (size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) { + BreakpointLocationSP bp_loc_sp = + bp_sp->GetLocationAtIndex(bp_loc_idx); + LineEntry bp_loc_line_entry; + const lldb::addr_t file_addr = + bp_loc_sp->GetAddress().GetFileAddress(); + if (file_addr == addr.GetFileAddress()) { + bool removed = + exe_ctx.GetTargetRef().RemoveBreakpointByID(bp_sp->GetID()); + assert(removed); + UNUSED_IF_ASSERT_DISABLED(removed); + return; // Existing breakpoint removed. + } + } + } + // No breakpoint found on the address, add it. + BreakpointSP bp_sp = + exe_ctx.GetTargetRef().CreateBreakpoint(addr, // lldb_private::Address + false, // internal + false); // request_hardware + } + } + protected: typedef std::set<uint32_t> BreakpointLines; typedef std::set<lldb::addr_t> BreakpointAddrs; @@ -3896,6 +4166,7 @@ protected: uint32_t m_stop_id; uint32_t m_frame_idx; int m_first_visible_line; + int m_first_visible_column; int m_min_x; int m_min_y; int m_max_x; @@ -3939,8 +4210,12 @@ void IOHandlerCursesGUI::Activate() { ApplicationDelegate::eMenuID_Process)); process_menu_sp->AddSubmenu(MenuSP(new Menu( "Attach", nullptr, 'a', ApplicationDelegate::eMenuID_ProcessAttach))); - process_menu_sp->AddSubmenu(MenuSP(new Menu( - "Detach", nullptr, 'd', ApplicationDelegate::eMenuID_ProcessDetach))); + process_menu_sp->AddSubmenu( + MenuSP(new Menu("Detach and resume", nullptr, 'd', + ApplicationDelegate::eMenuID_ProcessDetachResume))); + process_menu_sp->AddSubmenu( + MenuSP(new Menu("Detach suspended", nullptr, 's', + ApplicationDelegate::eMenuID_ProcessDetachSuspended))); process_menu_sp->AddSubmenu(MenuSP(new Menu( "Launch", nullptr, 'l', ApplicationDelegate::eMenuID_ProcessLaunch))); process_menu_sp->AddSubmenu(MenuSP(new Menu(Menu::Type::Separator))); @@ -4042,11 +4317,28 @@ void IOHandlerCursesGUI::Activate() { main_window_sp->CreateHelpSubwindow(); } - init_pair(1, COLOR_WHITE, COLOR_BLUE); - init_pair(2, COLOR_BLACK, COLOR_WHITE); - init_pair(3, COLOR_MAGENTA, COLOR_WHITE); - init_pair(4, COLOR_MAGENTA, COLOR_BLACK); - init_pair(5, COLOR_RED, COLOR_BLACK); + // All colors with black background. + init_pair(1, COLOR_BLACK, COLOR_BLACK); + init_pair(2, COLOR_RED, COLOR_BLACK); + init_pair(3, COLOR_GREEN, COLOR_BLACK); + init_pair(4, COLOR_YELLOW, COLOR_BLACK); + init_pair(5, COLOR_BLUE, COLOR_BLACK); + init_pair(6, COLOR_MAGENTA, COLOR_BLACK); + init_pair(7, COLOR_CYAN, COLOR_BLACK); + init_pair(8, COLOR_WHITE, COLOR_BLACK); + // All colors with blue background. + init_pair(9, COLOR_BLACK, COLOR_BLUE); + init_pair(10, COLOR_RED, COLOR_BLUE); + init_pair(11, COLOR_GREEN, COLOR_BLUE); + init_pair(12, COLOR_YELLOW, COLOR_BLUE); + init_pair(13, COLOR_BLUE, COLOR_BLUE); + init_pair(14, COLOR_MAGENTA, COLOR_BLUE); + init_pair(15, COLOR_CYAN, COLOR_BLUE); + init_pair(16, COLOR_WHITE, COLOR_BLUE); + // These must match the order in the color indexes enum. + init_pair(17, COLOR_BLACK, COLOR_WHITE); + init_pair(18, COLOR_MAGENTA, COLOR_WHITE); + static_assert(LastColorPairIndex == 18, "Color indexes do not match."); } } @@ -4065,4 +4357,8 @@ bool IOHandlerCursesGUI::Interrupt() { return false; } void IOHandlerCursesGUI::GotEOF() {} +void IOHandlerCursesGUI::TerminalSizeChanged() { + m_app_ap->TerminalSizeChanged(); +} + #endif // LLDB_ENABLE_CURSES diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp index 143ec8770bf4..627be94a303c 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -14,7 +14,6 @@ #include "lldb/Utility/Logging.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" -#include "lldb/Utility/Timer.h" #include "lldb/lldb-enumerations.h" #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" @@ -227,12 +226,6 @@ static char *GetItaniumDemangledStr(const char *M) { // makes use of ItaniumPartialDemangler's rich demangle info bool Mangled::DemangleWithRichManglingInfo( RichManglingContext &context, SkipMangledNameFn *skip_mangled_name) { - // We need to generate and cache the demangled name. - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "Mangled::DemangleWithRichNameIndexInfo (m_mangled = %s)", - m_mangled.GetCString()); - // Others are not meant to arrive here. ObjC names or C's main() for example // have their names stored in m_demangled, while m_mangled is empty. assert(m_mangled); @@ -298,11 +291,6 @@ ConstString Mangled::GetDemangledName() const { // Check to make sure we have a valid mangled name and that we haven't // already decoded our mangled name. if (m_mangled && m_demangled.IsNull()) { - // We need to generate and cache the demangled name. - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "Mangled::GetDemangledName (m_mangled = %s)", - m_mangled.GetCString()); - // Don't bother running anything that isn't mangled const char *mangled_name = m_mangled.GetCString(); ManglingScheme mangling_scheme = GetManglingScheme(m_mangled.GetStringRef()); diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index b76659ee3e07..1f9987c21658 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -419,8 +419,7 @@ void Module::DumpSymbolContext(Stream *s) { size_t Module::GetNumCompileUnits() { std::lock_guard<std::recursive_mutex> guard(m_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "Module::GetNumCompileUnits (module = %p)", + LLDB_SCOPED_TIMERF("Module::GetNumCompileUnits (module = %p)", static_cast<void *>(this)); if (SymbolFile *symbols = GetSymbolFile()) return symbols->GetNumCompileUnits(); @@ -441,9 +440,7 @@ CompUnitSP Module::GetCompileUnitAtIndex(size_t index) { bool Module::ResolveFileAddress(lldb::addr_t vm_addr, Address &so_addr) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "Module::ResolveFileAddress (vm_addr = 0x%" PRIx64 ")", + LLDB_SCOPED_TIMERF("Module::ResolveFileAddress (vm_addr = 0x%" PRIx64 ")", vm_addr); SectionList *section_list = GetSectionList(); if (section_list) @@ -594,9 +591,7 @@ uint32_t Module::ResolveSymbolContextsForFileSpec( const FileSpec &file_spec, uint32_t line, bool check_inlines, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "Module::ResolveSymbolContextForFilePath (%s:%u, " + LLDB_SCOPED_TIMERF("Module::ResolveSymbolContextForFilePath (%s:%u, " "check_inlines = %s, resolve_scope = 0x%8.8x)", file_spec.GetPath().c_str(), line, check_inlines ? "yes" : "no", resolve_scope); @@ -940,8 +935,7 @@ void Module::FindTypes_Impl( size_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap &types) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); if (SymbolFile *symbols = GetSymbolFile()) symbols->FindTypes(name, parent_decl_ctx, max_matches, searched_symbol_files, types); @@ -1028,8 +1022,7 @@ void Module::FindTypes( llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap &types) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); if (SymbolFile *symbols = GetSymbolFile()) symbols->FindTypes(pattern, languages, searched_symbol_files, types); } @@ -1040,8 +1033,7 @@ SymbolFile *Module::GetSymbolFile(bool can_create, Stream *feedback_strm) { if (!m_did_load_symfile.load() && can_create) { ObjectFile *obj_file = GetObjectFile(); if (obj_file != nullptr) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); m_symfile_up.reset( SymbolVendor::FindPlugin(shared_from_this(), feedback_strm)); m_did_load_symfile = true; @@ -1244,8 +1236,7 @@ ObjectFile *Module::GetObjectFile() { if (!m_did_load_objfile.load()) { std::lock_guard<std::recursive_mutex> guard(m_mutex); if (!m_did_load_objfile.load()) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "Module::GetObjectFile () module = %s", + LLDB_SCOPED_TIMERF("Module::GetObjectFile () module = %s", GetFileSpec().GetFilename().AsCString("")); lldb::offset_t data_offset = 0; lldb::offset_t file_size = 0; @@ -1312,9 +1303,8 @@ SectionList *Module::GetUnifiedSectionList() { const Symbol *Module::FindFirstSymbolWithNameAndType(ConstString name, SymbolType symbol_type) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, "Module::FindFirstSymbolWithNameAndType (name = %s, type = %i)", + LLDB_SCOPED_TIMERF( + "Module::FindFirstSymbolWithNameAndType (name = %s, type = %i)", name.AsCString(), symbol_type); if (Symtab *symtab = GetSymtab()) return symtab->FindFirstSymbolWithNameAndType( @@ -1342,9 +1332,7 @@ void Module::SymbolIndicesToSymbolContextList( void Module::FindFunctionSymbols(ConstString name, uint32_t name_type_mask, SymbolContextList &sc_list) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "Module::FindSymbolsFunctions (name = %s, mask = 0x%8.8x)", + LLDB_SCOPED_TIMERF("Module::FindSymbolsFunctions (name = %s, mask = 0x%8.8x)", name.AsCString(), name_type_mask); if (Symtab *symtab = GetSymtab()) symtab->FindFunctionSymbols(name, name_type_mask, sc_list); @@ -1355,10 +1343,8 @@ void Module::FindSymbolsWithNameAndType(ConstString name, SymbolContextList &sc_list) { // No need to protect this call using m_mutex all other method calls are // already thread safe. - - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, "Module::FindSymbolsWithNameAndType (name = %s, type = %i)", + LLDB_SCOPED_TIMERF( + "Module::FindSymbolsWithNameAndType (name = %s, type = %i)", name.AsCString(), symbol_type); if (Symtab *symtab = GetSymtab()) { std::vector<uint32_t> symbol_indexes; @@ -1372,10 +1358,7 @@ void Module::FindSymbolsMatchingRegExAndType(const RegularExpression ®ex, SymbolContextList &sc_list) { // No need to protect this call using m_mutex all other method calls are // already thread safe. - - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, + LLDB_SCOPED_TIMERF( "Module::FindSymbolsMatchingRegExAndType (regex = %s, type = %i)", regex.GetText().str().c_str(), symbol_type); if (Symtab *symtab = GetSymtab()) { diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 0345678ddaff..98f6ae2c62b0 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -82,8 +82,9 @@ ModuleListProperties::ModuleListProperties() { [this] { UpdateSymlinkMappings(); }); llvm::SmallString<128> path; - clang::driver::Driver::getDefaultModuleCachePath(path); - SetClangModulesCachePath(path); + if (clang::driver::Driver::getDefaultModuleCachePath(path)) { + lldbassert(SetClangModulesCachePath(FileSpec(path))); + } } bool ModuleListProperties::GetEnableExternalLookup() const { @@ -104,8 +105,8 @@ FileSpec ModuleListProperties::GetClangModulesCachePath() const { ->GetCurrentValue(); } -bool ModuleListProperties::SetClangModulesCachePath(llvm::StringRef path) { - return m_collection_sp->SetPropertyAtIndexAsString( +bool ModuleListProperties::SetClangModulesCachePath(const FileSpec &path) { + return m_collection_sp->SetPropertyAtIndexAsFileSpec( nullptr, ePropertyClangModulesCachePath, path); } @@ -171,7 +172,9 @@ void ModuleList::Append(const ModuleSP &module_sp, bool notify) { AppendImpl(module_sp, notify); } -void ModuleList::ReplaceEquivalent(const ModuleSP &module_sp) { +void ModuleList::ReplaceEquivalent( + const ModuleSP &module_sp, + llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules) { if (module_sp) { std::lock_guard<std::recursive_mutex> guard(m_modules_mutex); @@ -184,11 +187,14 @@ void ModuleList::ReplaceEquivalent(const ModuleSP &module_sp) { size_t idx = 0; while (idx < m_modules.size()) { - ModuleSP module_sp(m_modules[idx]); - if (module_sp->MatchesModuleSpec(equivalent_module_spec)) + ModuleSP test_module_sp(m_modules[idx]); + if (test_module_sp->MatchesModuleSpec(equivalent_module_spec)) { + if (old_modules) + old_modules->push_back(test_module_sp); RemoveImpl(m_modules.begin() + idx); - else + } else { ++idx; + } } // Now add the new module to the list Append(module_sp); @@ -291,14 +297,24 @@ size_t ModuleList::RemoveOrphans(bool mandatory) { if (!lock.try_lock()) return 0; } - collection::iterator pos = m_modules.begin(); size_t remove_count = 0; - while (pos != m_modules.end()) { - if (pos->unique()) { - pos = RemoveImpl(pos); - ++remove_count; - } else { - ++pos; + // Modules might hold shared pointers to other modules, so removing one + // module might make other other modules orphans. Keep removing modules until + // there are no further modules that can be removed. + bool made_progress = true; + while (made_progress) { + // Keep track if we make progress this iteration. + made_progress = false; + collection::iterator pos = m_modules.begin(); + while (pos != m_modules.end()) { + if (pos->unique()) { + pos = RemoveImpl(pos); + ++remove_count; + // We did make progress. + made_progress = true; + } else { + ++pos; + } } } return remove_count; @@ -330,10 +346,6 @@ void ModuleList::ClearImpl(bool use_notifier) { Module *ModuleList::GetModulePointerAtIndex(size_t idx) const { std::lock_guard<std::recursive_mutex> guard(m_modules_mutex); - return GetModulePointerAtIndexUnlocked(idx); -} - -Module *ModuleList::GetModulePointerAtIndexUnlocked(size_t idx) const { if (idx < m_modules.size()) return m_modules[idx].get(); return nullptr; @@ -731,11 +743,11 @@ size_t ModuleList::RemoveOrphanSharedModules(bool mandatory) { return GetSharedModuleList().RemoveOrphans(mandatory); } -Status ModuleList::GetSharedModule(const ModuleSpec &module_spec, - ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, - ModuleSP *old_module_sp_ptr, - bool *did_create_ptr, bool always_create) { +Status +ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, + bool *did_create_ptr, bool always_create) { ModuleList &shared_module_list = GetSharedModuleList(); std::lock_guard<std::recursive_mutex> guard( shared_module_list.m_modules_mutex); @@ -747,8 +759,6 @@ Status ModuleList::GetSharedModule(const ModuleSpec &module_spec, if (did_create_ptr) *did_create_ptr = false; - if (old_module_sp_ptr) - old_module_sp_ptr->reset(); const UUID *uuid_ptr = module_spec.GetUUIDPtr(); const FileSpec &module_file_spec = module_spec.GetFileSpec(); @@ -769,8 +779,8 @@ Status ModuleList::GetSharedModule(const ModuleSpec &module_spec, // Make sure the file for the module hasn't been modified if (module_sp->FileHasChanged()) { - if (old_module_sp_ptr && !*old_module_sp_ptr) - *old_module_sp_ptr = module_sp; + if (old_modules) + old_modules->push_back(module_sp); Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_MODULES)); if (log != nullptr) @@ -812,7 +822,7 @@ Status ModuleList::GetSharedModule(const ModuleSpec &module_spec, *did_create_ptr = true; } - shared_module_list.ReplaceEquivalent(module_sp); + shared_module_list.ReplaceEquivalent(module_sp, old_modules); return error; } } @@ -849,7 +859,7 @@ Status ModuleList::GetSharedModule(const ModuleSpec &module_spec, if (did_create_ptr) *did_create_ptr = true; - shared_module_list.ReplaceEquivalent(module_sp); + shared_module_list.ReplaceEquivalent(module_sp, old_modules); return Status(); } } @@ -924,8 +934,8 @@ Status ModuleList::GetSharedModule(const ModuleSpec &module_spec, located_binary_modulespec.GetFileSpec()); if (file_spec_mod_time != llvm::sys::TimePoint<>()) { if (file_spec_mod_time != module_sp->GetModificationTime()) { - if (old_module_sp_ptr) - *old_module_sp_ptr = module_sp; + if (old_modules) + old_modules->push_back(module_sp); shared_module_list.Remove(module_sp); module_sp.reset(); } @@ -947,7 +957,7 @@ Status ModuleList::GetSharedModule(const ModuleSpec &module_spec, if (did_create_ptr) *did_create_ptr = true; - shared_module_list.ReplaceEquivalent(module_sp); + shared_module_list.ReplaceEquivalent(module_sp, old_modules); } } else { located_binary_modulespec.GetFileSpec().GetPath(path, sizeof(path)); @@ -968,7 +978,7 @@ Status ModuleList::GetSharedModule(const ModuleSpec &module_spec, error.SetErrorStringWithFormat( "cannot locate a module for UUID '%s'", uuid_str.c_str()); else - error.SetErrorStringWithFormat("cannot locate a module"); + error.SetErrorString("cannot locate a module"); } } } diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp index 3545ef66cc38..97e1e8d14039 100644 --- a/lldb/source/Core/PluginManager.cpp +++ b/lldb/source/Core/PluginManager.cpp @@ -264,12 +264,13 @@ public: const std::vector<Instance> &GetInstances() const { return m_instances; } std::vector<Instance> &GetInstances() { return m_instances; } -private: Instance *GetInstanceAtIndex(uint32_t idx) { if (idx < m_instances.size()) return &m_instances[idx]; return nullptr; } + +private: std::vector<Instance> m_instances; }; @@ -1005,6 +1006,67 @@ PluginManager::GetSymbolVendorCreateCallbackAtIndex(uint32_t idx) { return GetSymbolVendorInstances().GetCallbackAtIndex(idx); } +#pragma mark Trace + +struct TraceInstance : public PluginInstance<TraceCreateInstance> { + TraceInstance(ConstString name, std::string description, + CallbackType create_callback, llvm::StringRef schema, + TraceGetStartCommand get_start_command) + : PluginInstance<TraceCreateInstance>(name, std::move(description), + create_callback), + schema(schema), get_start_command(get_start_command) {} + + llvm::StringRef schema; + TraceGetStartCommand get_start_command; +}; + +typedef PluginInstances<TraceInstance> TraceInstances; + +static TraceInstances &GetTracePluginInstances() { + static TraceInstances g_instances; + return g_instances; +} + +bool PluginManager::RegisterPlugin(ConstString name, const char *description, + TraceCreateInstance create_callback, + llvm::StringRef schema, + TraceGetStartCommand get_start_command) { + return GetTracePluginInstances().RegisterPlugin( + name, description, create_callback, schema, get_start_command); +} + +bool PluginManager::UnregisterPlugin(TraceCreateInstance create_callback) { + return GetTracePluginInstances().UnregisterPlugin(create_callback); +} + +TraceCreateInstance +PluginManager::GetTraceCreateCallback(ConstString plugin_name) { + return GetTracePluginInstances().GetCallbackForName(plugin_name); +} + +llvm::StringRef PluginManager::GetTraceSchema(ConstString plugin_name) { + for (const TraceInstance &instance : GetTracePluginInstances().GetInstances()) + if (instance.name == plugin_name) + return instance.schema; + return llvm::StringRef(); +} + +CommandObjectSP +PluginManager::GetTraceStartCommand(llvm::StringRef plugin_name, + CommandInterpreter &interpreter) { + for (const TraceInstance &instance : GetTracePluginInstances().GetInstances()) + if (instance.name.GetStringRef() == plugin_name) + return instance.get_start_command(interpreter); + return CommandObjectSP(); +} + +llvm::StringRef PluginManager::GetTraceSchema(size_t index) { + if (TraceInstance *instance = + GetTracePluginInstances().GetInstanceAtIndex(index)) + return instance->schema; + return llvm::StringRef(); +} + #pragma mark UnwindAssembly typedef PluginInstance<UnwindAssemblyCreateInstance> UnwindAssemblyInstance; @@ -1218,6 +1280,7 @@ void PluginManager::DebuggerInitialize(Debugger &debugger) { GetSymbolFileInstances().PerformDebuggerCallback(debugger); GetOperatingSystemInstances().PerformDebuggerCallback(debugger); GetStructuredDataPluginInstances().PerformDebuggerCallback(debugger); + GetTracePluginInstances().PerformDebuggerCallback(debugger); } // This is the preferred new way to register plugin specific settings. e.g. diff --git a/lldb/source/Core/SearchFilter.cpp b/lldb/source/Core/SearchFilter.cpp index ea51fb379181..e3327ff5e750 100644 --- a/lldb/source/Core/SearchFilter.cpp +++ b/lldb/source/Core/SearchFilter.cpp @@ -89,7 +89,7 @@ SearchFilterSP SearchFilter::CreateFromStructuredData( bool success = filter_dict.GetValueForKeyAsString( GetSerializationSubclassKey(), subclass_name); if (!success) { - error.SetErrorStringWithFormat("Filter data missing subclass key"); + error.SetErrorString("Filter data missing subclass key"); return result_sp; } @@ -228,11 +228,7 @@ void SearchFilter::SearchInModuleList(Searcher &searcher, ModuleList &modules) { return; } - std::lock_guard<std::recursive_mutex> guard(modules.GetMutex()); - const size_t numModules = modules.GetSize(); - - for (size_t i = 0; i < numModules; i++) { - ModuleSP module_sp(modules.GetModuleAtIndexUnlocked(i)); + for (ModuleSP module_sp : modules.Modules()) { if (!ModulePasses(module_sp)) continue; if (DoModuleIteration(module_sp, searcher) == Searcher::eCallbackReturnStop) @@ -262,14 +258,9 @@ SearchFilter::DoModuleIteration(const SymbolContext &context, return Searcher::eCallbackReturnContinue; } - const ModuleList &target_images = m_target_sp->GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); - - size_t n_modules = target_images.GetSize(); - for (size_t i = 0; i < n_modules; i++) { + for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { // If this is the last level supplied, then call the callback directly, // otherwise descend. - ModuleSP module_sp(target_images.GetModuleAtIndexUnlocked(i)); if (!ModulePasses(module_sp)) continue; @@ -434,11 +425,9 @@ void SearchFilterByModule::Search(Searcher &searcher) { const ModuleList &target_modules = m_target_sp->GetImages(); std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); - const size_t num_modules = target_modules.GetSize(); - for (size_t i = 0; i < num_modules; i++) { - Module *module = target_modules.GetModulePointerAtIndexUnlocked(i); - if (FileSpec::Match(m_module_spec, module->GetFileSpec())) { - SymbolContext matchingContext(m_target_sp, module->shared_from_this()); + for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { + if (FileSpec::Match(m_module_spec, module_sp->GetFileSpec())) { + SymbolContext matchingContext(m_target_sp, module_sp); Searcher::CallbackReturn shouldContinue; shouldContinue = DoModuleIteration(matchingContext, searcher); @@ -550,17 +539,11 @@ void SearchFilterByModuleList::Search(Searcher &searcher) { // If the module file spec is a full path, then we can just find the one // filespec that passes. Otherwise, we need to go through all modules and // find the ones that match the file name. - - const ModuleList &target_modules = m_target_sp->GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); - - const size_t num_modules = target_modules.GetSize(); - for (size_t i = 0; i < num_modules; i++) { - Module *module = target_modules.GetModulePointerAtIndexUnlocked(i); - if (m_module_spec_list.FindFileIndex(0, module->GetFileSpec(), false) == + for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { + if (m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) == UINT32_MAX) continue; - SymbolContext matchingContext(m_target_sp, module->shared_from_this()); + SymbolContext matchingContext(m_target_sp, module_sp); Searcher::CallbackReturn shouldContinue; shouldContinue = DoModuleIteration(matchingContext, searcher); @@ -752,13 +735,9 @@ void SearchFilterByModuleListAndCU::Search(Searcher &searcher) { // find the ones that match the file name. ModuleList matching_modules; - const ModuleList &target_images = m_target_sp->GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); - const size_t num_modules = target_images.GetSize(); bool no_modules_in_filter = m_module_spec_list.GetSize() == 0; - for (size_t i = 0; i < num_modules; i++) { - lldb::ModuleSP module_sp = target_images.GetModuleAtIndexUnlocked(i); + for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { if (!no_modules_in_filter && m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) == UINT32_MAX) diff --git a/lldb/source/Core/SourceManager.cpp b/lldb/source/Core/SourceManager.cpp index 7414dd281d43..e79fcb48742d 100644 --- a/lldb/source/Core/SourceManager.cpp +++ b/lldb/source/Core/SourceManager.cpp @@ -183,14 +183,14 @@ size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile( break; } - char prefix[32] = ""; + std::string prefix; if (bp_locs) { uint32_t bp_count = bp_locs->NumLineEntriesWithLine(line); if (bp_count > 0) - ::snprintf(prefix, sizeof(prefix), "[%u] ", bp_count); + prefix = llvm::formatv("[{0}]", bp_count); else - ::snprintf(prefix, sizeof(prefix), " "); + prefix = " "; } char buffer[3]; @@ -206,7 +206,8 @@ size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile( .str()); } - s->Printf("%s%s %-4u\t", prefix, current_line_highlight.c_str(), line); + s->Printf("%s%s %-4u\t", prefix.c_str(), current_line_highlight.c_str(), + line); // So far we treated column 0 as a special 'no column value', but // DisplaySourceLines starts counting columns from 0 (and no column is diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp index 63467644cdef..cc8f3f4e2615 100644 --- a/lldb/source/Core/Value.cpp +++ b/lldb/source/Core/Value.cpp @@ -39,27 +39,26 @@ using namespace lldb; using namespace lldb_private; Value::Value() - : m_value(), m_vector(), m_compiler_type(), m_context(nullptr), + : m_value(), m_compiler_type(), m_context(nullptr), m_value_type(eValueTypeScalar), m_context_type(eContextTypeInvalid), m_data_buffer() {} Value::Value(const Scalar &scalar) - : m_value(scalar), m_vector(), m_compiler_type(), m_context(nullptr), + : m_value(scalar), m_compiler_type(), m_context(nullptr), m_value_type(eValueTypeScalar), m_context_type(eContextTypeInvalid), m_data_buffer() {} Value::Value(const void *bytes, int len) - : m_value(), m_vector(), m_compiler_type(), m_context(nullptr), + : m_value(), m_compiler_type(), m_context(nullptr), m_value_type(eValueTypeHostAddress), m_context_type(eContextTypeInvalid), m_data_buffer() { SetBytes(bytes, len); } Value::Value(const Value &v) - : m_value(v.m_value), m_vector(v.m_vector), - m_compiler_type(v.m_compiler_type), m_context(v.m_context), - m_value_type(v.m_value_type), m_context_type(v.m_context_type), - m_data_buffer() { + : m_value(v.m_value), m_compiler_type(v.m_compiler_type), + m_context(v.m_context), m_value_type(v.m_value_type), + m_context_type(v.m_context_type), m_data_buffer() { const uintptr_t rhs_value = (uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS); if ((rhs_value != 0) && @@ -74,7 +73,6 @@ Value::Value(const Value &v) Value &Value::operator=(const Value &rhs) { if (this != &rhs) { m_value = rhs.m_value; - m_vector = rhs.m_vector; m_compiler_type = rhs.m_compiler_type; m_context = rhs.m_context; m_value_type = rhs.m_value_type; @@ -115,7 +113,6 @@ Value::ValueType Value::GetValueType() const { return m_value_type; } AddressType Value::GetValueAddressType() const { switch (m_value_type) { - default: case eValueTypeScalar: break; case eValueTypeLoadAddress: @@ -159,17 +156,6 @@ size_t Value::AppendDataToHostBuffer(const Value &rhs) { } } } break; - case eValueTypeVector: { - const size_t vector_size = rhs.m_vector.length; - if (vector_size > 0) { - const size_t new_size = curr_size + vector_size; - if (ResizeData(new_size) == new_size) { - ::memcpy(m_data_buffer.GetBytes() + curr_size, rhs.m_vector.bytes, - vector_size); - return vector_size; - } - } - } break; case eValueTypeFileAddress: case eValueTypeLoadAddress: case eValueTypeHostAddress: { @@ -291,9 +277,6 @@ lldb::Format Value::GetValueDefaultFormat() { bool Value::GetData(DataExtractor &data) { switch (m_value_type) { - default: - break; - case eValueTypeScalar: if (m_value.GetData(data)) return true; @@ -329,14 +312,6 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, return error; switch (m_value_type) { - case eValueTypeVector: - if (ast_type.IsValid()) - data.SetAddressByteSize(ast_type.GetPointerByteSize()); - else - data.SetAddressByteSize(sizeof(void *)); - data.SetData(m_vector.bytes, m_vector.length, m_vector.byte_order); - break; - case eValueTypeScalar: { data.SetByteOrder(endian::InlHostByteOrder()); if (ast_type.IsValid()) @@ -354,7 +329,7 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, return error; // Success; } - error.SetErrorStringWithFormat("extracting data from value failed"); + error.SetErrorString("extracting data from value failed"); break; } case eValueTypeLoadAddress: @@ -535,8 +510,7 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, if (address_type == eAddressTypeHost) { // The address is an address in this process, so just copy it. if (address == 0) { - error.SetErrorStringWithFormat( - "trying to read from host address of 0."); + error.SetErrorString("trying to read from host address of 0."); return error; } memcpy(dst, reinterpret_cast<uint8_t *>(address), byte_size); @@ -580,7 +554,7 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, address_type); } } else { - error.SetErrorStringWithFormat("out of memory"); + error.SetErrorString("out of memory"); } return error; @@ -593,7 +567,6 @@ Scalar &Value::ResolveValue(ExecutionContext *exe_ctx) { case eValueTypeScalar: // raw scalar value break; - default: case eValueTypeFileAddress: case eValueTypeLoadAddress: // load address value case eValueTypeHostAddress: // host address value (for memory in the process @@ -604,8 +577,9 @@ Scalar &Value::ResolveValue(ExecutionContext *exe_ctx) { Status error(GetValueAsData(exe_ctx, data, nullptr)); if (error.Success()) { Scalar scalar; - if (compiler_type.GetValueAsScalar(data, 0, data.GetByteSize(), - scalar)) { + if (compiler_type.GetValueAsScalar( + data, 0, data.GetByteSize(), scalar, + exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr)) { m_value = scalar; m_value_type = eValueTypeScalar; } else { @@ -634,7 +608,6 @@ Variable *Value::GetVariable() { void Value::Clear() { m_value.Clear(); - m_vector.Clear(); m_compiler_type.Clear(); m_value_type = eValueTypeScalar; m_context = nullptr; @@ -646,8 +619,6 @@ const char *Value::GetValueTypeAsCString(ValueType value_type) { switch (value_type) { case eValueTypeScalar: return "scalar"; - case eValueTypeVector: - return "vector"; case eValueTypeFileAddress: return "file address"; case eValueTypeLoadAddress: diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 3a775b07e5e1..da90092336d6 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -337,7 +337,6 @@ const char *ValueObject::GetLocationAsCStringImpl(const Value &value, switch (value_type) { case Value::eValueTypeScalar: - case Value::eValueTypeVector: if (value.GetContextType() == Value::eContextTypeRegisterInfo) { RegisterInfo *reg_info = value.GetRegisterInfo(); if (reg_info) { @@ -352,8 +351,7 @@ const char *ValueObject::GetLocationAsCStringImpl(const Value &value, } } if (m_location_str.empty()) - m_location_str = - (value_type == Value::eValueTypeVector) ? "vector" : "scalar"; + m_location_str = "scalar"; break; case Value::eValueTypeLoadAddress: @@ -849,7 +847,7 @@ bool ValueObject::SetData(DataExtractor &data, Status &error) { uint64_t count = 0; const Encoding encoding = GetCompilerType().GetEncoding(count); - const size_t byte_size = GetByteSize(); + const size_t byte_size = GetByteSize().getValueOr(0); Value::ValueType value_type = m_value.GetValueType(); @@ -892,7 +890,6 @@ bool ValueObject::SetData(DataExtractor &data, Status &error) { m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); } break; case Value::eValueTypeFileAddress: - case Value::eValueTypeVector: break; } @@ -1459,7 +1456,6 @@ addr_t ValueObject::GetAddressOf(bool scalar_is_load_address, switch (m_value.GetValueType()) { case Value::eValueTypeScalar: - case Value::eValueTypeVector: if (scalar_is_load_address) { if (address_type) *address_type = eAddressTypeLoad; @@ -1494,7 +1490,6 @@ addr_t ValueObject::GetPointerValue(AddressType *address_type) { switch (m_value.GetValueType()) { case Value::eValueTypeScalar: - case Value::eValueTypeVector: address = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); break; @@ -1524,7 +1519,7 @@ bool ValueObject::SetValueFromCString(const char *value_str, Status &error) { uint64_t count = 0; const Encoding encoding = GetCompilerType().GetEncoding(count); - const size_t byte_size = GetByteSize(); + const size_t byte_size = GetByteSize().getValueOr(0); Value::ValueType value_type = m_value.GetValueType(); @@ -1577,7 +1572,6 @@ bool ValueObject::SetValueFromCString(const char *value_str, Status &error) { } break; case Value::eValueTypeFileAddress: case Value::eValueTypeScalar: - case Value::eValueTypeVector: break; } } else { @@ -1702,8 +1696,7 @@ ValueObjectSP ValueObject::GetSyntheticArrayMember(size_t index, bool can_create) { ValueObjectSP synthetic_child_sp; if (IsPointerType() || IsArrayType()) { - char index_str[64]; - snprintf(index_str, sizeof(index_str), "[%" PRIu64 "]", (uint64_t)index); + std::string index_str = llvm::formatv("[{0}]", index); ConstString index_const_str(index_str); // Check if we have already created a synthetic array member in this valid // object. If we have we will re-use it. @@ -1730,8 +1723,7 @@ ValueObjectSP ValueObject::GetSyntheticBitFieldChild(uint32_t from, uint32_t to, bool can_create) { ValueObjectSP synthetic_child_sp; if (IsScalarType()) { - char index_str[64]; - snprintf(index_str, sizeof(index_str), "[%i-%i]", from, to); + std::string index_str = llvm::formatv("[{0}-{1}]", from, to); ConstString index_const_str(index_str); // Check if we have already created a synthetic array member in this valid // object. If we have we will re-use it. @@ -1741,13 +1733,13 @@ ValueObjectSP ValueObject::GetSyntheticBitFieldChild(uint32_t from, uint32_t to, uint32_t bit_field_offset = from; if (GetDataExtractor().GetByteOrder() == eByteOrderBig) bit_field_offset = - GetByteSize() * 8 - bit_field_size - bit_field_offset; + GetByteSize().getValueOr(0) * 8 - bit_field_size - bit_field_offset; // We haven't made a synthetic array member for INDEX yet, so lets make // one and cache it for any future reference. ValueObjectChild *synthetic_child = new ValueObjectChild( - *this, GetCompilerType(), index_const_str, GetByteSize(), 0, - bit_field_size, bit_field_offset, false, false, eAddressTypeInvalid, - 0); + *this, GetCompilerType(), index_const_str, + GetByteSize().getValueOr(0), 0, bit_field_size, bit_field_offset, + false, false, eAddressTypeInvalid, 0); // Cache the value if we got one back... if (synthetic_child) { @@ -1768,9 +1760,7 @@ ValueObjectSP ValueObject::GetSyntheticChildAtOffset( ValueObjectSP synthetic_child_sp; if (name_const_str.IsEmpty()) { - char name_str[64]; - snprintf(name_str, sizeof(name_str), "@%i", offset); - name_const_str.SetCString(name_str); + name_const_str.SetString("@" + std::to_string(offset)); } // Check if we have already created a synthetic array member in this valid @@ -3215,7 +3205,7 @@ bool ValueObject::CanProvideValue() { // we need to support invalid types as providers of values because some bare- // board debugging scenarios have no notion of types, but still manage to // have raw numeric values for things like registers. sigh. - const CompilerType &type(GetCompilerType()); + CompilerType type = GetCompilerType(); return (!type.IsValid()) || (0 != (type.GetTypeInfo() & eTypeHasValue)); } diff --git a/lldb/source/Core/ValueObjectCast.cpp b/lldb/source/Core/ValueObjectCast.cpp index 22e856be539b..7b6d3591faf4 100644 --- a/lldb/source/Core/ValueObjectCast.cpp +++ b/lldb/source/Core/ValueObjectCast.cpp @@ -47,7 +47,7 @@ size_t ValueObjectCast::CalculateNumChildren(uint32_t max) { return children_count <= max ? children_count : max; } -uint64_t ValueObjectCast::GetByteSize() { +llvm::Optional<uint64_t> ValueObjectCast::GetByteSize() { ExecutionContext exe_ctx(GetExecutionContextRef()); return m_value.GetValueByteSize(nullptr, &exe_ctx); } diff --git a/lldb/source/Core/ValueObjectChild.cpp b/lldb/source/Core/ValueObjectChild.cpp index 6205ed32c615..34baa19f0a24 100644 --- a/lldb/source/Core/ValueObjectChild.cpp +++ b/lldb/source/Core/ValueObjectChild.cpp @@ -57,15 +57,8 @@ size_t ValueObjectChild::CalculateNumChildren(uint32_t max) { static void AdjustForBitfieldness(ConstString &name, uint8_t bitfield_bit_size) { - if (name && bitfield_bit_size) { - const char *compiler_type_name = name.AsCString(); - if (compiler_type_name) { - std::vector<char> bitfield_type_name(strlen(compiler_type_name) + 32, 0); - ::snprintf(&bitfield_type_name.front(), bitfield_type_name.size(), - "%s:%u", compiler_type_name, bitfield_bit_size); - name.SetCString(&bitfield_type_name.front()); - } - } + if (name && bitfield_bit_size) + name.SetString(llvm::formatv("{0}:{1}", name, bitfield_bit_size).str()); } ConstString ValueObjectChild::GetTypeName() { @@ -118,8 +111,7 @@ bool ValueObjectChild::UpdateValue() { CompilerType parent_type(parent->GetCompilerType()); // Copy the parent scalar value and the scalar value type m_value.GetScalar() = parent->GetValue().GetScalar(); - Value::ValueType value_type = parent->GetValue().GetValueType(); - m_value.SetValueType(value_type); + m_value.SetValueType(parent->GetValue().GetValueType()); Flags parent_type_flags(parent_type.GetTypeInfo()); const bool is_instance_ptr_base = @@ -127,97 +119,77 @@ bool ValueObjectChild::UpdateValue() { (parent_type_flags.AnySet(lldb::eTypeInstanceIsPointer))); if (parent->GetCompilerType().ShouldTreatScalarValueAsAddress()) { - lldb::addr_t addr = parent->GetPointerValue(); - m_value.GetScalar() = addr; + m_value.GetScalar() = parent->GetPointerValue(); + switch (parent->GetAddressTypeOfChildren()) { + case eAddressTypeFile: { + lldb::ProcessSP process_sp(GetProcessSP()); + if (process_sp && process_sp->IsAlive()) + m_value.SetValueType(Value::eValueTypeLoadAddress); + else + m_value.SetValueType(Value::eValueTypeFileAddress); + } break; + case eAddressTypeLoad: + m_value.SetValueType(is_instance_ptr_base + ? Value::eValueTypeScalar + : Value::eValueTypeLoadAddress); + break; + case eAddressTypeHost: + m_value.SetValueType(Value::eValueTypeHostAddress); + break; + case eAddressTypeInvalid: + // TODO: does this make sense? + m_value.SetValueType(Value::eValueTypeScalar); + break; + } + } + switch (m_value.GetValueType()) { + case Value::eValueTypeLoadAddress: + case Value::eValueTypeFileAddress: + case Value::eValueTypeHostAddress: { + lldb::addr_t addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); if (addr == LLDB_INVALID_ADDRESS) { m_error.SetErrorString("parent address is invalid."); } else if (addr == 0) { m_error.SetErrorString("parent is NULL"); } else { - m_value.GetScalar() += m_byte_offset; - AddressType addr_type = parent->GetAddressTypeOfChildren(); - - switch (addr_type) { - case eAddressTypeFile: { - lldb::ProcessSP process_sp(GetProcessSP()); - if (process_sp && process_sp->IsAlive()) - m_value.SetValueType(Value::eValueTypeLoadAddress); - else - m_value.SetValueType(Value::eValueTypeFileAddress); - } break; - case eAddressTypeLoad: - m_value.SetValueType(is_instance_ptr_base - ? Value::eValueTypeScalar - : Value::eValueTypeLoadAddress); - break; - case eAddressTypeHost: - m_value.SetValueType(Value::eValueTypeHostAddress); - break; - case eAddressTypeInvalid: - // TODO: does this make sense? - m_value.SetValueType(Value::eValueTypeScalar); - break; - } - } - } else { - switch (value_type) { - case Value::eValueTypeLoadAddress: - case Value::eValueTypeFileAddress: - case Value::eValueTypeHostAddress: { - lldb::addr_t addr = - m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - if (addr == LLDB_INVALID_ADDRESS) { - m_error.SetErrorString("parent address is invalid."); - } else if (addr == 0) { - m_error.SetErrorString("parent is NULL"); - } else { - // Set this object's scalar value to the address of its value by - // adding its byte offset to the parent address - m_value.GetScalar() += GetByteOffset(); - - // If a bitfield doesn't fit into the child_byte_size'd - // window at child_byte_offset, move the window forward - // until it fits. The problem here is that Value has no - // notion of bitfields and thus the Value's DataExtractor - // is sized like the bitfields CompilerType; a sequence of - // bitfields, however, can be larger than their underlying - // type. - if (m_bitfield_bit_offset) { - const bool thread_and_frame_only_if_stopped = true; - ExecutionContext exe_ctx(GetExecutionContextRef().Lock( - thread_and_frame_only_if_stopped)); - if (auto type_bit_size = GetCompilerType().GetBitSize( - exe_ctx.GetBestExecutionContextScope())) { - uint64_t bitfield_end = - m_bitfield_bit_size + m_bitfield_bit_offset; - if (bitfield_end > *type_bit_size) { - uint64_t overhang_bytes = - (bitfield_end - *type_bit_size + 7) / 8; - m_value.GetScalar() += overhang_bytes; - m_bitfield_bit_offset -= overhang_bytes * 8; - } + // If a bitfield doesn't fit into the child_byte_size'd window at + // child_byte_offset, move the window forward until it fits. The + // problem here is that Value has no notion of bitfields and thus the + // Value's DataExtractor is sized like the bitfields CompilerType; a + // sequence of bitfields, however, can be larger than their underlying + // type. + if (m_bitfield_bit_offset) { + const bool thread_and_frame_only_if_stopped = true; + ExecutionContext exe_ctx(GetExecutionContextRef().Lock( + thread_and_frame_only_if_stopped)); + if (auto type_bit_size = GetCompilerType().GetBitSize( + exe_ctx.GetBestExecutionContextScope())) { + uint64_t bitfield_end = + m_bitfield_bit_size + m_bitfield_bit_offset; + if (bitfield_end > *type_bit_size) { + uint64_t overhang_bytes = + (bitfield_end - *type_bit_size + 7) / 8; + m_byte_offset += overhang_bytes; + m_bitfield_bit_offset -= overhang_bytes * 8; } } } - } break; - case Value::eValueTypeScalar: - // try to extract the child value from the parent's scalar value - { - Scalar scalar(m_value.GetScalar()); - if (m_bitfield_bit_size) - scalar.ExtractBitfield(m_bitfield_bit_size, - m_bitfield_bit_offset); - else - scalar.ExtractBitfield(8 * m_byte_size, 8 * m_byte_offset); - m_value.GetScalar() = scalar; - } - break; - default: - m_error.SetErrorString("parent has invalid value."); - break; + // Set this object's scalar value to the address of its value by + // adding its byte offset to the parent address + m_value.GetScalar() += m_byte_offset; + } + } break; + + case Value::eValueTypeScalar: + // try to extract the child value from the parent's scalar value + { + Scalar scalar(m_value.GetScalar()); + scalar.ExtractBitfield(8 * m_byte_size, 8 * m_byte_offset); + m_value.GetScalar() = scalar; } + break; } if (m_error.Success()) { diff --git a/lldb/source/Core/ValueObjectConstResult.cpp b/lldb/source/Core/ValueObjectConstResult.cpp index 8d84f8e62ccc..ceb4491f8666 100644 --- a/lldb/source/Core/ValueObjectConstResult.cpp +++ b/lldb/source/Core/ValueObjectConstResult.cpp @@ -40,8 +40,7 @@ ValueObjectConstResult::ValueObjectConstResult(ExecutionContextScope *exe_scope, ByteOrder byte_order, uint32_t addr_byte_size, lldb::addr_t address) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), - m_impl(this, address) { + : ValueObject(exe_scope, manager), m_impl(this, address) { SetIsConstant(); SetValueIsValid(true); m_data.SetByteOrder(byte_order); @@ -64,8 +63,7 @@ ValueObjectConstResult::ValueObjectConstResult( ExecutionContextScope *exe_scope, ValueObjectManager &manager, const CompilerType &compiler_type, ConstString name, const DataExtractor &data, lldb::addr_t address) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), - m_impl(this, address) { + : ValueObject(exe_scope, manager), m_impl(this, address) { m_data = data; if (!m_data.GetSharedDataBuffer()) { @@ -112,8 +110,7 @@ ValueObjectConstResult::ValueObjectConstResult( const CompilerType &compiler_type, ConstString name, const lldb::DataBufferSP &data_sp, lldb::ByteOrder data_byte_order, uint32_t data_addr_size, lldb::addr_t address) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), - m_impl(this, address) { + : ValueObject(exe_scope, manager), m_impl(this, address) { m_data.SetByteOrder(data_byte_order); m_data.SetAddressByteSize(data_addr_size); m_data.SetData(data_sp); @@ -143,7 +140,7 @@ ValueObjectConstResult::ValueObjectConstResult( ExecutionContextScope *exe_scope, ValueObjectManager &manager, const CompilerType &compiler_type, ConstString name, lldb::addr_t address, AddressType address_type, uint32_t addr_byte_size) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), + : ValueObject(exe_scope, manager), m_type_name(), m_impl(this, address) { m_value.GetScalar() = address; m_data.SetAddressByteSize(addr_byte_size); @@ -179,8 +176,7 @@ ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope, ValueObjectConstResult::ValueObjectConstResult(ExecutionContextScope *exe_scope, ValueObjectManager &manager, const Status &error) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), - m_impl(this) { + : ValueObject(exe_scope, manager), m_impl(this) { m_error = error; SetIsConstant(); } @@ -189,8 +185,7 @@ ValueObjectConstResult::ValueObjectConstResult(ExecutionContextScope *exe_scope, ValueObjectManager &manager, const Value &value, ConstString name, Module *module) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), - m_impl(this) { + : ValueObject(exe_scope, manager), m_impl(this) { m_value = value; m_name = name; ExecutionContext exe_ctx; @@ -208,9 +203,9 @@ lldb::ValueType ValueObjectConstResult::GetValueType() const { return eValueTypeConstResult; } -uint64_t ValueObjectConstResult::GetByteSize() { +llvm::Optional<uint64_t> ValueObjectConstResult::GetByteSize() { ExecutionContext exe_ctx(GetExecutionContextRef()); - if (m_byte_size == 0) { + if (!m_byte_size) { if (auto size = GetCompilerType().GetByteSize(exe_ctx.GetBestExecutionContextScope())) SetByteSize(*size); diff --git a/lldb/source/Core/ValueObjectDynamicValue.cpp b/lldb/source/Core/ValueObjectDynamicValue.cpp index ca66740cb55d..1c25b8c85a05 100644 --- a/lldb/source/Core/ValueObjectDynamicValue.cpp +++ b/lldb/source/Core/ValueObjectDynamicValue.cpp @@ -98,7 +98,7 @@ size_t ValueObjectDynamicValue::CalculateNumChildren(uint32_t max) { return m_parent->GetNumChildren(max); } -uint64_t ValueObjectDynamicValue::GetByteSize() { +llvm::Optional<uint64_t> ValueObjectDynamicValue::GetByteSize() { const bool success = UpdateValueIfNeeded(false); if (success && m_dynamic_type_info.HasType()) { ExecutionContext exe_ctx(GetExecutionContextRef()); diff --git a/lldb/source/Core/ValueObjectMemory.cpp b/lldb/source/Core/ValueObjectMemory.cpp index 91b2c6084928..abf7b38ed89a 100644 --- a/lldb/source/Core/ValueObjectMemory.cpp +++ b/lldb/source/Core/ValueObjectMemory.cpp @@ -139,10 +139,11 @@ size_t ValueObjectMemory::CalculateNumChildren(uint32_t max) { return child_count <= max ? child_count : max; } -uint64_t ValueObjectMemory::GetByteSize() { +llvm::Optional<uint64_t> ValueObjectMemory::GetByteSize() { + ExecutionContext exe_ctx(GetExecutionContextRef()); if (m_type_sp) - return m_type_sp->GetByteSize().getValueOr(0); - return m_compiler_type.GetByteSize(nullptr).getValueOr(0); + return m_type_sp->GetByteSize(exe_ctx.GetBestExecutionContextScope()); + return m_compiler_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); } lldb::ValueType ValueObjectMemory::GetValueType() const { @@ -167,9 +168,6 @@ bool ValueObjectMemory::UpdateValue() { Value::ValueType value_type = m_value.GetValueType(); switch (value_type) { - default: - llvm_unreachable("Unhandled expression result value kind..."); - case Value::eValueTypeScalar: // The variable value is in the Scalar value inside the m_value. We can // point our m_data right to it. diff --git a/lldb/source/Core/ValueObjectRegister.cpp b/lldb/source/Core/ValueObjectRegister.cpp index ec87c38fb367..27461e9cebc4 100644 --- a/lldb/source/Core/ValueObjectRegister.cpp +++ b/lldb/source/Core/ValueObjectRegister.cpp @@ -81,7 +81,7 @@ size_t ValueObjectRegisterSet::CalculateNumChildren(uint32_t max) { return 0; } -uint64_t ValueObjectRegisterSet::GetByteSize() { return 0; } +llvm::Optional<uint64_t> ValueObjectRegisterSet::GetByteSize() { return 0; } bool ValueObjectRegisterSet::UpdateValue() { m_error.Clear(); @@ -229,7 +229,9 @@ size_t ValueObjectRegister::CalculateNumChildren(uint32_t max) { return children_count <= max ? children_count : max; } -uint64_t ValueObjectRegister::GetByteSize() { return m_reg_info.byte_size; } +llvm::Optional<uint64_t> ValueObjectRegister::GetByteSize() { + return m_reg_info.byte_size; +} bool ValueObjectRegister::UpdateValue() { m_error.Clear(); diff --git a/lldb/source/Core/ValueObjectSyntheticFilter.cpp b/lldb/source/Core/ValueObjectSyntheticFilter.cpp index 32d1e6ab8368..cebf7abfe523 100644 --- a/lldb/source/Core/ValueObjectSyntheticFilter.cpp +++ b/lldb/source/Core/ValueObjectSyntheticFilter.cpp @@ -46,7 +46,7 @@ public: ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent, lldb::SyntheticChildrenSP filter) - : ValueObject(parent), m_synth_sp(filter), m_children_byindex(), + : ValueObject(parent), m_synth_sp(std::move(filter)), m_children_byindex(), m_name_toindex(), m_synthetic_children_cache(), m_synthetic_children_count(UINT32_MAX), m_parent_type_name(parent.GetTypeName()), @@ -121,7 +121,9 @@ bool ValueObjectSynthetic::MightHaveChildren() { return (m_might_have_children != eLazyBoolNo); } -uint64_t ValueObjectSynthetic::GetByteSize() { return m_parent->GetByteSize(); } +llvm::Optional<uint64_t> ValueObjectSynthetic::GetByteSize() { + return m_parent->GetByteSize(); +} lldb::ValueType ValueObjectSynthetic::GetValueType() const { return m_parent->GetValueType(); diff --git a/lldb/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp index 0d1e7b047a0a..5acb23aaac5b 100644 --- a/lldb/source/Core/ValueObjectVariable.cpp +++ b/lldb/source/Core/ValueObjectVariable.cpp @@ -105,15 +105,15 @@ size_t ValueObjectVariable::CalculateNumChildren(uint32_t max) { return child_count <= max ? child_count : max; } -uint64_t ValueObjectVariable::GetByteSize() { +llvm::Optional<uint64_t> ValueObjectVariable::GetByteSize() { ExecutionContext exe_ctx(GetExecutionContextRef()); CompilerType type(GetCompilerType()); if (!type.IsValid()) - return 0; + return {}; - return type.GetByteSize(exe_ctx.GetBestExecutionContextScope()).getValueOr(0); + return type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); } lldb::ValueType ValueObjectVariable::GetValueType() const { @@ -132,8 +132,11 @@ bool ValueObjectVariable::UpdateValue() { if (variable->GetLocationIsConstantValueData()) { // expr doesn't contain DWARF bytes, it contains the constant variable // value bytes themselves... - if (expr.GetExpressionData(m_data)) + if (expr.GetExpressionData(m_data)) { + if (m_data.GetDataStart() && m_data.GetByteSize()) + m_value.SetBytes(m_data.GetDataStart(), m_data.GetByteSize()); m_value.SetContext(Value::eContextTypeVariable, variable); + } else m_error.SetErrorString("empty constant data"); // constant bytes can't be edited - sorry @@ -193,8 +196,6 @@ bool ValueObjectVariable::UpdateValue() { const bool process_is_alive = process && process->IsAlive(); switch (value_type) { - case Value::eValueTypeVector: - // fall through case Value::eValueTypeScalar: // The variable value is in the Scalar value inside the m_value. We can // point our m_data right to it. @@ -292,7 +293,6 @@ void ValueObjectVariable::DoUpdateChildrenAddressType(ValueObject &valobj) { break; case Value::eValueTypeLoadAddress: case Value::eValueTypeScalar: - case Value::eValueTypeVector: valobj.SetAddressTypeOfChildren(eAddressTypeLoad); break; } |
