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