Skip to content

Commit 6bb3019

Browse files
authored
Branch island debug (#139166)
This patch allows lldb to step in across "branch islands" which is the Darwin linker's way of dealing with immediate branches to targets that are too far away for the immediate slot to make the jump. I submitted this a couple days ago and it failed on the arm64 bot. I was able to match the bot OS and Tool versions (they are a bit old at this point) and ran the test there but sadly it succeeded. The x86_64 bot also failed but that was my bad, I did @skipUnlessDarwin when I should have done @skipUnlessAppleSilicon. So this resubmission is with the proper decoration for the test, and with a bunch of debug output printed in case of failure. With any luck, if this resubmission fails again I'll be able to see what's going on.
1 parent 611d81b commit 6bb3019

File tree

9 files changed

+130
-7
lines changed

9 files changed

+130
-7
lines changed

lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "lldb/Target/Thread.h"
2727
#include "lldb/Target/ThreadPlanCallFunction.h"
2828
#include "lldb/Target/ThreadPlanRunToAddress.h"
29+
#include "lldb/Target/ThreadPlanStepInstruction.h"
2930
#include "lldb/Utility/DataBuffer.h"
3031
#include "lldb/Utility/DataBufferHeap.h"
3132
#include "lldb/Utility/LLDBLog.h"
@@ -923,15 +924,15 @@ DynamicLoaderDarwin::GetStepThroughTrampolinePlan(Thread &thread,
923924
if (current_symbol != nullptr) {
924925
std::vector<Address> addresses;
925926

927+
ConstString current_name =
928+
current_symbol->GetMangled().GetName(Mangled::ePreferMangled);
926929
if (current_symbol->IsTrampoline()) {
927-
ConstString trampoline_name =
928-
current_symbol->GetMangled().GetName(Mangled::ePreferMangled);
929930

930-
if (trampoline_name) {
931+
if (current_name) {
931932
const ModuleList &images = target_sp->GetImages();
932933

933934
SymbolContextList code_symbols;
934-
images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode,
935+
images.FindSymbolsWithNameAndType(current_name, eSymbolTypeCode,
935936
code_symbols);
936937
for (const SymbolContext &context : code_symbols) {
937938
Address addr = context.GetFunctionOrSymbolAddress();
@@ -945,8 +946,8 @@ DynamicLoaderDarwin::GetStepThroughTrampolinePlan(Thread &thread,
945946
}
946947

947948
SymbolContextList reexported_symbols;
948-
images.FindSymbolsWithNameAndType(
949-
trampoline_name, eSymbolTypeReExported, reexported_symbols);
949+
images.FindSymbolsWithNameAndType(current_name, eSymbolTypeReExported,
950+
reexported_symbols);
950951
for (const SymbolContext &context : reexported_symbols) {
951952
if (context.symbol) {
952953
Symbol *actual_symbol =
@@ -968,7 +969,7 @@ DynamicLoaderDarwin::GetStepThroughTrampolinePlan(Thread &thread,
968969
}
969970

970971
SymbolContextList indirect_symbols;
971-
images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeResolver,
972+
images.FindSymbolsWithNameAndType(current_name, eSymbolTypeResolver,
972973
indirect_symbols);
973974

974975
for (const SymbolContext &context : indirect_symbols) {
@@ -1028,6 +1029,23 @@ DynamicLoaderDarwin::GetStepThroughTrampolinePlan(Thread &thread,
10281029
thread_plan_sp = std::make_shared<ThreadPlanRunToAddress>(
10291030
thread, load_addrs, stop_others);
10301031
}
1032+
// One more case we have to consider is "branch islands". These are regular
1033+
// TEXT symbols but their names end in .island plus maybe a .digit suffix.
1034+
// They are to allow arm64 code to branch further than the size of the
1035+
// address slot allows. We just need to single-instruction step in that
1036+
// case.
1037+
static const char *g_branch_island_pattern = "\\.island\\.?[0-9]*$";
1038+
static RegularExpression g_branch_island_regex(g_branch_island_pattern);
1039+
1040+
bool is_branch_island = g_branch_island_regex.Execute(current_name);
1041+
if (!thread_plan_sp && is_branch_island) {
1042+
thread_plan_sp = std::make_shared<ThreadPlanStepInstruction>(
1043+
thread,
1044+
/* step_over= */ false, /* stop_others */ false, eVoteNoOpinion,
1045+
eVoteNoOpinion);
1046+
LLDB_LOG(log, "Stepping one instruction over branch island: '{0}'.",
1047+
current_name);
1048+
}
10311049
} else {
10321050
LLDB_LOGF(log, "Could not find symbol for step through.");
10331051
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
C_SOURCES := main.c foo.c
2+
CFLAGS_EXTRAS := -std=c99
3+
4+
include Makefile.rules
5+
6+
a.out: main.o padding1.o padding2.o padding3.o padding4.o foo.o
7+
${CC} ${LDFLAGS} foo.o padding1.o padding2.o padding3.o padding4.o main.o -o a.out
8+
9+
%.o: $(SRCDIR)/%.s
10+
${CC} -c $<
11+
12+
#padding1.o: padding1.s
13+
# ${CC} -c $(SRCDIR)/padding1.s
14+
15+
#padding2.o: padding2.s
16+
# ${CC} -c $(SRCDIR)/padding2.s
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
Make sure that we can step in across an arm64 branch island
3+
"""
4+
5+
6+
import lldb
7+
import lldbsuite.test.lldbutil as lldbutil
8+
from lldbsuite.test.lldbtest import *
9+
from lldbsuite.test.decorators import *
10+
11+
12+
class TestBranchIslandStepping(TestBase):
13+
NO_DEBUG_INFO_TESTCASE = True
14+
15+
@skipUnlessAppleSilicon
16+
def test_step_in_branch_island(self):
17+
"""Make sure we can step in across a branch island"""
18+
self.build()
19+
self.main_source_file = lldb.SBFileSpec("main.c")
20+
self.do_test()
21+
22+
def do_test(self):
23+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
24+
self, "Set a breakpoint here", self.main_source_file
25+
)
26+
27+
# Make sure that we did manage to generate a branch island for foo:
28+
syms = target.FindSymbols("foo.island", lldb.eSymbolTypeCode)
29+
self.assertEqual(len(syms), 1, "We did generate an island for foo")
30+
31+
# Gathering some info to dump in case of failure:
32+
trace_before = lldbutil.print_stacktrace(thread, True)
33+
func_before = thread.frames[0].function
34+
35+
thread.StepInto()
36+
stop_frame = thread.frames[0]
37+
# This is failing on the bot, but I can't reproduce the failure
38+
# locally. Let's see if we can dump some more info here to help
39+
# figure out what went wrong...
40+
if stop_frame.name.find("foo") == -1:
41+
stream = lldb.SBStream()
42+
print("Branch island symbols: ")
43+
syms[0].GetDescription(stream)
44+
for i in range(0, 6):
45+
for sep in ["", "."]:
46+
syms = target.FindSymbols(
47+
f"foo.island{sep}{i}", lldb.eSymbolTypeCode
48+
)
49+
if len(syms) > 0:
50+
stream.Print("\n")
51+
syms[0].GetDescription(stream)
52+
53+
print(stream.GetData())
54+
print(f"Start backtrace:")
55+
print(trace_before)
56+
print(f"\n'main' disassembly:\n{lldbutil.disassemble(target, func_before)}")
57+
print("\nEnd backtrace:\n")
58+
lldbutil.print_stacktrace(thread)
59+
print(
60+
f"\nStop disassembly:\n {lldbutil.disassemble(target, stop_frame.function)}"
61+
)
62+
63+
self.assertIn("foo", stop_frame.name, "Stepped into foo")
64+
var = stop_frame.FindVariable("a_variable_in_foo")
65+
self.assertTrue(var.IsValid(), "Found the variable in foo")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <stdio.h>
2+
3+
void foo() {
4+
int a_variable_in_foo = 10;
5+
printf("I am foo: %d.\n", a_variable_in_foo);
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
extern void foo();
2+
3+
int main() {
4+
foo(); // Set a breakpoint here
5+
return 0;
6+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.text
2+
_padding1:
3+
.space 120*1024*1024
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.text
2+
_padding2:
3+
.space 120*1024*1024
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.text
2+
_padding3:
3+
.space 120*1024*1024
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.text
2+
_padding4:
3+
.space 120*1024*1024

0 commit comments

Comments
 (0)