1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#ifndef DWARF_DEFINE_H
16#define DWARF_DEFINE_H
17
18#include <cinttypes>
19#include <string>
20#include <vector>
21
22namespace OHOS {
23namespace HiviewDFX {
24#define DW_EH_VERSION           1
25#define DW_EH_PE_FORMAT_MASK    0x0f    /* format of the encoded value */
26#define DW_EH_PE_APPL_MASK      0x70    /* how the value is to be applied */
27
28// https://dwarfstd.org/doc/DWARF5.pdf
29// 7.7.1 DWARF Expressions
30// Each operation is a 1-byte code that identifies that operation, followed by zero or more bytes of additional data
31// Table 7.9: DWARF operation encodings
32typedef enum {
33    DW_OP_reserved1 = 0x01,
34    DW_OP_reserved2,
35    DW_OP_addr,  // constant address (size is target specific)
36    DW_OP_reserved4,
37    DW_OP_reserved5,
38    DW_OP_deref,
39    DW_OP_reserved7,
40    DW_OP_const1u,  // 1-byte unsigned integer constant
41    DW_OP_const1s,  // 1-byte signed integer constant
42    DW_OP_const2u,  // 2-byte unsigned integer constant
43    DW_OP_const2s,  // 2-byte signed integer constant
44    DW_OP_const4u,  // 4-byte unsigned integer constant
45    DW_OP_const4s,  // 4-byte signed integer constant
46    DW_OP_const8u,  // 8-byte unsigned integer constant
47    DW_OP_const8s,  // 8-byte signed integer constant
48    DW_OP_constu,   // unsigned LEB128 integer constant
49    DW_OP_consts,   // signed LEB128 integer constant
50    DW_OP_dup,
51    DW_OP_drop,
52    DW_OP_over,
53    DW_OP_pick,  // 1-byte stack index
54    DW_OP_swap,
55    DW_OP_rot,
56    DW_OP_xderef,
57    DW_OP_abs,
58    DW_OP_and,
59    DW_OP_div,
60    DW_OP_minus,
61    DW_OP_mod,
62    DW_OP_mul,
63    DW_OP_neg,
64    DW_OP_not,
65    DW_OP_or,
66    DW_OP_plus,
67    DW_OP_plus_uconst,  // ULEB128 addend
68    DW_OP_shl,
69    DW_OP_shr,
70    DW_OP_shra,
71    DW_OP_xor,
72    DW_OP_bra,  // signed 2-byte constant
73    DW_OP_eq,
74    DW_OP_ge,
75    DW_OP_gt,
76    DW_OP_le,
77    DW_OP_lt,
78    DW_OP_ne,
79    DW_OP_skip,
80    DW_OP_lit0 = 0x30,  // literals 0 .. 31 = (DW_OP_lit0 + literal)
81    DW_OP_lit1, DW_OP_lit2, DW_OP_lit3, DW_OP_lit4,
82    DW_OP_lit5, DW_OP_lit6, DW_OP_lit7, DW_OP_lit8,
83    DW_OP_lit9, DW_OP_lit10, DW_OP_lit11, DW_OP_lit12,
84    DW_OP_lit13, DW_OP_lit14, DW_OP_lit15, DW_OP_lit16,
85    DW_OP_lit17, DW_OP_lit18, DW_OP_lit19, DW_OP_lit20,
86    DW_OP_lit21, DW_OP_lit22, DW_OP_lit23, DW_OP_lit24,
87    DW_OP_lit25, DW_OP_lit26, DW_OP_lit27, DW_OP_lit28,
88    DW_OP_lit29, DW_OP_lit30, DW_OP_lit31,
89    DW_OP_reg0 = 0x50,  // reg 0 .. 31 = (DW_OP_reg0 + regnum)
90    DW_OP_reg1, DW_OP_reg2, DW_OP_reg3, DW_OP_reg4,
91    DW_OP_reg5, DW_OP_reg6, DW_OP_reg7, DW_OP_reg8,
92    DW_OP_reg9, DW_OP_reg10, DW_OP_reg11, DW_OP_reg12,
93    DW_OP_reg13, DW_OP_reg14, DW_OP_reg15, DW_OP_reg16,
94    DW_OP_reg17, DW_OP_reg18, DW_OP_reg19, DW_OP_reg20,
95    DW_OP_reg21, DW_OP_reg22, DW_OP_reg23, DW_OP_reg24,
96    DW_OP_reg25, DW_OP_reg26, DW_OP_reg27, DW_OP_reg28,
97    DW_OP_reg29, DW_OP_reg30, DW_OP_reg31,
98    DW_OP_breg0 = 0x70,  // SLEB128 offset base register 0 .. 31 = (DW_OP_breg0 + regnum)
99    DW_OP_breg1, DW_OP_breg2, DW_OP_breg3, DW_OP_breg4,
100    DW_OP_breg5, DW_OP_breg6, DW_OP_breg7, DW_OP_breg8,
101    DW_OP_breg9, DW_OP_breg10, DW_OP_breg11, DW_OP_breg12,
102    DW_OP_breg13, DW_OP_breg14, DW_OP_breg15, DW_OP_breg16,
103    DW_OP_breg17, DW_OP_breg18, DW_OP_breg19, DW_OP_breg20,
104    DW_OP_breg21, DW_OP_breg22, DW_OP_breg23, DW_OP_breg24,
105    DW_OP_breg25, DW_OP_breg26, DW_OP_breg27, DW_OP_breg28,
106    DW_OP_breg29, DW_OP_breg30, DW_OP_breg31,
107    DW_OP_regx = 0x90,         // ULEB128 register
108    DW_OP_fbreg,        // SLEB128 offset
109    DW_OP_bregx,        // ULEB128 register, SLEB128 offset
110    DW_OP_piece,        // ULEB128 size of piece
111    DW_OP_deref_size,   // 1-byte size of data retrieved
112    DW_OP_xderef_size,  // 1-byte size of data retrieved
113    DW_OP_nop,
114    DW_OP_push_object_address,
115    DW_OP_call2,     // 2-byte offset of DIE
116    DW_OP_call4,     // 4-byte offset of DIE
117    DW_OP_call_ref,  // 4- or 8-byte offset of DIE
118    // dwarf4 added
119    DW_OP_form_tls_address,
120    DW_OP_call_frame_cfa,
121    DW_OP_bit_piece,       // ULEB128 size, ULEB128 offset
122    DW_OP_implicit_value,  // ULEB128 size, block of that size
123    DW_OP_stack_value,
124    // dwarf5 added
125    DW_OP_implicit_pointer,  // 4- or 8-byte offset of DIE, SLEB128 constant offset
126    DW_OP_addrx,             // ULEB128 indirect address
127    DW_OP_constx,            // ULEB128 indirect constant
128    DW_OP_entry_value,       // ULEB128 size, block of that size
129    DW_OP_const_type,        // ULEB128 type entry offset, 1-byte size, constant value
130    DW_OP_regval_type,       // ULEB128 register number, ULEB128 constant offset
131    DW_OP_deref_type,        // 1-byte size, ULEB128 type entry offset
132    DW_OP_xderef_type,       // 1-byte size, ULEB128 type entry offset
133    DW_OP_convert_type,      // ULEB128 type entry offset
134    DW_OP_reinterpret_type,  // ULEB128 type entry offset
135    DW_OP_lo_user = 0xe0,
136    DW_OP_hi_user = 0xff
137} DwarfOperater;
138
139// DWARF Call Frame Information
140// Call frame instructions are encoded in one or more bytes. The primary opcode is
141// encoded in the high order two bits of the first byte (that is, opcode = byte >> 6).
142// An operand or extended opcode may be encoded in the low order 6 bits.
143// Table 7.29: Call frame instruction encodings
144typedef enum {
145    DW_CFA_advance_loc = 0x40,  // high 2-bits 0x1, low 6-bits delta
146    DW_CFA_offset = 0x80,       // high 2-bits 0x2, low 6-bits register, ULEB128 offset
147    DW_CFA_restore = 0xc0,      // high 2-bits 0x3, low 6-bits register
148    // the value is the lower 6-bits, Operand1, Operand2
149    DW_CFA_nop = 0x00,
150    DW_CFA_set_loc,           // address
151    DW_CFA_advance_loc1,      // 1-byte delta
152    DW_CFA_advance_loc2,      // 2-byte delta
153    DW_CFA_advance_loc4,      // 4-byte delta
154    DW_CFA_offset_extended,   // ULEB128 register, ULEB128 offset
155    DW_CFA_restore_extended,  // ULEB128 register
156    DW_CFA_undefined,         // ULEB128 register
157    DW_CFA_same_value,        // ULEB128 register
158    DW_CFA_register,          // ULEB128 register, ULEB128 offset
159    DW_CFA_remember_state,
160    DW_CFA_restore_state,
161    DW_CFA_def_cfa,             // ULEB128 register, ULEB128 offset
162    DW_CFA_def_cfa_register,    // ULEB128 register
163    DW_CFA_def_cfa_offset,      // ULEB128 offset
164    DW_CFA_def_cfa_expression,  // BLOCK
165    DW_CFA_expression = 0x10,   // ULEB128 register, BLOCK
166    DW_CFA_offset_extended_sf,  // ULEB128 register, SLEB128 offset
167    DW_CFA_def_cfa_sf,          // ULEB128 register, SLEB128 offset
168    DW_CFA_def_cfa_offset_sf,   // SLEB128 offset
169    DW_CFA_val_offset,          // ULEB128, ULEB128
170    DW_CFA_val_offset_sf,       // ULEB128, SLEB128
171    DW_CFA_val_expression,      // ULEB128, BLOCK
172
173    DW_CFA_lo_user = 0x1c,
174    DW_CFA_AARCH64_negate_ra_state = 0x2d,
175    // GNU extensions
176    DW_CFA_GNU_args_size = 0x2e,
177    DW_CFA_GNU_negative_offset_extended = 0x2f,
178
179    DW_CFA_hi_user = 0x3c,
180} DwarfCfa;
181
182enum DwarfEncoding : uint8_t {
183    DW_EH_PE_omit = 0xff,
184
185    DW_EH_PE_absptr = 0x00,
186    DW_EH_PE_uleb128 = 0x01,
187    DW_EH_PE_udata2 = 0x02,
188    DW_EH_PE_udata4 = 0x03,
189    DW_EH_PE_udata8 = 0x04,
190    DW_EH_PE_sleb128 = 0x09,
191    DW_EH_PE_sdata2 = 0x0a,
192    DW_EH_PE_sdata4 = 0x0b,
193    DW_EH_PE_sdata8 = 0x0c,
194
195    DW_EH_PE_pcrel = 0x10,
196    DW_EH_PE_textrel = 0x20,
197    DW_EH_PE_datarel = 0x30,
198    DW_EH_PE_funcrel = 0x40,
199    DW_EH_PE_aligned = 0x50,
200    DW_EH_PE_indirect = 0x80,
201
202    DW_EH_PE_udata1 = 0x0d,
203    DW_EH_PE_sdata1 = 0x0e,
204    DW_EH_PE_block = 0x0f,
205};
206
207// we only need to parse eh_frame and eh_frame_hdr to get the dwarf-encoded unwind info
208// https://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
209// Parsed Common Information Entry Format
210struct CommonInfoEntry {
211    uint32_t codeAlignFactor = 0;
212    int32_t dataAlignFactor = 0;
213    uintptr_t returnAddressRegister = 0;
214    bool hasAugmentationData = false;
215    bool isSignalFrame = false;
216    uint8_t segmentSize = 0;
217    uintptr_t instructionsOff = 0;
218    uintptr_t instructionsEnd = 0;
219    // P
220    uint8_t personality = 0;
221    // L
222    uint8_t lsdaEncoding = 0;
223    // R
224    uint8_t pointerEncoding = 0;
225};
226
227// Parsed Frame Description Entry
228// Table 8-3. Frame Description Entry Format
229struct FrameDescEntry {
230    uintptr_t pcStart = 0;
231    uintptr_t pcEnd = 0;
232    uintptr_t lsda = 0;
233    uintptr_t instructionsOff = 0;
234    uintptr_t instructionsEnd = 0;
235    uintptr_t cieAddr = 0;
236    CommonInfoEntry cie;
237};
238
239struct DwarfTableEntry {
240    int32_t startPc = 0;
241    int32_t fdeOffset = 0;
242};
243
244} // namespace HiviewDFX
245} // namespace OHOS
246#endif
247