Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lldb/include/lldb/Target/LanguageRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ class LanguageRuntime : public Runtime, public PluginInterface {
return false;
}

virtual bool IsSymbolARuntimeThunk(const Symbol &symbol) { return false; }

// Given the name of a runtime symbol (e.g. in Objective-C, an ivar offset
// symbol), try to determine from the runtime what the value of that symbol
// would be. Useful when the underlying binary is stripped.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,3 +476,14 @@ CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread,

return ret_plan_sp;
}

bool CPPLanguageRuntime::IsSymbolARuntimeThunk(const Symbol &symbol) {
llvm::StringRef mangled_name =
symbol.GetMangled().GetMangledName().GetStringRef();
// Virtual function overriding from a non-virtual base use a "Th" prefix.
// Virtual function overriding from a virtual base must use a "Tv" prefix.
// Virtual function overriding thunks with covariant returns use a "Tc"
// prefix.
return mangled_name.starts_with("_ZTh") || mangled_name.starts_with("_ZTv") ||
mangled_name.starts_with("_ZTc");
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ class CPPLanguageRuntime : public LanguageRuntime {
bool stop_others) override;

bool IsAllowedRuntimeValue(ConstString name) override;

bool IsSymbolARuntimeThunk(const Symbol &symbol) override;

protected:
// Classes that inherit from CPPLanguageRuntime can see and modify these
CPPLanguageRuntime(Process *process);
Expand Down
51 changes: 40 additions & 11 deletions lldb/source/Target/ThreadPlanShouldStopHere.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "lldb/Target/ThreadPlanShouldStopHere.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/LLDBLog.h"
Expand Down Expand Up @@ -76,6 +77,18 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback(
}
}

// Check whether the frame we are in is a language runtime thunk, only for
// step out:
if (operation == eFrameCompareOlder) {
Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
if (symbol) {
ProcessSP process_sp(current_plan->GetThread().GetProcess());
for (auto *runtime : process_sp->GetLanguageRuntimes()) {
if (runtime->IsSymbolARuntimeThunk(*symbol))
should_stop_here = false;
}
}
}
// Always avoid code with line number 0.
// FIXME: At present the ShouldStop and the StepFromHere calculate this
// independently. If this ever
Expand Down Expand Up @@ -109,18 +122,34 @@ ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback(

if (sc.line_entry.line == 0) {
AddressRange range = sc.line_entry.range;

// If the whole function is marked line 0 just step out, that's easier &
// faster than continuing to step through it.
bool just_step_out = false;
if (sc.symbol && sc.symbol->ValueIsAddress()) {
Address symbol_end = sc.symbol->GetAddress();
symbol_end.Slide(sc.symbol->GetByteSize() - 1);
if (range.ContainsFileAddress(sc.symbol->GetAddress()) &&
range.ContainsFileAddress(symbol_end)) {
LLDB_LOGF(log, "Stopped in a function with only line 0 lines, just "
"stepping out.");
just_step_out = true;
if (sc.symbol) {
ProcessSP process_sp(current_plan->GetThread().GetProcess());

// If this is a runtime thunk, step through it, rather than stepping out
// because it's marked line 0.
bool is_thunk = false;
for (auto *runtime : process_sp->GetLanguageRuntimes()) {
if (runtime->IsSymbolARuntimeThunk(*sc.symbol)) {
LLDB_LOGF(log, "In runtime thunk %s - stepping out.",
sc.symbol->GetName().GetCString());
is_thunk = true;
}
}

// If the whole function is marked line 0 just step out, that's easier &
// faster than continuing to step through it.
// FIXME: This assumes that the function is a single line range. It could
// be a series of contiguous line 0 ranges. Check for that too.
if (!is_thunk && sc.symbol->ValueIsAddress()) {
Address symbol_end = sc.symbol->GetAddress();
symbol_end.Slide(sc.symbol->GetByteSize() - 1);
if (range.ContainsFileAddress(sc.symbol->GetAddress()) &&
range.ContainsFileAddress(symbol_end)) {
LLDB_LOGF(log, "Stopped in a function with only line 0 lines, just "
"stepping out.");
just_step_out = true;
}
}
}
if (!just_step_out) {
Expand Down
3 changes: 3 additions & 0 deletions lldb/test/API/lang/cpp/thunk/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
24 changes: 24 additions & 0 deletions lldb/test/API/lang/cpp/thunk/TestThunk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class ThunkTest(TestBase):
def test(self):
self.build()
lldbutil.run_to_name_breakpoint(self, "testit")

self.expect(
"step",
STEP_IN_SUCCEEDED,
substrs=["stop reason = step in", "Derived1::doit"],
)

self.runCmd("continue")

self.expect(
"step",
STEP_IN_SUCCEEDED,
substrs=["stop reason = step in", "Derived2::doit"],
)
36 changes: 36 additions & 0 deletions lldb/test/API/lang/cpp/thunk/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <stdio.h>

class Base1 {
public:
virtual ~Base1() {}
};

class Base2 {
public:
virtual void doit() = 0;
};

Base2 *b;

class Derived1 : public Base1, public Base2 {
public:
virtual void doit() { printf("Derived1\n"); }
};

class Derived2 : public Base2 {
public:
virtual void doit() { printf("Derived2\n"); }
};

void testit() { b->doit(); }

int main() {

b = new Derived1();
testit();

b = new Derived2();
testit();

return 0;
}