/* Print a cie.  Gather the print logic here so the
   control logic deciding what to print
   is clearer.
*/
int
print_one_cie(Dwarf_Debug dbg, Dwarf_Cie cie,
	      Dwarf_Unsigned cie_index, Dwarf_Half address_size,
	      struct dwconf_s *config_data)
{

    int cires = 0;
    Dwarf_Unsigned cie_length = 0;
    Dwarf_Small version = 0;
    string augmenter = "";
    Dwarf_Unsigned code_alignment_factor = 0;
    Dwarf_Signed data_alignment_factor = 0;
    Dwarf_Half return_address_register_rule = 0;
    Dwarf_Ptr initial_instructions = 0;
    Dwarf_Unsigned initial_instructions_length = 0;
    Dwarf_Off cie_off = 0;
    Dwarf_Error err = 0;

    cires = dwarf_get_cie_info(cie,
			       &cie_length,
			       &version,
			       &augmenter,
			       &code_alignment_factor,
			       &data_alignment_factor,
			       &return_address_register_rule,
			       &initial_instructions,
			       &initial_instructions_length, &err);
    if (cires == DW_DLV_ERROR) {
	print_error(dbg, "dwarf_get_cie_info", cires, err);
    }
    if (cires == DW_DLV_NO_ENTRY) {
	;			/* ? */
	printf("Impossible DW_DLV_NO_ENTRY on cie %d\n",
	       (int) cie_index);
	return DW_DLV_NO_ENTRY;
    }
    {
	printf("<%3lld>\tversion\t\t\t\t%d\n", cie_index, version);
	cires = dwarf_cie_section_offset(dbg, cie, &cie_off, &err);
	if (cires == DW_DLV_OK) {
	    printf("\tcie sec. offset %llu 0x%llx\n",
		   (unsigned long long) cie_off,
		   (unsigned long long) cie_off);

	}

	printf("\taugmentation\t\t\t%s\n", augmenter);
	printf("\tcode_alignment_factor\t\t%llu\n",
	       (unsigned long long) code_alignment_factor);
	printf("\tdata_alignment_factor\t\t%lld\n",
	       (long long) data_alignment_factor);
	printf("\treturn_address_register\t\t%d\n",
	       (int) return_address_register_rule);
	{
	    int ares = 0;
	    Dwarf_Small *data = 0;
	    Dwarf_Unsigned len = 0;

	    ares =
		dwarf_get_cie_augmentation_data(cie, &data, &len, &err);
	    if (ares == DW_DLV_NO_ENTRY) {
		/* do nothing. */
	    } else if (ares == DW_DLV_OK && len > 0) {
		int k2;

		printf("\teh aug data len 0x%llx", (long long) len);
		for (k2 = 0; data && k2 < len; ++k2) {
		    if (k2 == 0) {
			printf(" bytes 0x");
		    }
		    printf("%02x ", (unsigned char) data[k2]);
		}
		printf("\n");
	    }			/* else DW_DLV_ERROR or no data, do
				   nothing */
	}

	printf
	    ("\tbytes of initial instructions:\t%lld\n",
	     (long long) initial_instructions_length);
	printf("\tcie length :\t\t\t%lld\n", (long long) cie_length);
	print_frame_inst_bytes(dbg, initial_instructions, (Dwarf_Signed)
			       initial_instructions_length,
			       data_alignment_factor,
			       (int) code_alignment_factor,
			       address_size, config_data);
    }
    return DW_DLV_OK;
}
/*
    Gather the fde print logic here so the control logic
    determining what FDE to print is clearer.
*/
int
print_one_fde(Dwarf_Debug dbg, Dwarf_Fde fde,
	      Dwarf_Unsigned fde_index,
	      Dwarf_Cie * cie_data,
	      Dwarf_Signed cie_element_count,
	      Dwarf_Half address_size, int is_eh,
	      struct dwconf_s *config_data)
{
    Dwarf_Addr j = 0;
    Dwarf_Addr low_pc = 0;
    Dwarf_Unsigned func_length = 0;
    Dwarf_Ptr fde_bytes = NULL;
    Dwarf_Unsigned fde_bytes_length = 0;
    Dwarf_Off cie_offset = 0;
    Dwarf_Signed cie_index = 0;
    Dwarf_Off fde_offset = 0;
    Dwarf_Signed eh_table_offset = 0;
    int fres = 0;
    int offres = 0;
    string temps = 0;
    Dwarf_Error err = 0;
    int printed_intro_addr = 0;

