mailing list of musl libc
 help / color / mirror / code / Atom feed
* [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script
@ 2015-10-13 11:28 Alex Dowad
  2015-10-13 11:28 ` [PATCH 2/3] x86 CFI generation script recognizes when %ax, %ah, %al, etc. are overwritten Alex Dowad
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Alex Dowad @ 2015-10-13 11:28 UTC (permalink / raw)
  To: musl

thanks to R. Felker for noticing 2 separate problems:

- binary ops like ADD, AND, etc. overwrite the 2nd operand, not the 1st.
  this confusion resulted from mixing up Intel and GNU asm syntax.

- the regexps used to identify clobbered registers would erroneously match
  index registers. in other words, the following asm:

    mov $0, (%eax,%ebx,4)

...would cause EBX to be considered as overwritten, which might prevent a
debugger from displaying a variable's value in a higher stack frame.
---

Here is the latest iteration. I have merged 2 previously separate commits, and
fixed up the matching of registers (for the purpose of identifying overwritten
registers).

As usual, thanks for the feedback. AD

 tools/add-cfi.i386.awk | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/tools/add-cfi.i386.awk b/tools/add-cfi.i386.awk
index 5dc8794..bd7932f 100644
--- a/tools/add-cfi.i386.awk
+++ b/tools/add-cfi.i386.awk
@@ -184,13 +184,13 @@ function trashed(register) {
 }
 # this does NOT exhaustively check for all possible instructions which could
 # overwrite a register value inherited from the caller (just the common ones)
-/mov.*,%e(ax|bx|cx|dx|si|di|bp)/  { trashed(get_reg2()) }
-/(add|addl|sub|subl|and|or|xor|lea|sal|sar|shl|shr) %e(ax|bx|cx|dx|si|di|bp),/ {
-  trashed(get_reg1())
+/mov.*,%e(ax|bx|cx|dx|si|di|bp)$/  { trashed(get_reg2()) }
+/(add|addl|sub|subl|and|or|xor|lea|sal|sar|shl|shr).*,%e(ax|bx|cx|dx|si|di|bp)$/ {
+  trashed(get_reg2())
 }
-/^i?mul [^,]*$/                    { trashed("eax"); trashed("edx") }
-/^i?mul %e(ax|bx|cx|dx|si|di|bp),/ { trashed(get_reg1()) }
-/^i?div/                           { trashed("eax"); trashed("edx") }
+/^i?mul [^,]*$/                      { trashed("eax"); trashed("edx") }
+/^i?mul.*,%e(ax|bx|cx|dx|si|di|bp)$/ { trashed(get_reg2()) }
+/^i?div/                             { trashed("eax"); trashed("edx") }
 /(dec|inc|not|neg|pop) %e(ax|bx|cx|dx|si|di|bp)/  { trashed(get_reg()) }
 /cpuid/ { trashed("eax"); trashed("ebx"); trashed("ecx"); trashed("edx") }
 
-- 
2.0.0.GIT



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 2/3] x86 CFI generation script recognizes when %ax, %ah, %al, etc. are overwritten
  2015-10-13 11:28 [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script Alex Dowad
@ 2015-10-13 11:28 ` Alex Dowad
  2015-10-13 11:28 ` [PATCH 3/3] add CFI generation script for x86_64 Alex Dowad
  2015-10-13 22:42 ` [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script Rich Felker
  2 siblings, 0 replies; 12+ messages in thread
From: Alex Dowad @ 2015-10-13 11:28 UTC (permalink / raw)
  To: musl

this may help a debugger to know which variable values from higher stack frames
are still available and can legitimately be printed.

thanks to R. Felker for this suggestion.
---
 tools/add-cfi.i386.awk | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/tools/add-cfi.i386.awk b/tools/add-cfi.i386.awk
index bd7932f..9162e30 100644
--- a/tools/add-cfi.i386.awk
+++ b/tools/add-cfi.i386.awk
@@ -27,20 +27,29 @@ function get_const1() {
   match($0, /-?(0x[0-9a-fA-F]+|[0-9]+),/)
   return parse_const(substr($0, RSTART, RLENGTH-1))
 }
+
+function canonicalize_reg(register) {
+  if (match(register, /^e/))
+    return register
+  else if (match(register, /[hl]$/)) # AH, AL, BH, BL, etc
+    return "e" substr(register, 1, 1) "x"
+  else # AX, BX, CX, etc
+    return "e" register
+}
 function get_reg() {
   # only use if you already know there is 1 and only 1 register
-  match($0, /%e(ax|bx|cx|dx|si|di|bp)/)
-  return substr($0, RSTART+1, 3)
+  match($0, /%e?([abcd][hlx]|si|di|bp)/)
+  return canonicalize_reg(substr($0, RSTART+1, RLENGTH-1))
 }
 function get_reg1() {
   # for instructions with 2 operands, get 1st operand (assuming it is register)
-  match($0, /%e(ax|bx|cx|dx|si|di|bp),/)
-  return substr($0, RSTART+1, 3)
+  match($0, /%e?([abcd][hlx]|si|di|bp),/)
+  return canonicalize_reg(substr($0, RSTART+1, RLENGTH-2))
 }
 function get_reg2() {
   # for instructions with 2 operands, get 2nd operand (assuming it is register)
-  match($0, /,%e(ax|bx|cx|dx|si|di|bp)/)
-  return substr($0, RSTART+RLENGTH-3, 3)
+  match($0, /,%e?([abcd][hlx]|si|di|bp)/)
+  return canonicalize_reg(substr($0, RSTART+2, RLENGTH-2))
 }
 
 function adjust_sp_offset(delta) {
@@ -184,14 +193,14 @@ function trashed(register) {
 }
 # this does NOT exhaustively check for all possible instructions which could
 # overwrite a register value inherited from the caller (just the common ones)
-/mov.*,%e(ax|bx|cx|dx|si|di|bp)$/  { trashed(get_reg2()) }
-/(add|addl|sub|subl|and|or|xor|lea|sal|sar|shl|shr).*,%e(ax|bx|cx|dx|si|di|bp)$/ {
+/mov.*,%e?([abcd][hlx]|si|di|bp)$/  { trashed(get_reg2()) }
+/(add|addl|sub|subl|and|or|xor|lea|sal|sar|shl|shr).*,%e?([abcd][hlx]|si|di|bp)$/ {
   trashed(get_reg2())
 }
 /^i?mul [^,]*$/                      { trashed("eax"); trashed("edx") }
-/^i?mul.*,%e(ax|bx|cx|dx|si|di|bp)$/ { trashed(get_reg2()) }
+/^i?mul.*,%e?([abcd][hlx]|si|di|bp)$/ { trashed(get_reg2()) }
 /^i?div/                             { trashed("eax"); trashed("edx") }
-/(dec|inc|not|neg|pop) %e(ax|bx|cx|dx|si|di|bp)/  { trashed(get_reg()) }
+/(dec|inc|not|neg|pop) %e?([abcd][hlx]|si|di|bp)/  { trashed(get_reg()) }
 /cpuid/ { trashed("eax"); trashed("ebx"); trashed("ecx"); trashed("edx") }
 
 END {
-- 
2.0.0.GIT



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 3/3] add CFI generation script for x86_64
  2015-10-13 11:28 [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script Alex Dowad
  2015-10-13 11:28 ` [PATCH 2/3] x86 CFI generation script recognizes when %ax, %ah, %al, etc. are overwritten Alex Dowad
@ 2015-10-13 11:28 ` Alex Dowad
  2015-10-13 22:42 ` [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script Rich Felker
  2 siblings, 0 replies; 12+ messages in thread
From: Alex Dowad @ 2015-10-13 11:28 UTC (permalink / raw)
  To: musl

this makes debugging more pleasant when you have to dig into x86_64 assembly,
since GCC can obtain accurate stack traces. it turns out that the parts we care
about are almost exactly like i386, except for the register names!
---
 tools/add-cfi.x86_64.awk | 196 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 196 insertions(+)
 create mode 100644 tools/add-cfi.x86_64.awk

diff --git a/tools/add-cfi.x86_64.awk b/tools/add-cfi.x86_64.awk
new file mode 100644
index 0000000..bbc90da
--- /dev/null
+++ b/tools/add-cfi.x86_64.awk
@@ -0,0 +1,196 @@
+# Insert GAS CFI directives ("control frame information") into x86-64 asm input
+
+BEGIN {
+  # don't put CFI data in the .eh_frame ELF section (which we don't keep)
+  print ".cfi_sections .debug_frame"
+
+  # only emit CFI directives inside a function
+  in_function = 0
+
+  # emit .loc directives with line numbers from original source
+  printf ".file 1 \"%s\"\n", ARGV[1]
+  line_number = 0
+
+  # used to detect "call label; label:" trick
+  called = ""
+}
+
+function get_const1() {
+  # for instructions with 2 operands, get 1st operand (assuming it is constant)
+  match($0, /-?(0x[0-9a-fA-F]+|[0-9]+),/)
+  return parse_const(substr($0, RSTART, RLENGTH-1))
+}
+
+function canonicalize_reg(register) {
+  if (match(register, /^r/))
+    return register
+  else if (match(register, /^e/))
+    return "r" substr(register, 2, length(register)-1)
+  else if (match(register, /[hl]$/)) # AH, AL, BH, BL, etc
+    return "r" substr(register, 1, 1) "x"
+  else # AX, BX, CX, etc
+    return "r" register
+}
+function get_reg() {
+  # only use if you already know there is 1 and only 1 register
+  match($0, /%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)/)
+  return canonicalize_reg(substr($0, RSTART+1, RLENGTH-1))
+}
+function get_reg1() {
+  # for instructions with 2 operands, get 1st operand (assuming it is register)
+  match($0, /%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15),/)
+  return canonicalize_reg(substr($0, RSTART+1, RLENGTH-2))
+}
+function get_reg2() {
+  # for instructions with 2 operands, get 2nd operand (assuming it is register)
+  match($0, /,%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)/)
+  return canonicalize_reg(substr($0, RSTART+2, RLENGTH-2))
+}
+
+function adjust_sp_offset(delta) {
+  if (in_function)
+    printf ".cfi_adjust_cfa_offset %d\n", delta
+}
+
+{
+  line_number = line_number + 1
+
+  # clean the input up before doing anything else
+  # delete comments
+  gsub(/(#|\/\/).*/, "")
+
+  # canonicalize whitespace
+  gsub(/[ \t]+/, " ") # mawk doesn't understand \s
+  gsub(/ *, */, ",")
+  gsub(/ *: */, ": ")
+  gsub(/ $/, "")
+  gsub(/^ /, "")
+}
+
+# check for assembler directives which we care about
+/^\.(section|data|text)/ {
+  # a .cfi_startproc/.cfi_endproc pair should be within the same section
+  # otherwise, clang will choke when generating ELF output
+  if (in_function) {
+    print ".cfi_endproc"
+    in_function = 0
+  }
+}
+/^\.type [a-zA-Z0-9_]+,\@function/ {
+  functions[substr($2, 1, length($2)-10)] = 1
+}
+# not interested in assembler directives beyond this, just pass them through
+/^\./ {
+  print
+  next
+}
+
+/^[a-zA-Z0-9_]+:/ {
+  label = substr($1, 1, length($1)-1) # drop trailing :
+
+  if (called == label) {
+    # note adjustment of stack pointer from "call label; label:"
+    adjust_sp_offset(8)
+  }
+
+  if (functions[label]) {
+    if (in_function)
+      print ".cfi_endproc"
+
+    in_function = 1
+    print ".cfi_startproc"
+
+    for (register in saved)
+      delete saved[register]
+    for (register in dirty)
+      delete dirty[register]
+  }
+
+  # an instruction may follow on the same line, so continue processing
+}
+
+/^$/ { next }
+
+{
+  called = ""
+  printf ".loc 1 %d\n", line_number
+  print
+}
+
+# KEEPING UP WITH THE STACK POINTER
+# %rsp should only be adjusted by pushing/popping or adding/subtracting constants
+#
+/pushl?/ {
+  adjust_sp_offset(8)
+}
+/popl?/ {
+  adjust_sp_offset(-8)
+}
+/addl? \$-?(0x[0-9a-fA-F]+|[0-9]+),%rsp/ { adjust_sp_offset(-get_const1()) }
+/subl? \$-?(0x[0-9a-fA-F]+|[0-9]+),%rsp/ { adjust_sp_offset(get_const1()) }
+
+/call/ {
+  if (match($0, /call [0-9]+f/)) # "forward" label
+    called = substr($0, RSTART+5, RLENGTH-6)
+  else if (match($0, /call [0-9a-zA-Z_]+/))
+    called = substr($0, RSTART+5, RLENGTH-5)
+}
+
+# TRACKING REGISTER VALUES FROM THE PREVIOUS STACK FRAME
+#
+/pushl? %r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15)/ { # don't match "push (%reg)"
+  # if a register is being pushed, and its value has not changed since the
+  #   beginning of this function, the pushed value can be used when printing
+  #   local variables at the next level up the stack
+  # emit '.cfi_rel_offset' for that
+
+  if (in_function) {
+    register = get_reg()
+    if (!saved[register] && !dirty[register]) {
+      printf ".cfi_rel_offset %s,0\n", register
+      saved[register] = 1
+    }
+  }
+}
+
+/movl? %r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15),-?(0x[0-9a-fA-F]+|[0-9]+)?\(%rsp\)/ {
+  if (in_function) {
+    register = get_reg()
+    if (match($0, /-?(0x[0-9a-fA-F]+|[0-9]+)\(%rsp\)/)) {
+      offset = parse_const(substr($0, RSTART, RLENGTH-6))
+    } else {
+      offset = 0
+    }
+    if (!saved[register] && !dirty[register]) {
+      printf ".cfi_rel_offset %s,%d\n", register, offset
+      saved[register] = 1
+    }
+  }
+}
+
+# IF REGISTER VALUES ARE UNCEREMONIOUSLY TRASHED
+# ...then we want to know about it.
+#
+function trashed(register) {
+  if (in_function && !saved[register] && !dirty[register]) {
+    printf ".cfi_undefined %s\n", register
+  }
+  dirty[register] = 1
+}
+# this does NOT exhaustively check for all possible instructions which could
+# overwrite a register value inherited from the caller (just the common ones)
+/mov.*,%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)$/ { trashed(get_reg2()) }
+/(add|addl|sub|subl|and|or|xor|lea|sal|sar|shl|shr).*,%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)$/ {
+  trashed(get_reg2())
+}
+/^i?mul [^,]*$/ { trashed("rax"); trashed("rdx") }
+/^i?mul.*,%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)$/ { trashed(get_reg2()) }
+/^i?div/ { trashed("rax"); trashed("rdx") }
+
+/(dec|inc|not|neg|pop) %[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)/  { trashed(get_reg()) }
+/cpuid/ { trashed("rax"); trashed("rbx"); trashed("rcx"); trashed("rdx") }
+
+END {
+  if (in_function)
+    print ".cfi_endproc"
+}
-- 
2.0.0.GIT



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script
  2015-10-13 11:28 [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script Alex Dowad
  2015-10-13 11:28 ` [PATCH 2/3] x86 CFI generation script recognizes when %ax, %ah, %al, etc. are overwritten Alex Dowad
  2015-10-13 11:28 ` [PATCH 3/3] add CFI generation script for x86_64 Alex Dowad
@ 2015-10-13 22:42 ` Rich Felker
  2015-10-14 10:21   ` Alex
  2 siblings, 1 reply; 12+ messages in thread
From: Rich Felker @ 2015-10-13 22:42 UTC (permalink / raw)
  To: musl

On Tue, Oct 13, 2015 at 01:28:50PM +0200, Alex Dowad wrote:
> thanks to R. Felker for noticing 2 separate problems:
> 
> - binary ops like ADD, AND, etc. overwrite the 2nd operand, not the 1st.
>   this confusion resulted from mixing up Intel and GNU asm syntax.
> 
> - the regexps used to identify clobbered registers would erroneously match
>   index registers. in other words, the following asm:
> 
>     mov $0, (%eax,%ebx,4)
> 
> ....would cause EBX to be considered as overwritten, which might prevent a
> debugger from displaying a variable's value in a higher stack frame.
> ---
> 
> Here is the latest iteration. I have merged 2 previously separate commits, and
> fixed up the matching of registers (for the purpose of identifying overwritten
> registers).
> 
> As usual, thanks for the feedback. AD

Thanks! I'm committing them all now. I'm sorry for not catching this
before -- I realized that the index register thing was also an
existing bug in mov handling, not just a new bug added in the operand
order patch, so I split it out into a separate commit. I did basic
regression testing on i386 (making sure gdb backtrace from syscalls
still works) and tested that the x86_64 also seems to work (it does).

Rich


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script
  2015-10-13 22:42 ` [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script Rich Felker
@ 2015-10-14 10:21   ` Alex
  2015-10-14 19:14     ` Rich Felker
  0 siblings, 1 reply; 12+ messages in thread
From: Alex @ 2015-10-14 10:21 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 1028 bytes --]

On Wed, Oct 14, 2015 at 12:42 AM, Rich Felker <dalias@libc.org> wrote:

> On Tue, Oct 13, 2015 at 01:28:50PM +0200, Alex Dowad wrote:
> > Here is the latest iteration. I have merged 2 previously separate
> commits, and
> > fixed up the matching of registers (for the purpose of identifying
> overwritten
> > registers).
> >
> > As usual, thanks for the feedback. AD
>
> Thanks! I'm committing them all now. I'm sorry for not catching this
> before -- I realized that the index register thing was also an
> existing bug in mov handling, not just a new bug added in the operand
> order patch, so I split it out into a separate commit. I did basic
> regression testing on i386 (making sure gdb backtrace from syscalls
> still works) and tested that the x86_64 also seems to work (it does).


Thanks!

This has been an interesting exercise so far. Is there any other arch which
you think it would be worthwhile to develop a CFI generation script for? It
should be something which has enough users to avoid problems with bitrot.

AD

[-- Attachment #2: Type: text/html, Size: 1478 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script
  2015-10-14 10:21   ` Alex
@ 2015-10-14 19:14     ` Rich Felker
  2015-10-14 19:23       ` Alex
  0 siblings, 1 reply; 12+ messages in thread
From: Rich Felker @ 2015-10-14 19:14 UTC (permalink / raw)
  To: musl

On Wed, Oct 14, 2015 at 12:21:05PM +0200, Alex wrote:
> On Wed, Oct 14, 2015 at 12:42 AM, Rich Felker <dalias@libc.org> wrote:
> 
> > On Tue, Oct 13, 2015 at 01:28:50PM +0200, Alex Dowad wrote:
> > > Here is the latest iteration. I have merged 2 previously separate
> > commits, and
> > > fixed up the matching of registers (for the purpose of identifying
> > overwritten
> > > registers).
> > >
> > > As usual, thanks for the feedback. AD
> >
> > Thanks! I'm committing them all now. I'm sorry for not catching this
> > before -- I realized that the index register thing was also an
> > existing bug in mov handling, not just a new bug added in the operand
> > order patch, so I split it out into a separate commit. I did basic
> > regression testing on i386 (making sure gdb backtrace from syscalls
> > still works) and tested that the x86_64 also seems to work (it does).
> 
> Thanks!
> 
> This has been an interesting exercise so far. Is there any other arch which
> you think it would be worthwhile to develop a CFI generation script for? It
> should be something which has enough users to avoid problems with bitrot.

CFI is probably a lot less interesting on archs where you have a
plenty registers not to need to manipulate stack frames in asm
functions, since in that case the debugger mostly works fine without
CFI. I don't know right off which of the other archs have significant
amounts of asm that adjusts the stack pointer, but you could go
through and check them. Having ABI info for them all would be helpful;
I'm pasting my draft ABI reference (which might have errors) below.

Rich




aarch64
...
x30 lr
x31 zr or pc

arm
r0-r3 args/ret
r4-r11 saved
r12 temp (ip scratch)
r13 sp
r14 lr
r15 pc

microblaze
r0 zero
r1 sp
r2 ro sda
r3-r4 ret
r5-r10 args
r11-12 temp
r13 rw sda
r14 syscall ret addr
r15 function ret addr
r16 break ret addr
r17 exception ret addr
r18 assembler temp
r19-r20 saved
r21 thread pointer
r21-r31 saved

mips (http://www.inf.ed.ac.uk/teaching/courses/car/Notes/slide03.pdf)
$0 zero
$1 at (assembler temp)
$2-$3 ret (aka v0-v1)
$4-$7 args (aka a0-a3)
$8-$15 temp (aka t0-t7)
$16-$23 saved (aka s0-s7
$24 temp (aka t8)
$25 function call addr (aka t9)
$26-$27 kernel use
$28 gp, call-clobbered
$29 sp
$30 fp
$31 ra

or1k (openrisc-arch-1.1-rev0.pdf p.335)
r0 zero
r1 sp
r2 fp
r3-r8 args
r9 lr
r11,r12 retval (lo,hi)
r10 thread pointer
r14-r30(even) saved
r13-r31(odd) temp

powerpc (http://www.csd.uwo.ca/~mburrel/stuff/ppc-asm.html http://devpit.org/wiki/Debugging_PowerPC_ELF_Binaries)
0 temp
1 sp
2 toc (thread pointer)
3 ret, arg0
4-10 args
11-12 temp
13-31 saved
lr (not gpr; use mtlr/mflr)
30 got
11 plt temp
ctr plt temp

superh (http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/CD17839242.pdf p.9)
(http://shared-ptr.com/sh_insns.html)
r0-r3 ret
r2 struct ret addr
r4-r7 args
r8-r13 saved
r12 gp (saved)
r14 fp (saved)
r15 sp
pr lr
gbr thread ptr


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script
  2015-10-14 19:14     ` Rich Felker
@ 2015-10-14 19:23       ` Alex
  2015-10-14 19:27         ` Rich Felker
  0 siblings, 1 reply; 12+ messages in thread
From: Alex @ 2015-10-14 19:23 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 1067 bytes --]

On Wed, Oct 14, 2015 at 9:14 PM, Rich Felker <dalias@libc.org> wrote:

> On Wed, Oct 14, 2015 at 12:21:05PM +0200, Alex wrote:
> > This has been an interesting exercise so far. Is there any other arch
> which
> > you think it would be worthwhile to develop a CFI generation script for?
> It
> > should be something which has enough users to avoid problems with bitrot.
>
> CFI is probably a lot less interesting on archs where you have a
> plenty registers not to need to manipulate stack frames in asm
> functions, since in that case the debugger mostly works fine without
> CFI. I don't know right off which of the other archs have significant
> amounts of asm that adjusts the stack pointer, but you could go
> through and check them. Having ABI info for them all would be helpful;
> I'm pasting my draft ABI reference (which might have errors) below.


Fair enough. If it's not likely to help anyone, I'll leave the CFI
generation here.

Another idea: are you interested in an implementation of POSIX AIO which
uses the native AIO syscalls? Bad idea?

Thanks, AD

[-- Attachment #2: Type: text/html, Size: 1496 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script
  2015-10-14 19:23       ` Alex
@ 2015-10-14 19:27         ` Rich Felker
  2015-10-14 19:44           ` Alex
  0 siblings, 1 reply; 12+ messages in thread
From: Rich Felker @ 2015-10-14 19:27 UTC (permalink / raw)
  To: musl

On Wed, Oct 14, 2015 at 09:23:59PM +0200, Alex wrote:
> On Wed, Oct 14, 2015 at 9:14 PM, Rich Felker <dalias@libc.org> wrote:
> 
> > On Wed, Oct 14, 2015 at 12:21:05PM +0200, Alex wrote:
> > > This has been an interesting exercise so far. Is there any other arch
> > which
> > > you think it would be worthwhile to develop a CFI generation script for?
> > It
> > > should be something which has enough users to avoid problems with bitrot.
> >
> > CFI is probably a lot less interesting on archs where you have a
> > plenty registers not to need to manipulate stack frames in asm
> > functions, since in that case the debugger mostly works fine without
> > CFI. I don't know right off which of the other archs have significant
> > amounts of asm that adjusts the stack pointer, but you could go
> > through and check them. Having ABI info for them all would be helpful;
> > I'm pasting my draft ABI reference (which might have errors) below.
> 
> Fair enough. If it's not likely to help anyone, I'll leave the CFI
> generation here.
> 
> Another idea: are you interested in an implementation of POSIX AIO which
> uses the native AIO syscalls? Bad idea?

Those syscalls have nothing at all to do with POSIX AIO. They're
completely different. :(

Rich


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script
  2015-10-14 19:27         ` Rich Felker
@ 2015-10-14 19:44           ` Alex
  2015-10-14 19:51             ` Rich Felker
  0 siblings, 1 reply; 12+ messages in thread
From: Alex @ 2015-10-14 19:44 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 1868 bytes --]

On Wed, Oct 14, 2015 at 9:27 PM, Rich Felker <dalias@libc.org> wrote:

> On Wed, Oct 14, 2015 at 09:23:59PM +0200, Alex wrote:
> > On Wed, Oct 14, 2015 at 9:14 PM, Rich Felker <dalias@libc.org> wrote:
> >
> > > On Wed, Oct 14, 2015 at 12:21:05PM +0200, Alex wrote:
> > > > This has been an interesting exercise so far. Is there any other arch
> > > which
> > > > you think it would be worthwhile to develop a CFI generation script
> for?
> > > It
> > > > should be something which has enough users to avoid problems with
> bitrot.
> > >
> > > CFI is probably a lot less interesting on archs where you have a
> > > plenty registers not to need to manipulate stack frames in asm
> > > functions, since in that case the debugger mostly works fine without
> > > CFI. I don't know right off which of the other archs have significant
> > > amounts of asm that adjusts the stack pointer, but you could go
> > > through and check them. Having ABI info for them all would be helpful;
> > > I'm pasting my draft ABI reference (which might have errors) below.
> >
> > Fair enough. If it's not likely to help anyone, I'll leave the CFI
> > generation here.
> >
> > Another idea: are you interested in an implementation of POSIX AIO which
> > uses the native AIO syscalls? Bad idea?
>
> Those syscalls have nothing at all to do with POSIX AIO. They're
> completely different. :(


The interface presented by the raw syscalls is not the POSIX AIO interface,
but I haven't seen any reason yet why io_setup, io_submit, io_getevents,
etc. couldn't be used to implement the POSIX AIO interface. Is there such a
reason?

The payoff would be that you wouldn't have to spawn a thread for each AIO
operation. Instead, you could potentially spawn just one extra thread,
which would run in a loop, calling io_getevents() and doing some
recordkeeping each time an AIO operation completed.

AD

[-- Attachment #2: Type: text/html, Size: 2506 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script
  2015-10-14 19:44           ` Alex
@ 2015-10-14 19:51             ` Rich Felker
  2015-10-14 20:27               ` Alex
  0 siblings, 1 reply; 12+ messages in thread
From: Rich Felker @ 2015-10-14 19:51 UTC (permalink / raw)
  To: musl

On Wed, Oct 14, 2015 at 09:44:50PM +0200, Alex wrote:
> On Wed, Oct 14, 2015 at 9:27 PM, Rich Felker <dalias@libc.org> wrote:
> 
> > On Wed, Oct 14, 2015 at 09:23:59PM +0200, Alex wrote:
> > > On Wed, Oct 14, 2015 at 9:14 PM, Rich Felker <dalias@libc.org> wrote:
> > >
> > > > On Wed, Oct 14, 2015 at 12:21:05PM +0200, Alex wrote:
> > > > > This has been an interesting exercise so far. Is there any other arch
> > > > which
> > > > > you think it would be worthwhile to develop a CFI generation script
> > for?
> > > > It
> > > > > should be something which has enough users to avoid problems with
> > bitrot.
> > > >
> > > > CFI is probably a lot less interesting on archs where you have a
> > > > plenty registers not to need to manipulate stack frames in asm
> > > > functions, since in that case the debugger mostly works fine without
> > > > CFI. I don't know right off which of the other archs have significant
> > > > amounts of asm that adjusts the stack pointer, but you could go
> > > > through and check them. Having ABI info for them all would be helpful;
> > > > I'm pasting my draft ABI reference (which might have errors) below.
> > >
> > > Fair enough. If it's not likely to help anyone, I'll leave the CFI
> > > generation here.
> > >
> > > Another idea: are you interested in an implementation of POSIX AIO which
> > > uses the native AIO syscalls? Bad idea?
> >
> > Those syscalls have nothing at all to do with POSIX AIO. They're
> > completely different. :(
> 
> The interface presented by the raw syscalls is not the POSIX AIO interface,
> but I haven't seen any reason yet why io_setup, io_submit, io_getevents,
> etc. couldn't be used to implement the POSIX AIO interface. Is there such a
> reason?

They only work on certain types of devices/files, and only when the
offset and memory source/dest meet some arbitrary alignment
requirements. And those are just the big problems. I don't see any
indication that they match the subtle behavior requirements for POSIX
AIO in any way.

Rich


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script
  2015-10-14 19:51             ` Rich Felker
@ 2015-10-14 20:27               ` Alex
  0 siblings, 0 replies; 12+ messages in thread
From: Alex @ 2015-10-14 20:27 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 2194 bytes --]

On Wed, Oct 14, 2015 at 9:51 PM, Rich Felker <dalias@libc.org> wrote:

> On Wed, Oct 14, 2015 at 09:44:50PM +0200, Alex wrote:
> > On Wed, Oct 14, 2015 at 9:27 PM, Rich Felker <dalias@libc.org> wrote:
> >
> > > On Wed, Oct 14, 2015 at 09:23:59PM +0200, Alex wrote:
> > > > On Wed, Oct 14, 2015 at 9:14 PM, Rich Felker <dalias@libc.org>
> wrote:
> > > >
> > > > > On Wed, Oct 14, 2015 at 12:21:05PM +0200, Alex wrote:
> > > > > > This has been an interesting exercise so far. Is there any other
> arch
> > > > > which
> > > > > > you think it would be worthwhile to develop a CFI generation
> script
> > > for?
> > > > > It
> > > > > > should be something which has enough users to avoid problems with
> > > bitrot.
> > > > >
> > > > > CFI is probably a lot less interesting on archs where you have a
> > > > > plenty registers not to need to manipulate stack frames in asm
> > > > > functions, since in that case the debugger mostly works fine
> without
> > > > > CFI. I don't know right off which of the other archs have
> significant
> > > > > amounts of asm that adjusts the stack pointer, but you could go
> > > > > through and check them. Having ABI info for them all would be
> helpful;
> > > > > I'm pasting my draft ABI reference (which might have errors) below.
> > > >
> > > > Fair enough. If it's not likely to help anyone, I'll leave the CFI
> > > > generation here.
> > > >
> > > > Another idea: are you interested in an implementation of POSIX AIO
> which
> > > > uses the native AIO syscalls? Bad idea?
> > >
> > > Those syscalls have nothing at all to do with POSIX AIO. They're
> > > completely different. :(
> >
> > The interface presented by the raw syscalls is not the POSIX AIO
> interface,
> > but I haven't seen any reason yet why io_setup, io_submit, io_getevents,
> > etc. couldn't be used to implement the POSIX AIO interface. Is there
> such a
> > reason?
>
> They only work on certain types of devices/files, and only when the
> offset and memory source/dest meet some arbitrary alignment
> requirements. And those are just the big problems. I don't see any
> indication that they match the subtle behavior requirements for POSIX
> AIO in any way.


Gotcha, thanks.

[-- Attachment #2: Type: text/html, Size: 3078 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 3/3] add CFI generation script for x86_64
  2015-10-12 13:58 [PATCH 1/3] in i386 CFI script, binary ops like ADD or AND modify 2nd operand, not 1st Alex Dowad
@ 2015-10-12 13:59 ` Alex Dowad
  0 siblings, 0 replies; 12+ messages in thread
From: Alex Dowad @ 2015-10-12 13:59 UTC (permalink / raw)
  To: musl

this makes debugging more pleasant when you have to dig into x86_64 assembly,
since GCC can obtain accurate stack traces. it turns out that the parts we care
about are almost exactly like i386, except for the register names!
---
 tools/add-cfi.x86_64.awk | 185 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 185 insertions(+)
 create mode 100644 tools/add-cfi.x86_64.awk

diff --git a/tools/add-cfi.x86_64.awk b/tools/add-cfi.x86_64.awk
new file mode 100644
index 0000000..173fb16
--- /dev/null
+++ b/tools/add-cfi.x86_64.awk
@@ -0,0 +1,185 @@
+# Insert GAS CFI directives ("control frame information") into x86-64 asm input
+
+BEGIN {
+  # don't put CFI data in the .eh_frame ELF section (which we don't keep)
+  print ".cfi_sections .debug_frame"
+
+  # only emit CFI directives inside a function
+  in_function = 0
+
+  # emit .loc directives with line numbers from original source
+  printf ".file 1 \"%s\"\n", ARGV[1]
+  line_number = 0
+
+  # used to detect "call label; label:" trick
+  called = ""
+}
+
+function get_const1() {
+  # for instructions with 2 operands, get 1st operand (assuming it is constant)
+  match($0, /-?(0x[0-9a-fA-F]+|[0-9]+),/)
+  return parse_const(substr($0, RSTART, RLENGTH-1))
+}
+function get_reg() {
+  # only use if you already know there is 1 and only 1 register
+  match($0, /%r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15)/)
+  return substr($0, RSTART+1, RLENGTH-1)
+}
+function get_reg1() {
+  # for instructions with 2 operands, get 1st operand (assuming it is register)
+  match($0, /%r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15),/)
+  return substr($0, RSTART+1, RLENGTH-2)
+}
+function get_reg2() {
+  # for instructions with 2 operands, get 2nd operand (assuming it is register)
+  match($0, /,%r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15)/)
+  return substr($0, RSTART+2, RLENGTH-2)
+}
+
+function adjust_sp_offset(delta) {
+  if (in_function)
+    printf ".cfi_adjust_cfa_offset %d\n", delta
+}
+
+{
+  line_number = line_number + 1
+
+  # clean the input up before doing anything else
+  # delete comments
+  gsub(/(#|\/\/).*/, "")
+
+  # canonicalize whitespace
+  gsub(/[ \t]+/, " ") # mawk doesn't understand \s
+  gsub(/ *, */, ",")
+  gsub(/ *: */, ": ")
+  gsub(/ $/, "")
+  gsub(/^ /, "")
+}
+
+# check for assembler directives which we care about
+/^\.(section|data|text)/ {
+  # a .cfi_startproc/.cfi_endproc pair should be within the same section
+  # otherwise, clang will choke when generating ELF output
+  if (in_function) {
+    print ".cfi_endproc"
+    in_function = 0
+  }
+}
+/^\.type [a-zA-Z0-9_]+,\@function/ {
+  functions[substr($2, 1, length($2)-10)] = 1
+}
+# not interested in assembler directives beyond this, just pass them through
+/^\./ {
+  print
+  next
+}
+
+/^[a-zA-Z0-9_]+:/ {
+  label = substr($1, 1, length($1)-1) # drop trailing :
+
+  if (called == label) {
+    # note adjustment of stack pointer from "call label; label:"
+    adjust_sp_offset(8)
+  }
+
+  if (functions[label]) {
+    if (in_function)
+      print ".cfi_endproc"
+
+    in_function = 1
+    print ".cfi_startproc"
+
+    for (register in saved)
+      delete saved[register]
+    for (register in dirty)
+      delete dirty[register]
+  }
+
+  # an instruction may follow on the same line, so continue processing
+}
+
+/^$/ { next }
+
+{
+  called = ""
+  printf ".loc 1 %d\n", line_number
+  print
+}
+
+# KEEPING UP WITH THE STACK POINTER
+# %rsp should only be adjusted by pushing/popping or adding/subtracting constants
+#
+/pushl?/ {
+  adjust_sp_offset(8)
+}
+/popl?/ {
+  adjust_sp_offset(-8)
+}
+/addl? \$-?(0x[0-9a-fA-F]+|[0-9]+),%rsp/ { adjust_sp_offset(-get_const1()) }
+/subl? \$-?(0x[0-9a-fA-F]+|[0-9]+),%rsp/ { adjust_sp_offset(get_const1()) }
+
+/call/ {
+  if (match($0, /call [0-9]+f/)) # "forward" label
+    called = substr($0, RSTART+5, RLENGTH-6)
+  else if (match($0, /call [0-9a-zA-Z_]+/))
+    called = substr($0, RSTART+5, RLENGTH-5)
+}
+
+# TRACKING REGISTER VALUES FROM THE PREVIOUS STACK FRAME
+#
+/pushl? %r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15)/ { # don't match "push (%reg)"
+  # if a register is being pushed, and its value has not changed since the
+  #   beginning of this function, the pushed value can be used when printing
+  #   local variables at the next level up the stack
+  # emit '.cfi_rel_offset' for that
+
+  if (in_function) {
+    register = get_reg()
+    if (!saved[register] && !dirty[register]) {
+      printf ".cfi_rel_offset %s,0\n", register
+      saved[register] = 1
+    }
+  }
+}
+
+/movl? %r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15),-?(0x[0-9a-fA-F]+|[0-9]+)?\(%rsp\)/ {
+  if (in_function) {
+    register = get_reg()
+    if (match($0, /-?(0x[0-9a-fA-F]+|[0-9]+)\(%rsp\)/)) {
+      offset = parse_const(substr($0, RSTART, RLENGTH-6))
+    } else {
+      offset = 0
+    }
+    if (!saved[register] && !dirty[register]) {
+      printf ".cfi_rel_offset %s,%d\n", register, offset
+      saved[register] = 1
+    }
+  }
+}
+
+# IF REGISTER VALUES ARE UNCEREMONIOUSLY TRASHED
+# ...then we want to know about it.
+#
+function trashed(register) {
+  if (in_function && !saved[register] && !dirty[register]) {
+    printf ".cfi_undefined %s\n", register
+  }
+  dirty[register] = 1
+}
+# this does NOT exhaustively check for all possible instructions which could
+# overwrite a register value inherited from the caller (just the common ones)
+/mov.*,%r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15)$/ { trashed(get_reg2()) }
+/(add|addl|sub|subl|and|or|xor|lea|sal|sar|shl|shr).*,%r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15)$/ {
+  trashed(get_reg2())
+}
+/^i?mul [^,]*$/ { trashed("rax"); trashed("rdx") }
+/^i?mul.*,%r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15)$/ { trashed(get_reg2()) }
+/^i?div/ { trashed("rax"); trashed("rdx") }
+
+/(dec|inc|not|neg|pop) %r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15)/  { trashed(get_reg()) }
+/cpuid/ { trashed("rax"); trashed("rbx"); trashed("rcx"); trashed("rdx") }
+
+END {
+  if (in_function)
+    print ".cfi_endproc"
+}
-- 
2.0.0.GIT



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2015-10-14 20:27 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-13 11:28 [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script Alex Dowad
2015-10-13 11:28 ` [PATCH 2/3] x86 CFI generation script recognizes when %ax, %ah, %al, etc. are overwritten Alex Dowad
2015-10-13 11:28 ` [PATCH 3/3] add CFI generation script for x86_64 Alex Dowad
2015-10-13 22:42 ` [PATCHv3 1/3] fix matching errors for overwritten registers in x86 CFI generation script Rich Felker
2015-10-14 10:21   ` Alex
2015-10-14 19:14     ` Rich Felker
2015-10-14 19:23       ` Alex
2015-10-14 19:27         ` Rich Felker
2015-10-14 19:44           ` Alex
2015-10-14 19:51             ` Rich Felker
2015-10-14 20:27               ` Alex
  -- strict thread matches above, loose matches on Subject: below --
2015-10-12 13:58 [PATCH 1/3] in i386 CFI script, binary ops like ADD or AND modify 2nd operand, not 1st Alex Dowad
2015-10-12 13:59 ` [PATCH 3/3] add CFI generation script for x86_64 Alex Dowad

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).