From: Nadav Har'El <[email protected]>
Committer: Nadav Har'El <[email protected]>
Branch: master

syscall: fix CFI information for debugging with GDB

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]>
Message-Id: <[email protected]>

---
diff --git a/arch/x64/entry.S b/arch/x64/entry.S
--- a/arch/x64/entry.S
+++ b/arch/x64/entry.S
@@ -164,78 +164,52 @@ 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
-
-    # 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
     movq %r10, %rcx

# 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
@@ -258,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

--
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