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.

Reply via email to