    fres = dwarf_get_fde_range(fde,
			       &low_pc, &func_length,
			       &fde_bytes,
			       &fde_bytes_length,
			       &cie_offset, &cie_index,
			       &fde_offset, &err);
    if (fres == DW_DLV_ERROR) {
	print_error(dbg, "dwarf_get_fde_range", fres, err);
    }
    if (fres == DW_DLV_NO_ENTRY) {
	return DW_DLV_NO_ENTRY;
    }
    if (cu_name_flag &&
	fde_offset_for_cu_low != DW_DLV_BADOFFSET &&
	(fde_offset < fde_offset_for_cu_low ||
	 fde_offset > fde_offset_for_cu_high)) {
	return DW_DLV_NO_ENTRY;
    }
    /* eh_table_offset is IRIX ONLY. */
    fres = dwarf_get_fde_exception_info(fde, &eh_table_offset, &err);
    if (fres == DW_DLV_ERROR) {
	print_error(dbg, "dwarf_get_fde_exception_info", fres, err);
    }
    temps = get_fde_proc_name(dbg, low_pc);
    printf
	("<%3lld><%#llx:%#llx><%s><fde offset 0x%llx length: 0x%llx>",
	 cie_index, low_pc, (low_pc + func_length),
	 temps ? temps : "", fde_offset, fde_bytes_length);


    if (!is_eh) {
	/* IRIX uses eh_table_offset. */
	if (eh_table_offset == DW_DLX_NO_EH_OFFSET) {
	    printf("<eh offset %s>\n", "none");
	} else if (eh_table_offset == DW_DLX_EH_OFFSET_UNAVAILABLE) {
	    printf("<eh offset %s>\n", "unknown");
	} else {
	    printf("<eh offset 0x%llx>\n", eh_table_offset);
	}
    } else {
	int ares = 0;
	Dwarf_Small *data = 0;
	Dwarf_Unsigned len = 0;

	ares = dwarf_get_fde_augmentation_data(fde, &data, &len, &err);
	if (ares == DW_DLV_NO_ENTRY) {
	    /* do nothing. */
	} else if (ares == DW_DLV_OK) {
	    int k2;

	    printf("<eh aug data len 0x%llx", (long long) len);
	    for (k2 = 0; k2 < len; ++k2) {
		if (k2 == 0) {
		    printf(" bytes 0x");
		}
		printf("%02x ", (unsigned char) data[k2]);
	    }
	    printf(">");
	}			/* else DW_DLV_ERROR, do nothing */
        printf("\n");
    }
    /* call dwarf_get_fde_info_for_reg() to get whole matrix */

