/* Copyright (C) 2020 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. */ /* DWARF5 has the new .debug_loclists section. Here we print that data. The raw printing covers all the content of the section but without relating it to any compilation unit. Printing the actual address means printing with the actual DIEs on hand. */ #include #include /* FILE decl for dd_esb.h, printf etc */ #include "dwarf.h" #include "libdwarf.h" #include "libdwarf_private.h" #include "dd_defined_types.h" #include "dd_checkutil.h" #include "dd_glflags.h" #include "dd_globals.h" #include "dd_esb.h" #include "dd_esb_using_functions.h" #include "dd_sanitized.h" #if 0 static void dump_bytes(const char *msg,Dwarf_Small * start, long len) { Dwarf_Small *end = start + len; Dwarf_Small *cur = start; printf("%s (0x%lx) ",msg,(unsigned long)start); for (; cur < end; cur++) { printf("%02x", *cur); } printf("\n"); } #endif /* 0 */ static void print_sec_name(Dwarf_Debug dbg) { struct esb_s truename; char buf[DWARF_SECNAME_BUFFER_SIZE]; esb_constructor_fixed(&truename,buf,sizeof(buf)); get_true_section_name(dbg,".debug_loclists", &truename,TRUE); printf("\n%s\n\n",sanitized(esb_get_string(&truename))); esb_destructor(&truename); } static int print_offset_entry_table(Dwarf_Debug dbg, Dwarf_Unsigned contextnum, Dwarf_Unsigned offset_entry_count, Dwarf_Unsigned offset_of_offset_array, Dwarf_Unsigned offset_of_header, Dwarf_Unsigned offset_size, Dwarf_Error *error) { Dwarf_Unsigned e = 0; unsigned colmax = 2; unsigned col = 0; int res = 0; int hasnewline = TRUE; Dwarf_Unsigned loff = offset_of_offset_array; Dwarf_Unsigned goff = offset_of_header + loff; for ( ; e < offset_entry_count; ++e) { Dwarf_Unsigned value = 0; if (e == 0) { printf(" Location Offset Table :\n"); printf(" Location Offset Table at 0x%" DW_PR_XZEROS DW_PR_DUx "\n",offset_of_offset_array); printf(" (Added 0x%" DW_PR_DUx " to value for actual offsets)\n", offset_of_offset_array); printf(" [goff][loff][index]\n"); } hasnewline = FALSE; res = dwarf_get_loclist_offset_index_value(dbg, contextnum,e,&value,0,error); if (res != DW_DLV_OK) { return res; } if (col == 0) { printf(" [0x%" DW_PR_XZEROS DW_PR_DUx "]", goff); printf("[0x%" DW_PR_XZEROS DW_PR_DUx "]", loff); printf("[%2" DW_PR_DUu "]",e); } printf(" 0x%" DW_PR_XZEROS DW_PR_DUx, value); printf("(0x%" DW_PR_XZEROS DW_PR_DUx ")", value+offset_of_offset_array); loff += offset_size; goff += offset_size; col++; if (col == colmax) { printf("\n"); hasnewline = TRUE; col = 0; } } if (!hasnewline) { printf("\n"); } return DW_DLV_OK; } static void print_opsbytes(Dwarf_Unsigned expr_ops_blocklen, Dwarf_Small* expr_ops) { Dwarf_Unsigned i = 0; if (!expr_ops_blocklen) { return; } printf(" opsbytes:"); for ( ; i < expr_ops_blocklen; ++i ) { Dwarf_Small *b = expr_ops+i; printf(" %02x", *b); } printf(" "); } /* Print single raw lle */ static int print_single_lle(Dwarf_Unsigned lineoffset, Dwarf_Unsigned code, Dwarf_Unsigned v1, Dwarf_Unsigned v2, Dwarf_Unsigned expr_ops_blocklen, Dwarf_Small *expr_ops, Dwarf_Unsigned entrylen, Dwarf_Unsigned goff) { int res = DW_DLV_OK; const char *name = ""; struct esb_s m; esb_constructor(&m); res = dwarf_get_LLE_name((unsigned int)code,&name); if (res != DW_DLV_OK) { /* ASSERT: res == DW_DLV_NO_ENTRY, see dwarf_names.c */ esb_append_printf_u(&m, "",code); } else { esb_append(&m,name); } printf(" "); printf("[0x%" DW_PR_XZEROS DW_PR_DUx "]",goff); printf("[0x%" DW_PR_XZEROS DW_PR_DUx "] %-20s", lineoffset,esb_get_string(&m)); switch(code) { case DW_LLE_end_of_list: printf(" "); printf(" "); break; case DW_LLE_base_addressx: printf(" 0x%" DW_PR_XZEROS DW_PR_DUx ,v1); printf(" "); break; case DW_LLE_startx_endx: printf( " 0x%" DW_PR_XZEROS DW_PR_DUx " 0x%" DW_PR_XZEROS DW_PR_DUx ,v1,v2); break; case DW_LLE_startx_length: printf( " 0x%" DW_PR_XZEROS DW_PR_DUx " 0x%" DW_PR_XZEROS DW_PR_DUx ,v1,v2); break; case DW_LLE_offset_pair: printf( " 0x%" DW_PR_XZEROS DW_PR_DUx " 0x%" DW_PR_XZEROS DW_PR_DUx ,v1,v2); break; case DW_LLE_default_location: printf( " 0x%" DW_PR_XZEROS DW_PR_DUx " 0x%" DW_PR_XZEROS DW_PR_DUx ,v1,v2); break; case DW_LLE_base_address: printf( " 0x%" DW_PR_XZEROS DW_PR_DUx ,v1); printf(" "); break; case DW_LLE_start_end: printf( " 0x%" DW_PR_XZEROS DW_PR_DUx " 0x%" DW_PR_XZEROS DW_PR_DUx ,v1,v2); break; case DW_LLE_start_length: printf( " 0x%" DW_PR_XZEROS DW_PR_DUx " 0x%" DW_PR_XZEROS DW_PR_DUx ,v1,v2); break; default: printf(" ERROR: Unknown LLE code in .debug_loclists. %s\n", esb_get_string(&m)); simple_err_return_msg_either_action(res, esb_get_string(&m)); break; } printf( " %" DW_PR_DUu,entrylen); esb_destructor(&m); if (glflags.verbose && expr_ops_blocklen > 0) { printf("\n"); printf(" "); printf(" opslen %" DW_PR_DUu,expr_ops_blocklen); print_opsbytes(expr_ops_blocklen,expr_ops); } printf("\n"); return res; } /* Prints the raw content. Exactly as in .debug_loclists Similar to .debug_rnglists Here we print, but do not stop, on seeing DW_LLE_end_of_list. Only the end of list bytes stop the iteration. */ static int print_entire_loclist(Dwarf_Debug dbg, Dwarf_Unsigned contextnumber, Dwarf_Unsigned header_offset, Dwarf_Unsigned offset_of_first_loc, Dwarf_Unsigned offset_past_last_locentry, Dwarf_Error *error) { /* These offsets are rnglists section global offsets, not rnglist context local offsets. */ Dwarf_Unsigned curoffset = offset_of_first_loc; Dwarf_Unsigned endoffset = offset_past_last_locentry; int res = 0; Dwarf_Unsigned ct = 0; Dwarf_Unsigned loff = 0; Dwarf_Unsigned goff = 0; loff = offset_of_first_loc; goff = loff +header_offset; for ( ; curoffset < endoffset; ++ct ) { unsigned entrylen = 0; unsigned code = 0; Dwarf_Unsigned v1 = 0; Dwarf_Unsigned v2 = 0; Dwarf_Unsigned expr_ops_blocksize = 0; Dwarf_Unsigned expr_ops_offset = 0; Dwarf_Small *expr_ops_data = 0; if (!ct) { printf(" LocationList (raw)\n"); printf(" [goff ][loff ] " "entryname " "val1 val2 entrylen\n"); } /* This returns ops data as in DWARF. No application of base addresses or anything. */ res = dwarf_get_loclist_lle(dbg,contextnumber, curoffset,endoffset, &entrylen, &code,&v1,&v2, &expr_ops_blocksize,&expr_ops_offset,&expr_ops_data, error); if (res != DW_DLV_OK) { return res; } print_single_lle(curoffset, code,v1,v2,expr_ops_blocksize, expr_ops_data,entrylen,goff); curoffset += entrylen; goff += entrylen; if (curoffset > endoffset) { struct esb_s m; esb_constructor(&m); esb_append_printf_u(&m, "DW_DLE_USER_DECLARED_ERROR: " "final RLE in " ".debug_rnglists runs past end of its area " "so current offset 0x%" DW_PR_DUx,curoffset); esb_append_printf_u(&m," exceeds context 1-past-end" " offset of 0x%" DW_PR_DUx ".",endoffset); dwarf_error_creation(dbg,error, esb_get_string(&m)); esb_destructor(&m); return DW_DLV_ERROR; } } return DW_DLV_OK; } int print_raw_all_loclists(Dwarf_Debug dbg, Dwarf_Error *error) { int res = 0; Dwarf_Unsigned count = 0; Dwarf_Unsigned i = 0; res = dwarf_load_loclists(dbg,&count,error); if (res != DW_DLV_OK) { return res; } print_sec_name(dbg); printf(" Number of loclists contexts: %" DW_PR_DUu "\n", count); for (i = 0; i < count ; ++i) { Dwarf_Unsigned header_offset = 0; Dwarf_Small offset_size = 0; Dwarf_Small extension_size = 0; unsigned version = 0; /* 5 */ Dwarf_Small address_size = 0; Dwarf_Small segment_selector_size = 0; Dwarf_Unsigned offset_entry_count = 0; Dwarf_Unsigned offset_of_offset_array = 0; Dwarf_Unsigned offset_of_first_locentry = 0; Dwarf_Unsigned offset_past_last_locentry = 0; res = dwarf_get_loclist_context_basics(dbg,i, &header_offset, &offset_size, &extension_size, &version,&address_size,&segment_selector_size, &offset_entry_count,&offset_of_offset_array, &offset_of_first_locentry, &offset_past_last_locentry, error); if (res != DW_DLV_OK) { struct esb_s m; esb_constructor(&m); esb_append_printf_u(&m,"ERROR: Getting debug_rnglists " "entry %u we unexpectedly stop early.",i); simple_err_return_msg_either_action(res, esb_get_string(&m)); esb_destructor(&m); return res; } printf(" Context number : %3" DW_PR_DUu "\n",i); printf(" Version : %3u\n",version); printf(" address size : %3u\n",address_size); printf(" offset size : %3u\n",offset_size); if (glflags.verbose) { printf(" extension size : %3u\n",extension_size); } printf(" segment selector size : %3u\n", segment_selector_size); printf(" offset entry count : %3" DW_PR_DUu "\n", offset_entry_count); printf(" loclist size in bytes : %3" DW_PR_DUu "\n", offset_past_last_locentry - header_offset); printf(" Offset in section : " "0x%" DW_PR_XZEROS DW_PR_DUx"\n", header_offset); printf(" Offset of offsets : " "0x%" DW_PR_XZEROS DW_PR_DUx"\n", offset_of_offset_array); printf(" Offsetof first loc : " "0x%" DW_PR_XZEROS DW_PR_DUx"\n", offset_of_first_locentry); printf(" Offset past locations : " "0x%" DW_PR_XZEROS DW_PR_DUx"\n", offset_past_last_locentry); if (offset_entry_count) { res = print_offset_entry_table(dbg,i, offset_entry_count, offset_of_offset_array, header_offset, offset_size, error); if (res == DW_DLV_ERROR) { return res; } } if ((offset_of_first_locentry+1) < offset_past_last_locentry) { res = print_entire_loclist(dbg,i, header_offset, offset_of_first_locentry, offset_past_last_locentry, error); if (res != DW_DLV_OK) { return res; } } } return DW_DLV_OK; }