-
Notifications
You must be signed in to change notification settings - Fork 20
/
source_dwarf_frame_instructions.go
398 lines (344 loc) · 15.3 KB
/
source_dwarf_frame_instructions.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
// This file is part of Gopher2600.
//
// Gopher2600 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gopher2600 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package developer
import (
"fmt"
"github.com/jetsetilly/gopher2600/coprocessor/developer/leb128"
)
type frameTableRow struct {
// location (program counter) to which the current table state corresponds
location uint32
cfaRegister int
cfaOffset uint32
// the frame table can also contain the unwinding rules for the machine
// registers. we're not currently worried about these locations
}
type frameTable struct {
rows [2]frameTableRow
}
func (tab *frameTable) newRow() {
tab.rows[1] = tab.rows[0]
}
func (tab frameTable) String() string {
return fmt.Sprintf("loc: %08x; reg: %d; offset: %08x", tab.rows[0].location, tab.rows[0].cfaRegister, tab.rows[0].cfaOffset)
}
// returns number of bytes used in instructions array
func decodeFrameInstruction(cie *frameSectionCIE, instructions []byte, tab *frameTable) (int, error) {
// opcode descriptions taken from "6.4.2 Call Frame Instructions" of
// the "DWARF-4 Standard". Page numbers specified in the comment for
// each opcode
//
// opcode/operand values taken from "7.23 Call Frame Information" of
// the "DWARF-4 Standard"
opcode := (instructions[0] & 0xc0) >> 6
extendedOpcode := instructions[0] & 0x3f
switch opcode {
case 0x00:
switch extendedOpcode {
case 0x00:
// DW_CFA_nop
// (padding instruction)
// "The DW_CFA_nop instruction has no operands and no required actions. It is
// used as padding to make a CIE or FDE an appropriate size", page 136
return 1, nil
case 0x01:
// DW_CFA_set_loc
// (row creation instructions)
// "The DW_CFA_set_loc instruction takes a single operand that represents a target address. The
// required action is to create a new table row using the specified address as the location. All
// other values in the new row are initially identical to the current row. The new location value
// is always greater than the current one. If the segment_size field of this FDE's CIE is non-
// zero, the initial location is preceded by a segment selector of the given length"
tab.newRow()
address := uint32(instructions[1]) | uint32(instructions[2])<<8 | uint32(instructions[3])<<16 | uint32(instructions[4])<<24
tab.rows[0].location = address
return 5, nil
case 0x02:
// DW_CFA_advance_loc1
// (row creation instructions)
// "The DW_CFA_advance_loc1 instruction takes a single ubyte operand that represents a
// constant delta. This instruction is identical to DW_CFA_advance_loc except for the encoding
// and size of the delta operand", page 132
tab.newRow()
tab.rows[0].location += uint32(instructions[1])
return 2, nil
case 0x03:
// DW_CFA_advance_loc2
// (row creation instructions)
// "The DW_CFA_advance_loc2 instruction takes a single uhalf operand that represents a
// constant delta. This instruction is identical to DW_CFA_advance_loc except for the encoding
// and size of the delta operand", page 132
tab.newRow()
offset := uint32(instructions[1]) | uint32(instructions[2])<<8
tab.rows[0].location += offset
return 3, nil
case 0x04:
// DW_CFA_advance_loc4
// (row creation instructions)
// "The DW_CFA_advance_loc4 instruction takes a single uword operand that represents a
// constant delta. This instruction is identical to DW_CFA_advance_loc except for the encoding
// and size of the delta operand", page 132
tab.newRow()
offset := uint32(instructions[1]) | uint32(instructions[2])<<8 | uint32(instructions[3])<<16 | uint32(instructions[4])<<24
tab.rows[0].location += offset
return 5, nil
case 0x05:
// DW_CFA_offset_extended
// (register rule instructions)
// "The DW_CFA_offset_extended instruction takes two unsigned LEB128 operands
// representing a register number and a factored offset. This instruction is identical to
// DW_CFA_offset except for the encoding and size of the register operand", page 134
// unimplemented but we need to know how many bytes to consume
n := 1
_, l := leb128.DecodeULEB128(instructions[n:])
n += l
_, l = leb128.DecodeULEB128(instructions[n:])
n += l
return n, nil
case 0x06:
// DW_CFA_restore_extended
// (register rule instructions)
// "The DW_CFA_restore_extended instruction takes a single unsigned LEB128 operand that
// represents a register number. This instruction is identical to DW_CFA_restore except for the
// encoding and size of the register operand", page 136
// unimplemented but we need to know how many bytes to consume
n := 1
_, l := leb128.DecodeULEB128(instructions[n:])
n += l
return n, nil
case 0x07:
// DW_CFA_undefined
// (register rule instructions)
// "The DW_CFA_undefined instruction takes a single unsigned LEB128 operand that
// represents a register number. The required action is to set the rule for the
// specified register to 'undefined'", page 134
// unimplemented but we need to know how many bytes to consume
n := 1
_, l := leb128.DecodeULEB128(instructions[n:])
n += l
return n, nil
case 0x08:
// DW_CFA_same_value
// (register rule instructions)
// "The DW_CFA_same_value instruction takes a single unsigned LEB128 operand that
// represents a register number. The required action is to set the rule for the specified register to
// 'same value'", page 134
// unimplemented but we need to know how many bytes to consume
n := 1
_, l := leb128.DecodeULEB128(instructions[n:])
n += l
return n, nil
case 0x09:
// DW_CFA_register
// (register rule instructions)
// "The DW_CFA_register instruction takes two unsigned LEB128 operands representing
// register numbers. The required action is to set the rule for the first register to be register(R)
// where R is the second register", page 135
// unimplemented but we need to know how many bytes to consume
n := 1
_, l := leb128.DecodeULEB128(instructions[n:])
n += l
_, l = leb128.DecodeULEB128(instructions[n:])
n += l
return n, nil
case 0x0a:
// DW_CFA_remember_state
// (row state instructions)
// "The DW_CFA_remember_state instruction takes no operands. The required action is to push
// the set of rules for every register onto an implicit stack", page 136
// unimplemented
return 1, nil
case 0x0b:
// DW_CFA_restore_state
// (row state instructions)
// "The DW_CFA_restore_state instruction takes no operands. The required action is to pop the
// set of rules off the implicit stack and place them in the current row", page 136
// unimplemented
return 1, nil
case 0x0c:
// DW_CFA_def_cfa
// (CFA Definition Instructions)
// "The DW_CFA_def_cfa instruction takes two unsigned LEB128 operands representing
// a register number and a (non-factored) offset. The required action is to define
// the current CFA rule to use the provided register and offset", page 132
n := 1
reg, l := leb128.DecodeULEB128(instructions[n:])
n += l
offset, l := leb128.DecodeULEB128(instructions[n:])
n += l
tab.rows[0].cfaRegister = int(reg)
tab.rows[0].cfaOffset = uint32(offset)
return n, nil
case 0x0d:
// DW_CFA_def_cfa_register
// (CFA definition instructions)
// "The DW_CFA_def_cfa_register instruction takes a single unsigned LEB128 operand
// representing a register number. The required action is to define the current CFA rule to use
// the provided register (but to keep the old offset). This operation is valid only if the current
// CFA rule is defined to use a register and offset"
n := 1
reg, l := leb128.DecodeULEB128(instructions[n:])
n += l
tab.rows[0].cfaRegister = int(reg)
return n, nil
case 0x0e:
// DW_CFA_def_cfa_offset
// (CFA definition instructions)
// "The DW_CFA_def_cfa_offset instruction takes a single unsigned LEB128 operand
// representing a (non-factored) offset. The required action is to define the current CFA rule to
// use the provided offset (but to keep the old register). This operation is valid only if the
// current CFA rule is defined to use a register and offset", page 133
n := 1
offset, l := leb128.DecodeULEB128(instructions[n:])
n += l
tab.rows[0].cfaOffset = uint32(offset)
return n, nil
case 0x0f:
// DW_CFA_def_cfa_expression
// (CFA definition instructions)
// "The DW_CFA_def_cfa_expression instruction takes a single operand encoded as a
// DW_FORM_exprloc value representing a DWARF expression. The required action is
// to establish that expression as the means by which the current CFA is computed",
// page 133
return 0, fmt.Errorf("DW_CFA_def_cfa_expression not implemented")
case 0x10:
// DW_CFA_expression
// (register rule instructions)
// "The DW_CFA_expression instruction takes two operands: an unsigned LEB128 value
// representing a register number, and a DW_FORM_block value representing a DWARF
// expression. The required action is to change the rule for the register indicated by the register
// number to be an expression(E) rule where E is the DWARF expression. That is, the DWARF
// expression computes the address. The value of the CFA is pushed on the DWARF evaluation
// stack prior to execution of the DWARF expression", page 135
return 0, fmt.Errorf("DW_CFA_expression not implemented")
case 0x11:
// DW_CFA_offset_extended_sf
// (register rule instructions)
// "The DW_CFA_offset_extended_sf instruction takes two operands: an unsigned LEB128
// value representing a register number and a signed LEB128 factored offset. This instruction is
// identical to DW_CFA_offset_extended except that the second operand is signed and
// factored. The resulting offset is factored_offset * data_alignment_factor", page 134
// unimplemented but we need to know how many bytes to consume
n := 1
_, l := leb128.DecodeULEB128(instructions[n:])
n += l
_, l = leb128.DecodeSLEB128(instructions[n:])
n += l
return n, nil
case 0x12:
// DW_CFA_def_cfa_sf
// (CFA definition instructions)
// "The DW_CFA_def_cfa_sf instruction takes two operands: an unsigned LEB128 value
// representing a register number and a signed LEB128 factored offset. This instruction is
// identical to DW_CFA_def_cfa except that the second operand is signed and factored. The
// resulting offset is factored_offset * data_alignment_factor", page 133
// unimplemented but we need to know how many bytes to consume
n := 1
_, l := leb128.DecodeULEB128(instructions[n:])
n += l
_, l = leb128.DecodeSLEB128(instructions[n:])
n += l
return n, nil
case 0x13:
// DW_CFA_def_cfa_offset_sf
// (CFA definition instructions)
// "The DW_CFA_def_cfa_offset_sf instruction takes a signed LEB128 operand representing a
// factored offset. This instruction is identical to DW_CFA_def_cfa_offset except that the
// operand is signed and factored. The resulting offset is factored_offset *
// data_alignment_factor. This operation is valid only if the current CFA rule is defined to
// use a register and offset", page 133
// unimplemented but we need to know how many bytes to consume
n := 1
_, l := leb128.DecodeSLEB128(instructions[n:])
n += l
return n, nil
case 0x14:
// DW_CFA_val_offset
// (register rule instructions)
// "The DW_CFA_val_offset instruction takes two unsigned LEB128 operands representing a
// register number and a factored offset. The required action is to change the rule for the
// register indicated by the register number to be a val_offset(N) rule where the value of N is
// factored_offset * data_alignment_factor", page 134
// unimplemented but we need to know how many bytes to consume
n := 1
_, l := leb128.DecodeULEB128(instructions[n:])
n += l
_, l = leb128.DecodeULEB128(instructions[n:])
n += l
return n, nil
case 0x15:
// DW_CFA_val_offset_sf
// (register rule instructions)
// "The DW_CFA_val_offset_sf instruction takes two operands: an unsigned LEB128 value
// representing a register number and a signed LEB128 factored offset. This instruction is
// identical to DW_CFA_val_offset except that the second operand is signed and factored. The
// resulting offset is factored_offset * data_alignment_factor", page 135
// unimplemented but we need to know how many bytes to consume
n := 1
_, l := leb128.DecodeULEB128(instructions[n:])
n += l
_, l = leb128.DecodeSLEB128(instructions[n:])
n += l
return n, nil
case 0x16:
// DW_CFA_val_expression
// (register rule instructions)
// "The DW_CFA_val_expression instruction takes two operands: an unsigned LEB128 value
// representing a register number, and a DW_FORM_block value representing a DWARF
// expression. The required action is to change the rule for the register indicated by the register
// number to be a val_expression(E) rule where E is the DWARF expression. That is, the
// DWARF expression computes the value of the given register. The value of the CFA is
// pushed on the DWARF evaluation stack prior to execution of the DWARF expression"
return 0, fmt.Errorf("DW_CFA_val_expression not implemented")
case 0x1c:
// DW_CFA_lo_user
return 1, nil
case 0x3f:
// DW_CFA_hi_user
return 1, nil
}
case 0x01:
// DW_CFA_advance_loc
// (row creation instructions)
// "The DW_CFA_advance instruction takes a single operand (encoded with the opcode) that
// represents a constant delta. The required action is to create a new table row with a location
// value that is computed by taking the current entry’s location value and adding the value of
// delta * code_alignment_factor. All other values in the new row are initially identical
// to the current row", page 132
tab.rows[0].location += uint32(extendedOpcode) * uint32(cie.codeAlignment)
return 1, nil
case 0x02:
// DW_CFA_offset
// (register rule instructions)
// "The DW_CFA_offset instruction takes two operands: a register number (encoded with the
// opcode) and an unsigned LEB128 constant representing a factored offset. The required action
// is to change the rule for the register indicated by the register number to be an offset(N) rule
// where the value of N is factored offset * data_alignment_factor", page 134
// unimplemented but we need to know how many bytes to consume
n := 1
_, l := leb128.DecodeULEB128(instructions[n:])
n += l
return n, nil
case 0x03:
// DW_CFA_restore
// (register rule instructions)
// "The DW_CFA_restore instruction takes a single operand (encoded with the opcode) that
// represents a register number. The required action is to change the rule for the indicated
// register to the rule assigned it by the initial_instructions in the CIE"
// unimplemented
return 1, nil
}
return 0, fmt.Errorf("unknown call frame instruction: %02x", opcode)
}