    for (j = low_pc; j < low_pc + func_length; j++) {
	Dwarf_Half k;

	if (config_data->cf_interface_number == 3) {
	    Dwarf_Signed reg = 0;
	    Dwarf_Signed offset_relevant = 0;
	    Dwarf_Small value_type = 0;
	    Dwarf_Signed offset_or_block_len = 0;
	    Dwarf_Signed offset = 0;
	    Dwarf_Ptr block_ptr = 0;
	    Dwarf_Addr row_pc = 0;

	    int fires = dwarf_get_fde_info_for_cfa_reg3(fde,
							j,
							&value_type,
							&offset_relevant,
							&reg,
							&offset_or_block_len,
							&block_ptr,
							&row_pc,
							&err);

	    offset = offset_or_block_len;
	    if (fires == DW_DLV_ERROR) {
		print_error(dbg,
			    "dwarf_get_fde_info_for_reg", fires, err);
	    }
	    if (fires == DW_DLV_NO_ENTRY) {
		continue;
	    }
	    if (row_pc != j) {
		/* duplicate row */
		continue;
	    }
	    if (!printed_intro_addr) {
		printf("    %08llx:\t", j);
		printed_intro_addr = 1;
	    }
	    print_one_frame_reg_col(dbg, config_data->cf_cfa_reg,
				    value_type,
				    reg,
				    config_data,
				    offset_relevant, offset, block_ptr);
	}
	for (k = 0; k < config_data->cf_table_entry_count; k++) {
	    Dwarf_Signed reg = 0;
	    Dwarf_Signed offset_relevant = 0;
	    int fires = 0;
	    Dwarf_Small value_type = 0;
	    Dwarf_Ptr block_ptr = 0;
	    Dwarf_Signed offset_or_block_len = 0;
	    Dwarf_Signed offset = 0;
	    Dwarf_Addr row_pc = 0;

	    if (config_data->cf_interface_number == 3) {

		fires = dwarf_get_fde_info_for_reg3(fde,
						    k,
						    j,
						    &value_type,
						    &offset_relevant,
						    &reg,
						    &offset_or_block_len,
						    &block_ptr,
						    &row_pc, &err);
		offset = offset_or_block_len;
	    } else {		/* ASSERT:
				   config_data->cf_interface_number ==
				   2 */


		value_type = DW_EXPR_OFFSET;
		fires = dwarf_get_fde_info_for_reg(fde,
						   k,
						   j,
						   &offset_relevant,
						   &reg,
						   &offset, &row_pc,
						   &err);
	    }
	    if (fires == DW_DLV_ERROR) {
                printf("\n");
		print_error(dbg,
			    "dwarf_get_fde_info_for_reg", fires, err);
	    }
	    if (fires == DW_DLV_NO_ENTRY) {
		continue;
	    }
	    if (row_pc != j) {
		/* duplicate row */
		break;
	    }
	    if (!printed_intro_addr) {
		printf("    %08llx:\t", j);
		printed_intro_addr = 1;
	    }
	    print_one_frame_reg_col(dbg,k,
				    value_type,
				    reg,
				    config_data,
				    offset_relevant, offset, block_ptr);

	}
	if (printed_intro_addr) {
	    printf("\n");
	    printed_intro_addr = 0;
	}
    }
    if (verbose > 1) {
	Dwarf_Off fde_off;
	Dwarf_Off cie_off;

	/* get the fde instructions and print them in raw form, just
	   like cie instructions */
	Dwarf_Ptr instrs;
	Dwarf_Unsigned ilen;
	int res;

	res = dwarf_get_fde_instr_bytes(fde, &instrs, &ilen, &err);
	offres =
	    dwarf_fde_section_offset(dbg, fde, &fde_off, &cie_off,
				      &err);
	if (offres == DW_DLV_OK) {
	    printf("\tfde sec. offset %llu 0x%llx"
		   " cie offset for fde: %llu 0x%llx\n",
		   (unsigned long long) fde_off,
		   (unsigned long long) fde_off,
		   (unsigned long long) cie_off,
		   (unsigned long long) cie_off);

	}


	if (res == DW_DLV_OK) {
	    int cires = 0;
	    Dwarf_Unsigned cie_length = 0;
	    Dwarf_Small version = 0;
	    string augmenter;
	    Dwarf_Unsigned code_alignment_factor = 0;
	    Dwarf_Signed data_alignment_factor = 0;
	    Dwarf_Half return_address_register_rule = 0;
	    Dwarf_Ptr initial_instructions = 0;
	    Dwarf_Unsigned initial_instructions_length = 0;

	    if (cie_index >= cie_element_count) {
		printf("Bad cie index %lld with fde index %lld! "
		       "(table entry max %lld)\n",
		       (long long) cie_index, (long long) fde_index,
		       (long long) cie_element_count);
		exit(1);
	    }

	    cires = dwarf_get_cie_info(cie_data[cie_index],
				       &cie_length,
				       &version,
				       &augmenter,
				       &code_alignment_factor,
				       &data_alignment_factor,
				       &return_address_register_rule,
				       &initial_instructions,
				       &initial_instructions_length,
				       &err);
	    if (cires == DW_DLV_ERROR) {
		printf
		    ("Bad cie index %lld with fde index %lld!\n",
		     (long long) cie_index, (long long) fde_index);
		print_error(dbg, "dwarf_get_cie_info", cires, err);
	    }
	    if (cires == DW_DLV_NO_ENTRY) {
		;		/* ? */
	    } else {

		print_frame_inst_bytes(dbg, instrs,
				       (Dwarf_Signed) ilen,
				       data_alignment_factor,
				       (int) code_alignment_factor,
				       address_size, config_data);
	    }
	} else if (res == DW_DLV_NO_ENTRY) {
	    printf
		("Impossible: no instr bytes for fde index %d?\n",
		 (int) fde_index);
	} else {
	    /* DW_DLV_ERROR */
	    printf
		("Error: on gettinginstr bytes for fde index %d?\n",
		 (int) fde_index);
	    print_error(dbg, "dwarf_get_fde_instr_bytes", res, err);
	}

    }
    return DW_DLV_OK;
}
Beispiel #3
0
static void
_dwarf_cie_fde_test(Dwarf_Debug dbg, int eh, void (*_frame_test)(Dwarf_Debug,
    Dwarf_Fde, Dwarf_Addr, Dwarf_Unsigned, Dwarf_Unsigned))
{
	Dwarf_Cie *cielist, cie;
	Dwarf_Fde *fdelist, fde;
	Dwarf_Frame_Op *oplist;
	Dwarf_Signed ciecnt, fdecnt;
	Dwarf_Addr low_pc, high_pc;
	Dwarf_Unsigned func_len, fde_byte_len, fde_inst_len, bytes_in_cie;
	Dwarf_Unsigned cie_caf, cie_daf, cie_inst_len;
	Dwarf_Signed cie_index, opcnt;
	Dwarf_Off cie_offset, fde_offset;
	Dwarf_Ptr fde_bytes, fde_inst, cie_initinst;
	Dwarf_Half cie_ra;
	Dwarf_Small cie_version;
	Dwarf_Error de;
	const char *cfa_str;
	char *cie_augmenter;
	int i, j, r_fde_at_pc;

	if (eh) {
		if (dwarf_get_fde_list_eh(dbg, &cielist, &ciecnt, &fdelist,
		    &fdecnt, &de) != DW_DLV_OK) {
			tet_printf("dwarf_get_fde_list_eh failed: %s\n",
			    dwarf_errmsg(de));
			result = TET_FAIL;
			goto done;
		}
	} else {
		if (dwarf_get_fde_list(dbg, &cielist, &ciecnt, &fdelist,
		    &fdecnt, &de) != DW_DLV_OK) {
			tet_printf("dwarf_get_fde_list failed: %s\n",
			    dwarf_errmsg(de));
			result = TET_FAIL;
			goto done;
		}
	}
	TS_CHECK_INT(ciecnt);
	TS_CHECK_INT(fdecnt);

	/*
	 * Test dwarf_get_fde_at_pc using hard-coded PC values.
	 */

	tet_infoline("attempt to get fde at 0x08082a30");
	r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x08082a30, &fde, &low_pc,
	    &high_pc, &de);
	TS_CHECK_INT(r_fde_at_pc);
	if (r_fde_at_pc == DW_DLV_OK) {
		TS_CHECK_UINT(low_pc);
		TS_CHECK_UINT(high_pc);
	}

	tet_infoline("attempt to get fde at 0x08083087");
	r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x08083087, &fde, &low_pc,
	    &high_pc, &de);
	TS_CHECK_INT(r_fde_at_pc);
	if (r_fde_at_pc == DW_DLV_OK) {
		TS_CHECK_UINT(low_pc);
		TS_CHECK_UINT(high_pc);
	}

	tet_infoline("attempt to get fde at 0x080481f0");
	r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x080481f0, &fde, &low_pc,
	    &high_pc, &de);
	TS_CHECK_INT(r_fde_at_pc);
	if (r_fde_at_pc == DW_DLV_OK) {
		TS_CHECK_UINT(low_pc);
		TS_CHECK_UINT(high_pc);
	}

	tet_infoline("attempt to get fde at 0x08048564");
	r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x08048564, &fde, &low_pc,
	    &high_pc, &de);
	TS_CHECK_INT(r_fde_at_pc);
	if (r_fde_at_pc == DW_DLV_OK) {
		TS_CHECK_UINT(low_pc);
		TS_CHECK_UINT(high_pc);
	}

	tet_infoline("attempt to get fde at 0x00401280");
	r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x00401280, &fde, &low_pc,
	    &high_pc, &de);
	TS_CHECK_INT(r_fde_at_pc);
	if (r_fde_at_pc == DW_DLV_OK) {
		TS_CHECK_UINT(low_pc);
		TS_CHECK_UINT(high_pc);
	}

	tet_infoline("attempt to get fde at 0x004012b1");
	r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x004012b1, &fde, &low_pc,
	    &high_pc, &de);
	TS_CHECK_INT(r_fde_at_pc);
	if (r_fde_at_pc == DW_DLV_OK) {
		TS_CHECK_UINT(low_pc);
		TS_CHECK_UINT(high_pc);
	}

	/*
	 * Test each FDE contained in the FDE list.
	 */

	for (i = 0; i < fdecnt; i++) {
		if (dwarf_get_fde_n(fdelist, i, &fde, &de) != DW_DLV_OK) {
			tet_printf("dwarf_get_fde_n(%d) failed: %s\n", i,
			    dwarf_errmsg(de));
			result = TET_FAIL;
			continue;
		}
		if (dwarf_get_fde_range(fde, &low_pc, &func_len, &fde_bytes,
		    &fde_byte_len, &cie_offset, &cie_index, &fde_offset,
		    &de) == DW_DLV_ERROR) {
			tet_printf("dwarf_get_fde_range(%d) failed: %s\n", i,
			    dwarf_errmsg(de));
			result = TET_FAIL;
			continue;
		}
		TS_CHECK_UINT(low_pc);
		TS_CHECK_UINT(func_len);
		TS_CHECK_UINT(fde_byte_len);
		if (fde_byte_len > 0)
			TS_CHECK_BLOCK(fde_bytes, fde_byte_len);
		TS_CHECK_INT(cie_offset);
		TS_CHECK_INT(cie_index);
		TS_CHECK_INT(fde_offset);
		if (dwarf_get_cie_of_fde(fde, &cie, &de) != DW_DLV_OK) {
			tet_printf("dwarf_get_cie_of_fde(%d) failed: %s\n", i,
			    dwarf_errmsg(de));
			result = TET_FAIL;
			continue;
		}
		if (dwarf_get_cie_index(cie, &cie_index, &de) != DW_DLV_OK) {
			tet_printf("dwarf_get_cie_index(%d) failed: %s\n", i,
			    dwarf_errmsg(de));
			result = TET_FAIL;
			continue;
		}
		TS_CHECK_INT(cie_index);
		if (dwarf_get_cie_info(cie, &bytes_in_cie, &cie_version,
		    &cie_augmenter, &cie_caf, &cie_daf, &cie_ra, &cie_initinst,
		    &cie_inst_len, &de) != DW_DLV_OK) {
			tet_printf("dwarf_get_cie_info(%d) failed: %s\n", i,
			    dwarf_errmsg(de));
			result = TET_FAIL;
			continue;
		}
		TS_CHECK_UINT(bytes_in_cie);
		TS_CHECK_UINT(cie_version);
		TS_CHECK_STRING(cie_augmenter);
		TS_CHECK_UINT(cie_caf);
		TS_CHECK_UINT(cie_daf);
		TS_CHECK_UINT(cie_ra);
		TS_CHECK_UINT(cie_inst_len);
		if (cie_inst_len > 0)
			TS_CHECK_BLOCK(cie_initinst, cie_inst_len);
		if (dwarf_get_fde_instr_bytes(fde, &fde_inst, &fde_inst_len,
		    &de) != DW_DLV_OK) {
			tet_printf("dwarf_get_fde_instr_bytes(%d) failed: %s\n",
			    i, dwarf_errmsg(de));
			result = TET_FAIL;
			continue;
		}
		TS_CHECK_UINT(fde_inst_len);
		if (fde_inst_len > 0) {
			TS_CHECK_BLOCK(fde_inst, fde_inst_len);
			if (dwarf_expand_frame_instructions(cie, fde_inst,
			    fde_inst_len, &oplist, &opcnt, &de) != DW_DLV_OK) {
				tet_printf("dwarf_expand_frame_instructions(%d)"
				    " failed: %s\n", i, dwarf_errmsg(de));
				result = TET_FAIL;
				continue;
			}
			TS_CHECK_INT(opcnt);
			for (j = 0; j < opcnt; j++) {
				TS_CHECK_UINT(oplist[j].fp_base_op);
				if (oplist[j].fp_base_op != 0) {
					if (dwarf_get_CFA_name(
					    oplist[j].fp_base_op << 6,
					    &cfa_str) != DW_DLV_OK) {
						tet_printf("dwarf_get_CFA_name"
						    " failed\n");
						continue;
					}
					TS_CHECK_STRING(cfa_str);
				}
				TS_CHECK_UINT(oplist[j].fp_extended_op);
				if (oplist[j].fp_extended_op != 0) {
					if (dwarf_get_CFA_name(
					    oplist[j].fp_extended_op,
					    &cfa_str) != DW_DLV_OK) {
						tet_printf("dwarf_get_CFA_name"
						    " failed\n");
						continue;
					}
					TS_CHECK_STRING(cfa_str);
				}
				TS_CHECK_UINT(oplist[j].fp_register);
				TS_CHECK_INT(oplist[j].fp_offset);
				TS_CHECK_INT(oplist[j].fp_instr_offset);
			}
		}
		_frame_test(dbg, fde, low_pc, func_len, cie_caf);
	}

done:
	return;
}