Skip to content

Commit

Permalink
Put our dl_runtime_resolve prelude code in a .plt section in librrpag…
Browse files Browse the repository at this point in the history
…e.so, so that gdb's heuristics for stepping through dl_runtime_resolve step through our prelude code as well.

Resolves #3695
  • Loading branch information
rocallahan committed Feb 24, 2024
1 parent 5722778 commit 8cc36ce
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 32 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1545,6 +1545,7 @@ set(TESTS_WITH_PROGRAM
simple
x86/singlestep_pushf
stack_growth
step_into_lib
step_thread
strict_priorities
x86/string_instructions
Expand Down Expand Up @@ -1821,8 +1822,10 @@ if(BUILD_TESTS)
PROPERTIES COMPILE_FLAGS ${RR_TEST_FLAGS})
if(LIBRT)
target_link_libraries(constructor ${LIBRT})
target_link_libraries(step_into_lib ${LIBRT})
endif()
target_link_libraries(constructor test_lib)
target_link_libraries(step_into_lib test_lib)

# cpuid test needs to link with cpuid_loop.S
if (x86ish)
Expand Down Expand Up @@ -1977,8 +1980,10 @@ if(BUILD_TESTS)

if(LIBRT_32)
target_link_libraries(constructor_32 ${LIBRT_32})
target_link_libraries(step_into_lib_32 ${LIBRT_32})
endif()
target_link_libraries(constructor_32 test_lib_32)
target_link_libraries(step_into_lib_32 test_lib_32)

