xref: /aosp_15_r20/external/musl/tools/add-cfi.i386.awk (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
1*c9945492SAndroid Build Coastguard Worker# Insert GAS CFI directives ("control frame information") into x86-32 asm input
2*c9945492SAndroid Build Coastguard Worker#
3*c9945492SAndroid Build Coastguard Worker# CFI directives tell the assembler how to generate "stack frame" debug info
4*c9945492SAndroid Build Coastguard Worker# This information can tell a debugger (like gdb) how to find the current stack
5*c9945492SAndroid Build Coastguard Worker#   frame at any point in the program code, and how to find the values which
6*c9945492SAndroid Build Coastguard Worker#   various registers had at higher points in the call stack
7*c9945492SAndroid Build Coastguard Worker# With this information, the debugger can show a backtrace, and you can move up
8*c9945492SAndroid Build Coastguard Worker#   and down the call stack and examine the values of local variables
9*c9945492SAndroid Build Coastguard Worker
10*c9945492SAndroid Build Coastguard WorkerBEGIN {
11*c9945492SAndroid Build Coastguard Worker  # don't put CFI data in the .eh_frame ELF section (which we don't keep)
12*c9945492SAndroid Build Coastguard Worker  print ".cfi_sections .debug_frame"
13*c9945492SAndroid Build Coastguard Worker
14*c9945492SAndroid Build Coastguard Worker  # only emit CFI directives inside a function
15*c9945492SAndroid Build Coastguard Worker  in_function = 0
16*c9945492SAndroid Build Coastguard Worker
17*c9945492SAndroid Build Coastguard Worker  # emit .loc directives with line numbers from original source
18*c9945492SAndroid Build Coastguard Worker  printf ".file 1 \"%s\"\n", ARGV[1]
19*c9945492SAndroid Build Coastguard Worker  line_number = 0
20*c9945492SAndroid Build Coastguard Worker
21*c9945492SAndroid Build Coastguard Worker  # used to detect "call label; label:" trick
22*c9945492SAndroid Build Coastguard Worker  called = ""
23*c9945492SAndroid Build Coastguard Worker}
24*c9945492SAndroid Build Coastguard Worker
25*c9945492SAndroid Build Coastguard Workerfunction get_const1() {
26*c9945492SAndroid Build Coastguard Worker  # for instructions with 2 operands, get 1st operand (assuming it is constant)
27*c9945492SAndroid Build Coastguard Worker  match($0, /-?(0x[0-9a-fA-F]+|[0-9]+),/)
28*c9945492SAndroid Build Coastguard Worker  return parse_const(substr($0, RSTART, RLENGTH-1))
29*c9945492SAndroid Build Coastguard Worker}
30*c9945492SAndroid Build Coastguard Worker
31*c9945492SAndroid Build Coastguard Workerfunction canonicalize_reg(register) {
32*c9945492SAndroid Build Coastguard Worker  if (match(register, /^e/))
33*c9945492SAndroid Build Coastguard Worker    return register
34*c9945492SAndroid Build Coastguard Worker  else if (match(register, /[hl]$/)) # AH, AL, BH, BL, etc
35*c9945492SAndroid Build Coastguard Worker    return "e" substr(register, 1, 1) "x"
36*c9945492SAndroid Build Coastguard Worker  else # AX, BX, CX, etc
37*c9945492SAndroid Build Coastguard Worker    return "e" register
38*c9945492SAndroid Build Coastguard Worker}
39*c9945492SAndroid Build Coastguard Workerfunction get_reg() {
40*c9945492SAndroid Build Coastguard Worker  # only use if you already know there is 1 and only 1 register
41*c9945492SAndroid Build Coastguard Worker  match($0, /%e?([abcd][hlx]|si|di|bp)/)
42*c9945492SAndroid Build Coastguard Worker  return canonicalize_reg(substr($0, RSTART+1, RLENGTH-1))
43*c9945492SAndroid Build Coastguard Worker}
44*c9945492SAndroid Build Coastguard Workerfunction get_reg1() {
45*c9945492SAndroid Build Coastguard Worker  # for instructions with 2 operands, get 1st operand (assuming it is register)
46*c9945492SAndroid Build Coastguard Worker  match($0, /%e?([abcd][hlx]|si|di|bp),/)
47*c9945492SAndroid Build Coastguard Worker  return canonicalize_reg(substr($0, RSTART+1, RLENGTH-2))
48*c9945492SAndroid Build Coastguard Worker}
49*c9945492SAndroid Build Coastguard Workerfunction get_reg2() {
50*c9945492SAndroid Build Coastguard Worker  # for instructions with 2 operands, get 2nd operand (assuming it is register)
51*c9945492SAndroid Build Coastguard Worker  match($0, /,%e?([abcd][hlx]|si|di|bp)/)
52*c9945492SAndroid Build Coastguard Worker  return canonicalize_reg(substr($0, RSTART+2, RLENGTH-2))
53*c9945492SAndroid Build Coastguard Worker}
54*c9945492SAndroid Build Coastguard Worker
55*c9945492SAndroid Build Coastguard Workerfunction adjust_sp_offset(delta) {
56*c9945492SAndroid Build Coastguard Worker  if (in_function)
57*c9945492SAndroid Build Coastguard Worker    printf ".cfi_adjust_cfa_offset %d\n", delta
58*c9945492SAndroid Build Coastguard Worker}
59*c9945492SAndroid Build Coastguard Worker
60*c9945492SAndroid Build Coastguard Worker{
61*c9945492SAndroid Build Coastguard Worker  line_number = line_number + 1
62*c9945492SAndroid Build Coastguard Worker
63*c9945492SAndroid Build Coastguard Worker  # clean the input up before doing anything else
64*c9945492SAndroid Build Coastguard Worker  # delete comments
65*c9945492SAndroid Build Coastguard Worker  gsub(/(#|\/\/).*/, "")
66*c9945492SAndroid Build Coastguard Worker
67*c9945492SAndroid Build Coastguard Worker  # canonicalize whitespace
68*c9945492SAndroid Build Coastguard Worker  gsub(/[ \t]+/, " ") # mawk doesn't understand \s
69*c9945492SAndroid Build Coastguard Worker  gsub(/ *, */, ",")
70*c9945492SAndroid Build Coastguard Worker  gsub(/ *: */, ": ")
71*c9945492SAndroid Build Coastguard Worker  gsub(/ $/, "")
72*c9945492SAndroid Build Coastguard Worker  gsub(/^ /, "")
73*c9945492SAndroid Build Coastguard Worker}
74*c9945492SAndroid Build Coastguard Worker
75*c9945492SAndroid Build Coastguard Worker# check for assembler directives which we care about
76*c9945492SAndroid Build Coastguard Worker/^\.(section|data|text)/ {
77*c9945492SAndroid Build Coastguard Worker  # a .cfi_startproc/.cfi_endproc pair should be within the same section
78*c9945492SAndroid Build Coastguard Worker  # otherwise, clang will choke when generating ELF output
79*c9945492SAndroid Build Coastguard Worker  if (in_function) {
80*c9945492SAndroid Build Coastguard Worker    print ".cfi_endproc"
81*c9945492SAndroid Build Coastguard Worker    in_function = 0
82*c9945492SAndroid Build Coastguard Worker  }
83*c9945492SAndroid Build Coastguard Worker}
84*c9945492SAndroid Build Coastguard Worker/^\.type [a-zA-Z0-9_]+,@function/ {
85*c9945492SAndroid Build Coastguard Worker  functions[substr($2, 1, length($2)-10)] = 1
86*c9945492SAndroid Build Coastguard Worker}
87*c9945492SAndroid Build Coastguard Worker# not interested in assembler directives beyond this, just pass them through
88*c9945492SAndroid Build Coastguard Worker/^\./ {
89*c9945492SAndroid Build Coastguard Worker  print
90*c9945492SAndroid Build Coastguard Worker  next
91*c9945492SAndroid Build Coastguard Worker}
92*c9945492SAndroid Build Coastguard Worker
93*c9945492SAndroid Build Coastguard Worker/^[a-zA-Z0-9_]+:/ {
94*c9945492SAndroid Build Coastguard Worker  label = substr($1, 1, length($1)-1) # drop trailing :
95*c9945492SAndroid Build Coastguard Worker
96*c9945492SAndroid Build Coastguard Worker  if (called == label) {
97*c9945492SAndroid Build Coastguard Worker    # note adjustment of stack pointer from "call label; label:"
98*c9945492SAndroid Build Coastguard Worker    adjust_sp_offset(4)
99*c9945492SAndroid Build Coastguard Worker  }
100*c9945492SAndroid Build Coastguard Worker
101*c9945492SAndroid Build Coastguard Worker  if (functions[label]) {
102*c9945492SAndroid Build Coastguard Worker    if (in_function)
103*c9945492SAndroid Build Coastguard Worker      print ".cfi_endproc"
104*c9945492SAndroid Build Coastguard Worker
105*c9945492SAndroid Build Coastguard Worker    in_function = 1
106*c9945492SAndroid Build Coastguard Worker    print ".cfi_startproc"
107*c9945492SAndroid Build Coastguard Worker
108*c9945492SAndroid Build Coastguard Worker    for (register in saved)
109*c9945492SAndroid Build Coastguard Worker      delete saved[register]
110*c9945492SAndroid Build Coastguard Worker    for (register in dirty)
111*c9945492SAndroid Build Coastguard Worker      delete dirty[register]
112*c9945492SAndroid Build Coastguard Worker  }
113*c9945492SAndroid Build Coastguard Worker
114*c9945492SAndroid Build Coastguard Worker  # an instruction may follow on the same line, so continue processing
115*c9945492SAndroid Build Coastguard Worker}
116*c9945492SAndroid Build Coastguard Worker
117*c9945492SAndroid Build Coastguard Worker/^$/ { next }
118*c9945492SAndroid Build Coastguard Worker
119*c9945492SAndroid Build Coastguard Worker{
120*c9945492SAndroid Build Coastguard Worker  called = ""
121*c9945492SAndroid Build Coastguard Worker  printf ".loc 1 %d\n", line_number
122*c9945492SAndroid Build Coastguard Worker  print
123*c9945492SAndroid Build Coastguard Worker}
124*c9945492SAndroid Build Coastguard Worker
125*c9945492SAndroid Build Coastguard Worker# KEEPING UP WITH THE STACK POINTER
126*c9945492SAndroid Build Coastguard Worker# We do NOT attempt to understand foolish and ridiculous tricks like stashing
127*c9945492SAndroid Build Coastguard Worker#   the stack pointer and then using %esp as a scratch register, or bitshifting
128*c9945492SAndroid Build Coastguard Worker#   it or taking its square root or anything stupid like that.
129*c9945492SAndroid Build Coastguard Worker# %esp should only be adjusted by pushing/popping or adding/subtracting constants
130*c9945492SAndroid Build Coastguard Worker#
131*c9945492SAndroid Build Coastguard Worker/pushl?/ {
132*c9945492SAndroid Build Coastguard Worker  if (match($0, / %(ax|bx|cx|dx|di|si|bp|sp)/))
133*c9945492SAndroid Build Coastguard Worker    adjust_sp_offset(2)
134*c9945492SAndroid Build Coastguard Worker  else
135*c9945492SAndroid Build Coastguard Worker    adjust_sp_offset(4)
136*c9945492SAndroid Build Coastguard Worker}
137*c9945492SAndroid Build Coastguard Worker/popl?/ {
138*c9945492SAndroid Build Coastguard Worker  if (match($0, / %(ax|bx|cx|dx|di|si|bp|sp)/))
139*c9945492SAndroid Build Coastguard Worker    adjust_sp_offset(-2)
140*c9945492SAndroid Build Coastguard Worker  else
141*c9945492SAndroid Build Coastguard Worker    adjust_sp_offset(-4)
142*c9945492SAndroid Build Coastguard Worker}
143*c9945492SAndroid Build Coastguard Worker/addl? \$-?(0x[0-9a-fA-F]+|[0-9]+),%esp/ { adjust_sp_offset(-get_const1()) }
144*c9945492SAndroid Build Coastguard Worker/subl? \$-?(0x[0-9a-fA-F]+|[0-9]+),%esp/ { adjust_sp_offset(get_const1()) }
145*c9945492SAndroid Build Coastguard Worker
146*c9945492SAndroid Build Coastguard Worker/call/ {
147*c9945492SAndroid Build Coastguard Worker  if (match($0, /call [0-9]+f/)) # "forward" label
148*c9945492SAndroid Build Coastguard Worker    called = substr($0, RSTART+5, RLENGTH-6)
149*c9945492SAndroid Build Coastguard Worker  else if (match($0, /call [0-9a-zA-Z_]+/))
150*c9945492SAndroid Build Coastguard Worker    called = substr($0, RSTART+5, RLENGTH-5)
151*c9945492SAndroid Build Coastguard Worker}
152*c9945492SAndroid Build Coastguard Worker
153*c9945492SAndroid Build Coastguard Worker# TRACKING REGISTER VALUES FROM THE PREVIOUS STACK FRAME
154*c9945492SAndroid Build Coastguard Worker#
155*c9945492SAndroid Build Coastguard Worker/pushl? %e(ax|bx|cx|dx|si|di|bp)/ { # don't match "push (%reg)"
156*c9945492SAndroid Build Coastguard Worker  # if a register is being pushed, and its value has not changed since the
157*c9945492SAndroid Build Coastguard Worker  #   beginning of this function, the pushed value can be used when printing
158*c9945492SAndroid Build Coastguard Worker  #   local variables at the next level up the stack
159*c9945492SAndroid Build Coastguard Worker  # emit '.cfi_rel_offset' for that
160*c9945492SAndroid Build Coastguard Worker
161*c9945492SAndroid Build Coastguard Worker  if (in_function) {
162*c9945492SAndroid Build Coastguard Worker    register = get_reg()
163*c9945492SAndroid Build Coastguard Worker    if (!saved[register] && !dirty[register]) {
164*c9945492SAndroid Build Coastguard Worker      printf ".cfi_rel_offset %s,0\n", register
165*c9945492SAndroid Build Coastguard Worker      saved[register] = 1
166*c9945492SAndroid Build Coastguard Worker    }
167*c9945492SAndroid Build Coastguard Worker  }
168*c9945492SAndroid Build Coastguard Worker}
169*c9945492SAndroid Build Coastguard Worker
170*c9945492SAndroid Build Coastguard Worker/movl? %e(ax|bx|cx|dx|si|di|bp),-?(0x[0-9a-fA-F]+|[0-9]+)?\(%esp\)/ {
171*c9945492SAndroid Build Coastguard Worker  if (in_function) {
172*c9945492SAndroid Build Coastguard Worker    register = get_reg()
173*c9945492SAndroid Build Coastguard Worker    if (match($0, /-?(0x[0-9a-fA-F]+|[0-9]+)\(%esp\)/)) {
174*c9945492SAndroid Build Coastguard Worker      offset = parse_const(substr($0, RSTART, RLENGTH-6))
175*c9945492SAndroid Build Coastguard Worker    } else {
176*c9945492SAndroid Build Coastguard Worker      offset = 0
177*c9945492SAndroid Build Coastguard Worker    }
178*c9945492SAndroid Build Coastguard Worker    if (!saved[register] && !dirty[register]) {
179*c9945492SAndroid Build Coastguard Worker      printf ".cfi_rel_offset %s,%d\n", register, offset
180*c9945492SAndroid Build Coastguard Worker      saved[register] = 1
181*c9945492SAndroid Build Coastguard Worker    }
182*c9945492SAndroid Build Coastguard Worker  }
183*c9945492SAndroid Build Coastguard Worker}
184*c9945492SAndroid Build Coastguard Worker
185*c9945492SAndroid Build Coastguard Worker# IF REGISTER VALUES ARE UNCEREMONIOUSLY TRASHED
186*c9945492SAndroid Build Coastguard Worker# ...then we want to know about it.
187*c9945492SAndroid Build Coastguard Worker#
188*c9945492SAndroid Build Coastguard Workerfunction trashed(register) {
189*c9945492SAndroid Build Coastguard Worker  if (in_function && !saved[register] && !dirty[register]) {
190*c9945492SAndroid Build Coastguard Worker    printf ".cfi_undefined %s\n", register
191*c9945492SAndroid Build Coastguard Worker  }
192*c9945492SAndroid Build Coastguard Worker  dirty[register] = 1
193*c9945492SAndroid Build Coastguard Worker}
194*c9945492SAndroid Build Coastguard Worker# this does NOT exhaustively check for all possible instructions which could
195*c9945492SAndroid Build Coastguard Worker# overwrite a register value inherited from the caller (just the common ones)
196*c9945492SAndroid Build Coastguard Worker/mov.*,%e?([abcd][hlx]|si|di|bp)$/  { trashed(get_reg2()) }
197*c9945492SAndroid Build Coastguard Worker/(add|addl|sub|subl|and|or|xor|lea|sal|sar|shl|shr).*,%e?([abcd][hlx]|si|di|bp)$/ {
198*c9945492SAndroid Build Coastguard Worker  trashed(get_reg2())
199*c9945492SAndroid Build Coastguard Worker}
200*c9945492SAndroid Build Coastguard Worker/^i?mul [^,]*$/                      { trashed("eax"); trashed("edx") }
201*c9945492SAndroid Build Coastguard Worker/^i?mul.*,%e?([abcd][hlx]|si|di|bp)$/ { trashed(get_reg2()) }
202*c9945492SAndroid Build Coastguard Worker/^i?div/                             { trashed("eax"); trashed("edx") }
203*c9945492SAndroid Build Coastguard Worker/(dec|inc|not|neg|pop) %e?([abcd][hlx]|si|di|bp)/  { trashed(get_reg()) }
204*c9945492SAndroid Build Coastguard Worker/cpuid/ { trashed("eax"); trashed("ebx"); trashed("ecx"); trashed("edx") }
205*c9945492SAndroid Build Coastguard Worker
206*c9945492SAndroid Build Coastguard WorkerEND {
207*c9945492SAndroid Build Coastguard Worker  if (in_function)
208*c9945492SAndroid Build Coastguard Worker    print ".cfi_endproc"
209*c9945492SAndroid Build Coastguard Worker}
210