diff options
Diffstat (limited to 'dwarfdump/print_frames.c')
-rw-r--r-- | dwarfdump/print_frames.c | 1823 |
1 files changed, 1823 insertions, 0 deletions
diff --git a/dwarfdump/print_frames.c b/dwarfdump/print_frames.c new file mode 100644 index 0000000..01e4130 --- /dev/null +++ b/dwarfdump/print_frames.c @@ -0,0 +1,1823 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2011 SN Systems Ltd. All Rights Reserved. + Portions Copyright (C) 2007-2011 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street - Fifth Floor, Boston MA 02110-1301, USA. + + Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane, + Mountain View, CA 94043, or: + + http://www.sgi.com + + For further information regarding this notice, see: + + http://oss.sgi.com/projects/GenInfo/NoticeExplan + + + + $Header: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/dwarfdump/RCS/print_frames.c,v 1.5 2006/06/14 20:34:02 davea Exp $ */ + +/* The address of the Free Software Foundation is + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. + SGI has moved from the Crittenden Lane address. +*/ + +/* From 199x through 2010 print_frames relied on + the order of the fdes matching the order of the functions + in the CUs when it came to printing a function name with + an FDE. This sometimes worked for SGI/IRIX because of + the way the compiler often emitted things. It always worked poorly + for gcc and other compilers. + + As of 2010 the addrmap.h addrmap.h code provides help + in doing a better job when the tsearch functions (part of + POSIX) are available. */ + +#include "globals.h" + +#include "print_frames.h" +#include "dwconf.h" +#include "esb.h" +#include "addrmap.h" + +static void +print_one_frame_reg_col(Dwarf_Debug dbg, + Dwarf_Unsigned rule_id, + Dwarf_Small value_type, + Dwarf_Unsigned reg_used, + Dwarf_Half addr_size, + struct dwconf_s *config_data, + Dwarf_Signed offset_relevant, + Dwarf_Signed offset, Dwarf_Ptr block_ptr); + +/* A strcpy which ensures NUL terminated string + and never overruns the output. +*/ +void +safe_strcpy(char *out, long outlen, const char *in, long inlen) +{ + if (inlen >= (outlen - 1)) { + strncpy(out, in, outlen - 1); + out[outlen - 1] = 0; + } else { + strcpy(out, in); + } +} + +/* For inlined functions, try to find name */ +static int +get_abstract_origin_funcname(Dwarf_Debug dbg,Dwarf_Attribute attr, + char *name_out, unsigned maxlen) +{ + Dwarf_Off off = 0; + Dwarf_Die origin_die = 0; + Dwarf_Attribute *atlist = NULL; + Dwarf_Signed atcnt = 0; + Dwarf_Signed i = 0; + int dres = 0; + int atres; + int name_found = 0; + int res = dwarf_global_formref(attr,&off,&err); + if(res != DW_DLV_OK) { + return DW_DLV_NO_ENTRY; + } + dres = dwarf_offdie(dbg,off,&origin_die,&err); + if(dres != DW_DLV_OK) { + return DW_DLV_NO_ENTRY; + } + atres = dwarf_attrlist(origin_die, &atlist, &atcnt, &err); + if (atres != DW_DLV_OK) { + dwarf_dealloc(dbg,origin_die,DW_DLA_DIE); + return DW_DLV_NO_ENTRY; + } + for (i = 0; i < atcnt; i++) { + Dwarf_Half lattr; + int ares; + ares = dwarf_whatattr(atlist[i], &lattr, &err); + if (ares == DW_DLV_ERROR) { + break; + } else if (ares == DW_DLV_OK) { + if(lattr == DW_AT_name) { + int sres = 0; + char* temps = 0; + sres = dwarf_formstring(atlist[i], &temps, &err); + if (sres == DW_DLV_OK) { + long len = (long) strlen(temps); + safe_strcpy(name_out, maxlen, temps, len); + name_found = 1; + break; + } + } + } + } + for (i = 0; i < atcnt; i++) { + dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR); + } + dwarf_dealloc(dbg, atlist, DW_DLA_LIST); + dwarf_dealloc(dbg,origin_die,DW_DLA_DIE); + if(!name_found) { + return DW_DLV_NO_ENTRY; + } + return DW_DLV_OK; +} +/* + Returns 1 if a proc with this low_pc found. + Else returns 0. + + From print_die.c this has no pcMap passed in, + we do not really have a sensible context, so this + really just looks at the current attributes for a name. +*/ +int +get_proc_name(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr low_pc, + char *proc_name_buf, int proc_name_buf_len, void **pcMap) +{ + Dwarf_Signed atcnt = 0; + Dwarf_Signed i = 0; + Dwarf_Attribute *atlist = NULL; + Dwarf_Addr low_pc_die = 0; + int atres = 0; + int funcres = 1; + int funcpcfound = 0; + int funcnamefound = 0; + + proc_name_buf[0] = 0; /* always set to something */ + if(pcMap) { + struct Addr_Map_Entry *ame = 0; + ame = addr_map_find(low_pc,pcMap); + if(ame && ame->mp_name) { + /* mp_name is NULL only if we ran out of heap space. */ + safe_strcpy(proc_name_buf, proc_name_buf_len, + ame->mp_name,(long) strlen(ame->mp_name)); + return 1; + } + } + + atres = dwarf_attrlist(die, &atlist, &atcnt, &err); + if (atres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_attrlist", atres, err); + return 0; + } + if (atres == DW_DLV_NO_ENTRY) { + return 0; + } + for (i = 0; i < atcnt; i++) { + Dwarf_Half attr = 0; + int ares = 0; + string temps = 0; + int sres = 0; + int dres = 0; + + if (funcnamefound == 1 && funcpcfound == 1) { + /* stop as soon as both found */ + break; + } + ares = dwarf_whatattr(atlist[i], &attr, &err); + if (ares == DW_DLV_ERROR) { + print_error(dbg, "get_proc_name whatattr error", ares, err); + } else if (ares == DW_DLV_OK) { + switch (attr) { + case DW_AT_specification: + case DW_AT_abstract_origin: + { + if(!funcnamefound) { + /* Only use this if we have not seen DW_AT_name + yet .*/ + int aores = get_abstract_origin_funcname(dbg, + atlist[i], proc_name_buf,proc_name_buf_len); + if(aores == DW_DLV_OK) { + /* FOUND THE NAME */ + funcnamefound = 1; + } + } + } + break; + case DW_AT_name: + /* Even if we saw DW_AT_abstract_origin, go ahead + and take DW_AT_name. */ + sres = dwarf_formstring(atlist[i], &temps, &err); + if (sres == DW_DLV_ERROR) { + print_error(dbg, + "formstring in get_proc_name failed", + sres, err); + /* 50 is safe wrong length since is bigger than the + actual string */ + safe_strcpy(proc_name_buf, proc_name_buf_len, + "ERROR in dwarf_formstring!", 50); + } else if (sres == DW_DLV_NO_ENTRY) { + /* 50 is safe wrong length since is bigger than the + actual string */ + safe_strcpy(proc_name_buf, proc_name_buf_len, + "NO ENTRY on dwarf_formstring?!", 50); + } else { + long len = (long) strlen(temps); + + safe_strcpy(proc_name_buf, proc_name_buf_len, temps, + len); + } + funcnamefound = 1; /* FOUND THE NAME */ + break; + case DW_AT_low_pc: + dres = dwarf_formaddr(atlist[i], &low_pc_die, &err); + if (dres == DW_DLV_ERROR) { + print_error(dbg, "formaddr in get_proc_name failed", + dres, err); + low_pc_die = ~low_pc; + /* ensure no match */ + } + funcpcfound = 1; + + break; + default: + break; + } + } + } + for (i = 0; i < atcnt; i++) { + dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR); + } + dwarf_dealloc(dbg, atlist, DW_DLA_LIST); + if(funcnamefound && funcpcfound && pcMap ) { + /* Insert every name to map, not just the one + we are looking for. + This version does extra work in that + early symbols in a CU will be inserted + multiple times (the extra times have no + effect), the dwarfdump2 + version of this does less work. */ + addr_map_insert(low_pc_die,proc_name_buf,pcMap); + } + if (funcnamefound == 0 || funcpcfound == 0 || low_pc != low_pc_die) { + funcres = 0; + } + return (funcres); +} + +/* Modified Depth First Search looking for the procedure: + a) only looks for children of subprogram. + b) With subprogram looks at current die *before* looking + for a child. + + Needed since some languages, including SGI MP Fortran, + have nested functions. + Return 0 on failure, 1 on success. +*/ +static int +load_nested_proc_name(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr low_pc, + char *ret_name_buf, int ret_name_buf_len, + void **pcMap) +{ + char name_buf[BUFSIZ]; + Dwarf_Die curdie = die; + int die_locally_gotten = 0; + Dwarf_Die prev_child = 0; + Dwarf_Die newchild = 0; + Dwarf_Die newsibling = 0; + Dwarf_Half tag; + Dwarf_Error err = 0; + int chres = DW_DLV_OK; + + ret_name_buf[0] = 0; + name_buf[0] = 0; + while (chres == DW_DLV_OK) { + int tres; + + tres = dwarf_tag(curdie, &tag, &err); + newchild = 0; + err = 0; + if (tres == DW_DLV_OK) { + int lchres; + + if (tag == DW_TAG_subprogram) { + int proc_name_v = get_proc_name(dbg, curdie, low_pc, + name_buf, BUFSIZ,pcMap); + if (proc_name_v) { + safe_strcpy(ret_name_buf, ret_name_buf_len, + name_buf, (long) strlen(name_buf)); + if (die_locally_gotten) { + /* If we got this die from the parent, we do + not want to dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + return 1; + } + /* Check children of subprograms recursively should + this really be check children of anything, + or just children of subprograms? */ + + lchres = dwarf_child(curdie, &newchild, &err); + if (lchres == DW_DLV_OK) { + /* look for inner subprogram */ + int newprog = + load_nested_proc_name(dbg, newchild, low_pc, + name_buf, BUFSIZ, + pcMap); + + dwarf_dealloc(dbg, newchild, DW_DLA_DIE); + if (newprog) { + /* Found it. We could just take this name or + we could concatenate names together For now, + just take name */ + if (die_locally_gotten) { + /* If we got this die from the parent, we + do not want to dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + safe_strcpy(ret_name_buf, ret_name_buf_len, + name_buf, (long) strlen(name_buf)); + return 1; + } + } else if (lchres == DW_DLV_NO_ENTRY) { + /* nothing to do */ + } else { + print_error(dbg, + "load_nested_proc_name dwarf_child() failed ", + chres, err); + if (die_locally_gotten) { + /* If we got this die from the parent, we do + not want to dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + return 0; + } + } /* end if TAG_subprogram */ + } else { + print_error(dbg, "no tag on child read ", tres, err); + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want + to dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + return 0; + } + /* try next sibling */ + prev_child = curdie; + chres = dwarf_siblingof(dbg, curdie, &newsibling, &err); + if (chres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_cu_header On Child read ", chres, + err); + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want + to dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + return 0; + } else if (chres == DW_DLV_NO_ENTRY) { + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want + to dealloc here! */ + dwarf_dealloc(dbg, prev_child, DW_DLA_DIE); + } + return 0;/* proc name not at this level */ + } else { + /* DW_DLV_OK */ + curdie = newsibling; + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want + to dealloc here! */ + dwarf_dealloc(dbg, prev_child, DW_DLA_DIE); + } + prev_child = 0; + die_locally_gotten = 1; + } + + } + if (die_locally_gotten) { + /* If we got this die from the parent, we do not want to + dealloc here! */ + dwarf_dealloc(dbg, curdie, DW_DLA_DIE); + } + return 0; +} + +/* For SGI MP Fortran and other languages, functions + nest! As a result, we must dig thru all functions, + not just the top level. + This remembers the CU die and restarts each search at the start + of the current cu. +*/ +static string +get_fde_proc_name(Dwarf_Debug dbg, Dwarf_Addr low_pc, + void **pcMap, + int *all_cus_seen) +{ + static char proc_name[BUFSIZ]; + Dwarf_Unsigned cu_header_length = 0; + Dwarf_Unsigned abbrev_offset = 0; + Dwarf_Half version_stamp = 0; + Dwarf_Half address_size = 0; + Dwarf_Unsigned next_cu_offset = 0; + int cures = DW_DLV_OK; + int dres = DW_DLV_OK; + int chres = DW_DLV_OK; + int looping = 0; + + proc_name[0] = 0; + { + struct Addr_Map_Entry *ame = 0; + ame = addr_map_find(low_pc,pcMap); + if(ame && ame->mp_name) { + /* mp_name is only NULL here if we just ran out of heap memory! */ + safe_strcpy(proc_name, sizeof(proc_name), + ame->mp_name,(long) strlen(ame->mp_name)); + return proc_name; + } + if (*all_cus_seen) { + return ""; + } + } + if (current_cu_die_for_print_frames == NULL) { + /* Call depends on dbg->cu_context to know what to do. */ + cures = dwarf_next_cu_header(dbg, &cu_header_length, + &version_stamp, &abbrev_offset, + &address_size, &next_cu_offset, + &err); + if (cures == DW_DLV_ERROR) { + return NULL; + } else if (cures == DW_DLV_NO_ENTRY) { + /* loop thru the list again */ + current_cu_die_for_print_frames = 0; + ++looping; + } else { /* DW_DLV_OK */ + dres = dwarf_siblingof(dbg, NULL, + ¤t_cu_die_for_print_frames, + &err); + if (dres == DW_DLV_ERROR) { + return NULL; + } + } + } + if (dres == DW_DLV_OK) { + Dwarf_Die child = 0; + + if (current_cu_die_for_print_frames == 0) { + /* no information. Possibly a stripped file */ + return NULL; + } + chres = + dwarf_child(current_cu_die_for_print_frames, &child, &err); + if (chres == DW_DLV_ERROR) { + print_error(dbg, "dwarf_cu_header on child read ", chres, + err); + } else if (chres == DW_DLV_NO_ENTRY) { + } else { /* DW_DLV_OK */ + int gotname = + load_nested_proc_name(dbg, child, low_pc, proc_name, + BUFSIZ,pcMap); + + dwarf_dealloc(dbg, child, DW_DLA_DIE); + if (gotname) { + return (proc_name); + } + child = 0; + } + } + for (;;) { + Dwarf_Die ldie = 0; + + cures = dwarf_next_cu_header(dbg, &cu_header_length, + &version_stamp, &abbrev_offset, + &address_size, &next_cu_offset, + &err); + if (cures != DW_DLV_OK) { + *all_cus_seen = 1; + break; + } + + dres = dwarf_siblingof(dbg, NULL, &ldie, &err); + if (current_cu_die_for_print_frames) { + dwarf_dealloc(dbg, current_cu_die_for_print_frames, + DW_DLA_DIE); + } + current_cu_die_for_print_frames = 0; + if (dres == DW_DLV_ERROR) { + print_error(dbg, + "dwarf_cu_header Child Read finding proc name for .debug_frame", + chres, err); + continue; + } else if (dres == DW_DLV_NO_ENTRY) { + ++looping; + if (looping > 1) { + print_error(dbg, "looping on cu headers!", dres, err); + return NULL; + } + continue; + } + /* DW_DLV_OK */ + current_cu_die_for_print_frames = ldie; + { + int chres = 0; + Dwarf_Die child = 0; + + chres = + dwarf_child(current_cu_die_for_print_frames, &child, + &err); + if (chres == DW_DLV_ERROR) { + print_error(dbg, "dwarf Child Read ", chres, err); + } else if (chres == DW_DLV_NO_ENTRY) { + + ;/* do nothing, loop on cu */ + } else { + /* DW_DLV_OK) */ + + int gotname = + load_nested_proc_name(dbg, child, low_pc, proc_name, + BUFSIZ,pcMap); + + dwarf_dealloc(dbg, child, DW_DLA_DIE); + if (gotname) { + return (proc_name); + } + } + } + } + return (NULL); +} + +/* Gather the fde print logic here so the control logic + determining what FDE to print is clearer. */ +static 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, + void **pcMap, + void **lowpcSet, + int * all_cus_seen) +{ + 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); + } + if(suppress_nested_name_search) { + temps = 0; + } else { +#ifdef HAVE_TSEARCH + struct Addr_Map_Entry *mp = 0; + temps = get_fde_proc_name(dbg, low_pc,pcMap,all_cus_seen); + mp = addr_map_find(low_pc,lowpcSet); + if (check_frames || check_frames_extended) { + DWARF_CHECK_COUNT(fde_duplication,1); + } + if (mp) { + if (check_frames || check_frames_extended) { + char msg[400]; + if(temps && (strlen(temps) > 0)) { + snprintf(msg,sizeof(msg),"An fde low pc of 0x%" + DW_PR_DUx + " is not the first fde with that pc. " + "The first is named \"%s\"", + (Dwarf_Unsigned)low_pc, + temps); + } else { + snprintf(msg,sizeof(msg),"An fde low pc of 0x%" + DW_PR_DUx + " is not the first fde with that pc. " + "The first is not named.", + (Dwarf_Unsigned)low_pc); + + } + DWARF_CHECK_ERROR(fde_duplication,msg); + } + } else { + addr_map_insert(low_pc,0,lowpcSet); + } +#endif + } + + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("<%5" DW_PR_DSd "><0x%" DW_PR_XZEROS DW_PR_DUx + ":0x%" DW_PR_XZEROS DW_PR_DUx + "><%s><fde offset 0x%" DW_PR_XZEROS DW_PR_DUx + " length: 0x%" DW_PR_XZEROS DW_PR_DUx ">", + cie_index, (Dwarf_Unsigned)low_pc, + (Dwarf_Unsigned)(low_pc + func_length), + temps ? temps : "", (Dwarf_Unsigned)fde_offset, fde_bytes_length); + } + + + + if (!is_eh) { + /* IRIX uses eh_table_offset. */ + /* Do not print if in check mode */ + if (!check_frames_extended) { + 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%" DW_PR_XZEROS DW_PR_DUx + ">\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) { + /* Do not print if in check mode */ + if (!check_frames_extended) { + int k2 = 0; + + printf("<eh aug data len 0x%" DW_PR_DUx , 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 */ + + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("\n"); + + } + } + + for (j = low_pc; j < low_pc + func_length; j++) { + Dwarf_Half k = 0; + + 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, + ®, + &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; + } + + /* Do not print if in check mode */ + if (!printed_intro_addr && !check_frames_extended) { + printf(" 0x%" DW_PR_XZEROS DW_PR_DUx + ": ", (Dwarf_Unsigned)j); + printed_intro_addr = 1; + } + print_one_frame_reg_col(dbg, config_data->cf_cfa_reg, + value_type, + reg, + address_size, + 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, + ®, + &offset_or_block_len, + &block_ptr, + &row_pc, &err); + offset = offset_or_block_len; + } else { + /* This interface is deprecated. Is the old + MIPS/DWARF2 interface. */ + /* ASSERT: config_data->cf_interface_number == 2 */ + value_type = DW_EXPR_OFFSET; + fires = dwarf_get_fde_info_for_reg(fde, + k, + j, + &offset_relevant, + ®, + &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; + } + + /* Do not print if in check mode */ + if (!printed_intro_addr && !check_frames_extended) { + printf(" 0x%" DW_PR_XZEROS DW_PR_DUx ": ", + (Dwarf_Unsigned)j); + printed_intro_addr = 1; + } + print_one_frame_reg_col(dbg,k, + value_type, + reg, + address_size, + config_data, + offset_relevant, offset, block_ptr); + } + if (printed_intro_addr) { + printf("\n"); + printed_intro_addr = 0; + } + } + if (verbose > 1) { + Dwarf_Off fde_off = 0; + Dwarf_Off cie_off = 0; + + /* Get the fde instructions and print them in raw form, just + like cie instructions */ + Dwarf_Ptr instrs = 0; + Dwarf_Unsigned ilen = 0; + int res = 0; + + 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) { + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf(" fde section offset %" DW_PR_DUu + " 0x%" DW_PR_XZEROS DW_PR_DUx + " cie offset for fde: %" DW_PR_DUu + " 0x%" DW_PR_XZEROS DW_PR_DUx "\n", + (Dwarf_Unsigned) fde_off, + (Dwarf_Unsigned) fde_off, + (Dwarf_Unsigned) cie_off, + (Dwarf_Unsigned) cie_off); + } + } + + + if (res == DW_DLV_OK) { + int cires = 0; + Dwarf_Unsigned cie_length = 0; + Dwarf_Small version = 0; + string augmenter = 0; + 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 %" DW_PR_DSd + " with fde index %" DW_PR_DUu "! " + "(table entry max %" DW_PR_DSd ")\n", + cie_index, fde_index, + 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 %" DW_PR_DSd + " with fde index %" DW_PR_DUu "!\n", + cie_index, fde_index); + print_error(dbg, "dwarf_get_cie_info", cires, err); + } + if (cires == DW_DLV_NO_ENTRY) { + ; /* ? */ + } else { + /* Do not print if in check mode */ + if (!check_frames_extended) { + 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 %" + DW_PR_DUu "?\n", + fde_index); + } else { + /* DW_DLV_ERROR */ + printf("Error: on gettinginstr bytes for fde index %" + DW_PR_DUu "?\n", + fde_index); + print_error(dbg, "dwarf_get_fde_instr_bytes", res, err); + } + + } + return DW_DLV_OK; +} + + +/* 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 %" DW_PR_DUu "\n", + cie_index); + return DW_DLV_NO_ENTRY; + } + { + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("<%5" DW_PR_DUu ">\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 section offset\t\t%" DW_PR_DUu + " 0x%" DW_PR_XZEROS DW_PR_DUx "\n", + (Dwarf_Unsigned) cie_off, + (Dwarf_Unsigned) cie_off); + } + printf("\taugmentation\t\t\t%s\n", augmenter); + printf("\tcode_alignment_factor\t\t%" DW_PR_DUu "\n", + code_alignment_factor); + printf("\tdata_alignment_factor\t\t%" DW_PR_DSd "\n", + data_alignment_factor); + printf("\treturn_address_register\t\t%d\n", + 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) { + /* Do not print if in check mode */ + if (!check_frames_extended) { + int k2 = 0; + + printf(" eh aug data len 0x%" DW_PR_DUx , 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 */ + } + + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("\tbytes of initial instructions\t%" DW_PR_DUu "\n", + initial_instructions_length); + printf("\tcie length\t\t\t%" DW_PR_DUu "\n", cie_length); + /* For better layout */ + printf("\tinitial instructions\n"); + 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; +} + +void +get_string_from_locs(Dwarf_Debug dbg, + Dwarf_Ptr bytes_in, + Dwarf_Unsigned block_len, + Dwarf_Half addr_size, + struct esb_s *out_string) +{ + + Dwarf_Locdesc *locdescarray = 0; + Dwarf_Signed listlen = 0; + Dwarf_Error err2 =0; + int skip_locdesc_header=1; + int res = 0; + int res2 = dwarf_loclist_from_expr_a(dbg, + bytes_in,block_len, + addr_size, + &locdescarray, + &listlen,&err2); + if (res2 == DW_DLV_ERROR) { + print_error(dbg, "dwarf_get_loclist_from_expr_a", + res2, err2); + } + if(res2==DW_DLV_NO_ENTRY) { + return; + } + /* lcnt is always 1 */ + + /* Use locdescarray here.*/ + res = dwarfdump_print_one_locdesc(dbg, + locdescarray, + skip_locdesc_header, + out_string); + if(res != DW_DLV_OK) { + printf("Bad status from _dwarf_print_one_locdesc %d\n",res); + exit(1); + } + + dwarf_dealloc(dbg, locdescarray->ld_s, DW_DLA_LOC_BLOCK); + dwarf_dealloc(dbg, locdescarray, DW_DLA_LOCDESC); + return ; +} + +/* Print the frame instructions in detail for a glob of instructions. +*/ + +/*ARGSUSED*/ void +print_frame_inst_bytes(Dwarf_Debug dbg, + Dwarf_Ptr cie_init_inst, Dwarf_Signed len, + Dwarf_Signed data_alignment_factor, + int code_alignment_factor, Dwarf_Half addr_size, + struct dwconf_s *config_data) +{ + unsigned char *instp = (unsigned char *) cie_init_inst; + Dwarf_Unsigned uval = 0; + Dwarf_Unsigned uval2 = 0; + unsigned int uleblen = 0; + unsigned int off = 0; + unsigned int loff = 0; + unsigned short u16 = 0; + unsigned int u32 = 0; + unsigned long long u64; + + for (; len > 0;) { + unsigned char ibyte = *instp; + int top = ibyte & 0xc0; + int bottom = ibyte & 0x3f; + int delta = 0; + int reg = 0; + + switch (top) { + case DW_CFA_advance_loc: + delta = ibyte & 0x3f; + printf("\t%2u DW_CFA_advance_loc %d", off, + (int) (delta * code_alignment_factor)); + if (verbose) { + printf(" (%d * %d)", (int) delta, + (int) code_alignment_factor); + } + printf("\n"); + break; + case DW_CFA_offset: + loff = off; + reg = ibyte & 0x3f; + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_offset ", loff); + printreg((Dwarf_Signed) reg, config_data); + printf(" %" DW_PR_DSd , (Dwarf_Signed) + (((Dwarf_Signed) uval) * data_alignment_factor)); + if (verbose) { + printf(" (%" DW_PR_DUu " * %" DW_PR_DSd ")", uval, + data_alignment_factor); + } + printf("\n"); + break; + + case DW_CFA_restore: + reg = ibyte & 0x3f; + printf("\t%2u DW_CFA_restore ", off); + printreg((Dwarf_Signed) reg, config_data); + printf("\n"); + break; + + default: + loff = off; + switch (bottom) { + case DW_CFA_set_loc: + /* operand is address, so need address size */ + /* which will be 4 or 8. */ + switch (addr_size) { + case 4: + { + __uint32_t v32 = 0; + memcpy(&v32, instp + 1, addr_size); + uval = v32; + } + break; + case 8: + { + __uint64_t v64 = 0; + memcpy(&v64, instp + 1, addr_size); + uval = v64; + } + break; + default: + printf + ("Error: Unexpected address size %d in DW_CFA_set_loc!\n", + addr_size); + uval = 0; + } + + instp += addr_size; + len -= (Dwarf_Signed) addr_size; + off += addr_size; + printf("\t%2u DW_CFA_set_loc %" DW_PR_DUu "\n", + loff, uval); + break; + case DW_CFA_advance_loc1: + delta = (unsigned char) *(instp + 1); + uval2 = delta; + instp += 1; + len -= 1; + off += 1; + printf("\t%2u DW_CFA_advance_loc1 %" DW_PR_DUu "\n", + loff, uval2); + break; + case DW_CFA_advance_loc2: + memcpy(&u16, instp + 1, 2); + uval2 = u16; + instp += 2; + len -= 2; + off += 2; + printf("\t%2u DW_CFA_advance_loc2 %" DW_PR_DUu "\n", + loff, uval2); + break; + case DW_CFA_advance_loc4: + memcpy(&u32, instp + 1, 4); + uval2 = u32; + instp += 4; + len -= 4; + off += 4; + printf("\t%2u DW_CFA_advance_loc4 %" DW_PR_DUu "\n", + loff, uval2); + break; + case DW_CFA_MIPS_advance_loc8: + memcpy(&u64, instp + 1, 8); + uval2 = u64; + instp += 8; + len -= 8; + off += 8; + printf("\t%2u DW_CFA_MIPS_advance_loc8 %" DW_PR_DUu "\n", + loff, uval2); + break; + case DW_CFA_offset_extended: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + uval2 = + local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_offset_extended ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" %" DW_PR_DSd , + (Dwarf_Signed) (((Dwarf_Signed) uval2) * + data_alignment_factor)); + if (verbose) { + printf(" (%" DW_PR_DUu " * %d)", uval2, + (int) data_alignment_factor); + } + printf("\n"); + break; + + case DW_CFA_restore_extended: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_restore_extended ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf("\n"); + break; + case DW_CFA_undefined: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_undefined ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf("\n"); + break; + case DW_CFA_same_value: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_same_value ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf("\n"); + break; + case DW_CFA_register: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + uval2 = + local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_register ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" = "); + printreg((Dwarf_Signed) uval2, config_data); + printf("\n"); + break; + case DW_CFA_remember_state: + printf("\t%2u DW_CFA_remember_state\n", loff); + break; + case DW_CFA_restore_state: + printf("\t%2u DW_CFA_restore_state\n", loff); + break; + case DW_CFA_def_cfa: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + uval2 = + local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_def_cfa ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" %" DW_PR_DUu , (unsigned long long) uval2); + printf("\n"); + break; + case DW_CFA_def_cfa_register: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_def_cfa_register ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf("\n"); + break; + case DW_CFA_def_cfa_offset: + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_def_cfa_offset %" DW_PR_DUu "\n", + loff, uval); + break; + + case DW_CFA_nop: + printf("\t%2u DW_CFA_nop\n", loff); + break; + + case DW_CFA_def_cfa_expression: /* DWARF3 */ + { + Dwarf_Unsigned block_len = + local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf + ("\t%2u DW_CFA_def_cfa_expression expr block len %" + DW_PR_DUu "\n", + loff, + block_len); + dump_block("\t\t", (char *) instp+1, + (Dwarf_Signed) block_len); + printf("\n"); + if(verbose) { + struct esb_s exprstring; + esb_constructor(&exprstring); + get_string_from_locs(dbg, + instp+1,block_len,addr_size,&exprstring); + printf("\t\t%s\n",esb_get_string(&exprstring)); + esb_destructor(&exprstring); + } + instp += block_len; + len -= block_len; + off += block_len; + } + break; + case DW_CFA_expression: /* DWARF3 */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + Dwarf_Unsigned block_len = + local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf + ("\t%2u DW_CFA_expression %" DW_PR_DUu + " expr block len %" DW_PR_DUu "\n", + loff, uval, + block_len); + dump_block("\t\t", (char *) instp+1, + (Dwarf_Signed) block_len); + printf("\n"); + if(verbose) { + struct esb_s exprstring; + esb_constructor(&exprstring); + get_string_from_locs(dbg, + instp+1,block_len,addr_size,&exprstring); + printf("\t\t%s\n",esb_get_string(&exprstring)); + esb_destructor(&exprstring); + } + instp += block_len; + len -= block_len; + off += block_len; + } + break; + case DW_CFA_offset_extended_sf: /* DWARF3 */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_offset_extended_sf ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" %" DW_PR_DSd , (Dwarf_Signed) + ((sval2) * data_alignment_factor)); + if (verbose) { + printf(" (%" DW_PR_DSd " * %d)", sval2, + (int) data_alignment_factor); + } + } + printf("\n"); + break; + case DW_CFA_def_cfa_sf: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_def_cfa_sf ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" %" DW_PR_DSd , (long long) sval2); + printf(" (*data alignment factor=>%" DW_PR_DSd ")", + (Dwarf_Signed)(sval2*data_alignment_factor)); + } + printf("\n"); + break; + case DW_CFA_def_cfa_offset_sf: /* DWARF3 */ + { + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + Dwarf_Signed sval = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_def_cfa_offset_sf %" + DW_PR_DSd " (*data alignment factor=> %" + DW_PR_DSd ")\n", + loff, sval, + (Dwarf_Signed)(data_alignment_factor*sval)); + + } + break; + case DW_CFA_val_offset: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_val_offset ", loff); + printreg((Dwarf_Signed)uval, config_data); + printf(" %" DW_PR_DSd , + (Dwarf_Signed) (sval2 * + data_alignment_factor)); + if (verbose) { + printf(" (%" DW_PR_DSd " * %d)", + (Dwarf_Signed) sval2, + (int) data_alignment_factor); + } + } + printf("\n"); + + break; + case DW_CFA_val_offset_sf: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Signed sval2 = + local_dwarf_decode_s_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf("\t%2u DW_CFA_val_offset_sf ", loff); + printreg((Dwarf_Signed) uval, config_data); + printf(" %" DW_PR_DSd , (signed long long) + ((sval2) * data_alignment_factor)); + if (verbose) { + printf(" (%" DW_PR_DSd " * %d)", sval2, + (int) data_alignment_factor); + } + } + printf("\n"); + + break; + case DW_CFA_val_expression: /* DWARF3 */ + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + uval = local_dwarf_decode_u_leb128(instp + 1, &uleblen); + instp += uleblen; + len -= uleblen; + off += uleblen; + { + Dwarf_Unsigned block_len = + local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + + instp += uleblen; + len -= uleblen; + off += uleblen; + printf + ("\t%2u DW_CFA_val_expression %" DW_PR_DUu + " expr block len %" DW_PR_DUu "\n", + loff, uval, + block_len); + dump_block("\t\t", (char *) instp+1, + (Dwarf_Signed) block_len); + printf("\n"); + if(verbose) { + struct esb_s exprstring; + esb_constructor(&exprstring); + get_string_from_locs(dbg, + instp+1,block_len,addr_size,&exprstring); + printf("\t\t%s\n",esb_get_string(&exprstring)); + esb_destructor(&exprstring); + } + instp += block_len; + len -= block_len; + off += block_len; + } + + + break; + + +#ifdef DW_CFA_GNU_window_save + case DW_CFA_GNU_window_save:{ + /* no information: this just tells unwinder to + restore the window registers from the previous + frame's window save area */ + printf("\t%2u DW_CFA_GNU_window_save \n", loff); + } + break; +#endif +#ifdef DW_CFA_GNU_negative_offset_extended + case DW_CFA_GNU_negative_offset_extended:{ + printf("\t%2u DW_CFA_GNU_negative_offset_extended \n", + loff); + } + break; +#endif +#ifdef DW_CFA_GNU_args_size + /* single uleb128 is the current arg area size in + bytes. no register exists yet to save this in */ + case DW_CFA_GNU_args_size:{ + Dwarf_Unsigned lreg = 0; + + /* instp is always 1 byte back, so we need +1 + when we use it. See the final increment + of this for loop. */ + lreg = local_dwarf_decode_u_leb128(instp + 1, + &uleblen); + printf("\t%2u DW_CFA_GNU_args_size arg size: %" + DW_PR_DUu "\n", + loff, lreg); + instp += uleblen; + len -= uleblen; + off += uleblen; + } + break; +#endif + + default: + printf(" %u Unexpected op 0x%x: \n", + loff, (unsigned int) bottom); + len = 0; + break; + } + } + instp++; + len--; + off++; + } +} + +/* Print our register names for the cases we have a name. + Delegate to the configure code to actually do the print. +*/ +void +printreg(Dwarf_Signed reg, struct dwconf_s *config_data) +{ + print_reg_from_config_data(reg, config_data); +} + +/* Actually does the printing of a rule in the table. + This may print something or may print nothing! */ +static void +print_one_frame_reg_col(Dwarf_Debug dbg, + Dwarf_Unsigned rule_id, + Dwarf_Small value_type, + Dwarf_Unsigned reg_used, + Dwarf_Half addr_size, + struct dwconf_s *config_data, + Dwarf_Signed offset_relevant, + Dwarf_Signed offset, + Dwarf_Ptr block_ptr) +{ + char *type_title = ""; + int print_type_title = 1; + + if (check_frames_extended) { + return; + } + + if (config_data->cf_interface_number == 2) + print_type_title = 0; + + switch (value_type) { + case DW_EXPR_OFFSET: + type_title = "off"; + goto preg2; + case DW_EXPR_VAL_OFFSET: + type_title = "valoff"; + + preg2: + if (reg_used == config_data->cf_initial_rule_value) { + break; + } + if (print_type_title) + printf("<%s ", type_title); + printreg((Dwarf_Signed) rule_id, config_data); + printf("="); + if (offset_relevant == 0) { + printreg((Dwarf_Signed) reg_used, config_data); + printf(" "); + } else { + printf("%02" DW_PR_DSd , offset); + printf("("); + printreg((Dwarf_Signed) reg_used, config_data); + printf(") "); + } + if (print_type_title) + printf("%s", "> "); + break; + case DW_EXPR_EXPRESSION: + type_title = "expr"; + goto pexp2; + case DW_EXPR_VAL_EXPRESSION: + type_title = "valexpr"; + + pexp2: + if (print_type_title) + printf("<%s ", type_title); + printreg((Dwarf_Signed) rule_id, config_data); + printf("="); + printf("expr-block-len=%" DW_PR_DSd , offset); + if (print_type_title) + printf("%s", "> "); + if (verbose) { + char pref[40]; + + strcpy(pref, "<"); + strcat(pref, type_title); + strcat(pref, "bytes:"); + dump_block(pref, block_ptr, offset); + printf("%s", "> "); + if(verbose) { + struct esb_s exprstring; + esb_constructor(&exprstring); + get_string_from_locs(dbg, + block_ptr,offset,addr_size,&exprstring); + printf("<expr:%s>",esb_get_string(&exprstring)); + esb_destructor(&exprstring); + } + } + break; + default: + printf("Internal error in libdwarf, value type %d\n", + value_type); + exit(1); + } + return; +} + + +/* get all the data in .debug_frame (or .eh_frame). + The '3' versions mean print using the dwarf3 new interfaces. + The non-3 mean use the old interfaces. + All combinations of requests are possible. */ +extern void +print_frames(Dwarf_Debug dbg, int print_debug_frame, int print_eh_frame, + struct dwconf_s *config_data) +{ + Dwarf_Signed i; + int fres = 0; + Dwarf_Half address_size = 0; + int framed = 0; + void * map_lowpc_to_name = 0; + + current_section_id = DEBUG_FRAME; + + /* The address size here will not be right for all frames. + Only in DWARF4 is there a real address size known + in the frame data itself. If any DIE + is known then a real address size can be gotten from + dwarf_get_die_address_size(). */ + fres = dwarf_get_address_size(dbg, &address_size, &err); + if (fres != DW_DLV_OK) { + print_error(dbg, "dwarf_get_address_size", fres, err); + } + for (framed = 0; framed < 2; ++framed) { + Dwarf_Cie *cie_data = NULL; + Dwarf_Signed cie_element_count = 0; + Dwarf_Fde *fde_data = NULL; + Dwarf_Signed fde_element_count = 0; + int frame_count = 0; + int cie_count = 0; + int all_cus_seen = 0; + void * lowpcSet = 0; + char *framename = 0; + int silent_if_missing = 0; + int is_eh = 0; + + if (framed == 0) { + if (!print_debug_frame) { + continue; + } + framename = ".debug_frame"; + /* Big question here is how to print all the info? + Can print the logical matrix, but that is huge, + though could skip lines that don't change. + Either that, or print the instruction statement program + that describes the changes. */ + fres = dwarf_get_fde_list(dbg, &cie_data, &cie_element_count, + &fde_data, &fde_element_count, &err); + if(check_harmless) { + print_any_harmless_errors(dbg); + } + } else { + if (!print_eh_frame) { + continue; + } + is_eh = 1; + /* This is gnu g++ exceptions in a .eh_frame section. Which + is just like .debug_frame except that the empty, or + 'special' CIE_id is 0, not -1 (to distinguish fde from + cie). And the augmentation is "eh". As of egcs-1.1.2 + anyway. A non-zero cie_id is in a fde and is the + difference between the fde address and the beginning of + the cie it belongs to. This makes sense as this is + intended to be referenced at run time, and is part of + the running image. For more on augmentation strings, see + libdwarf/dwarf_frame.c. */ + + /* Big question here is how to print all the info? + Can print the logical matrix, but that is huge, + though could skip lines that don't change. + Either that, or print the instruction statement program + that describes the changes. */ + silent_if_missing = 1; + framename = ".eh_frame"; + fres = dwarf_get_fde_list_eh(dbg, &cie_data, + &cie_element_count, &fde_data, + &fde_element_count, &err); + if(check_harmless) { + print_any_harmless_errors(dbg); + } + } + + /* Do not print any frame info if in check mode */ + if (check_frames) { + addr_map_destroy(lowpcSet); + lowpcSet = 0; + continue; + } + + if (fres == DW_DLV_ERROR) { + printf("\n%s\n", framename); + print_error(dbg, "dwarf_get_fde_list", fres, err); + } else if (fres == DW_DLV_NO_ENTRY) { + if (!silent_if_missing) { + printf("\n%s\n", framename); + } + /* no frame information */ + } else { /* DW_DLV_OK */ + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("\n%s\n", framename); + printf("\nfde:\n"); + } + + for (i = 0; i < fde_element_count; i++) { + print_one_fde(dbg, fde_data[i], + i, cie_data, cie_element_count, + address_size, is_eh, config_data, + &map_lowpc_to_name, + &lowpcSet, + &all_cus_seen); + ++frame_count; + if(frame_count >= break_after_n_units) { + break; + } + } + /* Print the cie set. */ + if (verbose) { + /* Do not print if in check mode */ + if (!check_frames_extended) { + printf("\ncie:\n"); + } + for (i = 0; i < cie_element_count; i++) { + print_one_cie(dbg, cie_data[i], i, address_size, + config_data); + ++cie_count; + if(cie_count >= break_after_n_units) { + break; + } + } + } + dwarf_fde_cie_list_dealloc(dbg, cie_data, cie_element_count, + fde_data, fde_element_count); + } + addr_map_destroy(lowpcSet); + lowpcSet = 0; + } + if (current_cu_die_for_print_frames) { + dwarf_dealloc(dbg, current_cu_die_for_print_frames, DW_DLA_DIE); + current_cu_die_for_print_frames = 0; + } + addr_map_destroy(map_lowpc_to_name); +} + |