# cpuid test needs to link with cpuid_loop.S
add_executable(cpuid_32 32/x86/cpuid.c 32/x86/cpuid_loop.S)
Expand Down
25 changes: 5 additions & 20 deletions src/Monkeypatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1516,8 +1516,7 @@ static void set_and_record_bytes(RecordTask* t, ElfReader& reader,
* register so that CPU-specific behaviors involving that register don't leak
* into stack memory.
*/
static void patch_dl_runtime_resolve(Monkeypatcher& patcher,
RecordTask* t, ElfReader& reader,
static void patch_dl_runtime_resolve(RecordTask* t, ElfReader& reader,
uintptr_t elf_addr,
remote_ptr<void> map_start,
size_t map_size,
Expand Down Expand Up @@ -1547,27 +1546,13 @@ static void patch_dl_runtime_resolve(Monkeypatcher& patcher,
return;
}

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

remote_ptr<uint8_t> extended_call_start =
allocate_extended_jump_x86ish<X64DLRuntimeResolvePrelude>(
t, patcher.extended_jump_pages, call_patch_end);
if (extended_call_start.is_null()) {
return;
}
uint8_t stub_patch[X64DLRuntimeResolvePrelude::size];
X64DLRuntimeResolvePrelude::substitute(stub_patch);
write_and_record_bytes(t, extended_call_start, stub_patch);

intptr_t call_offset = extended_call_start - call_patch_end;
int32_t call_offset32 = (int32_t)call_offset;
ASSERT(t, call_offset32 == call_offset)
<< "allocate_extended_jump_x86ish didn't work";
X64CallMonkeypatch::substitute(call_patch, call_offset32);
X64AbsoluteIndirectCallMonkeypatch::substitute(call_patch,
RR_PAGE_ADDR - PRELOAD_LIBRARY_PAGE_SIZE);
write_and_record_bytes(t, call_patch_start, call_patch);

// pad with NOPs to the next instruction
Expand Down Expand Up @@ -1657,7 +1642,7 @@ void Monkeypatcher::patch_after_mmap(RecordTask* t, remote_ptr<void> start,
(syms.is_name(i, "_dl_runtime_resolve_fxsave") ||
syms.is_name(i, "_dl_runtime_resolve_xsave") ||
syms.is_name(i, "_dl_runtime_resolve_xsavec"))) {
patch_dl_runtime_resolve(*this, t, reader, syms.addr(i), start, size,
patch_dl_runtime_resolve(t, reader, syms.addr(i), start, size,
offset_bytes);
}
}
Expand Down
16 changes: 4 additions & 12 deletions src/assembly_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ def bytes(self):
RawBytes(0xe9), # jmp $relative_addr
Field('relative_addr', 4),
),
'X64AbsoluteIndirectCallMonkeypatch': AssemblyTemplate(
RawBytes(0xff, 0x14, 0x25), # call [absolute_addr]
Field('absolute_addr', 4),
),
'X64SyscallStubExtendedJump': AssemblyTemplate(
# This code must match the stubs in syscall_hook.S.
RawBytes(0x48, 0x89, 0x24, 0x25, 0x10, 0x10, 0x00, 0x70), # movq %rsp,(stub_scratch_1)
Expand Down Expand Up @@ -194,18 +198,6 @@ def bytes(self):
RawBytes(0x48, 0x89, 0xe3), # mov %rsp,%rbx
RawBytes(0x48, 0x83, 0xe4, 0xc0), # and $0xffffffffffffffc0,%rsp
),
'X64DLRuntimeResolvePrelude': AssemblyTemplate(
RawBytes(0xd9, 0x74, 0x24, 0xe0), # fstenv -32(%rsp)
RawBytes(0x48, 0xc7, 0x44, 0x24, 0xf4, 0x00, 0x00, 0x00, 0x00), # movq $0,-12(%rsp)
RawBytes(0xd9, 0x64, 0x24, 0xe0), # fldenv -32(%rsp)
RawBytes(0x48, 0x87, 0x1c, 0x24), # xchg (%rsp),%rbx
# r11 is destroyed anyways by _dl_runtime_resolve, so we can use it here.
RawBytes(0x49, 0x89, 0xdb), # mov %rbx,%r11
RawBytes(0x48, 0x89, 0xe3), # mov %rsp,%rbx
RawBytes(0x48, 0x83, 0xe4, 0xc0), # and $0xffffffffffffffc0,%rsp
RawBytes(0x41, 0x53), # push %r11
RawBytes(0xc3), # ret
),
'X64EndBr': AssemblyTemplate(
RawBytes(0xf3, 0x0f, 0x1e, 0xfa)
),
Expand Down
1 change: 1 addition & 0 deletions src/preload/rr_page.ld.in
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ SECTIONS
scripts can't specify these locations for legacy reasons */
.sh_placeholder : { *(.sh_placeholder) } :header
. = 0x70000000 - @PRELOAD_LIBRARY_PAGE_SIZE@;
.plt : { *(.plt) } :text
.vdso.text : { *(.vdso.text) } :text
. = 0x70000000;
.record.text : { *(.record.text) } :text
Expand Down
20 changes: 20 additions & 0 deletions src/preload/rr_vdso.S
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,26 @@

#if defined(__x86_64__)

.section .plt, "a", @progbits

// Current address is 0x70000000 - PRELOAD_LIBRARY_PAGE_SIZE
// The following is equal to __rr_dl_runtime_resolve_prelude,
// but doesn't introduce a relocation record.
.quad 0x70000000 - PRELOAD_LIBRARY_PAGE_SIZE + 8

STARTPROC_GLOBAL(__rr_dl_runtime_resolve_prelude)
fstenv -32(%rsp)
movq $0,-12(%rsp)
fldenv -32(%rsp)
xchg (%rsp),%rbx
# r11 is destroyed anyway by _dl_runtime_resolve, so we can use it here.
mov %rbx,%r11
mov %rsp,%rbx
and $0xffffffffffffffc0,%rsp
push %r11
ret
CFI_ENDPROC

#define SYSCALL(which) \
movq $which, %rax; \
syscall; \
Expand Down
10 changes: 10 additions & 0 deletions src/test/step_into_lib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* -*- Mode: C; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */

#include "util.h"

void lib_exit_success(void);

int main(void) {
lib_exit_success();
return 0;
}
12 changes: 12 additions & 0 deletions src/test/step_into_lib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from util import *
import re

send_gdb('b main')
expect_gdb('Breakpoint 1')
send_gdb('continue')
expect_gdb('Breakpoint 1')
send_gdb('s')
# Should have stepped into lib_exit_success where there's an atomic_puts
expect_gdb('atomic_puts')

ok()
2 changes: 2 additions & 0 deletions src/test/step_into_lib.run
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
source `dirname $0`/util.sh
debug_test_gdb_only

0 comments on commit 8cc36ce

Please sign in to comment.