static void process_line_table(Dwarf_Debug dbg, const char *sec_name, Dwarf_Line *linebuf, Dwarf_Signed linecount, Dwarf_Bool is_logicals_table, Dwarf_Bool is_actuals_table) { char *padding = 0; Dwarf_Signed i = 0; Dwarf_Addr pc = 0; Dwarf_Unsigned lineno = 0; Dwarf_Unsigned logicalno = 0; Dwarf_Unsigned column = 0; Dwarf_Unsigned call_context = 0; string subprog_name = 0; string subprog_filename = 0; Dwarf_Unsigned subprog_line = 0; Dwarf_Error err = 0; Dwarf_Bool newstatement = 0; Dwarf_Bool lineendsequence = 0; Dwarf_Bool new_basic_block = 0; int sres = 0; int ares = 0; int lires = 0; int cores = 0; Dwarf_Addr elf_max_address = 0; Dwarf_Bool SkipRecord = FALSE; current_section_id = DEBUG_LINE; struct esb_s lastsrc; /* line_flag is TRUE */ esb_constructor(&lastsrc); get_address_size_and_max(dbg,0,&elf_max_address,&err); /* Padding for a nice layout */ padding = line_print_pc ? " " : ""; if (do_print_dwarf) { /* Check if print of <pc> address is needed. */ printf("\n"); if (is_logicals_table) { printf("Logicals Table:\n"); printf("%sNS new statement, PE prologue end, " "EB epilogue begin\n",padding); printf("%sDI=val discriminator value\n", padding); printf("%sCC=val context, SB=val subprogram\n", padding); } else if (is_actuals_table) { printf("Actuals Table:\n"); printf("%sBB new basic block, ET end of text sequence\n" "%sIS=val ISA number\n",padding,padding); } else { /* Standard DWARF line table. */ printf("%sNS new statement, BB new basic block, " "ET end of text sequence\n",padding); printf("%sPE prologue end, EB epilogue begin\n",padding); printf("%sIS=val ISA number, DI=val discriminator value\n", padding); } if (is_logicals_table || is_actuals_table) { printf("[ row] "); } if (line_print_pc) { printf("<pc> "); } if (is_logicals_table) { printf("[lno,col] NS PE EB DI= CC= SB= uri: \"filepath\"\n"); } else if (is_actuals_table) { printf("[logical] BB ET IS=\n"); } else { printf("[row,col] NS BB ET PE EB IS= DI= uri: \"filepath\"\n"); } } for (i = 0; i < linecount; i++) { Dwarf_Line line = linebuf[i]; string filename = 0; int nsres = 0; Dwarf_Bool found_line_error = FALSE; Dwarf_Bool has_is_addr_set = FALSE; char *where = NULL; if (check_decl_file && checking_this_compiler()) { /* A line record with addr=0 was detected */ if (SkipRecord) { /* Skip records that do not have ís_addr_set' */ ares = dwarf_line_is_addr_set(line, &has_is_addr_set, &err); if (ares == DW_DLV_OK && has_is_addr_set) { SkipRecord = FALSE; } else { /* Keep ignoring records until we have one with 'is_addr_set' */ continue; } } } if (check_lines && checking_this_compiler()) { DWARF_CHECK_COUNT(lines_result,1); } filename = "<unknown>"; if (!is_actuals_table) { sres = dwarf_linesrc(line, &filename, &err); if (sres == DW_DLV_ERROR) { /* Do not terminate processing */ where = "dwarf_linesrc()"; record_line_error(where,err); found_line_error = TRUE; } } pc = 0; ares = dwarf_lineaddr(line, &pc, &err); if (ares == DW_DLV_ERROR) { /* Do not terminate processing */ where = "dwarf_lineaddr()"; record_line_error(where,err); found_line_error = TRUE; pc = 0; } if (ares == DW_DLV_NO_ENTRY) { pc = 0; } if (is_actuals_table) { lires = dwarf_linelogical(line, &logicalno, &err); if (lires == DW_DLV_ERROR) { /* Do not terminate processing */ where = "dwarf_linelogical()"; record_line_error(where,err); found_line_error = TRUE; } if (lires == DW_DLV_NO_ENTRY) { logicalno = -1LL; } column = 0; } else { lires = dwarf_lineno(line, &lineno, &err); if (lires == DW_DLV_ERROR) { /* Do not terminate processing */ where = "dwarf_lineno()"; record_line_error(where,err); found_line_error = TRUE; } if (lires == DW_DLV_NO_ENTRY) { lineno = -1LL; } cores = dwarf_lineoff_b(line, &column, &err); if (cores == DW_DLV_ERROR) { /* Do not terminate processing */ where = "dwarf_lineoff()"; record_line_error(where,err); found_line_error = TRUE; } if (cores == DW_DLV_NO_ENTRY) { /* Zero was always the correct default, meaning the left edge. DWARF2/3/4 spec sec 6.2.2 */ column = 0; } } /* Process any possible error condition, though we won't be at the first such error. */ if (check_decl_file && checking_this_compiler()) { DWARF_CHECK_COUNT(decl_file_result,1); if (found_line_error) { DWARF_CHECK_ERROR2(decl_file_result,where,dwarf_errmsg(err)); } else if (do_check_dwarf) { /* Check the address lies with a valid [lowPC:highPC] in the .text section*/ if (IsValidInBucketGroup(pRangesInfo,pc)) { /* Valid values; do nothing */ } else { /* At this point may be we are dealing with a linkonce symbol. The problem we have here is we have consumed the deug_info section and we are dealing just with the records from the .debug_line, so no PU_name is available and no high_pc. Traverse the linkonce table if try to match the pc value with one of those ranges. */ if (check_lines && checking_this_compiler()) { DWARF_CHECK_COUNT(lines_result,1); } if (FindAddressInBucketGroup(pLinkonceInfo,pc)){ /* Valid values; do nothing */ } else { /* The SN Systems Linker generates line records with addr=0, when dealing with linkonce symbols and no stripping */ if (pc) { char addr_tmp[100]; if (check_lines && checking_this_compiler()) { snprintf(addr_tmp,sizeof(addr_tmp), "%s: Address" " 0x%" DW_PR_XZEROS DW_PR_DUx " outside a valid .text range", sec_name,pc); DWARF_CHECK_ERROR(lines_result, addr_tmp); } } else { SkipRecord = TRUE; } } } /* Check the last record for the .debug_line, the one created by DW_LNE_end_sequence, is the same as the high_pc address for the last known user program unit (PU) */ if ((i + 1 == linecount) && seen_PU_high_address && !is_logicals_table) { /* Ignore those PU that have been stripped by the linker; their low_pc values are set to -1 (snc linker only) */ /* It is perfectly sensible for a compiler to leave a few bytes of NOP or other stuff after the last instruction in a subprogram, for cache-alignment or other purposes, so a mismatch here is not necessarily an error. */ if (check_lines && checking_this_compiler()) { DWARF_CHECK_COUNT(lines_result,1); if ((pc != PU_high_address) && (PU_base_address != elf_max_address)) { char addr_tmp[100]; snprintf(addr_tmp,sizeof(addr_tmp), "%s: Address" " 0x%" DW_PR_XZEROS DW_PR_DUx " may be incorrect" " as DW_LNE_end_sequence address", sec_name,pc); DWARF_CHECK_ERROR(lines_result, addr_tmp); } } } } } /* Display the error information */ if (found_line_error || record_dwarf_error) { if (check_verbose_mode && PRINTING_UNIQUE) { /* Print the record number for better error description */ printf("Record = %" DW_PR_DUu " Addr = 0x%" DW_PR_XZEROS DW_PR_DUx " [%4" DW_PR_DUu ",%2" DW_PR_DUu "] '%s'\n", i, pc,lineno,column,filename); /* The compilation unit was already printed */ if (!check_decl_file) { PRINT_CU_INFO(); } } record_dwarf_error = FALSE; /* Due to a fatal error, skip current record */ if (found_line_error) { continue; } } if (do_print_dwarf) { if (is_logicals_table || is_actuals_table) { printf("[%4" DW_PR_DUu "] ", i + 1); } /* Check if print of <pc> address is needed. */ if (line_print_pc) { printf("0x%" DW_PR_XZEROS DW_PR_DUx " ", pc); } if (is_actuals_table) { printf("[%7" DW_PR_DUu "]", logicalno); } else { printf("[%4" DW_PR_DUu ",%2" DW_PR_DUu "]", lineno, column); } } if (!is_actuals_table) { nsres = dwarf_linebeginstatement(line, &newstatement, &err); if (nsres == DW_DLV_OK) { if (newstatement && do_print_dwarf) { printf(" %s","NS"); } } else if (nsres == DW_DLV_ERROR) { print_error(dbg, "linebeginstatment failed", nsres, err); } } if (!is_logicals_table) { nsres = dwarf_lineblock(line, &new_basic_block, &err); if (nsres == DW_DLV_OK) { if (new_basic_block && do_print_dwarf) { printf(" %s","BB"); } } else if (nsres == DW_DLV_ERROR) { print_error(dbg, "lineblock failed", nsres, err); } nsres = dwarf_lineendsequence(line, &lineendsequence, &err); if (nsres == DW_DLV_OK) { if (lineendsequence && do_print_dwarf) { printf(" %s", "ET"); } } else if (nsres == DW_DLV_ERROR) { print_error(dbg, "lineendsequence failed", nsres, err); } } if (do_print_dwarf) { Dwarf_Bool prologue_end = 0; Dwarf_Bool epilogue_begin = 0; Dwarf_Unsigned isa = 0; Dwarf_Unsigned discriminator = 0; int disres = dwarf_prologue_end_etc(line, &prologue_end,&epilogue_begin, &isa,&discriminator,&err); if (disres == DW_DLV_ERROR) { print_error(dbg, "dwarf_prologue_end_etc() failed", disres, err); } if (prologue_end && !is_actuals_table) { printf(" PE"); } if (epilogue_begin && !is_actuals_table) { printf(" EB"); } if (isa && !is_logicals_table) { printf(" IS=0x%" DW_PR_DUx, isa); } if (discriminator && !is_actuals_table) { printf(" DI=0x%" DW_PR_DUx, discriminator); } if (is_logicals_table) { call_context = 0; disres = dwarf_linecontext(line, &call_context, &err); if (disres == DW_DLV_ERROR) { print_error(dbg, "dwarf_linecontext() failed", disres, err); } if (call_context) { printf(" CC=%" DW_PR_DUu, call_context); } subprog_name = 0; disres = dwarf_line_subprog(line, &subprog_name, &subprog_filename, &subprog_line, &err); if (disres == DW_DLV_ERROR) { print_error(dbg, "dwarf_line_subprog() failed", disres, err); } if (subprog_name && strlen(subprog_name)) { /* We do not print an empty name. Clutters things up. */ printf(" SB=\"%s\"", subprog_name); } } } if (!is_actuals_table) { if (i > 0 && verbose < 3 && strcmp(filename,esb_get_string(&lastsrc)) == 0) { /* Do not print name. */ } else { struct esb_s urs; esb_constructor(&urs); esb_append(&urs, " uri: \""); translate_to_uri(filename,&urs); esb_append(&urs,"\""); if (do_print_dwarf) { printf("%s",esb_get_string(&urs)); } esb_destructor(&urs); esb_empty_string(&lastsrc); esb_append(&lastsrc,filename); } if (sres == DW_DLV_OK) { dwarf_dealloc(dbg, filename, DW_DLA_STRING); } } if (do_print_dwarf) { printf("\n"); } } esb_destructor(&lastsrc); }
/** * @brief Process one line number record. * @param line Line to process. */ void DwarfLineContainer::loadLine(Dwarf_Line line) { // Address associated with line. Dwarf_Addr addr = 0; m_res = dwarf_lineaddr(line, &addr, &m_error); if (m_res == DW_DLV_ERROR) { DWARF_ERROR(getDwarfError(m_error)); return; } if (m_res == DW_DLV_NO_ENTRY) { addr = EMPTY_ADDR; } // Source statement line number. Dwarf_Unsigned lineno; m_res = dwarf_lineno(line, &lineno, &m_error); if (m_res == DW_DLV_ERROR) { DWARF_ERROR(getDwarfError(m_error)); return; } if (m_res == DW_DLV_NO_ENTRY) { lineno = EMPTY_UNSIGNED; } // Column number at which statement represented by line begins. Dwarf_Unsigned column; m_res = dwarf_lineoff_b(line, &column, &m_error); if (m_res == DW_DLV_ERROR) { DWARF_ERROR(getDwarfError(m_error)); return; } if (m_res == DW_DLV_NO_ENTRY) { column = EMPTY_UNSIGNED; } // Name of src file where line occurs. char *s = nullptr; string f; m_res = dwarf_linesrc(line, &s, &m_error); if (m_res == DW_DLV_ERROR) { DWARF_ERROR(getDwarfError(m_error)); return; } if (m_res == DW_DLV_NO_ENTRY || s==nullptr) f = EMPTY_STR; else f = s; dwarf_dealloc(m_parentFile->m_dbg, s, DW_DLA_STRING); // Is line marked as beginning of the statement? Dwarf_Bool statBeg; m_res = dwarf_linebeginstatement(line, &statBeg, &m_error); if (m_res != DW_DLV_OK) { DWARF_ERROR(getDwarfError(m_error)); return; } // Is line marked as ending a text sequence? Dwarf_Bool seqEnd; m_res = dwarf_lineendsequence(line, &seqEnd, &m_error); if (m_res != DW_DLV_OK) { DWARF_ERROR(getDwarfError(m_error)); return; } // Is line marked as not beginning basic block? Dwarf_Bool basicBlockBeg; m_res = dwarf_lineblock(line, &basicBlockBeg, &m_error); if (m_res != DW_DLV_OK) { DWARF_ERROR(getDwarfError(m_error)); return; } Dwarf_Bool prologueEnd, epilogueBegin; Dwarf_Unsigned isa, discriminator; m_res = dwarf_prologue_end_etc(line, &prologueEnd, &epilogueBegin, &isa, &discriminator, &m_error); if (m_res != DW_DLV_OK) { DWARF_ERROR(getDwarfError(m_error)); return; } // Create line record. DwarfLine *l = new DwarfLine(this, *findSrcFile(f)); l->lineNum = lineno; l->addr = addr; l->col = column; if (statBeg) l->flags += DwarfLine::STAT_BEG; if (seqEnd) l->flags += DwarfLine::SEQ_END; if (basicBlockBeg) l->flags += DwarfLine::BASE_BLOCK_BEG; if (prologueEnd) l->flags += DwarfLine::PROLOGUE_END; if (epilogueBegin) l->flags += DwarfLine::EPILOGUE_BEGIN; m_data.push_back(l); }
static void _dwarf_lineno(Dwarf_Die die) { Dwarf_Line *linebuf, ln; Dwarf_Signed linecount, lineoff; Dwarf_Unsigned lineno, srcfileno; Dwarf_Addr lineaddr; Dwarf_Half tag; Dwarf_Error de; Dwarf_Bool linebeginstatement, lineendsequence, lineblock; char *linesrc; int r_srclines; int i; if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { tet_printf("dwarf_tag failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; return; } r_srclines = dwarf_srclines(die, &linebuf, &linecount, &de); TS_CHECK_INT(r_srclines); if (r_srclines == DW_DLV_ERROR) { tet_printf("dwarf_srclines should not fail but still failed:", " %s", dwarf_errmsg(de)); return; } if (r_srclines != DW_DLV_OK) return; for (i = 0; i < linecount; i++) { ln = linebuf[i]; if (dwarf_linebeginstatement(ln, &linebeginstatement, &de) != DW_DLV_OK) { tet_printf("dwarf_linebeginstatement failed: %s", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_INT(linebeginstatement); if (dwarf_linebeginstatement(ln, &linebeginstatement, &de) != DW_DLV_OK) { tet_printf("dwarf_linebeginstatement failed: %s", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_INT(linebeginstatement); if (dwarf_lineendsequence(ln, &lineendsequence, &de) != DW_DLV_OK) { tet_printf("dwarf_lineendsequence failed: %s", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_INT(lineendsequence); if (dwarf_lineno(ln, &lineno, &de) != DW_DLV_OK) { tet_printf("dwarf_lineno failed: %s", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_UINT(lineno); if (dwarf_line_srcfileno(ln, &srcfileno, &de) != DW_DLV_OK) { tet_printf("dwarf_line_srcfileno failed: %s", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_UINT(srcfileno); if (dwarf_lineaddr(ln, &lineaddr, &de) != DW_DLV_OK) { tet_printf("dwarf_lineaddr failed: %s", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_UINT(lineaddr); if (dwarf_lineoff(ln, &lineoff, &de) != DW_DLV_OK) { tet_printf("dwarf_lineoff failed: %s", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_INT(lineoff); if (dwarf_linesrc(ln, &linesrc, &de) != DW_DLV_OK) { tet_printf("dwarf_linesrc failed: %s", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_STRING(linesrc); if (dwarf_lineblock(ln, &lineblock, &de) != DW_DLV_OK) { tet_printf("dwarf_lineblock failed: %s", dwarf_errmsg(de)); result = TET_FAIL; } TS_CHECK_INT(lineblock); } }
int main (int argc, char *argv[]) { int cnt; Dwfl *dwfl = NULL; (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &cnt, &dwfl); assert (dwfl != NULL); Dwarf_Die *cu = NULL; Dwarf_Addr bias; do { cu = dwfl_nextcu (dwfl, cu, &bias); if (cu != NULL) { Dwfl_Module *mod = dwfl_cumodule (cu); const char *modname = (dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ?: "<unknown>"); const char *cuname = (dwarf_diename (cu) ?: "<unknown>"); printf ("mod: %s CU: [%" PRIx64 "] %s\n", modname, dwarf_dieoffset (cu), cuname); size_t lines; if (dwfl_getsrclines (cu, &lines) != 0) continue; // No lines... for (size_t i = 0; i < lines; i++) { Dwfl_Line *line = dwfl_onesrcline (cu, i); Dwarf_Addr addr; int lineno; int colno; Dwarf_Word mtime; Dwarf_Word length; const char *src = dwfl_lineinfo (line, &addr, &lineno, &colno, &mtime, &length); Dwarf_Addr dw_bias; Dwarf_Line *dw_line = dwfl_dwarf_line (line, &dw_bias); assert (bias == dw_bias); Dwarf_Addr dw_addr; if (dwarf_lineaddr (dw_line, &dw_addr) != 0) error (EXIT_FAILURE, 0, "dwarf_lineaddr: %s", dwarf_errmsg (-1)); assert (addr == dw_addr + dw_bias); unsigned int dw_op_index; if (dwarf_lineop_index (dw_line, &dw_op_index) != 0) error (EXIT_FAILURE, 0, "dwarf_lineop_index: %s", dwarf_errmsg (-1)); int dw_lineno; if (dwarf_lineno (dw_line, &dw_lineno) != 0) error (EXIT_FAILURE, 0, "dwarf_lineno: %s", dwarf_errmsg (-1)); assert (lineno == dw_lineno); int dw_colno; if (dwarf_linecol (dw_line, &dw_colno) != 0) error (EXIT_FAILURE, 0, "dwarf_lineno: %s", dwarf_errmsg (-1)); assert (colno == dw_colno); bool begin; if (dwarf_linebeginstatement (dw_line, &begin) != 0) error (EXIT_FAILURE, 0, "dwarf_linebeginstatement: %s", dwarf_errmsg (-1)); bool end; if (dwarf_lineendsequence (dw_line, &end) != 0) error (EXIT_FAILURE, 0, "dwarf_lineendsequence: %s", dwarf_errmsg (-1)); bool pend; if (dwarf_lineprologueend (dw_line, &pend) != 0) error (EXIT_FAILURE, 0, "dwarf_lineprologueend: %s", dwarf_errmsg (-1)); bool ebegin; if (dwarf_lineepiloguebegin (dw_line, &ebegin) != 0) error (EXIT_FAILURE, 0, "dwarf_lineepiloguebegin: %s", dwarf_errmsg (-1)); bool block; if (dwarf_lineblock (dw_line, &block) != 0) error (EXIT_FAILURE, 0, "dwarf_lineblock: %s", dwarf_errmsg (-1)); unsigned int isa; if (dwarf_lineisa (dw_line, &isa) != 0) error (EXIT_FAILURE, 0, "dwarf_lineisa: %s", dwarf_errmsg (-1)); unsigned int disc; if (dwarf_linediscriminator (dw_line, &disc) != 0) error (EXIT_FAILURE, 0, "dwarf_linediscriminator: %s", dwarf_errmsg (-1)); const char *dw_src; Dwarf_Word dw_mtime; Dwarf_Word dw_length; dw_src = dwarf_linesrc (dw_line, &dw_mtime, &dw_length); assert (strcmp (src, dw_src) == 0); assert (mtime == dw_mtime); assert (length == dw_length); printf ("%zd %#" PRIx64 " %s:%d:%d\n" " time: %#" PRIX64 ", len: %" PRIu64 ", idx: %d, b: %d, e: %d" ", pe: %d, eb: %d, block: %d" ", isa: %d, disc: %d\n", i, addr, src, lineno, colno, mtime, length, dw_op_index, begin, end, pend, ebegin, block, isa, disc); Dwarf_Die *linecu = dwfl_linecu (line); assert (cu == linecu); Dwfl_Module *linemod = dwfl_linemodule (line); assert (mod == linemod); } } } while (cu != NULL); dwfl_end (dwfl); return 0; }