xref: /aosp_15_r20/external/google-breakpad/docs/symbol_files.md (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1# Introduction
2
3Given a minidump file, the Breakpad processor produces stack traces that include
4function names and source locations. However, minidump files contain only the
5byte-by-byte contents of threads' registers and stacks, without function names
6or machine-code-to-source mapping data. The processor consults Breakpad symbol
7files for the information it needs to produce human-readable stack traces from
8the binary-only minidump file.
9
10The platform-specific symbol dumping tools parse the debugging information the
11compiler provides (whether as DWARF or STABS sections in an ELF file or as
12stand-alone PDB files), and write that information back out in the Breakpad
13symbol file format. This format is much simpler and less detailed than compiler
14debugging information, and values legibility over compactness.
15
16# Overview
17
18Breakpad symbol files are ASCII text files, with lines delimited as appropriate
19for the host platform. Each line is a _record_, divided into fields by single
20spaces; in some cases, the last field of the record can contain spaces. The
21first field is a string indicating what sort of record the line represents
22(except for line records; these are very common, making them the default saves
23space). Some fields hold decimal or hexadecimal numbers; hexadecimal numbers
24have no "0x" prefix, and use lower-case letters.
25
26Breakpad symbol files contain the following record types. With some
27restrictions, these may appear in any order.
28
29*   A `MODULE` record describes the executable file or shared library from which
30    this data was derived, for use by symbol suppliers. A `MODULE' record should
31    be the first record in the file.
32
33*   A `FILE` record gives a source file name, and assigns it a number by which
34    other records can refer to it.
35
36*   An `INLINE_ORIGIN` record holds an inline function name for `INLINE` records
37    to refer to.
38
39*   A `FUNC` record describes a function present in the source code.
40
41*   An `INLINE` record describes the inline function's nest level, call site
42    line and call site source file to which the given ranges of machine code
43    should be attributed.
44
45*   A line record indicates to which source file and line a given range of
46    machine code should be attributed. The line is attributed to the function
47    defined by the most recent `FUNC` record.
48
49*   A `PUBLIC` record gives the address of a linker symbol.
50
51*   A `STACK` record provides information necessary to produce stack traces.
52
53# `MODULE` records
54
55A `MODULE` record provides meta-information about the module the symbol file
56describes. It has the form:
57
58> `MODULE` _operatingsystem_ _architecture_ _id_ _name_
59
60For example: `MODULE Linux x86 D3096ED481217FD4C16B29CD9BC208BA0 firefox-bin
61` These records provide meta-information about the executable or shared library
62from which this symbol file was generated. A symbol supplier might use this
63information to find the correct symbol files to use to interpret a given
64minidump, or to perform other sorts of validation. If present, a `MODULE` record
65should be the first line in the file.
66
67The fields are separated by spaces, and cannot contain spaces themselves, except
68for _name_.
69
70*   The _operatingsystem_ field names the operating system on which the
71    executable or shared library was intended to run. This field should have one
72    of the following values:
73
74    | **Value** | **Meaning** |
75    |:----------|:--------------------|
76    | Linux | Linux |
77    | mac | Macintosh OSX |
78    | windows | Microsoft Windows |
79
80*   The _architecture_ field indicates what processor architecture the
81    executable or shared library contains machine code for. This field should
82    have one of the following values:
83
84    | **Value** | **Instruction Set Architecture** |
85    |:----------|:---------------------------------|
86    | x86 | Intel IA-32 |
87    | x86\_64 | AMD64/Intel 64 |
88    | ppc | 32-bit PowerPC |
89    | ppc64 | 64-bit PowerPC |
90    | unknown | unknown |
91
92*   The _id_ field is a sequence of hexadecimal digits that identifies the exact
93    executable or library whose contents the symbol file describes. The way in
94    which it is computed varies from platform to platform.
95
96*   The _name_ field contains the base name (the final component of the
97    directory path) of the executable or library. It may contain spaces, and
98    extends to the end of the line.
99
100# `FILE` records
101
102A `FILE` record holds a source file name for other records to refer to. It has
103the form:
104
105> `FILE` _number_ _name_
106
107For example: `FILE 2 /home/jimb/mc/in/browser/app/nsBrowserApp.cpp
108`
109
110A `FILE` record provides the name of a source file, and assigns it a number
111which other records (line records, in particular) can use to refer to that file
112name. The _number_ field is a decimal number. The _name_ field is the name of
113the file; it may contain spaces.
114
115# `INLINE_ORIGIN` records
116
117An `INLINE_ORIGIN` record holds an inline function name for `INLINE` records to
118refer to. It has the form:
119
120> `INLINE_ORIGIN` _number_ _name_
121
122For example: `INLINE_ORIGIN 2 nsQueryInterfaceWithError::operator()(nsID const&,
123void**) const
124`
125
126An `INLINE_ORIGIN` record provides the name of an inline function, and assigns
127it a number which other records (`INLINE` records, in particular) can use to
128refer to that function name. The _number_ field is a decimal number. The _name_
129field is the name of the inline function; it may contain spaces.
130
131# `FUNC` records
132
133A `FUNC` record describes a source-language function. It has the form:
134
135> `FUNC` _[m]_ _address_ _size_ _parameter\_size_ _name_
136
137For example: `FUNC m c184 30 0 nsQueryInterfaceWithError::operator()(nsID const&,
138void**) const
139`
140
141The _m_ field is optional. If present it indicates that multiple symbols
142reference this function's instructions. (In which case, only one symbol name is
143mentioned within the breakpad file.) Multiple symbols referencing the same
144instructions may occur due to identical code folding by the linker.
145
146The _address_ and _size_ fields are hexadecimal numbers indicating the start
147address and length in bytes of the machine code instructions the function
148occupies. (Breakpad symbol files cannot accurately describe functions whose code
149is not contiguous.) The start address is relative to the module's load address.
150
151The _parameter\_size_ field is a hexadecimal number indicating the size, in
152bytes, of the arguments pushed on the stack for this function. Some calling
153conventions, like the Microsoft Windows `stdcall` convention, require the called
154function to pop parameters passed to it on the stack from its caller before
155returning. The stack walker uses this value, along with data from `STACK`
156records, to step from the called function's frame to the caller's frame.
157
158The _name_ field is the name of the function. In languages that use linker
159symbol name mangling like C++, this should be the source language name (the
160"unmangled" form). This field may contain spaces.
161
162# `INLINE` records
163
164An `INLINE` record describes the inline function's nest level, call site line
165and call site source file to which the given ranges of machine code should be
166attributed. It has the form:
167
168> `INLINE` _inline_nest_level_ _call_site_line_ _call_site_file_num_
169> _origin_num_ [_address_ _size_]+
170
171For example: `INLINE 0 10 3 4 d30 2a fa1 b
172`
173
174The _inline_nest_level_ field is a decimal number that means it's inlined at the
175function described by a previous `INLINE` record which has _inline_nest_level_
176one less than its. In the example below, first and third `INLINE` records have
177_inline_nest_level_ 0, which means they are inlined inside the function
178described by the `FUNC` record. The second `INLINE` record has
179_inline_nest_level_ 1 means that it's inlined at the inline function described
180by first `INLINE` record.
181```
182FUNC ...
183INLINE 0 ...
184INLINE 1 ...
185INLINE 0 ...
186```
187
188The _call_site_line_ and _call_site_file_num_ fields are decimal numbers
189indicating where this inline function being called at.
190
191The _origin_num_ field refers to an `INLINE_ORIGIN` record that has the name
192of the inline function.
193
194The _address_ and _size_ fields are hexadecimal numbers indicating the start
195address and length in bytes of the machine code. The address is relative to the
196module's load address. There could be more than one [_address_ _size_] range
197pair, since inline functions could have discontinuous address ranges. The ranges
198of an `INLINE` record are always inside the ranges described by its parent
199record (a `FUNC` record or an `INLINE` record).
200
201The `INLINE` record is assumed to belong to the function described by the last
202preceding `FUNC` record. `INLINE` records may not appear before the first `FUNC`
203record.
204
205# Line records
206
207A line record describes the source file and line number to which a given range
208of machine code should be attributed. It has the form:
209
210> _address_ _size_ _line_ _filenum_
211
212For example: `c184 7 59 4
213`
214
215Because they are so common, line records do not begin with a string indicating
216the record type. All other record types' names use upper-case letters;
217hexadecimal numbers, like a line record's _address_, use lower-case letters.
218
219The _address_ and _size_ fields are hexadecimal numbers indicating the start
220address and length in bytes of the machine code. The address is relative to the
221module's load address.
222
223The _line_ field is the line number to which the machine code should be
224attributed, in decimal; the first line of the source file is line number 1. The
225_filenum_ field is a decimal number appearing in a prior `FILE` record; the name
226given in that record is the source file name for the machine code.
227
228The line is assumed to belong to the function described by the last preceding
229`FUNC` record. Line records may not appear before the first `FUNC' record.
230
231No two line records in a symbol file cover the same range of addresses. However,
232there may be many line records with identical line and file numbers, as a given
233source line may contribute many non-contiguous blocks of machine code.
234
235# `PUBLIC` records
236
237A `PUBLIC` record describes a publicly visible linker symbol, such as that used
238to identify an assembly language entry point or region of memory. It has the
239form:
240
241> PUBLIC _[m]_ _address_ _parameter\_size_ _name_
242
243For example: `PUBLIC m 2160 0 Public2_1
244`
245
246The Breakpad processor essentially treats a `PUBLIC` record as defining a
247function with no line number data and an indeterminate size: the code extends to
248the next address mentioned. If a given address is covered by both a `PUBLIC`
249record and a `FUNC` record, the processor uses the `FUNC` data.
250
251The _m_ field is optional. If present it indicates that multiple symbols
252reference this function's instructions. (In which case, only one symbol name is
253mentioned within the breakpad file.) Multiple symbols referencing the same
254instructions may occur due to identical code folding by the linker.
255
256The _address_ field is a hexadecimal number indicating the symbol's address,
257relative to the module's load address.
258
259The _parameter\_size_ field is a hexadecimal number indicating the size of the
260parameters passed to the code whose entry point the symbol marks, if known. This
261field has the same meaning as the _parameter\_size_ field of a `FUNC` record;
262see that description for more details.
263
264The _name_ field is the name of the symbol. In languages that use linker symbol
265name mangling like C++, this should be the source language name (the "unmangled"
266form). This field may contain spaces.
267
268# `STACK WIN` records
269
270Given a stack frame, a `STACK WIN` record indicates how to find the frame that
271called it. It has the form:
272
273> STACK WIN _type_ _rva_ _code\_size_ _prologue\_size_ _epilogue\_size_
274> _parameter\_size_ _saved\_register\_size_ _local\_size_ _max\_stack\_size_
275> _has\_program\_string_ _program\_string\_OR\_allocates\_base\_pointer_
276
277For example: `STACK WIN 4 2170 14 1 0 0 0 0 0 1 $eip 4 + ^ = $esp $ebp 8 + =
278$ebp $ebp ^ =
279`
280
281All fields of a `STACK WIN` record, except for the last, are hexadecimal
282numbers.
283
284The _type_ field indicates what sort of stack frame data this record holds. Its
285value should be one of the values of the
286[StackFrameTypeEnum](http://msdn.microsoft.com/en-us/library/bc5207xw%28VS.100%29.aspx)
287type in Microsoft's
288[Debug Interface Access (DIA)](http://msdn.microsoft.com/en-us/library/x93ctkx8%28VS.100%29.aspx) API.
289Breakpad uses only records of type 4 (`FrameTypeFrameData`) and 0
290(`FrameTypeFPO`); it ignores others. These types differ only in whether the last
291field is an _allocates\_base\_pointer_ flag (`FrameTypeFPO`) or a program string
292(`FrameTypeFrameData`). If more than one record covers a given address, Breakpad
293prefers `FrameTypeFrameData` records over `FrameTypeFPO` records.
294
295The _rva_ and _code\_size_ fields give the starting address and length in bytes
296of the machine code covered by this record. The starting address is relative to
297the module's load address.
298
299The _prologue\_size_ and _epilogue\_size_ fields give the length, in bytes, of
300the prologue and epilogue machine code within the record's range. Breakpad does
301not use these values.
302
303The _parameter\_size_ field gives the number of argument bytes this function
304expects to have been passed. This field has the same meaning as the
305_parameter\_size_ field of a `FUNC` record; see that description for more
306details.
307
308The _saved\_register\_size_ field gives the number of bytes in the stack frame
309dedicated to preserving the values of any callee-saves registers used by this
310function.
311
312The _local\_size_ field gives the number of bytes in the stack frame dedicated
313to holding the function's local variables and temporary values.
314
315The _max\_stack\_size_ field gives the maximum number of bytes pushed on the
316stack in the frame. Breakpad does not use this value.
317
318If the _has\_program\_string_ field is zero, then the `STACK WIN` record's final
319field is an _allocates\_base\_pointer_ flag, as a hexadecimal number; this is
320expected for records whose _type_ is 0. Otherwise, the final field is a program
321string.
322
323## Interpreting a `STACK WIN` record
324
325Given the register values for a frame F, we can find the calling frame as
326follows:
327
328*   If the _has\_program\_string_ field of a `STACK WIN` record is zero, then
329    the final field is _allocates\_base\_pointer_, a flag indicating whether the
330    frame uses the frame pointer register, `%ebp`, as a general-purpose
331    register.
332    *   If _allocates\_base\_pointer_ is true, then `%ebp` does not point to the
333        frame's base address. Instead,
334        *   Let _next\_parameter\_size_ be the parameter size of the function
335            frame F called (**not** this record's _parameter\_size_ field), or
336            zero if F is the youngest frame on the stack. You must find this
337            value in F's callee's `FUNC`, `STACK WIN`, or `PUBLIC` records.
338        *   Let _frame\_size_ be the sum of the _local\_size_ field, the
339            _saved\_register\_size_ field, and _next\_parameter\_size_. > > With
340            those definitions in place, we can recover the calling frame as
341            follows:
342        *   F's return address is at `%esp +`_frame\_size_,
343        *   the caller's value of `%ebp` is saved at `%esp
344            +`_next\_parameter\_size_`+`_saved\_register\_size_`- 8`, and
345        *   the caller's value of `%esp` just before the call instruction was
346            `%esp +`_frame\_size_`+ 4`. > > (Why do we include
347            _next\_parameter\_size_ in the sum when computing _frame\_size_ and
348            the address of the saved `%ebp`? When a function A has called a
349            function B, the arguments that A pushed for B are considered part of
350            A's stack frame: A's value for `%esp` points at the last argument
351            pushed for B. Thus, we must include the size of those arguments
352            (given by the debugging info for B) along with the size of A's
353            register save area and local variable area (given by the debugging
354            info for A) when computing the overall size of A's frame.)
355    *   If _allocates\_base\_pointer_ is false, then F's function doesn't use
356        `%ebp` at all. You may recover the calling frame as above, except that
357        the caller's value of `%ebp` is the same as F's value for `%ebp`, so no
358        steps are necessary to recover it.
359*   If the _has\_program\_string_ field of a `STACK WIN` record is not zero,
360    then the record's final field is a string containing a program to be
361    interpreted to recover the caller's frame. The comments in the
362    [postfix\_evaluator.h](../src/processor/postfix_evaluator.h#40)
363    header file explain the language in which the program is written. You should
364    place the following variables in the dictionary before interpreting the
365    program:
366    *   `$ebp` and `$esp` should be the values of the `%ebp` and `%esp`
367        registers in F.
368    *   `.cbParams`, `.cbSavedRegs`, and `.cbLocals`, should be the values of
369        the `STACK WIN` record's _parameter\_size_, _saved\_register\_size_, and
370        _local\_size_ fields.
371    *   `.raSearchStart` should be set to the address on the stack to begin
372        scanning for a return address, if necessary. The Breakpad processor sets
373        this to the value of `%esp` in F, plus the _frame\_size_ value mentioned
374        above.
375
376> If the program stores values for `$eip`, `$esp`, `$ebp`, `$ebx`, `$esi`, or
377> `$edi`, then those are the values of the given registers in the caller. If the
378> value of `$eip` is zero, that indicates that the end of the stack has been
379> reached.
380
381The Breakpad processor checks that the value yielded by the above for the
382calling frame's instruction address refers to known code; if the address seems
383to be bogus, then it uses a heuristic search to find F's return address and
384stack base.
385
386# `STACK CFI` records
387
388`STACK CFI` ("Call Frame Information") records describe how to walk the stack
389when execution is at a given machine instruction. These records take one of two
390forms:
391
392> `STACK CFI INIT` _address_ _size_ _register<sub>1</sub>_:
393> _expression<sub>1</sub>_ _register<sub>2</sub>_: _expression<sub>2</sub>_ ...
394>
395> `STACK CFI` _address_ _register<sub>1</sub>_: _expression<sub>1</sub>_
396> _register<sub>2</sub>_: _expression<sub>2</sub>_ ...
397
398For example:
399
400```
401STACK CFI INIT 804c4b0 40 .cfa: $esp 4 + $eip: .cfa 4 - ^
402STACK CFI 804c4b1 .cfa: $esp 8 + $ebp: .cfa 8 - ^
403```
404
405The _address_ and _size_ fields are hexadecimal numbers. Each
406_register_<sub>i</sub> is the name of a register or pseudoregister. Each
407_expression_ is a Breakpad postfix expression, which may contain spaces, but
408never ends with a colon. (The appropriate register names for a given
409architecture are determined when `STACK CFI` records are first enabled for that
410architecture, and should be documented in the appropriate
411`stackwalker_`_architecture_`.cc` source file.)
412
413STACK CFI records describe, at each machine instruction in a given function, how
414to recover the values the machine registers had in the function's caller.
415Naturally, some registers' values are simply lost, but there are three cases in
416which they can be recovered:
417
418*   You can always recover the program counter, because that's the function's
419    return address. If the function is ever going to return, the PC must be
420    saved somewhere.
421
422*   You can always recover the stack pointer. The function is responsible for
423    popping its stack frame before it returns to the caller, so it must be able
424    to restore this, as well.
425
426*   You should be able to recover the values of callee-saves registers. These
427    are registers whose values the callee must preserve, either by saving them
428    in its own stack frame before using them and re-loading them before
429    returning, or by not using them at all.
430
431(As an exception, note that functions which never return may not save any of
432this data. It may not be possible to walk the stack past such functions' stack
433frames.)
434
435Given rules for recovering the values of a function's caller's registers, we can
436walk up the stack. Starting with the current set of registers --- the PC of the
437instruction we're currently executing, the current stack pointer, etc. --- we
438use CFI to recover the values those registers had in the caller of the current
439frame. This gives us a PC in the caller whose CFI we can look up; we apply the
440process again to find that function's caller; and so on.
441
442Concretely, CFI records represent a table with a row for each machine
443instruction address and a column for each register. The table entry for a given
444address and register contains a rule describing how, when the PC is at that
445address, to restore the value that register had in the caller.
446
447There are some special columns:
448
449*   A column named `.cfa`, for "Canonical Frame Address", tells how to compute
450    the base address of the frame; other entries can refer to the CFA in their
451    rules.
452
453*   A column named `.ra` represents the return address.
454
455For example, suppose we have a machine with 32-bit registers, one-byte
456instructions, a stack that grows downwards, and an assembly language that
457resembles C. Suppose further that we have a function whose machine code looks
458like this:
459
460```
461func:                                ; entry point; return address at sp
462func+0:      sp -= 16                ; allocate space for stack frame
463func+1:      sp[12] = r0             ; save 4-byte r0 at sp+12
464             ...                     ; stuff that doesn't affect stack
465func+10:     sp -= 4; *sp = x        ; push some 4-byte x on the stack
466             ...                     ; stuff that doesn't affect stack
467func+20:     r0 = sp[16]             ; restore saved r0
468func+21:     sp += 20                ; pop whole stack frame
469func+22:     pc = *sp; sp += 4       ; pop return address and jump to it
470```
471
472The following table would describe the function above:
473
474| **code address** | **.cfa** | **r0 (on Google Code)** | **r1 (on Google Code)** | ... | **.ra**  |
475|:-----------------|:---------|:------------------------|:------------------------|:----|:---------|
476| func+0           | sp       |                         |                         |     | `cfa[0]` |
477| func+1           | sp+16    |                         |                         |     | `cfa[0]` |
478| func+2           | sp+16    | `cfa[-4]`               |                         |     | `cfa[0]` |
479| func+11          | sp+20    | `cfa[-4]`               |                         |     | `cfa[0]` |
480| func+21          | sp+20    |                         |                         |     | `cfa[0]` |
481| func+22          | sp       |                         |                         |     | `cfa[0]` |
482
483Some things to note here:
484
485*   Each row describes the state of affairs **before** executing the instruction
486    at the given address. Thus, the row for func+0 describes the state before we
487    execute the first instruction, which allocates the stack frame. In the next
488    row, the formula for computing the CFA has changed, reflecting the
489    allocation.
490
491*   The other entries are written in terms of the CFA; this allows them to
492    remain unchanged as the stack pointer gets bumped around. For example, to
493    find the caller's value for r0 (on Google Code) at func+2, we would first
494    compute the CFA by adding 16 to the sp, and then subtract four from that to
495    find the address at which r0 (on Google Code) was saved.
496
497*   Although the example doesn't show this, most calling conventions designate
498    "callee-saves" and "caller-saves" registers. The callee must restore the
499    values of "callee-saves" registers before returning (if it uses them at
500    all), whereas the callee is free to use "caller-saves" registers without
501    restoring their values. A function that uses caller-saves registers
502    typically does not save their original values at all; in this case, the CFI
503    marks such registers' values as "unrecoverable".
504
505*   Exactly where the CFA points in the frame --- at the return address? below
506    it? At some fixed point within the frame? --- is a question of definition
507    that depends on the architecture and ABI in use. But by definition, the CFA
508    remains constant throughout the lifetime of the frame. It's up to
509    architecture- specific code to know what significance to assign the CFA, if
510    any.
511
512To save space, the most common type of CFI record only mentions the table
513entries at which changes take place. So for the above, the CFI data would only
514actually mention the non-blank entries here:
515
516| **insn** | **cfa** | **r0 (on Google Code)** | **r1 (on Google Code)** | ... | **ra**   |
517|:---------|:--------|:------------------------|:------------------------|:----|:---------|
518| func+0   | sp      |                         |                         |     | `cfa[0]` |
519| func+1   | sp+16   |                         |                         |     |          |
520| func+2   |         | `cfa[-4]`               |                         |     |          |
521| func+11  | sp+20   |                         |                         |     |          |
522| func+21  |         | r0 (on Google Code)     |                         |     |          |
523| func+22  | sp      |                         |                         |     |          |
524
525A `STACK CFI INIT` record indicates that, at the machine instruction at
526_address_, belonging to some function, the value that _register<sub>n</sub>_ had
527in that function's caller can be recovered by evaluating
528_expression<sub>n</sub>_. The values of any callee-saves registers not mentioned
529are assumed to be unchanged. (`STACK CFI` records never mention caller-saves
530registers.) These rules apply starting at _address_ and continue up to, but not
531including, the address given in the next `STACK CFI` record. The _size_ field is
532the total number of bytes of machine code covered by this record and any
533subsequent `STACK CFI` records (until the next `STACK CFI INIT` record). The
534_address_ field is relative to the module's load address.
535
536A `STACK CFI` record (no `INIT`) is the same, except that it mentions only those
537registers whose recovery rules have changed from the previous CFI record. There
538must be a prior `STACK CFI INIT` or `STACK CFI` record in the symbol file. The
539_address_ field of this record must be greater than that of the previous record,
540and it must not be at or beyond the end of the range given by the most recent
541`STACK CFI INIT` record. The address is relative to the module's load address.
542
543Each expression is a breakpad-style postfix expression. Expressions may contain
544spaces, but their tokens may not end with colons. When an expression mentions a
545register, it refers to the value of that register in the callee, even if a prior
546name/expression pair gives that register's value in the caller. The exception is
547`.cfa`, which refers to the canonical frame address computed by the .cfa rule in
548force at the current instruction.
549
550The special expression `.undef` indicates that the given register's value cannot
551be recovered.
552
553The register names preceding the expressions are always followed by colons. The
554expressions themselves never contain tokens ending with colons.
555
556There are two special register names:
557
558*   `.cfa` ("Canonical Frame Address") is the base address of the stack frame.
559    Other registers' rules may refer to this. If no rule is provided for the
560    stack pointer, the value of `.cfa` is the caller's stack pointer.
561
562*   `.ra` is the return address. This is the value of the restored program
563    counter. We use `.ra` instead of the architecture-specific name for the
564    program counter.
565
566The Breakpad stack walker requires that there be rules in force for `.cfa` and
567`.ra` at every code address from which it unwinds. If those rules are not
568present, the stack walker will ignore the `STACK CFI` data, and try to use a
569different strategy.
570
571So the CFI for the example function above would be as follows, if `func` were at
572address 0x1000 (relative to the module's load address):
573
574```
575STACK CFI INIT 1000 .cfa: $sp .ra: .cfa ^
576STACK CFI      1001 .cfa: $sp 16 +
577STACK CFI      1002 $r0: .cfa 4 - ^
578STACK CFI      100b .cfa: $sp 20 +
579STACK CFI      1015 $r0: $r0
580STACK CFI      1016 .cfa: $sp
581```
582