1 /*-
2 * Copyright (c) 2010 Kai Wang
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
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: dwarf_frame.c 2084 2011-10-27 04:48:12Z jkoshy $
27 */
28
29 #include <assert.h>
30 #include <dwarf.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <libdwarf.h>
34 #include <string.h>
35
36 #include "driver.h"
37 #include "tet_api.h"
38
39 /*
40 * Test case for dwarf line informatio API.
41 */
42 static void tp_dwarf_frame2(void);
43 static void tp_dwarf_frame3(void);
44 static struct dwarf_tp dwarf_tp_array[] = {
45 {"tp_dwarf_frame2",tp_dwarf_frame2},
46 {"tp_dwarf_frame3",tp_dwarf_frame3},
47 {NULL, NULL},
48 };
49 static int result = TET_UNRESOLVED;
50 #include "driver.c"
51
52 #define _MAX_REG_NUM 10
53
54 static void
_frame2_test(Dwarf_Debug dbg,Dwarf_Fde fde,Dwarf_Addr pc,Dwarf_Unsigned func_len,Dwarf_Unsigned caf)55 _frame2_test(Dwarf_Debug dbg, Dwarf_Fde fde, Dwarf_Addr pc,
56 Dwarf_Unsigned func_len, Dwarf_Unsigned caf)
57 {
58 Dwarf_Signed offset_relevant, register_num, offset;
59 Dwarf_Addr pc_end, row_pc;
60 Dwarf_Regtable reg_table;
61 Dwarf_Error de;
62 int i, cnt;
63
64 (void) dwarf_set_frame_cfa_value(dbg, DW_FRAME_CFA_COL);
65
66 /* Sanity check for invalid table_column. */
67 if (dwarf_get_fde_info_for_reg(fde, 9999, 0, &offset_relevant,
68 ®ister_num, &offset, &row_pc, &de) != DW_DLV_ERROR) {
69 tet_infoline("dwarf_get_fde_info_for_reg didn't return"
70 " DW_DLV_ERROR when called with invalid table_column"
71 " value");
72 result = TET_FAIL;
73 return;
74 }
75
76 cnt = 0;
77 pc_end = pc + func_len;
78 while (pc < pc_end && cnt < 16) {
79 tet_printf("query CFA register pc %#jx\n", (uintmax_t) pc);
80 /*
81 * XXX If application want to use DW_FRAME_CFA_COL for CFA,
82 * it should call dwarf_set_frame_cfa_value() to set that
83 * explicitly. So here DW_FRAME_CFA_COL might not be refering
84 * to the CFA at all, depends on whether CFA(0) is set by
85 * dwarf_set_frame_cfa_value.
86 */
87 if (dwarf_get_fde_info_for_reg(fde, DW_FRAME_CFA_COL,
88 pc, &offset_relevant, ®ister_num, &offset,
89 &row_pc, &de) != DW_DLV_OK) {
90 tet_printf("dwarf_get_fde_info_for_reg(cfa) failed: %s",
91 dwarf_errmsg(de));
92 result = TET_FAIL;
93 return;
94 }
95 TS_CHECK_INT(offset_relevant);
96 TS_CHECK_INT(offset);
97 TS_CHECK_INT(register_num);
98 TS_CHECK_UINT(row_pc);
99 for (i = 1; i < _MAX_REG_NUM; i++) {
100 tet_printf("query register %d\n", i);
101 if (dwarf_get_fde_info_for_reg(fde, i, pc,
102 &offset_relevant, ®ister_num, &offset,
103 &row_pc, &de) != DW_DLV_OK) {
104 tet_printf("dwarf_get_fde_info_for_reg(%d)"
105 " failed: %s", i, dwarf_errmsg(de));
106 result = TET_FAIL;
107 goto next;
108 }
109 TS_CHECK_INT(offset_relevant);
110 TS_CHECK_INT(offset);
111 TS_CHECK_INT(register_num);
112 TS_CHECK_UINT(row_pc);
113 }
114 tet_infoline("query all register");
115 if (dwarf_get_fde_info_for_all_regs(fde, pc, ®_table,
116 &row_pc, &de) != DW_DLV_OK) {
117 tet_printf("dwarf_get_fde_info_for_all_regs failed: %s",
118 dwarf_errmsg(de));
119 result = TET_FAIL;
120 goto next;
121 }
122 TS_CHECK_UINT(row_pc);
123 for (i = 0; i < _MAX_REG_NUM; i++) {
124 tet_printf("check reg_table[%d]\n", i);
125 TS_CHECK_UINT(reg_table.rules[i].dw_offset_relevant);
126 TS_CHECK_UINT(reg_table.rules[i].dw_regnum);
127 TS_CHECK_UINT(reg_table.rules[i].dw_offset);
128 }
129
130 next:
131 pc += caf;
132 cnt++;
133 }
134 }
135
136 static void
_frame3_test(Dwarf_Debug dbg,Dwarf_Fde fde,Dwarf_Addr pc,Dwarf_Unsigned func_len,Dwarf_Unsigned caf)137 _frame3_test(Dwarf_Debug dbg, Dwarf_Fde fde, Dwarf_Addr pc,
138 Dwarf_Unsigned func_len, Dwarf_Unsigned caf)
139 {
140 Dwarf_Signed offset_relevant, register_num, offset_or_block_len;
141 Dwarf_Addr pc_end, row_pc;
142 Dwarf_Ptr block_ptr;
143 Dwarf_Regtable3 reg_table3;
144 Dwarf_Small value_type;
145 Dwarf_Error de;
146 int i, cnt;
147
148 /* Initialise regster table (DWARF3). */
149 reg_table3.rt3_reg_table_size = DW_REG_TABLE_SIZE;
150 reg_table3.rt3_rules = calloc(reg_table3.rt3_reg_table_size,
151 sizeof(Dwarf_Regtable_Entry3));
152 if (reg_table3.rt3_rules == NULL) {
153 tet_infoline("calloc failed when initialising reg_table3");
154 result = TET_FAIL;
155 return;
156 }
157
158 /* Sanity check for invalid table_column. */
159 if (dwarf_get_fde_info_for_reg3(fde, 9999, 0, &value_type,
160 &offset_relevant, ®ister_num, &offset_or_block_len, &block_ptr,
161 &row_pc, &de) != DW_DLV_ERROR) {
162 tet_infoline("dwarf_get_fde_info_for_reg3 didn't return"
163 " DW_DLV_ERROR when called with invalid table_column"
164 " value");
165 result = TET_FAIL;
166 return;
167 }
168
169 cnt = 0;
170 pc_end = pc + func_len;
171 while (pc < pc_end && cnt < 16) {
172 tet_printf("query CFA(3) register pc %#jx\n", (uintmax_t) pc);
173 if (dwarf_get_fde_info_for_cfa_reg3(fde, pc, &value_type,
174 &offset_relevant, ®ister_num, &offset_or_block_len,
175 &block_ptr, &row_pc, &de) != DW_DLV_OK) {
176 tet_printf("dwarf_get_fde_info_for_reg3(cfa) failed: %s",
177 dwarf_errmsg(de));
178 result = TET_FAIL;
179 return;
180 }
181 TS_CHECK_INT(value_type);
182 TS_CHECK_INT(offset_relevant);
183 TS_CHECK_INT(offset_or_block_len);
184 TS_CHECK_INT(register_num);
185 TS_CHECK_UINT(row_pc);
186 if (value_type == DW_EXPR_EXPRESSION ||
187 value_type == DW_EXPR_VAL_EXPRESSION)
188 TS_CHECK_BLOCK(block_ptr, offset_or_block_len);
189 for (i = 1; i < _MAX_REG_NUM; i++) {
190 tet_printf("query register(3) %d\n", i);
191 if (dwarf_get_fde_info_for_reg3(fde, i, pc, &value_type,
192 &offset_relevant, ®ister_num,
193 &offset_or_block_len, &block_ptr,
194 &row_pc, &de) != DW_DLV_OK) {
195 tet_printf("dwarf_get_fde_info_for_reg3(%d)"
196 " failed: %s", i, dwarf_errmsg(de));
197 result = TET_FAIL;
198 goto next;
199 }
200 TS_CHECK_INT(value_type);
201 TS_CHECK_INT(offset_relevant);
202 TS_CHECK_INT(offset_or_block_len);
203 TS_CHECK_INT(register_num);
204 TS_CHECK_UINT(row_pc);
205 if (value_type == DW_EXPR_EXPRESSION ||
206 value_type == DW_EXPR_VAL_EXPRESSION)
207 TS_CHECK_BLOCK(block_ptr, offset_or_block_len);
208 }
209 tet_infoline("query all register(3)");
210 if (dwarf_get_fde_info_for_all_regs3(fde, pc, ®_table3,
211 &row_pc, &de) != DW_DLV_OK) {
212 tet_printf("dwarf_get_fde_info_for_all_regs failed: %s",
213 dwarf_errmsg(de));
214 result = TET_FAIL;
215 goto next;
216 }
217 TS_CHECK_UINT(row_pc);
218
219 #define CFA3 reg_table3.rt3_cfa_rule
220 #define RT3 reg_table3.rt3_rules
221 TS_CHECK_UINT(CFA3.dw_offset_relevant);
222 TS_CHECK_UINT(CFA3.dw_value_type);
223 TS_CHECK_UINT(CFA3.dw_regnum);
224 TS_CHECK_UINT(CFA3.dw_offset_or_block_len);
225 if (CFA3.dw_value_type == DW_EXPR_EXPRESSION ||
226 CFA3.dw_value_type == DW_EXPR_VAL_EXPRESSION)
227 TS_CHECK_BLOCK(CFA3.dw_block_ptr,
228 CFA3.dw_offset_or_block_len);
229 for (i = 0; i < _MAX_REG_NUM; i++) {
230 tet_printf("check reg_table3[%d]\n", i);
231 TS_CHECK_UINT(RT3[i].dw_offset_relevant);
232 TS_CHECK_UINT(RT3[i].dw_value_type);
233 TS_CHECK_UINT(RT3[i].dw_regnum);
234 TS_CHECK_UINT(RT3[i].dw_offset_or_block_len);
235 if (RT3[i].dw_value_type == DW_EXPR_EXPRESSION ||
236 RT3[i].dw_value_type == DW_EXPR_VAL_EXPRESSION)
237 TS_CHECK_BLOCK(RT3[i].dw_block_ptr,
238 RT3[i].dw_offset_or_block_len);
239 }
240 #undef CFA3
241 #undef RT3
242
243 next:
244 pc += caf;
245 cnt++;
246 }
247 }
248
249 static void
_dwarf_cie_fde_test(Dwarf_Debug dbg,int eh,void (* _frame_test)(Dwarf_Debug,Dwarf_Fde,Dwarf_Addr,Dwarf_Unsigned,Dwarf_Unsigned))250 _dwarf_cie_fde_test(Dwarf_Debug dbg, int eh, void (*_frame_test)(Dwarf_Debug,
251 Dwarf_Fde, Dwarf_Addr, Dwarf_Unsigned, Dwarf_Unsigned))
252 {
253 Dwarf_Cie *cielist, cie;
254 Dwarf_Fde *fdelist, fde;
255 Dwarf_Frame_Op *oplist;
256 Dwarf_Signed ciecnt, fdecnt;
257 Dwarf_Addr low_pc, high_pc;
258 Dwarf_Unsigned func_len, fde_byte_len, fde_inst_len, bytes_in_cie;
259 Dwarf_Unsigned cie_caf, cie_daf, cie_inst_len;
260 Dwarf_Signed cie_index, opcnt;
261 Dwarf_Off cie_offset, fde_offset;
262 Dwarf_Ptr fde_bytes, fde_inst, cie_initinst;
263 Dwarf_Half cie_ra;
264 Dwarf_Small cie_version;
265 Dwarf_Error de;
266 const char *cfa_str;
267 char *cie_augmenter;
268 int i, j, r_fde_at_pc;
269
270 if (eh) {
271 if (dwarf_get_fde_list_eh(dbg, &cielist, &ciecnt, &fdelist,
272 &fdecnt, &de) != DW_DLV_OK) {
273 tet_printf("dwarf_get_fde_list_eh failed: %s\n",
274 dwarf_errmsg(de));
275 result = TET_FAIL;
276 goto done;
277 }
278 } else {
279 if (dwarf_get_fde_list(dbg, &cielist, &ciecnt, &fdelist,
280 &fdecnt, &de) != DW_DLV_OK) {
281 tet_printf("dwarf_get_fde_list failed: %s\n",
282 dwarf_errmsg(de));
283 result = TET_FAIL;
284 goto done;
285 }
286 }
287 TS_CHECK_INT(ciecnt);
288 TS_CHECK_INT(fdecnt);
289
290 /*
291 * Test dwarf_get_fde_at_pc using hard-coded PC values.
292 */
293
294 tet_infoline("attempt to get fde at 0x08082a30");
295 r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x08082a30, &fde, &low_pc,
296 &high_pc, &de);
297 TS_CHECK_INT(r_fde_at_pc);
298 if (r_fde_at_pc == DW_DLV_OK) {
299 TS_CHECK_UINT(low_pc);
300 TS_CHECK_UINT(high_pc);
301 }
302
303 tet_infoline("attempt to get fde at 0x08083087");
304 r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x08083087, &fde, &low_pc,
305 &high_pc, &de);
306 TS_CHECK_INT(r_fde_at_pc);
307 if (r_fde_at_pc == DW_DLV_OK) {
308 TS_CHECK_UINT(low_pc);
309 TS_CHECK_UINT(high_pc);
310 }
311
312 tet_infoline("attempt to get fde at 0x080481f0");
313 r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x080481f0, &fde, &low_pc,
314 &high_pc, &de);
315 TS_CHECK_INT(r_fde_at_pc);
316 if (r_fde_at_pc == DW_DLV_OK) {
317 TS_CHECK_UINT(low_pc);
318 TS_CHECK_UINT(high_pc);
319 }
320
321 tet_infoline("attempt to get fde at 0x08048564");
322 r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x08048564, &fde, &low_pc,
323 &high_pc, &de);
324 TS_CHECK_INT(r_fde_at_pc);
325 if (r_fde_at_pc == DW_DLV_OK) {
326 TS_CHECK_UINT(low_pc);
327 TS_CHECK_UINT(high_pc);
328 }
329
330 tet_infoline("attempt to get fde at 0x00401280");
331 r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x00401280, &fde, &low_pc,
332 &high_pc, &de);
333 TS_CHECK_INT(r_fde_at_pc);
334 if (r_fde_at_pc == DW_DLV_OK) {
335 TS_CHECK_UINT(low_pc);
336 TS_CHECK_UINT(high_pc);
337 }
338
339 tet_infoline("attempt to get fde at 0x004012b1");
340 r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x004012b1, &fde, &low_pc,
341 &high_pc, &de);
342 TS_CHECK_INT(r_fde_at_pc);
343 if (r_fde_at_pc == DW_DLV_OK) {
344 TS_CHECK_UINT(low_pc);
345 TS_CHECK_UINT(high_pc);
346 }
347
348 /*
349 * Test each FDE contained in the FDE list.
350 */
351
352 for (i = 0; i < fdecnt; i++) {
353 if (dwarf_get_fde_n(fdelist, i, &fde, &de) != DW_DLV_OK) {
354 tet_printf("dwarf_get_fde_n(%d) failed: %s\n", i,
355 dwarf_errmsg(de));
356 result = TET_FAIL;
357 continue;
358 }
359 if (dwarf_get_fde_range(fde, &low_pc, &func_len, &fde_bytes,
360 &fde_byte_len, &cie_offset, &cie_index, &fde_offset,
361 &de) == DW_DLV_ERROR) {
362 tet_printf("dwarf_get_fde_range(%d) failed: %s\n", i,
363 dwarf_errmsg(de));
364 result = TET_FAIL;
365 continue;
366 }
367 TS_CHECK_UINT(low_pc);
368 TS_CHECK_UINT(func_len);
369 TS_CHECK_UINT(fde_byte_len);
370 if (fde_byte_len > 0)
371 TS_CHECK_BLOCK(fde_bytes, fde_byte_len);
372 TS_CHECK_INT(cie_offset);
373 TS_CHECK_INT(cie_index);
374 TS_CHECK_INT(fde_offset);
375 if (dwarf_get_cie_of_fde(fde, &cie, &de) != DW_DLV_OK) {
376 tet_printf("dwarf_get_cie_of_fde(%d) failed: %s\n", i,
377 dwarf_errmsg(de));
378 result = TET_FAIL;
379 continue;
380 }
381 if (dwarf_get_cie_index(cie, &cie_index, &de) != DW_DLV_OK) {
382 tet_printf("dwarf_get_cie_index(%d) failed: %s\n", i,
383 dwarf_errmsg(de));
384 result = TET_FAIL;
385 continue;
386 }
387 TS_CHECK_INT(cie_index);
388 if (dwarf_get_cie_info(cie, &bytes_in_cie, &cie_version,
389 &cie_augmenter, &cie_caf, &cie_daf, &cie_ra, &cie_initinst,
390 &cie_inst_len, &de) != DW_DLV_OK) {
391 tet_printf("dwarf_get_cie_info(%d) failed: %s\n", i,
392 dwarf_errmsg(de));
393 result = TET_FAIL;
394 continue;
395 }
396 TS_CHECK_UINT(bytes_in_cie);
397 TS_CHECK_UINT(cie_version);
398 TS_CHECK_STRING(cie_augmenter);
399 TS_CHECK_UINT(cie_caf);
400 TS_CHECK_UINT(cie_daf);
401 TS_CHECK_UINT(cie_ra);
402 TS_CHECK_UINT(cie_inst_len);
403 if (cie_inst_len > 0)
404 TS_CHECK_BLOCK(cie_initinst, cie_inst_len);
405 if (dwarf_get_fde_instr_bytes(fde, &fde_inst, &fde_inst_len,
406 &de) != DW_DLV_OK) {
407 tet_printf("dwarf_get_fde_instr_bytes(%d) failed: %s\n",
408 i, dwarf_errmsg(de));
409 result = TET_FAIL;
410 continue;
411 }
412 TS_CHECK_UINT(fde_inst_len);
413 if (fde_inst_len > 0) {
414 TS_CHECK_BLOCK(fde_inst, fde_inst_len);
415 if (dwarf_expand_frame_instructions(cie, fde_inst,
416 fde_inst_len, &oplist, &opcnt, &de) != DW_DLV_OK) {
417 tet_printf("dwarf_expand_frame_instructions(%d)"
418 " failed: %s\n", i, dwarf_errmsg(de));
419 result = TET_FAIL;
420 continue;
421 }
422 TS_CHECK_INT(opcnt);
423 for (j = 0; j < opcnt; j++) {
424 TS_CHECK_UINT(oplist[j].fp_base_op);
425 if (oplist[j].fp_base_op != 0) {
426 if (dwarf_get_CFA_name(
427 oplist[j].fp_base_op << 6,
428 &cfa_str) != DW_DLV_OK) {
429 tet_printf("dwarf_get_CFA_name"
430 " failed\n");
431 continue;
432 }
433 TS_CHECK_STRING(cfa_str);
434 }
435 TS_CHECK_UINT(oplist[j].fp_extended_op);
436 if (oplist[j].fp_extended_op != 0) {
437 if (dwarf_get_CFA_name(
438 oplist[j].fp_extended_op,
439 &cfa_str) != DW_DLV_OK) {
440 tet_printf("dwarf_get_CFA_name"
441 " failed\n");
442 continue;
443 }
444 TS_CHECK_STRING(cfa_str);
445 }
446 TS_CHECK_UINT(oplist[j].fp_register);
447 TS_CHECK_INT(oplist[j].fp_offset);
448 TS_CHECK_INT(oplist[j].fp_instr_offset);
449 }
450 }
451 _frame_test(dbg, fde, low_pc, func_len, cie_caf);
452 }
453
454 done:
455 return;
456 }
457
458 static void
tp_dwarf_frame2(void)459 tp_dwarf_frame2(void)
460 {
461 Dwarf_Debug dbg;
462 Dwarf_Error de;
463 int fd;
464
465 result = TET_UNRESOLVED;
466
467 TS_DWARF_INIT(dbg, fd, de);
468
469 _dwarf_cie_fde_test(dbg, 0, _frame2_test);
470 _dwarf_cie_fde_test(dbg, 1, _frame2_test);
471
472 if (result == TET_UNRESOLVED)
473 result = TET_PASS;
474 done:
475 TS_DWARF_FINISH(dbg, de);
476 TS_RESULT(result);
477 }
478
479 static void
tp_dwarf_frame3(void)480 tp_dwarf_frame3(void)
481 {
482 Dwarf_Debug dbg;
483 Dwarf_Error de;
484 int fd;
485
486 result = TET_UNRESOLVED;
487
488 TS_DWARF_INIT(dbg, fd, de);
489
490 _dwarf_cie_fde_test(dbg, 0, _frame3_test);
491 _dwarf_cie_fde_test(dbg, 1, _frame3_test);
492
493 if (result == TET_UNRESOLVED)
494 result = TET_PASS;
495 done:
496 TS_DWARF_FINISH(dbg, de);
497 TS_RESULT(result);
498 }
499