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 	    &register_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, &register_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, &register_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, &reg_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, &register_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, &register_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, &register_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, &reg_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