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