Skip to content

Commit 8cc36ce

Browse files
committed
Put our dl_runtime_resolve prelude code in a .plt section in librrpage.so, so that gdb's heuristics for stepping through dl_runtime_resolve step through our prelude code as well.
Resolves #3695
1 parent 5722778 commit 8cc36ce

8 files changed

+59
-32
lines changed

CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,7 @@ set(TESTS_WITH_PROGRAM
15451545
simple
15461546
x86/singlestep_pushf
15471547
stack_growth
1548+
step_into_lib
15481549
step_thread
15491550
strict_priorities
15501551
x86/string_instructions
@@ -1821,8 +1822,10 @@ if(BUILD_TESTS)
18211822
PROPERTIES COMPILE_FLAGS ${RR_TEST_FLAGS})
18221823
if(LIBRT)
18231824
target_link_libraries(constructor ${LIBRT})
1825+
target_link_libraries(step_into_lib ${LIBRT})
18241826
endif()
18251827
target_link_libraries(constructor test_lib)
1828+
target_link_libraries(step_into_lib test_lib)
18261829

18271830
# cpuid test needs to link with cpuid_loop.S
18281831
if (x86ish)
@@ -1977,8 +1980,10 @@ if(BUILD_TESTS)
19771980

19781981
if(LIBRT_32)
19791982
target_link_libraries(constructor_32 ${LIBRT_32})
1983+
target_link_libraries(step_into_lib_32 ${LIBRT_32})
19801984
endif()
19811985
target_link_libraries(constructor_32 test_lib_32)
1986+
target_link_libraries(step_into_lib_32 test_lib_32)
19821987

19831988
# cpuid test needs to link with cpuid_loop.S
19841989
add_executable(cpuid_32 32/x86/cpuid.c 32/x86/cpuid_loop.S)

src/Monkeypatcher.cc

