1 /*
2 Copyright (c) 2009-2015 David Anderson.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the example nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY David Anderson ''AS IS'' AND ANY
17 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL David Anderson BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 */
28 /* simplereader.c
29 This is an example of code reading dwarf .debug_frame.
30 It is kept as simple as possible to expose essential features.
31 It does not do all possible error reporting or error handling.
32
33 It specifically calls dwarf_expand_frame_instructions()
34 to verify that works without crashing!
35
36 To use, try
37 make
38 ./frame1 frame1
39
40 gcc/clang may produce .eh_frame without .debug_frame.
41 To read .eh_frame call dwarf_get_fde_list_eh()
42 below instead of dwarf_get_fde_list() .
43 */
44 #include <sys/types.h> /* For open() */
45 #include <sys/stat.h> /* For open() */
46 #include <fcntl.h> /* For open() */
47 #include <stdlib.h> /* For exit() */
48 #include <unistd.h> /* For close() */
49 #include <string.h> /* For strcmp* */
50 #include <stdio.h>
51 #include <errno.h>
52 #include "dwarf.h"
53 #include "libdwarf.h"
54
55
56 static void read_frame_data(Dwarf_Debug dbg);
57 static void print_fde_instrs(Dwarf_Debug dbg, Dwarf_Fde fde,
58 Dwarf_Error *error);
59 static void print_regtable(Dwarf_Regtable3 *tab3);
60 static void
61 print_cie_instrs(Dwarf_Cie cie,Dwarf_Error *error);
62
63
64 #define UNDEF_VAL 2000
65 #define SAME_VAL 2001
66 #define CFA_VAL 2002
67
68
69 int
main(int argc,char ** argv)70 main(int argc, char **argv)
71 {
72
73 Dwarf_Debug dbg = 0;
74 int fd = -1;
75 const char *filepath = "<stdin>";
76 int res = DW_DLV_ERROR;
77 Dwarf_Error error;
78 Dwarf_Handler errhand = 0;
79 Dwarf_Ptr errarg = 0;
80 int regtabrulecount = 0;
81
82 if(argc < 2) {
83 fd = 0; /* stdin */
84 } else {
85 filepath = argv[1];
86 fd = open(filepath,O_RDONLY);
87 }
88 if(fd < 0) {
89 printf("Failure attempting to open %s\n",filepath);
90 }
91 res = dwarf_init(fd,DW_DLC_READ,errhand,errarg, &dbg,&error);
92 if(res != DW_DLV_OK) {
93 printf("Giving up, dwarf_init failed, cannot do DWARF processing\n");
94 exit(1);
95 }
96 /* Do this setting after init before any real operations.
97 These return the old values, but here we do not
98 need to know the old values. The sizes and
99 values here are higher than most ABIs and entirely
100 arbitrary.
101
102 The setting of initial_value to
103 the same as undefined-value (the other possible choice being
104 same-value) is arbitrary, different ABIs do differ, and
105 you have to know which is right. */
106 regtabrulecount=1999;
107 dwarf_set_frame_undefined_value(dbg, UNDEF_VAL);
108 dwarf_set_frame_rule_initial_value(dbg, UNDEF_VAL);
109 dwarf_set_frame_same_value(dbg,SAME_VAL);
110 dwarf_set_frame_cfa_value(dbg,CFA_VAL);
111 dwarf_set_frame_rule_table_size(dbg,regtabrulecount);
112
113 read_frame_data(dbg);
114 res = dwarf_finish(dbg,&error);
115 if(res != DW_DLV_OK) {
116 printf("dwarf_finish failed!\n");
117 }
118 close(fd);
119 return 0;
120 }
121
122 static void
read_frame_data(Dwarf_Debug dbg)123 read_frame_data(Dwarf_Debug dbg)
124 {
125 Dwarf_Error error;
126 Dwarf_Signed cie_element_count = 0;
127 Dwarf_Signed fde_element_count = 0;
128 Dwarf_Cie *cie_data = 0;
129 Dwarf_Fde *fde_data = 0;
130 int res = DW_DLV_ERROR;
131 Dwarf_Signed fdenum = 0;
132
133
134 /* If you wish to read .eh_frame data, use
135 dwarf_get_fde_list_eh() instead. */
136 res = dwarf_get_fde_list(dbg,&cie_data,&cie_element_count,
137 &fde_data,&fde_element_count,&error);
138 if(res == DW_DLV_NO_ENTRY) {
139 printf("No .debug_frame data present\n");
140 printf("Try dwarf_get_fde_list_eh() to read .eh_frame data\n");
141 exit(0);
142 }
143 if( res == DW_DLV_ERROR) {
144 printf("Error reading frame data ");
145 exit(1);
146 }
147 printf( "%" DW_PR_DSd " cies present. "
148 "%" DW_PR_DSd " fdes present. \n",
149 cie_element_count,fde_element_count);
150 /*if(fdenum >= fde_element_count) {
151 printf("Want fde %d but only %" DW_PR_DSd " present\n",fdenum,
152 fde_element_count);
153 exit(1);
154 }*/
155
156 for(fdenum = 0; fdenum < fde_element_count; ++fdenum) {
157 Dwarf_Cie cie = 0;
158 printf("Print cie of fde %" DW_PR_DSd "\n",fdenum);
159 res = dwarf_get_cie_of_fde(fde_data[fdenum],&cie,&error);
160 if(res != DW_DLV_OK) {
161 printf("Error accessing fdenum %" DW_PR_DSd
162 " to get its cie\n",fdenum);
163 exit(1);
164 }
165 print_cie_instrs(cie,&error);
166 printf("Print fde %" DW_PR_DSd "\n",fdenum);
167 print_fde_instrs(dbg,fde_data[fdenum],&error);
168 }
169
170 /* Done with the data. */
171 dwarf_fde_cie_list_dealloc(dbg,cie_data,cie_element_count,
172 fde_data, fde_element_count);
173 return;
174 }
175 static void
print_cie_instrs(Dwarf_Cie cie,Dwarf_Error * error)176 print_cie_instrs(Dwarf_Cie cie,Dwarf_Error *error)
177 {
178 int res = DW_DLV_ERROR;
179 Dwarf_Unsigned bytes_in_cie = 0;
180 Dwarf_Small version = 0;
181 char *augmentation = 0;
182 Dwarf_Unsigned code_alignment_factor = 0;
183 Dwarf_Signed data_alignment_factor = 0;
184 Dwarf_Half return_address_register_rule = 0;
185 Dwarf_Ptr instrp = 0;
186 Dwarf_Unsigned instr_len = 0;
187
188 res = dwarf_get_cie_info(cie,&bytes_in_cie,
189 &version, &augmentation, &code_alignment_factor,
190 &data_alignment_factor, &return_address_register_rule,
191 &instrp,&instr_len,error);
192 if(res != DW_DLV_OK) {
193 printf("Unable to get cie info!\n");
194 exit(1);
195 }
196 }
197
198 static void
print_frame_instrs(Dwarf_Frame_Op * frame_op_list,Dwarf_Signed frame_op_count)199 print_frame_instrs(Dwarf_Frame_Op *frame_op_list,
200 Dwarf_Signed frame_op_count)
201 {
202 Dwarf_Signed i = 0;
203 printf("Base op. Ext op. Reg. Offset. Instr-offset.\n");
204 for(i = 0; i < frame_op_count; ++i) {
205 printf("[%" DW_PR_DSd "]", i);
206 printf(" %d. ", frame_op_list[i].fp_base_op);
207 printf(" %d. ", frame_op_list[i].fp_extended_op);
208 printf(" %" DW_PR_DSd ". ", frame_op_list[i].fp_offset);
209 printf(" 0x%" DW_PR_DUx ". ", frame_op_list[i].fp_instr_offset);
210 printf("\n");
211 }
212 }
213
214 static void
print_fde_instrs(Dwarf_Debug dbg,Dwarf_Fde fde,Dwarf_Error * error)215 print_fde_instrs(Dwarf_Debug dbg,
216 Dwarf_Fde fde, Dwarf_Error *error)
217 {
218 int res;
219 Dwarf_Addr lowpc = 0;
220 Dwarf_Unsigned func_length = 0;
221 Dwarf_Ptr fde_bytes;
222 Dwarf_Unsigned fde_byte_length = 0;
223 Dwarf_Off cie_offset = 0;
224 Dwarf_Signed cie_index = 0;
225 Dwarf_Off fde_offset = 0;
226 Dwarf_Addr arbitrary_addr = 0;
227 Dwarf_Addr actual_pc = 0;
228 Dwarf_Regtable3 tab3;
229 int oldrulecount = 0;
230 Dwarf_Ptr outinstrs = 0;
231 Dwarf_Unsigned instrslen = 0;
232 Dwarf_Frame_Op * frame_op_list = 0;
233 Dwarf_Signed frame_op_count = 0;
234 Dwarf_Cie cie = 0;
235
236
237 res = dwarf_get_fde_range(fde,&lowpc,&func_length,&fde_bytes,
238 &fde_byte_length,&cie_offset,&cie_index,&fde_offset,error);
239 if(res != DW_DLV_OK) {
240 printf("Problem getting fde range \n");
241 exit(1);
242 }
243
244 arbitrary_addr = lowpc + (func_length/2);
245 printf("function low pc 0x%" DW_PR_DUx
246 " and length 0x%" DW_PR_DUx
247 " and addr we choose 0x%" DW_PR_DUx
248 "\n",
249 lowpc,func_length,arbitrary_addr);
250
251 /* 1 is arbitrary. We are winding up getting the
252 rule count here while leaving things unchanged. */
253 oldrulecount = dwarf_set_frame_rule_table_size(dbg,1);
254 dwarf_set_frame_rule_table_size(dbg,oldrulecount);
255
256 tab3.rt3_reg_table_size = oldrulecount;
257 tab3.rt3_rules = (struct Dwarf_Regtable_Entry3_s *) malloc(
258 sizeof(struct Dwarf_Regtable_Entry3_s)* oldrulecount);
259 if (!tab3.rt3_rules) {
260 printf("Unable to malloc for %d rules\n",oldrulecount);
261 exit(1);
262 }
263
264 res = dwarf_get_fde_info_for_all_regs3(fde,arbitrary_addr ,
265 &tab3,&actual_pc,error);
266
267 if(res != DW_DLV_OK) {
268 printf("dwarf_get_fde_info_for_all_regs3 failed!\n");
269 exit(1);
270 }
271 print_regtable(&tab3);
272
273 res = dwarf_get_fde_instr_bytes(fde,&outinstrs,&instrslen,error);
274 if(res != DW_DLV_OK) {
275 printf("dwarf_get_fde_instr_bytes failed!\n");
276 exit(1);
277 }
278 res = dwarf_get_cie_of_fde(fde,&cie,error);
279 if(res != DW_DLV_OK) {
280 printf("Error getting cie from fde\n");
281 exit(1);
282 }
283
284 res = dwarf_expand_frame_instructions(cie,
285 outinstrs,instrslen,&frame_op_list,
286 &frame_op_count,error);
287 if(res != DW_DLV_OK) {
288 printf("dwarf_expand_frame_instructions failed!\n");
289 exit(1);
290 }
291 printf("Frame op count: %" DW_PR_DUu "\n",frame_op_count);
292 print_frame_instrs(frame_op_list,frame_op_count);
293
294 dwarf_dealloc(dbg,frame_op_list, DW_DLA_FRAME_BLOCK);
295 free(tab3.rt3_rules);
296 }
297
298 static void
print_reg(int r)299 print_reg(int r)
300 {
301 switch(r) {
302 case SAME_VAL:
303 printf(" %d SAME_VAL ",r);
304 break;
305 case UNDEF_VAL:
306 printf(" %d UNDEF_VAL ",r);
307 break;
308 case CFA_VAL:
309 printf(" %d (CFA) ",r);
310 break;
311 default:
312 printf(" r%d ",r);
313 break;
314 }
315 }
316
317 static void
print_one_regentry(const char * prefix,struct Dwarf_Regtable_Entry3_s * entry)318 print_one_regentry(const char *prefix,
319 struct Dwarf_Regtable_Entry3_s *entry)
320 {
321 int is_cfa = !strcmp("cfa",prefix);
322 printf("%s ",prefix);
323 printf("type: %d %s ",
324 entry->dw_value_type,
325 (entry->dw_value_type == DW_EXPR_OFFSET)? "DW_EXPR_OFFSET":
326 (entry->dw_value_type == DW_EXPR_VAL_OFFSET)? "DW_EXPR_VAL_OFFSET":
327 (entry->dw_value_type == DW_EXPR_EXPRESSION)? "DW_EXPR_EXPRESSION":
328 (entry->dw_value_type == DW_EXPR_VAL_EXPRESSION)?
329 "DW_EXPR_VAL_EXPRESSION":
330 "Unknown");
331 switch(entry->dw_value_type) {
332 case DW_EXPR_OFFSET:
333 print_reg(entry->dw_regnum);
334 printf(" offset_rel? %d ",entry->dw_offset_relevant);
335 if(entry->dw_offset_relevant) {
336 printf(" offset %" DW_PR_DSd " " ,
337 entry->dw_offset_or_block_len);
338 if(is_cfa) {
339 printf("defines cfa value");
340 } else {
341 printf("address of value is CFA plus signed offset");
342 }
343 if(!is_cfa && entry->dw_regnum != CFA_VAL) {
344 printf(" compiler botch, regnum != CFA_VAL");
345 }
346 } else {
347 printf("value in register");
348 }
349 break;
350 case DW_EXPR_VAL_OFFSET:
351 print_reg(entry->dw_regnum);
352 printf(" offset %" DW_PR_DSd " " ,
353 entry->dw_offset_or_block_len);
354 if(is_cfa) {
355 printf("does this make sense? No?");
356 } else {
357 printf("value at CFA plus signed offset");
358 }
359 if(!is_cfa && entry->dw_regnum != CFA_VAL) {
360 printf(" compiler botch, regnum != CFA_VAL");
361 }
362 break;
363 case DW_EXPR_EXPRESSION:
364 print_reg(entry->dw_regnum);
365 printf(" offset_rel? %d ",entry->dw_offset_relevant);
366 printf(" offset %" DW_PR_DSd " " ,
367 entry->dw_offset_or_block_len);
368 printf("Block ptr set? %s ",entry->dw_block_ptr?"yes":"no");
369 printf(" Value is at address given by expr val ");
370 /* printf(" block-ptr 0x%" DW_PR_DUx " ",
371 (Dwarf_Unsigned)entry->dw_block_ptr); */
372 break;
373 case DW_EXPR_VAL_EXPRESSION:
374 printf(" expression byte len %" DW_PR_DSd " " ,
375 entry->dw_offset_or_block_len);
376 printf("Block ptr set? %s ",entry->dw_block_ptr?"yes":"no");
377 printf(" Value is expr val ");
378 if(!entry->dw_block_ptr) {
379 printf("Compiler botch. ");
380 }
381 /* printf(" block-ptr 0x%" DW_PR_DUx " ",
382 (Dwarf_Unsigned)entry->dw_block_ptr); */
383 break;
384 }
385 printf("\n");
386 }
387
388 static void
print_regtable(Dwarf_Regtable3 * tab3)389 print_regtable(Dwarf_Regtable3 *tab3)
390 {
391 int r;
392 /* We won't print too much. A bit arbitrary. */
393 int max = 10;
394 if(max > tab3->rt3_reg_table_size) {
395 max = tab3->rt3_reg_table_size;
396 }
397 print_one_regentry("cfa",&tab3->rt3_cfa_rule);
398
399 for(r = 0; r < max; r++) {
400 char rn[30];
401 snprintf(rn,sizeof(rn),"reg %d",r);
402 print_one_regentry(rn,tab3->rt3_rules+r);
403 }
404
405
406 }
407
408
409
410
411