/src/libdwarf/fuzz/fuzz_set_frame_all.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2021 Google LLC |
2 | | Licensed under the Apache License, Version 2.0 (the "License"); |
3 | | you may not use this file except in compliance with the License. |
4 | | You may obtain a copy of the License at |
5 | | http://www.apache.org/licenses/LICENSE-2.0 |
6 | | Unless required by applicable law or agreed to in writing, software |
7 | | distributed under the License is distributed on an "AS IS" BASIS, |
8 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
9 | | See the License for the specific language governing permissions and |
10 | | limitations under the License. |
11 | | */ |
12 | | #include <fcntl.h> /* open() O_RDONLY O_BINARY */ |
13 | | #include <limits.h> |
14 | | #include <stdint.h> |
15 | | #include <stdio.h> |
16 | | #include <stdlib.h> |
17 | | #include <string.h> |
18 | | #include <sys/types.h> |
19 | | #include <unistd.h> |
20 | | #include "dwarf.h" |
21 | | #include "libdwarf.h" |
22 | | |
23 | | #ifndef O_BINARY |
24 | 13.9k | #define O_BINARY 0 /* So it does nothing in Linux/Unix */ |
25 | | #endif |
26 | 707k | #define DW_PR_DUx "llx" |
27 | | #define DW_PR_DSx "llx" |
28 | 132k | #define DW_PR_DUu "llu" |
29 | 63.8k | #define DW_PR_DSd "lld" |
30 | | |
31 | | static void read_frame_data(Dwarf_Debug dbg, const char *sec); |
32 | | static void print_fde_instrs(Dwarf_Debug dbg, Dwarf_Fde fde, |
33 | | Dwarf_Error *error); |
34 | | static void print_regtable(Dwarf_Regtable3 *tab3); |
35 | | static void print_cie_instrs(Dwarf_Cie cie, Dwarf_Error *error); |
36 | | static void print_fde_selected_regs(Dwarf_Fde fde); |
37 | | static void print_reg(int r); |
38 | | static void dump_block(char *prefix, Dwarf_Small *data, Dwarf_Unsigned len); |
39 | | |
40 | 352k | #define UNDEF_VAL 2000 |
41 | 352k | #define SAME_VAL 2001 |
42 | 36.4k | #define CFA_VAL 2002 |
43 | 352k | #define INITIAL_VAL UNDEF_VAL |
44 | | |
45 | | /* Because this code does exit() without |
46 | | calling dwarf_finish() in case of certain |
47 | | errors in corrupted objects, executing the program is |
48 | | guaranteed to leak memory when that class |
49 | | of errors is found in the object file being read. |
50 | | |
51 | | David Anderson |
52 | | |
53 | | As of 30 May 2023 all the exit() calls (other |
54 | | than the open() call) are changed to |
55 | | return; instead so we do not leak memory. |
56 | | In addition the tab3.rt3_rules the code mallocs |
57 | | here is always freed here now. */ |
58 | | |
59 | 13.9k | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
60 | 13.9k | char filename[256]; |
61 | 13.9k | sprintf(filename, "/tmp/libfuzzer.%d", getpid()); |
62 | | |
63 | 13.9k | FILE *fp = fopen(filename, "wb"); |
64 | 13.9k | if (!fp) { |
65 | 0 | return 0; |
66 | 0 | } |
67 | 13.9k | fwrite(data, size, 1, fp); |
68 | 13.9k | fclose(fp); |
69 | | |
70 | 13.9k | Dwarf_Debug dbg = 0; |
71 | 13.9k | int res = DW_DLV_ERROR; |
72 | 13.9k | Dwarf_Error error = 0; |
73 | 13.9k | Dwarf_Handler errhand = 0; |
74 | 13.9k | Dwarf_Ptr errarg = 0; |
75 | 13.9k | int regtabrulecount = 0; |
76 | 13.9k | int curopt = 0; |
77 | | |
78 | 13.9k | int fd = open(filename, O_RDONLY | O_BINARY); |
79 | 13.9k | if (fd < 0) { |
80 | 0 | printf("Unable to open %s, giving up.\n", filename); |
81 | 0 | exit(EXIT_FAILURE); |
82 | 0 | } |
83 | | |
84 | 13.9k | res = dwarf_init_b(fd, DW_GROUPNUMBER_ANY, errhand, errarg, &dbg, &error); |
85 | | |
86 | 13.9k | if (res != DW_DLV_OK) { |
87 | 7.49k | printf("Giving up, dwarf_init failed, " |
88 | 7.49k | "cannot do DWARF processing\n"); |
89 | 7.49k | if (res == DW_DLV_ERROR) { |
90 | 5.09k | printf("Error code %s\n", dwarf_errmsg(error)); |
91 | 5.09k | } |
92 | 7.49k | dwarf_dealloc_error(dbg, error); |
93 | 7.49k | } else { |
94 | 6.46k | Dwarf_Half frame_values[] = {SHRT_MIN, SHRT_MAX, 0}; |
95 | 25.8k | for (int i = 0; i < 3; i++) { |
96 | 19.4k | dwarf_set_frame_undefined_value(dbg, frame_values[i]); |
97 | 19.4k | read_frame_data(dbg, ".debug_frame"); |
98 | 19.4k | read_frame_data(dbg, ".eh_frame"); |
99 | 19.4k | } |
100 | 25.8k | for (int i = 0; i < 3; i++) { |
101 | 19.4k | dwarf_set_frame_rule_initial_value(dbg, frame_values[i]); |
102 | 19.4k | read_frame_data(dbg, ".debug_frame"); |
103 | 19.4k | read_frame_data(dbg, ".eh_frame"); |
104 | 19.4k | } |
105 | 25.8k | for (int i = 0; i < 3; i++) { |
106 | 19.4k | dwarf_set_frame_same_value(dbg, frame_values[i]); |
107 | 19.4k | read_frame_data(dbg, ".debug_frame"); |
108 | 19.4k | read_frame_data(dbg, ".eh_frame"); |
109 | 19.4k | } |
110 | 25.8k | for (int i = 0; i < 3; i++) { |
111 | 19.4k | dwarf_set_frame_cfa_value(dbg, frame_values[i]); |
112 | 19.4k | read_frame_data(dbg, ".debug_frame"); |
113 | 19.4k | read_frame_data(dbg, ".eh_frame"); |
114 | 19.4k | } |
115 | 25.8k | for (int i = 0; i < 3; i++) { |
116 | 19.4k | dwarf_set_frame_rule_table_size(dbg, frame_values[i]); |
117 | 19.4k | read_frame_data(dbg, ".debug_frame"); |
118 | 19.4k | read_frame_data(dbg, ".eh_frame"); |
119 | 19.4k | } |
120 | 6.46k | } |
121 | | |
122 | 13.9k | res = dwarf_finish(dbg); |
123 | 13.9k | close(fd); |
124 | 13.9k | unlink(filename); |
125 | 13.9k | return 0; |
126 | 13.9k | } |
127 | | |
128 | 1.40k | static void dump_block(char *prefix, Dwarf_Small *data, Dwarf_Unsigned len) { |
129 | 1.40k | Dwarf_Small *end_data = data + len; |
130 | 1.40k | Dwarf_Small *cur = data; |
131 | 1.40k | int i = 0; |
132 | | |
133 | 1.40k | printf("%s", prefix); |
134 | 12.9k | for (; cur < end_data; ++cur, ++i) { |
135 | 11.5k | if (i > 0 && i % 4 == 0) |
136 | 2.32k | printf(" "); |
137 | 11.5k | printf("%02x", 0xff & *cur); |
138 | 11.5k | } |
139 | 1.40k | } |
140 | | |
141 | 194k | static void read_frame_data(Dwarf_Debug dbg, const char *sect) { |
142 | 194k | Dwarf_Error error; |
143 | 194k | Dwarf_Signed cie_element_count = 0; |
144 | 194k | Dwarf_Signed fde_element_count = 0; |
145 | 194k | Dwarf_Cie *cie_data = 0; |
146 | 194k | Dwarf_Fde *fde_data = 0; |
147 | 194k | int res = DW_DLV_ERROR; |
148 | 194k | Dwarf_Signed fdenum = 0; |
149 | | |
150 | 194k | printf(" Print %s\n", sect); |
151 | 194k | if (!strcmp(sect, ".eh_frame")) { |
152 | 97.0k | res = dwarf_get_fde_list_eh(dbg, &cie_data, &cie_element_count, &fde_data, |
153 | 97.0k | &fde_element_count, &error); |
154 | 97.0k | } else { |
155 | 97.0k | res = dwarf_get_fde_list(dbg, &cie_data, &cie_element_count, &fde_data, |
156 | 97.0k | &fde_element_count, &error); |
157 | 97.0k | } |
158 | 194k | if (res == DW_DLV_NO_ENTRY) { |
159 | 98.1k | printf("No %s data present\n", sect); |
160 | 98.1k | return; |
161 | 98.1k | } |
162 | 95.9k | if (res == DW_DLV_ERROR) { |
163 | 89.4k | printf("Error reading frame data \n"); |
164 | 89.4k | return; |
165 | 89.4k | } |
166 | 6.42k | printf("%" DW_PR_DSd " cies present. " |
167 | 6.42k | "%" DW_PR_DSd " fdes present. \n", |
168 | 6.42k | cie_element_count, fde_element_count); |
169 | 36.4k | for (fdenum = 0; fdenum < fde_element_count; ++fdenum) { |
170 | 30.0k | Dwarf_Cie cie = 0; |
171 | | |
172 | 30.0k | Dwarf_Fde fde; |
173 | 30.0k | dwarf_get_fde_n(fde_data, fdenum, &fde, &error); |
174 | | |
175 | 30.0k | res = dwarf_get_cie_of_fde(fde, &cie, &error); |
176 | 30.0k | if (res != DW_DLV_OK) { |
177 | 0 | printf("Error accessing cie of fdenum %" DW_PR_DSd " to get its cie\n", |
178 | 0 | fdenum); |
179 | 0 | return; |
180 | 0 | } |
181 | 30.0k | printf("Print cie of fde %" DW_PR_DSd "\n", fdenum); |
182 | 30.0k | print_cie_instrs(cie, &error); |
183 | 30.0k | printf("Print fde %" DW_PR_DSd "\n", fdenum); |
184 | 30.0k | print_fde_selected_regs(fde_data[fdenum]); |
185 | 30.0k | print_fde_instrs(dbg, fde_data[fdenum], &error); |
186 | | |
187 | 30.0k | Dwarf_Signed dw_offset_into_exception_tables; |
188 | 30.0k | Dwarf_Signed dw_idx; |
189 | | |
190 | 30.0k | dwarf_get_fde_exception_info(fde_data[fdenum], |
191 | 30.0k | &dw_offset_into_exception_tables, &error); |
192 | 30.0k | dwarf_get_cie_index(cie, &dw_idx, &error); |
193 | | |
194 | 30.0k | Dwarf_Small *dw_augdata; |
195 | 30.0k | Dwarf_Unsigned dw_augdata_len; |
196 | 30.0k | dwarf_get_cie_augmentation_data(cie, &dw_augdata, &dw_augdata_len, &error); |
197 | | |
198 | 30.0k | Dwarf_Small *fde_augdata; |
199 | 30.0k | Dwarf_Unsigned fde_augdata_len; |
200 | 30.0k | dwarf_get_fde_augmentation_data(fde, &fde_augdata, &fde_augdata_len, |
201 | 30.0k | &error); |
202 | | |
203 | 30.0k | Dwarf_Off dw_fde_off; |
204 | 30.0k | Dwarf_Off dw_cie_off; |
205 | | |
206 | 30.0k | dwarf_fde_section_offset(dbg, fde, &dw_fde_off, &dw_cie_off, &error); |
207 | 30.0k | dwarf_cie_section_offset(dbg, cie, &dw_cie_off, &error); |
208 | 30.0k | } |
209 | | |
210 | 6.42k | dwarf_dealloc_fde_cie_list(dbg, cie_data, cie_element_count, fde_data, |
211 | 6.42k | fde_element_count); |
212 | 6.42k | return; |
213 | 6.42k | } |
214 | | |
215 | 30.0k | static void print_cie_instrs(Dwarf_Cie cie, Dwarf_Error *error) { |
216 | 30.0k | int res = DW_DLV_ERROR; |
217 | 30.0k | Dwarf_Unsigned bytes_in_cie = 0; |
218 | 30.0k | Dwarf_Small version = 0; |
219 | 30.0k | char *augmentation = 0; |
220 | 30.0k | Dwarf_Unsigned code_alignment_factor = 0; |
221 | 30.0k | Dwarf_Signed data_alignment_factor = 0; |
222 | 30.0k | Dwarf_Half return_address_register_rule = 0; |
223 | 30.0k | Dwarf_Small *instrp = 0; |
224 | 30.0k | Dwarf_Unsigned instr_len = 0; |
225 | 30.0k | Dwarf_Half offset_size = 0; |
226 | | |
227 | 30.0k | res = dwarf_get_cie_info_b(cie, &bytes_in_cie, &version, &augmentation, |
228 | 30.0k | &code_alignment_factor, &data_alignment_factor, |
229 | 30.0k | &return_address_register_rule, &instrp, &instr_len, |
230 | 30.0k | &offset_size, error); |
231 | 30.0k | if (res != DW_DLV_OK) { |
232 | 0 | printf("Unable to get cie info!\n"); |
233 | 0 | return; |
234 | 0 | } |
235 | 30.0k | } |
236 | | |
237 | | static void print_fde_col(Dwarf_Signed k, Dwarf_Addr jsave, |
238 | | Dwarf_Small value_type, Dwarf_Signed offset_relevant, |
239 | | Dwarf_Signed reg_used, Dwarf_Signed offset, |
240 | | Dwarf_Block *block, Dwarf_Addr row_pc, |
241 | 353k | Dwarf_Bool has_more_rows, Dwarf_Addr subsequent_pc) { |
242 | 353k | char *type_title = ""; |
243 | 353k | Dwarf_Unsigned rule_id = k; |
244 | | |
245 | 353k | printf(" pc=0x%" DW_PR_DUx, jsave); |
246 | 353k | if (row_pc != jsave) { |
247 | 1.39k | printf(" row_pc=0x%" DW_PR_DUx, row_pc); |
248 | 1.39k | } |
249 | 353k | printf(" col=%" DW_PR_DSd " ", k); |
250 | 353k | switch (value_type) { |
251 | 351k | case DW_EXPR_OFFSET: |
252 | 351k | type_title = "off"; |
253 | 351k | goto preg2; |
254 | 518 | case DW_EXPR_VAL_OFFSET: |
255 | 518 | type_title = "valoff"; |
256 | | |
257 | 352k | preg2: |
258 | 352k | printf("<%s ", type_title); |
259 | 352k | if (reg_used == SAME_VAL) { |
260 | 0 | printf(" SAME_VAL"); |
261 | 0 | break; |
262 | 352k | } else if (reg_used == INITIAL_VAL) { |
263 | 0 | printf(" INITIAL_VAL"); |
264 | 0 | break; |
265 | 0 | } |
266 | 352k | print_reg(rule_id); |
267 | | |
268 | 352k | printf("="); |
269 | 352k | if (offset_relevant == 0) { |
270 | 290k | print_reg(reg_used); |
271 | 290k | printf(" "); |
272 | 290k | } else { |
273 | 62.0k | printf("%02" DW_PR_DSd, offset); |
274 | 62.0k | printf("("); |
275 | 62.0k | print_reg(reg_used); |
276 | 62.0k | printf(") "); |
277 | 62.0k | } |
278 | 352k | break; |
279 | 438 | case DW_EXPR_EXPRESSION: |
280 | 438 | type_title = "expr"; |
281 | 438 | goto pexp2; |
282 | 305 | case DW_EXPR_VAL_EXPRESSION: |
283 | 305 | type_title = "valexpr"; |
284 | | |
285 | 743 | pexp2: |
286 | 743 | printf("<%s ", type_title); |
287 | 743 | print_reg(rule_id); |
288 | 743 | printf("="); |
289 | 743 | printf("expr-block-len=%" DW_PR_DUu, block->bl_len); |
290 | 743 | { |
291 | 743 | char pref[40]; |
292 | | |
293 | 743 | strcpy(pref, "<"); |
294 | 743 | strcat(pref, type_title); |
295 | 743 | strcat(pref, "bytes:"); |
296 | 743 | dump_block(pref, block->bl_data, block->bl_len); |
297 | 743 | printf("%s", "> \n"); |
298 | | #if 0 |
299 | | if (glflags.verbose) { |
300 | | struct esb_s exprstring; |
301 | | esb_constructor(&exprstring); |
302 | | get_string_from_locs(dbg, |
303 | | block_ptr,offset,addr_size, |
304 | | offset_size,version,&exprstring); |
305 | | printf("<expr:%s>",esb_get_string(&exprstring)); |
306 | | esb_destructor(&exprstring); |
307 | | } |
308 | | #endif |
309 | 743 | } |
310 | 743 | break; |
311 | 0 | default: |
312 | 0 | printf("Internal error in libdwarf, value type %d\n", value_type); |
313 | 0 | return; |
314 | 353k | } |
315 | 353k | printf(" more=%d", has_more_rows); |
316 | 353k | printf(" next=0x%" DW_PR_DUx, subsequent_pc); |
317 | 353k | printf("%s", "> "); |
318 | 353k | printf("\n"); |
319 | 353k | } |
320 | | |
321 | | static const Dwarf_Block dwblockzero; |
322 | 30.0k | static void print_fde_selected_regs(Dwarf_Fde fde) { |
323 | 30.0k | Dwarf_Error oneferr = 0; |
324 | 30.0k | static int selected_cols[] = {1, 3, 5}; |
325 | 30.0k | static int selected_cols_count = |
326 | 30.0k | sizeof(selected_cols) / sizeof(selected_cols[0]); |
327 | 30.0k | Dwarf_Signed k = 0; |
328 | 30.0k | int fres = 0; |
329 | | |
330 | 30.0k | Dwarf_Addr low_pc = 0; |
331 | 30.0k | Dwarf_Unsigned func_length = 0; |
332 | 30.0k | Dwarf_Small *fde_bytes = NULL; |
333 | 30.0k | Dwarf_Unsigned fde_bytes_length = 0; |
334 | 30.0k | Dwarf_Off cie_offset = 0; |
335 | 30.0k | Dwarf_Signed cie_index = 0; |
336 | 30.0k | Dwarf_Off fde_offset = 0; |
337 | 30.0k | Dwarf_Fde curfde = fde; |
338 | 30.0k | Dwarf_Cie cie = 0; |
339 | 30.0k | Dwarf_Addr jsave = 0; |
340 | 30.0k | Dwarf_Addr high_addr = 0; |
341 | 30.0k | Dwarf_Addr next_jsave = 0; |
342 | 30.0k | Dwarf_Bool has_more_rows = 0; |
343 | 30.0k | Dwarf_Addr subsequent_pc = 0; |
344 | 30.0k | Dwarf_Error error = 0; |
345 | 30.0k | int res = 0; |
346 | | |
347 | 30.0k | fres = dwarf_get_fde_range(curfde, &low_pc, &func_length, &fde_bytes, |
348 | 30.0k | &fde_bytes_length, &cie_offset, &cie_index, |
349 | 30.0k | &fde_offset, &oneferr); |
350 | | |
351 | 30.0k | if (fres == DW_DLV_ERROR) { |
352 | 0 | printf("FAIL: dwarf_get_fde_range err %" DW_PR_DUu " line %d\n", |
353 | 0 | dwarf_errno(oneferr), __LINE__); |
354 | 0 | return; |
355 | 0 | } |
356 | 30.0k | if (fres == DW_DLV_NO_ENTRY) { |
357 | 0 | printf("No fde range data available\n"); |
358 | 0 | return; |
359 | 0 | } |
360 | 30.0k | res = dwarf_get_cie_of_fde(fde, &cie, &error); |
361 | 30.0k | if (res != DW_DLV_OK) { |
362 | 0 | printf("Error getting cie from fde\n"); |
363 | 0 | return; |
364 | 0 | } |
365 | | |
366 | 30.0k | high_addr = low_pc + func_length; |
367 | 147k | for (jsave = low_pc; next_jsave < high_addr; jsave = next_jsave) { |
368 | 128k | next_jsave = jsave + 1; |
369 | 128k | printf("\n"); |
370 | 481k | for (k = 0; k < selected_cols_count; ++k) { |
371 | 364k | Dwarf_Unsigned reg = 0; |
372 | 364k | Dwarf_Unsigned offset_relevant = 0; |
373 | 364k | int fires = 0; |
374 | 364k | Dwarf_Small value_type = 0; |
375 | 364k | Dwarf_Block block; |
376 | 364k | Dwarf_Unsigned offset; |
377 | 364k | Dwarf_Addr row_pc = 0; |
378 | | |
379 | 364k | block = dwblockzero; |
380 | 364k | fires = dwarf_get_fde_info_for_reg3_b( |
381 | 364k | curfde, selected_cols[k], jsave, &value_type, &offset_relevant, ®, |
382 | 364k | &offset, &block, &row_pc, &has_more_rows, &subsequent_pc, &oneferr); |
383 | 364k | if (fires == DW_DLV_ERROR) { |
384 | 11.1k | printf("FAIL: dwarf_get_fde_info_for_reg3_b, " |
385 | 11.1k | "reading reg err %s line %d\n", |
386 | 11.1k | dwarf_errmsg(oneferr), __LINE__); |
387 | 11.1k | return; |
388 | 11.1k | } |
389 | 353k | if (fires == DW_DLV_NO_ENTRY) { |
390 | 0 | continue; |
391 | 0 | } |
392 | 353k | print_fde_col(selected_cols[k], jsave, value_type, offset_relevant, reg, |
393 | 353k | offset, &block, row_pc, has_more_rows, subsequent_pc); |
394 | 353k | if (has_more_rows) { |
395 | 304k | next_jsave = subsequent_pc; |
396 | 304k | } else { |
397 | 48.4k | next_jsave = high_addr; |
398 | 48.4k | } |
399 | 353k | } |
400 | 128k | } |
401 | 30.0k | } |
402 | | |
403 | | static int print_frame_instrs(Dwarf_Debug dbg, |
404 | | Dwarf_Frame_Instr_Head frame_instr_head, |
405 | | Dwarf_Unsigned frame_instr_count, |
406 | 17.0k | Dwarf_Error *error) { |
407 | 17.0k | Dwarf_Unsigned i = 0; |
408 | | |
409 | 17.0k | printf("\nPrint %" DW_PR_DUu " frame instructions\n", frame_instr_count); |
410 | 308k | for (; i < frame_instr_count; ++i) { |
411 | 291k | int res = 0; |
412 | 291k | Dwarf_Unsigned instr_offset_in_instrs = 0; |
413 | 291k | Dwarf_Small cfa_operation = 0; |
414 | 291k | const char *fields = 0; |
415 | 291k | Dwarf_Unsigned u0 = 0; |
416 | 291k | Dwarf_Unsigned u1 = 0; |
417 | 291k | Dwarf_Unsigned u2 = 0; |
418 | 291k | Dwarf_Signed s0 = 0; |
419 | 291k | Dwarf_Signed s1 = 0; |
420 | 291k | Dwarf_Block expression_block; |
421 | 291k | Dwarf_Unsigned code_alignment_factor = 0; |
422 | 291k | Dwarf_Signed data_alignment_factor = 0; |
423 | 291k | const char *op_name = 0; |
424 | | |
425 | 291k | expression_block = dwblockzero; |
426 | 291k | res = dwarf_get_frame_instruction_a( |
427 | 291k | frame_instr_head, i, &instr_offset_in_instrs, &cfa_operation, &fields, |
428 | 291k | &u0, &u1, &u2, &s0, &s1, &code_alignment_factor, &data_alignment_factor, |
429 | 291k | &expression_block, error); |
430 | 291k | res = dwarf_get_frame_instruction( |
431 | 291k | frame_instr_head, i, &instr_offset_in_instrs, &cfa_operation, &fields, |
432 | 291k | &u0, &u1, &s0, &s1, &code_alignment_factor, &data_alignment_factor, |
433 | 291k | &expression_block, error); |
434 | | |
435 | 291k | if (res != DW_DLV_OK) { |
436 | 0 | if (res == DW_DLV_ERROR) { |
437 | 0 | printf("ERROR reading frame instruction " |
438 | 0 | "%" DW_PR_DUu "\n", |
439 | 0 | frame_instr_count); |
440 | 0 | if(error) { |
441 | 0 | dwarf_dealloc_error(dbg, *error); |
442 | 0 | *error = 0; |
443 | 0 | } |
444 | 0 | } else { |
445 | 0 | printf("NO ENTRY reading frame instruction " |
446 | 0 | " %" DW_PR_DUu "\n", |
447 | 0 | frame_instr_count); |
448 | 0 | } |
449 | 0 | break; |
450 | 0 | } |
451 | 291k | dwarf_get_CFA_name(cfa_operation, &op_name); |
452 | 291k | printf("[%2" DW_PR_DUu "] %" DW_PR_DUu " %s ", i, instr_offset_in_instrs, |
453 | 291k | op_name); |
454 | 291k | switch (fields[0]) { |
455 | 127k | case 'u': { |
456 | 127k | if (!fields[1]) { |
457 | 39.9k | printf("%" DW_PR_DUu "\n", u0); |
458 | 39.9k | } |
459 | 127k | if (fields[1] == 'c') { |
460 | 87.7k | Dwarf_Unsigned final = u0 * code_alignment_factor; |
461 | 87.7k | printf("%" DW_PR_DUu, final); |
462 | | #if 0 |
463 | | if (glflags.verbose) { |
464 | | printf(" (%" DW_PR_DUu " * %" DW_PR_DUu, |
465 | | u0,code_alignment_factor); |
466 | | |
467 | | } |
468 | | #endif |
469 | 87.7k | printf("\n"); |
470 | 87.7k | } |
471 | 127k | } break; |
472 | 84.9k | case 'r': { |
473 | 84.9k | if (!fields[1]) { |
474 | 39.1k | printf("r%" DW_PR_DUu "\n", u0); |
475 | 39.1k | break; |
476 | 39.1k | } |
477 | 45.8k | if (fields[1] == 'u') { |
478 | 43.2k | if (!fields[2]) { |
479 | 5.07k | printf("%" DW_PR_DUu, u1); |
480 | 5.07k | printf("\n"); |
481 | 5.07k | break; |
482 | 5.07k | } |
483 | 38.2k | if (fields[2] == 'd') { |
484 | 37.8k | Dwarf_Signed final = (Dwarf_Signed)u0 * data_alignment_factor; |
485 | 37.8k | printf("%" DW_PR_DUu, final); |
486 | 37.8k | printf("\n"); |
487 | 37.8k | } |
488 | 38.2k | } |
489 | 40.7k | if (fields[1] == 'r') { |
490 | 735 | printf("r%" DW_PR_DUu "\n", u0); |
491 | 735 | printf(" "); |
492 | 735 | printf("r%" DW_PR_DUu "\n", u1); |
493 | 735 | printf("\n"); |
494 | 735 | } |
495 | 40.7k | if (fields[1] == 's') { |
496 | 1.39k | if (fields[2] == 'd') { |
497 | 1.39k | Dwarf_Signed final = 0; |
498 | 1.39k | printf("r%" DW_PR_DUu "\n", u0); |
499 | 1.39k | final = s1 * data_alignment_factor; |
500 | 1.39k | printf("%" DW_PR_DSd, final); |
501 | | /* The original did not do this check for 'a' |
502 | | but it's harmless to the testing, so added. 2023-06-10 */ |
503 | 1.39k | if (fields[3] == 'a') { |
504 | 365 | printf(" addrspace %" DW_PR_DUu ,u2); |
505 | 365 | } |
506 | | #if 0 |
507 | | if (glflags.verbose) { |
508 | | printf(" (%" DW_PR_DSd " * %" DW_PR_DSd, |
509 | | s1,data_alignment_factor); |
510 | | } |
511 | | #endif |
512 | 1.39k | printf("\n"); |
513 | 1.39k | } |
514 | 1.39k | } |
515 | 40.7k | if (fields[1] == 'b') { |
516 | | /* rb */ |
517 | 425 | printf("r%" DW_PR_DUu "\n", u0); |
518 | 425 | printf("%" DW_PR_DUu, u0); |
519 | 425 | printf(" expr block len %" DW_PR_DUu "\n", expression_block.bl_len); |
520 | 425 | dump_block(" ", expression_block.bl_data, |
521 | 425 | (Dwarf_Signed)expression_block.bl_len); |
522 | 425 | printf("\n"); |
523 | | #if 0 |
524 | | if (glflags.verbose) { |
525 | | print_expression(dbg,die,&expression_block, |
526 | | addr_size,offset_size, |
527 | | version); |
528 | | } |
529 | | #endif |
530 | 425 | } |
531 | 40.7k | } break; |
532 | 390 | case 's': { |
533 | 390 | if (fields[1] == 'd') { |
534 | 390 | Dwarf_Signed final = s0 * data_alignment_factor; |
535 | | |
536 | 390 | printf(" %" DW_PR_DSd, final); |
537 | | #if 0 |
538 | | if (glflags.verbose) { |
539 | | printf(" (%" DW_PR_DSd " * %" DW_PR_DSd, |
540 | | s0,data_alignment_factor); |
541 | | } |
542 | | #endif |
543 | 390 | printf("\n"); |
544 | 390 | } |
545 | 390 | } break; |
546 | 233 | case 'b': { |
547 | 233 | if (!fields[1]) { |
548 | 233 | printf(" expr block len %" DW_PR_DUu "\n", expression_block.bl_len); |
549 | 233 | dump_block(" ", expression_block.bl_data, |
550 | 233 | (Dwarf_Signed)expression_block.bl_len); |
551 | 233 | printf("\n"); |
552 | | #if 0 |
553 | | if (glflags.verbose) { |
554 | | print_expression(dbg,die,&expression_block, |
555 | | addr_size,offset_size, |
556 | | version); |
557 | | } |
558 | | #endif |
559 | 233 | } |
560 | 233 | } break; |
561 | 77.7k | case 0: |
562 | 77.7k | printf("\n"); |
563 | 77.7k | break; |
564 | 0 | default: |
565 | 0 | printf("UNKNOWN FIELD 0x%x\n", fields[0]); |
566 | 291k | } |
567 | 291k | } |
568 | 17.0k | return DW_DLV_OK; |
569 | 17.0k | } |
570 | | |
571 | | static void print_fde_instrs(Dwarf_Debug dbg, Dwarf_Fde fde, |
572 | 30.0k | Dwarf_Error *error) { |
573 | 30.0k | int res; |
574 | 30.0k | Dwarf_Addr lowpc = 0; |
575 | 30.0k | Dwarf_Unsigned func_length = 0; |
576 | 30.0k | Dwarf_Small *fde_bytes; |
577 | 30.0k | Dwarf_Unsigned fde_byte_length = 0; |
578 | 30.0k | Dwarf_Off cie_offset = 0; |
579 | 30.0k | Dwarf_Signed cie_index = 0; |
580 | 30.0k | Dwarf_Off fde_offset = 0; |
581 | 30.0k | Dwarf_Addr arbitrary_addr = 0; |
582 | 30.0k | Dwarf_Addr actual_pc = 0; |
583 | 30.0k | Dwarf_Regtable3 tab3; |
584 | 30.0k | int oldrulecount = 0; |
585 | 30.0k | Dwarf_Small *outinstrs = 0; |
586 | 30.0k | Dwarf_Unsigned instrslen = 0; |
587 | 30.0k | Dwarf_Cie cie = 0; |
588 | | |
589 | 30.0k | res = dwarf_get_fde_range(fde, &lowpc, &func_length, &fde_bytes, |
590 | 30.0k | &fde_byte_length, &cie_offset, &cie_index, |
591 | 30.0k | &fde_offset, error); |
592 | 30.0k | if (res != DW_DLV_OK) { |
593 | | /* So nothing clears the error record here, |
594 | | the caller does not know the call failed. |
595 | | Terrible code, but interesting testcase. */ |
596 | 0 | printf("Problem getting fde range \n"); |
597 | 0 | return; |
598 | 0 | } |
599 | | |
600 | 30.0k | arbitrary_addr = lowpc + (func_length / 2); |
601 | 30.0k | printf("function low pc 0x%" DW_PR_DUx " and length 0x%" DW_PR_DUx |
602 | 30.0k | " and midpoint addr we choose 0x%" DW_PR_DUx "\n", |
603 | 30.0k | lowpc, func_length, arbitrary_addr); |
604 | | |
605 | 30.0k | oldrulecount = dwarf_set_frame_rule_table_size(dbg, 1); |
606 | 30.0k | dwarf_set_frame_rule_table_size(dbg, oldrulecount); |
607 | | |
608 | 30.0k | tab3.rt3_reg_table_size = oldrulecount; |
609 | 30.0k | tab3.rt3_rules = (struct Dwarf_Regtable_Entry3_s *)malloc( |
610 | 30.0k | sizeof(struct Dwarf_Regtable_Entry3_s) * oldrulecount); |
611 | 30.0k | if (!tab3.rt3_rules) { |
612 | 0 | printf("Unable to malloc for %d rules\n", oldrulecount); |
613 | 0 | return; |
614 | 0 | } |
615 | | |
616 | 30.0k | res = dwarf_get_fde_info_for_all_regs3(fde, arbitrary_addr, &tab3, &actual_pc, |
617 | 30.0k | error); |
618 | 30.0k | printf("function actual addr of row 0x%" DW_PR_DUx "\n", actual_pc); |
619 | | |
620 | 30.0k | if (res != DW_DLV_OK) { |
621 | 8.15k | printf("dwarf_get_fde_info_for_all_regs3 failed!\n"); |
622 | 8.15k | free(tab3.rt3_rules); |
623 | 8.15k | return; |
624 | 8.15k | } |
625 | 21.8k | print_regtable(&tab3); |
626 | | |
627 | 21.8k | res = dwarf_get_fde_instr_bytes(fde, &outinstrs, &instrslen, error); |
628 | 21.8k | if (res != DW_DLV_OK) { |
629 | 0 | free(tab3.rt3_rules); |
630 | 0 | printf("dwarf_get_fde_instr_bytes failed!\n"); |
631 | 0 | return; |
632 | 0 | } |
633 | 21.8k | res = dwarf_get_cie_of_fde(fde, &cie, error); |
634 | 21.8k | if (res != DW_DLV_OK) { |
635 | 0 | free(tab3.rt3_rules); |
636 | 0 | printf("Error getting cie from fde\n"); |
637 | 0 | return; |
638 | 0 | } |
639 | | |
640 | 21.8k | { |
641 | 21.8k | Dwarf_Frame_Instr_Head frame_instr_head = 0; |
642 | 21.8k | Dwarf_Unsigned frame_instr_count = 0; |
643 | 21.8k | res = dwarf_expand_frame_instructions(cie, outinstrs, instrslen, |
644 | 21.8k | &frame_instr_head, &frame_instr_count, |
645 | 21.8k | error); |
646 | 21.8k | if (res != DW_DLV_OK) { |
647 | 4.80k | free(tab3.rt3_rules); |
648 | 4.80k | printf("dwarf_expand_frame_instructions failed!\n"); |
649 | 4.80k | return; |
650 | 4.80k | } |
651 | 17.0k | printf("Frame op count: %" DW_PR_DUu "\n", frame_instr_count); |
652 | 17.0k | print_frame_instrs(dbg, frame_instr_head, frame_instr_count, error); |
653 | | |
654 | 17.0k | dwarf_dealloc_frame_instr_head(frame_instr_head); |
655 | 17.0k | } |
656 | 0 | free(tab3.rt3_rules); |
657 | 17.0k | } |
658 | | |
659 | 945k | static void print_reg(int r) { |
660 | 945k | switch (r) { |
661 | 0 | case SAME_VAL: |
662 | 0 | printf(" %d SAME_VAL ", r); |
663 | 0 | break; |
664 | 0 | case UNDEF_VAL: |
665 | 0 | printf(" %d UNDEF_VAL ", r); |
666 | 0 | break; |
667 | 0 | case CFA_VAL: |
668 | 0 | printf(" %d (CFA) ", r); |
669 | 0 | break; |
670 | 945k | default: |
671 | 945k | printf(" r%d ", r); |
672 | 945k | break; |
673 | 945k | } |
674 | 945k | } |
675 | | |
676 | | static void print_one_regentry(const char *prefix, |
677 | 240k | struct Dwarf_Regtable_Entry3_s *entry) { |
678 | 240k | int is_cfa = !strcmp("cfa", prefix); |
679 | 240k | printf("%s ", prefix); |
680 | 240k | printf("type: %d %s ", entry->dw_value_type, |
681 | 240k | (entry->dw_value_type == DW_EXPR_OFFSET) ? "DW_EXPR_OFFSET" |
682 | 240k | : (entry->dw_value_type == DW_EXPR_VAL_OFFSET) ? "DW_EXPR_VAL_OFFSET" |
683 | 1.11k | : (entry->dw_value_type == DW_EXPR_EXPRESSION) ? "DW_EXPR_EXPRESSION" |
684 | 571 | : (entry->dw_value_type == DW_EXPR_VAL_EXPRESSION) |
685 | 229 | ? "DW_EXPR_VAL_EXPRESSION" |
686 | 229 | : "Unknown"); |
687 | 240k | switch (entry->dw_value_type) { |
688 | 239k | case DW_EXPR_OFFSET: |
689 | 239k | print_reg(entry->dw_regnum); |
690 | 239k | printf(" offset_rel? %d ", entry->dw_offset_relevant); |
691 | 239k | if (entry->dw_offset_relevant) { |
692 | 51.4k | printf(" offset %" DW_PR_DSd " ", entry->dw_offset); |
693 | 51.4k | if (is_cfa) { |
694 | 15.4k | printf("defines cfa value"); |
695 | 35.9k | } else { |
696 | 35.9k | printf("address of value is CFA plus signed offset"); |
697 | 35.9k | } |
698 | 51.4k | if (!is_cfa && entry->dw_regnum != CFA_VAL) { |
699 | 35.9k | printf(" compiler botch, regnum != CFA_VAL"); |
700 | 35.9k | } |
701 | 188k | } else { |
702 | 188k | printf("value in register"); |
703 | 188k | } |
704 | 239k | break; |
705 | 544 | case DW_EXPR_VAL_OFFSET: |
706 | 544 | print_reg(entry->dw_regnum); |
707 | 544 | printf(" offset %" DW_PR_DSd " ", entry->dw_offset); |
708 | 544 | if (is_cfa) { |
709 | 0 | printf("does this make sense? No?"); |
710 | 544 | } else { |
711 | 544 | printf("value at CFA plus signed offset"); |
712 | 544 | } |
713 | 544 | if (!is_cfa && entry->dw_regnum != CFA_VAL) { |
714 | 544 | printf(" compiler botch, regnum != CFA_VAL"); |
715 | 544 | } |
716 | 544 | break; |
717 | 342 | case DW_EXPR_EXPRESSION: |
718 | 342 | print_reg(entry->dw_regnum); |
719 | 342 | printf(" offset_rel? %d ", entry->dw_offset_relevant); |
720 | 342 | printf(" offset %" DW_PR_DUu " ", entry->dw_offset); |
721 | 342 | printf("Block ptr set? %s ", entry->dw_block.bl_data ? "yes" : "no"); |
722 | 342 | printf(" Value is at address given by expr val "); |
723 | 342 | break; |
724 | 229 | case DW_EXPR_VAL_EXPRESSION: |
725 | 229 | printf(" expression byte len %" DW_PR_DUu " ", entry->dw_block.bl_len); |
726 | 229 | printf("Block ptr set? %s ", entry->dw_block.bl_data ? "yes" : "no"); |
727 | 229 | printf(" Value is expr val "); |
728 | 229 | if (!entry->dw_block.bl_data) { |
729 | 0 | printf("Compiler or libdwarf botch, " |
730 | 0 | "NULL block data pointer. "); |
731 | 0 | } |
732 | 229 | break; |
733 | 0 | default: |
734 | 0 | break; |
735 | 240k | } |
736 | 240k | printf("\n"); |
737 | 240k | } |
738 | | |
739 | 21.8k | static void print_regtable(Dwarf_Regtable3 *tab3) { |
740 | 21.8k | int r; |
741 | 21.8k | int max = 10; |
742 | 21.8k | if (max > tab3->rt3_reg_table_size) { |
743 | 0 | max = tab3->rt3_reg_table_size; |
744 | 0 | } |
745 | 21.8k | print_one_regentry("cfa", &tab3->rt3_cfa_rule); |
746 | | |
747 | 240k | for (r = 0; r < max; r++) { |
748 | 218k | char rn[30]; |
749 | 218k | snprintf(rn, sizeof(rn), "reg %d", r); |
750 | 218k | print_one_regentry(rn, tab3->rt3_rules + r); |
751 | 218k | } |
752 | 21.8k | } |