+5-20
Original file line numberDiff line numberDiff line change
@@ -1516,8 +1516,7 @@ static void set_and_record_bytes(RecordTask* t, ElfReader& reader,
15161516
* register so that CPU-specific behaviors involving that register don't leak
15171517
* into stack memory.
15181518
*/
1519-
static void patch_dl_runtime_resolve(Monkeypatcher& patcher,
1520-
RecordTask* t, ElfReader& reader,
1519+
static void patch_dl_runtime_resolve(RecordTask* t, ElfReader& reader,
15211520
uintptr_t elf_addr,
15221521
remote_ptr<void> map_start,
15231522
size_t map_size,
@@ -1547,27 +1546,13 @@ static void patch_dl_runtime_resolve(Monkeypatcher& patcher,
15471546
return;
15481547
}
15491548

1550-
uint8_t call_patch[X64CallMonkeypatch::size];
1549+
uint8_t call_patch[X64AbsoluteIndirectCallMonkeypatch::size];
15511550
// We're patching in a relative call, so we need to compute the offset from
15521551
// the end of the call to our actual destination.
15531552
auto call_patch_start = addr.cast<uint8_t>();
1554-
auto call_patch_end = call_patch_start + sizeof(call_patch);
15551553

1556-
remote_ptr<uint8_t> extended_call_start =
1557-
allocate_extended_jump_x86ish<X64DLRuntimeResolvePrelude>(
1558-
t, patcher.extended_jump_pages, call_patch_end);
1559-
if (extended_call_start.is_null()) {
1560-
return;
1561-
}
1562-
uint8_t stub_patch[X64DLRuntimeResolvePrelude::size];
1563-
X64DLRuntimeResolvePrelude::substitute(stub_patch);
1564-
write_and_record_bytes(t, extended_call_start, stub_patch);
1565-
1566-
intptr_t call_offset = extended_call_start - call_patch_end;
1567-
int32_t call_offset32 = (int32_t)call_offset;
1568-
ASSERT(t, call_offset32 == call_offset)
1569-
<< "allocate_extended_jump_x86ish didn't work";
1570-
X64CallMonkeypatch::substitute(call_patch, call_offset32);
1554+
X64AbsoluteIndirectCallMonkeypatch::substitute(call_patch,
1555+
RR_PAGE_ADDR - PRELOAD_LIBRARY_PAGE_SIZE);
15711556
write_and_record_bytes(t, call_patch_start, call_patch);
15721557

15731558
// pad with NOPs to the next instruction
@@ -1657,7 +1642,7 @@ void Monkeypatcher::patch_after_mmap(RecordTask* t, remote_ptr<void> start,
16571642
(syms.is_name(i, "_dl_runtime_resolve_fxsave") ||
16581643
syms.is_name(i, "_dl_runtime_resolve_xsave") ||
16591644
syms.is_name(i, "_dl_runtime_resolve_xsavec"))) {
1660-
patch_dl_runtime_resolve(*this, t, reader, syms.addr(i), start, size,
1645+
patch_dl_runtime_resolve(t, reader, syms.addr(i), start, size,
16611646
offset_bytes);
16621647
}
16631648
}

src/assembly_templates.py

+4-12
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ def bytes(self):
132132
RawBytes(0xe9), # jmp $relative_addr
133133
Field('relative_addr', 4),
134134
),
135+
'X64AbsoluteIndirectCallMonkeypatch': AssemblyTemplate(
136+
RawBytes(0xff, 0x14, 0x25), # call [absolute_addr]
137+
Field('absolute_addr', 4),
138+
),
135139
'X64SyscallStubExtendedJump': AssemblyTemplate(
136140
# This code must match the stubs in syscall_hook.S.
137141
RawBytes(0x48, 0x89, 0x24, 0x25, 0x10, 0x10, 0x00, 0x70), # movq %rsp,(stub_scratch_1)
@@ -194,18 +198,6 @@ def bytes(self):
194198
RawBytes(0x48, 0x89, 0xe3), # mov %rsp,%rbx
195199
RawBytes(0x48, 0x83, 0xe4, 0xc0), # and $0xffffffffffffffc0,%rsp
196200
),
197-
'X64DLRuntimeResolvePrelude': AssemblyTemplate(
198-
RawBytes(0xd9, 0x74, 0x24, 0xe0), # fstenv -32(%rsp)
199-
RawBytes(0x48, 0xc7, 0x44, 0x24, 0xf4, 0x00, 0x00, 0x00, 0x00), # movq $0,-12(%rsp)
200-
RawBytes(0xd9, 0x64, 0x24, 0xe0), # fldenv -32(%rsp)
201-
RawBytes(0x48, 0x87, 0x1c, 0x24), # xchg (%rsp),%rbx
202-
# r11 is destroyed anyways by _dl_runtime_resolve, so we can use it here.
203-
RawBytes(0x49, 0x89, 0xdb), # mov %rbx,%r11
204-
RawBytes(0x48, 0x89, 0xe3), # mov %rsp,%rbx
205-
RawBytes(0x48, 0x83, 0xe4, 0xc0), # and $0xffffffffffffffc0,%rsp
206-
RawBytes(0x41, 0x53), # push %r11
207-
RawBytes(0xc3), # ret
208-
),
209201
'X64EndBr': AssemblyTemplate(
210202
RawBytes(0xf3, 0x0f, 0x1e, 0xfa)
211203
),

src/preload/rr_page.ld.in

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ SECTIONS
3232
scripts can't specify these locations for legacy reasons */
3333
.sh_placeholder : { *(.sh_placeholder) } :header
3434
. = 0x70000000 - @PRELOAD_LIBRARY_PAGE_SIZE@;
35+
.plt : { *(.plt) } :text
3536
.vdso.text : { *(.vdso.text) } :text
3637
. = 0x70000000;
3738
.record.text : { *(.record.text) } :text

src/preload/rr_vdso.S

+20
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,26 @@
1313

1414
#if defined(__x86_64__)
1515

16+
.section .plt, "a", @progbits
17+
18+
// Current address is 0x70000000 - PRELOAD_LIBRARY_PAGE_SIZE
19+
// The following is equal to __rr_dl_runtime_resolve_prelude,
20+
// but doesn't introduce a relocation record.
21+
.quad 0x70000000 - PRELOAD_LIBRARY_PAGE_SIZE + 8
22+
23+
STARTPROC_GLOBAL(__rr_dl_runtime_resolve_prelude)
24+
fstenv -32(%rsp)
25+
movq $0,-12(%rsp)
26+
fldenv -32(%rsp)
27+
xchg (%rsp),%rbx
28+
# r11 is destroyed anyway by _dl_runtime_resolve, so we can use it here.
29+
mov %rbx,%r11
30+
mov %rsp,%rbx
31+
and $0xffffffffffffffc0,%rsp
32+
push %r11
33+
ret
34+
CFI_ENDPROC
35+
1636
#define SYSCALL(which) \
1737
movq $which, %rax; \
1838
syscall; \

src/test/step_into_lib.c

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* -*- Mode: C; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
2+
3+
#include "util.h"
4+
5+
void lib_exit_success(void);
6+
7+
int main(void) {
8+
lib_exit_success();
9+
return 0;
10+
}

src/test/step_into_lib.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from util import *
2+
import re
3+
4+
send_gdb('b main')
5+
expect_gdb('Breakpoint 1')
6+
send_gdb('continue')
7+
expect_gdb('Breakpoint 1')
8+
send_gdb('s')
9+
# Should have stepped into lib_exit_success where there's an atomic_puts
10+
expect_gdb('atomic_puts')
11+
12+
ok()

src/test/step_into_lib.run

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
source `dirname $0`/util.sh
2+
debug_test_gdb_only

0 commit comments

Comments
 (0)