Context: lldb might crash when running to a debuggee crashing state and do a target symbols add command. Backtrace: ``` #0 0x000055ca6790dc65 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/hyubo/osmeta/external/llvm-project/llvm/lib/Support/Unix/Signals.inc:848:11 #1 0x000055ca6790e434 PrintStackTraceSignalHandler(void*) /home/hyubo/osmeta/external/llvm-project/llvm/lib/Support/Unix/Signals.inc:931:1 #2 0x000055ca6790b839 llvm::sys::RunSignalHandlers() /home/hyubo/osmeta/external/llvm-project/llvm/lib/Support/Signals.cpp:104:5 #3 0x000055ca6790ff6b SignalHandler(int, siginfo_t*, void*) /home/hyubo/osmeta/external/llvm-project/llvm/lib/Support/Unix/Signals.inc:430:38 #4 0x00007fe9e5e44560 __restore_rt /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/signal/../sysdeps/unix/sysv/linux/libc_sigaction.c:13:0 #5 0x00007fe9e5f25649 syscall /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/misc/../sysdeps/unix/sysv/linux/x86_64/syscall.S:38:0 #6 0x00007fe9ec649170 SignalHandler(int, siginfo_t*, void*) /home/hyubo/osmeta/external/llvm-project/llvm/lib/Support/Unix/Signals.inc:429:7 #7 0x00007fe9e5e44560 __restore_rt /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/signal/../sysdeps/unix/sysv/linux/libc_sigaction.c:13:0 #8 0x00007fe9ebb77bf0 lldb_private::operator<(lldb_private::StackID const&, lldb_private::StackID const&) /home/hyubo/osmeta/external/llvm-project/lldb/source/Target/StackID.cpp:99:16 #9 0x00007fe9ebb6863d CompareStackID(std::shared_ptr<lldb_private::StackFrame> const&, lldb_private::StackID const&) /home/hyubo/osmeta/external/llvm-project/lldb/source/Target/StackFrameList.cpp:683:3 #10 0x00007fe9ebb6d049 bool __gnu_cxx::__ops::_Iter_comp_val<bool (*)(std::shared_ptr<lldb_private::StackFrame> const&, lldb_private::StackID const&)>::operator()<__gnu_cxx::__normal_iterator<std::shared_ptr<lldb_private::StackFrame>*, std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>>, lldb_private::StackID const>(__gnu_cxx::__normal_iterator<std::shared_ptr<lldb_private::StackFrame>*, std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>>, lldb_private::StackID const&) /mnt/gvfs/third-party2/libgcc/d1129753c8361ac8e9453c0f4291337a4507ebe6/11.x/platform010/5684a5a/include/c++/11.x/bits/predefined_ops.h:196:4 #11 0x00007fe9ebb6cefe __gnu_cxx::__normal_iterator<std::shared_ptr<lldb_private::StackFrame>*, std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>> std::__lower_bound<__gnu_cxx::__normal_iterator<std::shared_ptr<lldb_private::StackFrame>*, std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>>, lldb_private::StackID, __gnu_cxx::__ops::_Iter_comp_val<bool (*)(std::shared_ptr<lldb_private::StackFrame> const&, lldb_private::StackID const&)>>(__gnu_cxx::__normal_iterator<std::shared_ptr<lldb_private::StackFrame>*, std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>>, __gnu_cxx::__normal_iterator<std::shared_ptr<lldb_private::StackFrame>*, std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>>, lldb_private::StackID const&, __gnu_cxx::__ops::_Iter_comp_val<bool (*)(std::shared_ptr<lldb_private::StackFrame> const&, lldb_private::StackID const&)>) /mnt/gvfs/third-party2/libgcc/d1129753c8361ac8e9453c0f4291337a4507ebe6/11.x/platform010/5684a5a/include/c++/11.x/bits/stl_algobase.h:1464:8 #12 0x00007fe9ebb6cdfc __gnu_cxx::__normal_iterator<std::shared_ptr<lldb_private::StackFrame>*, std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>> std::lower_bound<__gnu_cxx::__normal_iterator<std::shared_ptr<lldb_private::StackFrame>*, std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>>, lldb_private::StackID, bool (*)(std::shared_ptr<lldb_private::StackFrame> const&, lldb_private::StackID const&)>(__gnu_cxx::__normal_iterator<std::shared_ptr<lldb_private::StackFrame>*, std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>>, __gnu_cxx::__normal_iterator<std::shared_ptr<lldb_private::StackFrame>*, std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>>, lldb_private::StackID const&, bool (*)(std::shared_ptr<lldb_private::StackFrame> const&, lldb_private::StackID const&)) /mnt/gvfs/third-party2/libgcc/d1129753c8361ac8e9453c0f4291337a4507ebe6/11.x/platform010/5684a5a/include/c++/11.x/bits/stl_algo.h:2062:14 #13 0x00007fe9ebb685fa auto llvm::lower_bound<std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>&, lldb_private::StackID const&, bool (*)(std::shared_ptr<lldb_private::StackFrame> const&, lldb_private::StackID const&)>(std::vector<std::shared_ptr<lldb_private::StackFrame>, std::allocator<std::shared_ptr<lldb_private::StackFrame>>>&, lldb_private::StackID const&, bool (*)(std::shared_ptr<lldb_private::StackFrame> const&, lldb_private::StackID const&)) /home/hyubo/osmeta/external/llvm-project/llvm/include/llvm/ADT/STLExtras.h:2001:10 #14 0x00007fe9ebb68441 lldb_private::StackFrameList::GetFrameWithStackID(lldb_private::StackID const&) /home/hyubo/osmeta/external/llvm-project/lldb/source/Target/StackFrameList.cpp:697:11 #15 0x00007fe9ebbee395 lldb_private::Thread::GetFrameWithStackID(lldb_private::StackID const&) /home/hyubo/osmeta/external/llvm-project/lldb/include/lldb/Target/Thread.h:459:7 #16 0x00007fe9ebac7cf7 lldb_private::ExecutionContextRef::GetFrameSP() const /home/hyubo/osmeta/external/llvm-project/lldb/source/Target/ExecutionContext.cpp:643:25 #17 0x00007fe9ebac80e1 lldb_private::GetStoppedExecutionContext(lldb_private::ExecutionContextRef const*) /home/hyubo/osmeta/external/llvm-project/lldb/source/Target/ExecutionContext.cpp:164:34 #18 0x00007fe9eb8903fa lldb_private::Statusline::Redraw(std::optional<lldb_private::ExecutionContextRef>) /home/hyubo/osmeta/external/llvm-project/lldb/source/Core/Statusline.cpp:139:7 #19 0x00007fe9eb7ac8be lldb_private::Debugger::RedrawStatusline(std::optional<lldb_private::ExecutionContextRef>) /home/hyubo/osmeta/external/llvm-project/lldb/source/Core/Debugger.cpp:1233:3 #20 0x00007fe9eb804d1e lldb_private::IOHandlerEditline::RedrawCallback() /home/hyubo/osmeta/external/llvm-project/lldb/source/Core/IOHandler.cpp:446:3 #21 0x00007fe9eb80aa81 lldb_private::IOHandlerEditline::IOHandlerEditline(lldb_private::Debugger&, lldb_private::IOHandler::Type, std::shared_ptr<lldb_private::File> const&, std::shared_ptr<lldb_private::LockableStreamFile> const&, std::shared_ptr<lldb_private::LockableStreamFile> const&, unsigned int, char const*, llvm::StringRef, llvm::StringRef, bool, bool, unsigned int, lldb_private::IOHandlerDelegate&)::$_2::operator()() const /home/hyubo/osmeta/external/llvm-project/lldb/source/Core/IOHandler.cpp:262:73 #22 0x00007fe9eb80aa5d void llvm::detail::UniqueFunctionBase<void>::CallImpl<lldb_private::IOHandlerEditline::IOHandlerEditline(lldb_private::Debugger&, lldb_private::IOHandler::Type, std::shared_ptr<lldb_private::File> const&, std::shared_ptr<lldb_private::LockableStreamFile> const&, std::shared_ptr<lldb_private::LockableStreamFile> const&, unsigned int, char const*, llvm::StringRef, llvm::StringRef, bool, bool, unsigned int, lldb_private::IOHandlerDelegate&)::$_2>(void*) /home/hyubo/osmeta/external/llvm-project/llvm/include/llvm/ADT/FunctionExtras.h:213:5 #23 0x00007fe9eb93bfbf llvm::unique_function<void ()>::operator()() /home/hyubo/osmeta/external/llvm-project/llvm/include/llvm/ADT/FunctionExtras.h:365:5 #24 0x00007fe9eb93bb80 lldb_private::Editline::GetCharacter(wchar_t*) /home/hyubo/osmeta/external/llvm-project/lldb/source/Host/common/Editline.cpp:0:5 #25 0x00007fe9eb941a18 lldb_private::Editline::ConfigureEditor(bool)::$_0::operator()(editline*, wchar_t*) const /home/hyubo/osmeta/external/llvm-project/lldb/source/Host/common/Editline.cpp:1287:5 #26 0x00007fe9eb9419e2 lldb_private::Editline::ConfigureEditor(bool)::$_0::__invoke(editline*, wchar_t*) /home/hyubo/osmeta/external/llvm-project/lldb/source/Host/common/Editline.cpp:1286:27 #27 0x00007fe9f3384e26 el_getc /home/engshare/third-party2/libedit/3.1/src/libedit/src/read.c:439:14 #28 0x00007fe9f3384e26 el_getc /home/engshare/third-party2/libedit/3.1/src/libedit/src/read.c:400:1 #29 0x00007fe9f3384f90 read_getcmd /home/engshare/third-party2/libedit/3.1/src/libedit/src/read.c:247:14 #30 0x00007fe9f3384f90 el_gets /home/engshare/third-party2/libedit/3.1/src/libedit/src/read.c:586:14 #31 0x00007fe9eb9409f3 lldb_private::Editline::GetLine(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, bool&) /home/hyubo/osmeta/external/llvm-project/lldb/source/Host/common/Editline.cpp:1636:16 #32 0x00007fe9eb8044d7 lldb_private::IOHandlerEditline::GetLine(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, bool&) /home/hyubo/osmeta/external/llvm-project/lldb/source/Core/IOHandler.cpp:339:5 #33 0x00007fe9eb805609 lldb_private::IOHandlerEditline::Run() /home/hyubo/osmeta/external/llvm-project/lldb/source/Core/IOHandler.cpp:600:11 #34 0x00007fe9eb7b214c lldb_private::Debugger::RunIOHandlers() /home/hyubo/osmeta/external/llvm-project/lldb/source/Core/Debugger.cpp:1280:16 #35 0x00007fe9eb98f00f lldb_private::CommandInterpreter::RunCommandInterpreter(lldb_private::CommandInterpreterRunOptions&) /home/hyubo/osmeta/external/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp:3620:16 #36 0x00007fe9eb4f0e09 lldb::SBDebugger::RunCommandInterpreter(bool, bool) /home/hyubo/osmeta/external/llvm-project/lldb/source/API/SBDebugger.cpp:1234:42 #37 0x000055ca6788d6b0 Driver::MainLoop() /home/hyubo/osmeta/external/llvm-project/lldb/tools/driver/Driver.cpp:677:3 #38 0x000055ca6788e226 main /home/hyubo/osmeta/external/llvm-project/lldb/tools/driver/Driver.cpp:887:17 #39 0x00007fe9e5e2c657 __libc_start_call_main /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #40 0x00007fe9e5e2c718 call_init /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../csu/libc-start.c:128:20 #41 0x00007fe9e5e2c718 __libc_start_main@GLIBC_2.2.5 /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../csu/libc-start.c:379:5 #42 0x000055ca67889a11 _start /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/x86_64/start.S:118:0 Segmentation fault (core dumped) ``` When `target symbols add` is run, `Symtab::AddSymbol()` can reallocate the underlying `std::vector<Symbol>` and resize it, invalidating all existing Symbol* pointers. While `Process::Flush()` clears stale stack frames, the statusline caches its own `ExecutionContextRef` containing a `StackID` with a `SymbolContextScope*` (which can be a `Symbol*`). This cached reference is not cleared by `Process::Flush()`, so the next statusline redraw accesses a dangling pointer and crashes. Fix this by adding `Statusline::Flush()` which clears the cached frame, `Debugger::Flush()` which forwards to it under the statusline mutex, and calling `Debugger::Flush()` from `Process::Flush()` so that all flush paths (symbol add, exec, module load) also invalidate the statusline's stale state. After this fix, lldb is not crashing anymore, new symbols from a symbol file are correctly loaded --------- Co-authored-by: George Hu <georgehuyubo@gmail.com>
160 lines
5.3 KiB
C++
160 lines
5.3 KiB
C++
//===-- Statusline.cpp ---------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Core/Statusline.h"
|
|
#include "lldb/Core/Debugger.h"
|
|
#include "lldb/Core/FormatEntity.h"
|
|
#include "lldb/Host/StreamFile.h"
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
|
#include "lldb/Symbol/SymbolContext.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Target/StackFrame.h"
|
|
#include "lldb/Utility/AnsiTerminal.h"
|
|
#include "lldb/Utility/StreamString.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Locale.h"
|
|
|
|
#define ESCAPE "\x1b"
|
|
#define ANSI_NORMAL ESCAPE "[0m"
|
|
#define ANSI_SAVE_CURSOR ESCAPE "7"
|
|
#define ANSI_RESTORE_CURSOR ESCAPE "8"
|
|
#define ANSI_CLEAR_BELOW ESCAPE "[J"
|
|
#define ANSI_CLEAR_SCREEN ESCAPE "[2J"
|
|
#define ANSI_SET_SCROLL_ROWS ESCAPE "[1;%ur"
|
|
#define ANSI_TO_START_OF_ROW ESCAPE "[%u;1f"
|
|
#define ANSI_REVERSE_VIDEO ESCAPE "[7m"
|
|
#define ANSI_UP_ROWS ESCAPE "[%dA"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
Statusline::Statusline(Debugger &debugger)
|
|
: m_debugger(debugger), m_terminal_width(m_debugger.GetTerminalWidth()),
|
|
m_terminal_height(m_debugger.GetTerminalHeight()) {}
|
|
|
|
Statusline::~Statusline() { Disable(); }
|
|
|
|
void Statusline::TerminalSizeChanged() {
|
|
m_terminal_width = m_debugger.GetTerminalWidth();
|
|
m_terminal_height = m_debugger.GetTerminalHeight();
|
|
|
|
UpdateScrollWindow(ResizeStatusline);
|
|
|
|
// Redraw the old statusline.
|
|
Redraw(std::nullopt);
|
|
}
|
|
|
|
void Statusline::Enable(std::optional<ExecutionContextRef> exe_ctx_ref) {
|
|
// Reduce the scroll window to make space for the status bar below.
|
|
UpdateScrollWindow(EnableStatusline);
|
|
|
|
// Draw the statusline.
|
|
Redraw(exe_ctx_ref);
|
|
}
|
|
|
|
void Statusline::Disable() {
|
|
// Extend the scroll window to cover the status bar.
|
|
UpdateScrollWindow(DisableStatusline);
|
|
}
|
|
|
|
void Statusline::Draw(std::string str) {
|
|
lldb::LockableStreamFileSP stream_sp = m_debugger.GetOutputStreamSP();
|
|
if (!stream_sp)
|
|
return;
|
|
|
|
str = ansi::TrimAndPad(str, m_terminal_width);
|
|
|
|
LockedStreamFile locked_stream = stream_sp->Lock();
|
|
locked_stream << ANSI_SAVE_CURSOR;
|
|
locked_stream.Printf(ANSI_TO_START_OF_ROW,
|
|
static_cast<unsigned>(m_terminal_height));
|
|
|
|
// Use "reverse video" to make sure the statusline has a background. Only do
|
|
// this when colors are disabled, and rely on the statusline format otherwise.
|
|
if (!m_debugger.GetUseColor())
|
|
locked_stream << ANSI_REVERSE_VIDEO;
|
|
|
|
locked_stream << str;
|
|
locked_stream << ANSI_NORMAL;
|
|
locked_stream << ANSI_RESTORE_CURSOR;
|
|
}
|
|
|
|
void Statusline::UpdateScrollWindow(ScrollWindowMode mode) {
|
|
assert(m_terminal_width != 0 && m_terminal_height != 0);
|
|
|
|
lldb::LockableStreamFileSP stream_sp = m_debugger.GetOutputStreamSP();
|
|
if (!stream_sp)
|
|
return;
|
|
|
|
const unsigned reduced_scroll_rows = m_terminal_height - 1;
|
|
{ // Scope for locked_stream:
|
|
LockedStreamFile locked_stream = stream_sp->Lock();
|
|
|
|
switch (mode) {
|
|
case EnableStatusline:
|
|
// Move everything on the screen up.
|
|
locked_stream << '\n';
|
|
locked_stream.Printf(ANSI_UP_ROWS, 1);
|
|
// Reduce the scroll window.
|
|
locked_stream << ANSI_SAVE_CURSOR;
|
|
locked_stream.Printf(ANSI_SET_SCROLL_ROWS, reduced_scroll_rows);
|
|
locked_stream << ANSI_RESTORE_CURSOR;
|
|
break;
|
|
case DisableStatusline:
|
|
// Reset the scroll window.
|
|
locked_stream << ANSI_SAVE_CURSOR;
|
|
locked_stream.Printf(ANSI_SET_SCROLL_ROWS,
|
|
static_cast<unsigned>(m_terminal_height));
|
|
locked_stream << ANSI_RESTORE_CURSOR;
|
|
// Clear the screen below to hide the old statusline.
|
|
locked_stream << ANSI_CLEAR_BELOW;
|
|
break;
|
|
case ResizeStatusline:
|
|
// Clear the screen and update the scroll window.
|
|
// FIXME: Find a better solution (#146919).
|
|
locked_stream << ANSI_CLEAR_SCREEN;
|
|
locked_stream.Printf(ANSI_SET_SCROLL_ROWS, reduced_scroll_rows);
|
|
break;
|
|
}
|
|
}
|
|
m_debugger.RefreshIOHandler();
|
|
}
|
|
|
|
void Statusline::ClearExecutionContext() { m_exe_ctx_ref.ClearFrame(); }
|
|
|
|
void Statusline::Redraw(std::optional<ExecutionContextRef> exe_ctx_ref) {
|
|
// Update the cached execution context.
|
|
if (exe_ctx_ref)
|
|
m_exe_ctx_ref = *exe_ctx_ref;
|
|
|
|
// Lock the execution context.
|
|
ExecutionContext exe_ctx =
|
|
m_exe_ctx_ref.Lock(/*thread_and_frame_only_if_stopped=*/false);
|
|
|
|
// Compute the symbol context if we're stopped.
|
|
SymbolContext sym_ctx;
|
|
llvm::Expected<StoppedExecutionContext> stopped_exe_ctx =
|
|
GetStoppedExecutionContext(&m_exe_ctx_ref);
|
|
if (stopped_exe_ctx) {
|
|
// The StoppedExecutionContext only ensures that we hold the run lock.
|
|
// The process could be in an exited or unloaded state and have no frame.
|
|
if (auto frame_sp = stopped_exe_ctx->GetFrameSP())
|
|
sym_ctx = frame_sp->GetSymbolContext(eSymbolContextEverything);
|
|
} else {
|
|
// We can draw the statusline without being stopped.
|
|
llvm::consumeError(stopped_exe_ctx.takeError());
|
|
}
|
|
|
|
StreamString stream;
|
|
FormatEntity::Entry format = m_debugger.GetStatuslineFormat();
|
|
FormatEntity::Formatter(&sym_ctx, &exe_ctx, nullptr, false, false)
|
|
.Format(format, stream);
|
|
|
|
Draw(stream.GetString().str());
|
|
}
|