GDB uses DWARF CFI meta-instructions to know how to backtrace through
function call frames, and which registers get saved where.
This patch fixes the CFI instructions in the syscall_entry() assembly
code. After this patch, if we are in system call code we can backtrack
through the syscall_entry() - for example:
5 0x000000000059c10b in syscall_wrapper (number=186) at linux.cc:332
6 0x0000000000480245 in syscall_entry () at arch/x64/entry.S:238
7 0x0000100000c00bce in main (argc=1, argv=<optimized out>)
at /home/nyh/osv/tests/tst-syscall.cc:49
8 0x000000000063526e in osv::application::run_main (this=0xffffa00003079910,
path="tests/tst-syscall.so", argc=1, argv=0xffffa00001f88170)
at core/app.cc:338
Note how syscall_entry() looks like a normal function - it no longer
pretends to be a "signal frame". In particular, we no longer need to
obey a specific layout of the registers saved on the stack, so I took
this opportunity to remove some of the useless things we saved (like rax,
which will be overwritten by a return value anyway) or saved multiple times
(rcx, rsp).
Signed-off-by: Nadav Har'El <[email protected]>
---
arch/x64/entry.S | 105 ++++++++++++++++++++++---------------------------------
1 file changed, 41 insertions(+), 64 deletions(-)
diff --git a/arch/x64/entry.S b/arch/x64/entry.S
index e265a30..2bd8df5 100644
--- a/arch/x64/entry.S
+++ b/arch/x64/entry.S
@@ -164,66 +164,44 @@ call_signal_handler_thunk:
syscall_entry:
.type syscall_entry, @function
.cfi_startproc simple
+ .cfi_undefined rcx # was overwritten with rip by the syscall instruction
+ .cfi_undefined r11 # was overwritten with rflags by the syscall instruction
+ .cfi_register rip, rcx # rcx took previous rip value
+ .cfi_register rflags, r11 # r11 took previous rflags value
# There is no ring transition and rflags are left unchanged.
# Skip the "red zone" allowed by the AMD64 ABI (the caller used a
# SYSCALL instruction and doesn't know he called a function):
subq $128, %rsp
+ .cfi_def_cfa %rsp, 0
# We need to save and restore the caller's %rbp anyway, so let's also
# set it up properly for old-style frame-pointer backtracing to work
# (e.g., backtrace_safe()). Also need to push the return address before
# the rbp to get a normal frame. Our return address is in rcx.
- pushq %rcx
- pushq %rbp
+ pushq_cfi %rcx
+ .cfi_rel_offset %rip, 0
+ pushq_cfi %rbp
movq %rsp, %rbp
+ .cfi_rel_offset %rsp, 0
#
# From
http://stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-on-x86-64:
# "User-level applications use as integer registers for passing the
sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9. The kernel interface uses %rdi,
%rsi, %rdx, %r10, %r8 and %r9"
# FIXME: fpu
- # build the stack frame by hand
- pushq %rsp
- subq $8, %rsp # rip was saved in rcx by the syscall instruction
- pushq %rax
- pushq %rbx
- pushq %rcx # contains rip before syscall instruction
- pushq %rdx
- pushq %rsi
- pushq %rdi
- pushq %r8
- pushq %r9
- pushq %r10
- pushq %r11 # contains rflags before syscall instruction
- pushq %r12
- pushq %r13
- pushq %r14
- pushq %r15
-
- # stack contains a signal_frame
- .cfi_signal_frame
- .cfi_def_cfa %rsp, 0
- .cfi_register rip,rcx # rcx took previous rip value
- .cfi_register rflags,r11 # r11 took previous rflags value
- .cfi_undefined rcx # was overwritten with rip by the syscall instruction
- .cfi_undefined r11 # was overwritten with rflags by the syscall
instruction
- .cfi_offset %r15, 0x00
- .cfi_offset %r14, 0x08
- .cfi_offset %r13, 0x10
- .cfi_offset %r12, 0x18
- .cfi_offset %r11, 0x20
- .cfi_offset %r10, 0x28
- .cfi_offset %r9, 0x30
- .cfi_offset %r8, 0x38
- .cfi_offset %rbp, 0x40
- .cfi_offset %rdi, 0x48
- .cfi_offset %rsi, 0x50
- .cfi_offset %rdx, 0x58
- .cfi_offset %rcx, 0x60
- .cfi_offset %rbx, 0x68
- .cfi_offset %rax, 0x70
- .cfi_offset %rip, 0x80
- .cfi_offset %rsp, 0x98
+ pushq_cfi %rbx
+ pushq_cfi %rdx
+ pushq_cfi %rsi
+ pushq_cfi %rdi
+ pushq_cfi %r8
+ pushq_cfi %r9
+ pushq_cfi %r10
+ pushq_cfi %r11 # contains rflags before syscall instruction
+ .cfi_rel_offset %rflags, 0
+ pushq_cfi %r12
+ pushq_cfi %r13
+ pushq_cfi %r14
+ pushq_cfi %r15
# The kernel interface use r10 as fourth argument while the user interface
use rcx
# so overwrite rcx with r10
@@ -231,7 +209,7 @@ syscall_entry:
# prepare function call parameter: r9 is on the stack since it's the
seventh param
# because we shift existing params by one to make room for syscall number
- pushq %r9
+ pushq_cfi %r9
movq %r8, %r9
movq %rcx, %r8
movq %rdx, %rcx
@@ -254,34 +232,33 @@ syscall_entry:
# restore it from 8(%rsp).
pushq %rsp
pushq (%rsp)
+ .cfi_adjust_cfa_offset 16
andq $-0x10, %rsp
+ .cfi_rel_offset %rsp, 8
callq syscall_wrapper
movq 8(%rsp), %rsp
+ .cfi_adjust_cfa_offset -16
- popq %r9
+ popq_cfi %r9
# in Linux user and kernel return value are in rax so we have nothing to
do for return values
- popq %r15
- popq %r14
- popq %r13
- popq %r12
- popq %r11
- popq %r10
- popq %r9
- popq %r8
- popq %rdi
- popq %rsi
- popq %rdx
- popq %rcx
- popq %rbx
- addq $8, %rsp # skip rax emplacement (return value is in rax)
- addq $8, %rsp # rip emplacement (rip cannot be popped)
- popq %rsp
+ popq_cfi %r15
+ popq_cfi %r14
+ popq_cfi %r13
+ popq_cfi %r12
+ popq_cfi %r11
+ popq_cfi %r10
+ popq_cfi %r9
+ popq_cfi %r8
+ popq_cfi %rdi
+ popq_cfi %rsi
+ popq_cfi %rdx
+ popq_cfi %rbx
- popq %rbp
- popq %rcx
+ popq_cfi %rbp
+ popq_cfi %rcx
addq $128, %rsp # undo red-zone skip
--
2.7.4
--
You received this message because you are subscribed to the Google Groups "OSv
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.