From: Petr Machata Date: Mon, 30 Nov 2009 18:19:49 +0000 (+0100) Subject: dwarflint: Fix checking of DW_AT_stmt_list and DW_AT_decl_file X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=25f238cdba11beee7e2417fcfb53b55f977909bd;p=thirdparty%2Felfutils.git dwarflint: Fix checking of DW_AT_stmt_list and DW_AT_decl_file * or rather fix first, implement other --- diff --git a/src/dwarflint/check_debug_info.cc b/src/dwarflint/check_debug_info.cc index 2f1ff8f35..fc3e8c1d0 100644 --- a/src/dwarflint/check_debug_info.cc +++ b/src/dwarflint/check_debug_info.cc @@ -401,7 +401,11 @@ namespace void check_lineptr (uint64_t value, struct value_check_cb_ctx const *ctx) { - ref_record_add (&ctx->cu->line_refs, value, ctx->where); + if (ctx->cu->stmt_list.addr != (uint64_t)-1) + wr_error (*ctx->where) + << "DW_AT_stmt_list mentioned twice in a CU." << std::endl; + ctx->cu->stmt_list.addr = value; + ctx->cu->stmt_list.who = *ctx->where; } /* Callback for locptr values. */ @@ -411,6 +415,12 @@ namespace ref_record_add (&ctx->cu->loc_refs, value, ctx->where); } + void + check_decl_file (uint64_t value, struct value_check_cb_ctx const *ctx) + { + ref_record_add (&ctx->cu->decl_file_refs, value, ctx->where); + } + /* Returns: -1 in case of error @@ -642,56 +652,67 @@ namespace }; } /* Setup rangeptr or lineptr checking. */ - else if (it->name == DW_AT_ranges - || it->name == DW_AT_stmt_list) - switch (form) + else + switch (it->name) { - case DW_FORM_data8: - if (cu->head->offset_size == 4) - // xxx could now also be checked during abbrev loading - wr_error (where) - << pri::attr (it->name) - << " with form DW_FORM_data8 in 32-bit CU." << std::endl; - /* fall-through */ - - case DW_FORM_data4: - case DW_FORM_sec_offset: - check_someptr = true; - if (it->name == DW_AT_ranges) - { - value_check_cb = check_rangeptr; - extra_mc = mc_ranges; - } - else - { - assert (it->name == DW_AT_stmt_list); - value_check_cb = check_lineptr; - extra_mc = mc_line; - } - break; + case DW_AT_ranges: + case DW_AT_stmt_list: + { + switch (form) + { + case DW_FORM_data8: + if (cu->head->offset_size == 4) + // xxx could now also be checked during abbrev loading + wr_error (where) + << pri::attr (it->name) + << " with form DW_FORM_data8 in 32-bit CU." + << std::endl; + /* fall-through */ + + case DW_FORM_data4: + case DW_FORM_sec_offset: + check_someptr = true; + if (it->name == DW_AT_ranges) + { + value_check_cb = check_rangeptr; + extra_mc = mc_ranges; + } + else + { + assert (it->name == DW_AT_stmt_list); + value_check_cb = check_lineptr; + extra_mc = mc_line; + } + break; + + default: + /* Only print error if it's indirect. Otherwise we + gave diagnostic during abbrev loading. */ + if (indirect) + wr_error (where) + << pri::attr (it->name) + << " with invalid (indirect) form \"" + << pri::form (form) << "\"." << std::endl; + } + break; - default: - /* Only print error if it's indirect. Otherwise we - gave diagnostic during abbrev loading. */ - if (indirect) - wr_error (where) - << pri::attr (it->name) - << " with invalid (indirect) form \"" << pri::form (form) - << "\"." << std::endl; + case DW_AT_low_pc: + relocatedp = &low_pc_relocated; + symbolp = &low_pc_symbol; + valuep = &low_pc; + break; + + case DW_AT_high_pc: + relocatedp = &high_pc_relocated; + symbolp = &high_pc_symbol; + valuep = &high_pc; + break; + + case DW_AT_decl_file: + value_check_cb = check_decl_file; + break; + } } - /* Setup low_pc and high_pc checking. */ - else if (it->name == DW_AT_low_pc) - { - relocatedp = &low_pc_relocated; - symbolp = &low_pc_symbol; - valuep = &low_pc; - } - else if (it->name == DW_AT_high_pc) - { - relocatedp = &high_pc_relocated; - symbolp = &high_pc_symbol; - valuep = &high_pc; - } /* Load attribute value and setup per-form checking. */ switch (form) @@ -1041,8 +1062,8 @@ check_debug_info::check_info_structural () cu cur; memset (&cur, 0, sizeof (cur)); cur.head = &head; - cur.low_pc = (uint64_t)-1; - //cur.next = (cu *)(uintptr_t)0xdead; + cur.low_pc = cur.stmt_list.addr = (uint64_t)-1; + cur.next = (cu *)(uintptr_t)0xdead; cus.push_back (cur); } cu &cur = cus.back (); @@ -1175,8 +1196,8 @@ check_debug_info::~check_debug_info () addr_record_free (&it->die_addrs); ref_record_free (&it->die_refs); ref_record_free (&it->range_refs); - ref_record_free (&it->line_refs); ref_record_free (&it->loc_refs); + ref_record_free (&it->decl_file_refs); } coverage_free (&cu_cov.cov); } diff --git a/src/dwarflint/check_debug_line.cc b/src/dwarflint/check_debug_line.cc index 284ba02af..8ff26584c 100644 --- a/src/dwarflint/check_debug_line.cc +++ b/src/dwarflint/check_debug_line.cc @@ -21,7 +21,6 @@ namespace bool used; }; typedef std::vector include_directories_t; - include_directories_t _m_include_directories; struct file_t { @@ -30,17 +29,17 @@ namespace bool used; }; typedef std::vector files_t; - files_t _m_files; public: explicit check_debug_line (dwarflint &lint); /* Directory index. */ - bool read_directory_index (read_ctx *ctx, + bool read_directory_index (include_directories_t &include_directories, + files_t &files, read_ctx *ctx, const char *name, uint64_t *ptr, where *where, bool &retval) { - size_t nfile = _m_files.size () + 1; + size_t nfile = files.size () + 1; if (!checked_read_uleb128 (ctx, ptr, where, "directory index")) return false; @@ -51,7 +50,7 @@ namespace << " has absolute pathname, but refers to directory != 0." << std::endl; - if (*ptr > _m_include_directories.size ()) + if (*ptr > include_directories.size ()) /* Not >=, dirs are indexed from 1. */ { wr_message (*where, cat (mc_impact_4, mc_line, mc_header)) @@ -63,22 +62,23 @@ namespace retval = false; } else if (*ptr != 0) - _m_include_directories[*ptr - 1].used = true; + include_directories[*ptr - 1].used = true; return true; } bool - use_file (uint64_t file_idx, where *where) + use_file (files_t &files, uint64_t file_idx, + where *where, char const *msg = "") { - if (file_idx == 0 || file_idx > _m_files.size ()) + if (file_idx == 0 || file_idx > files.size ()) { wr_error (*where) - << "DW_LNS_set_file: invalid file index " << file_idx << '.' - << std::endl; + << msg << "invalid file index " << file_idx << '.' + << std::endl; return false; } else - _m_files[file_idx - 1].used = true; + files[file_idx - 1].used = true; return true; } }; @@ -89,6 +89,8 @@ namespace check_debug_line::check_debug_line (dwarflint &lint) : _m_sec (lint.check (_m_sec)) { + check_debug_info *cus = lint.toplev_check (); + addr_record line_tables; WIPE (line_tables); @@ -219,6 +221,7 @@ check_debug_line::check_debug_line (dwarflint &lint) goto skip; } + include_directories_t include_directories; while (!read_ctx_eof (&sub_ctx)) { const char *name = read_ctx_read_str (&sub_ctx); @@ -226,17 +229,18 @@ check_debug_line::check_debug_line (dwarflint &lint) { wr_error (where) << "can't read name of include directory #" - << _m_include_directories.size () + 1 // Numbered from 1. + << include_directories.size () + 1 // Numbered from 1. << '.' << std::endl; goto skip; } if (*name == 0) break; - _m_include_directories.push_back ((include_directory_t){name, false}); + include_directories.push_back ((include_directory_t){name, false}); } /* File names. */ + files_t files; while (1) { const char *name = read_ctx_read_str (&sub_ctx); @@ -244,7 +248,7 @@ check_debug_line::check_debug_line (dwarflint &lint) { wr_error (where) << "can't read name of file #" - << _m_files.size () + 1 // Numbered from 1. + << files.size () + 1 // Numbered from 1. << '.' << std::endl; goto skip; } @@ -252,7 +256,8 @@ check_debug_line::check_debug_line (dwarflint &lint) break; uint64_t dir_idx; - if (!read_directory_index (&sub_ctx, name, &dir_idx, &where, success)) + if (!read_directory_index (include_directories, files, + &sub_ctx, name, &dir_idx, &where, success)) goto skip; /* Time of last modification. */ @@ -267,7 +272,30 @@ check_debug_line::check_debug_line (dwarflint &lint) &where, "file size of file entry")) goto skip; - _m_files.push_back ((struct file_t){name, dir_idx, false}); + files.push_back ((struct file_t){name, dir_idx, false}); + } + + /* Now that we have table of filenames, validate DW_AT_decl_file + references. We don't include filenames defined through + DW_LNE_define_file in consideration. */ + + if (cus != NULL) + { + bool found = false; + for (std::vector::const_iterator it = cus->cus.begin (); + it != cus->cus.end (); ++it) + if (it->stmt_list.addr == set_offset) + { + found = true; + for (size_t i = 0; i < it->decl_file_refs.size; ++i) + if (!use_file (files, + it->decl_file_refs.refs[i].addr, + &it->decl_file_refs.refs[i].who)) + success = false; + } + if (!found) + wr_message (where, mc_line) + << "no CU uses this line table." << std::endl; } /* Skip the rest of the header. */ @@ -336,7 +364,7 @@ check_debug_line::check_debug_line (dwarflint &lint) { uint64_t ctx_offset = read_ctx_get_offset (&sub_ctx); uint64_t addr; - if (!read_ctx_read_offset (&sub_ctx, addr_64, &addr)) + if (!read_ctx_read_offset (&sub_ctx, addr_64, &addr)) { wr_error (where) << "can't read operand of DW_LNE_set_address." @@ -368,10 +396,11 @@ check_debug_line::check_debug_line (dwarflint &lint) goto skip; } uint64_t dir_idx; - if (!read_directory_index (&sub_ctx, name, &dir_idx, - &where, success)) + if (!read_directory_index (include_directories, + files, &sub_ctx, name, + &dir_idx, &where, success)) goto skip; - _m_files.push_back + files.push_back ((struct file_t){name, dir_idx, false}); operands = 2; /* Skip mtime & size of the file. */ } @@ -436,7 +465,7 @@ check_debug_line::check_debug_line (dwarflint &lint) if (!checked_read_uleb128 (&sub_ctx, &file_idx, &where, "DW_LNS_set_file operand")) goto skip; - if (!use_file (file_idx, &where)) + if (!use_file (files, file_idx, &where, "DW_LNS_set_file: ")) success = false; first_file = false; } @@ -452,7 +481,7 @@ check_debug_line::check_debug_line (dwarflint &lint) if (opcode < opcode_base) operands = std_opc_lengths[opcode - 1]; - switch (opcode) + switch (opcode) { #define ONE_KNOWN_DW_LNS(NAME, CODE) case CODE: break; ALL_KNOWN_DW_LNS @@ -482,7 +511,8 @@ check_debug_line::check_debug_line (dwarflint &lint) if (first_file) { - if (!use_file (1, &where)) + if (!use_file (files, 1, &where, + "initial value of `file' register: ")) success = false; first_file = false; } @@ -491,20 +521,20 @@ check_debug_line::check_debug_line (dwarflint &lint) seen_opcode = true; } - for (size_t i = 0; i < _m_include_directories.size (); ++i) - if (!_m_include_directories[i].used) + for (size_t i = 0; i < include_directories.size (); ++i) + if (!include_directories[i].used) wr_message (where, cat (mc_impact_3, mc_acc_bloat, mc_line, mc_header)) << "the include #" << i + 1 - << " `" << _m_include_directories[i].name + << " `" << include_directories[i].name << "' is not used." << std::endl; - for (size_t i = 0; i < _m_files.size (); ++i) - if (!_m_files[i].used) + for (size_t i = 0; i < files.size (); ++i) + if (!files[i].used) wr_message (where, cat (mc_impact_3, mc_acc_bloat, mc_line, mc_header)) << "the file #" << i + 1 - << " `" << _m_files[i].name << "' is not used." << std::endl; + << " `" << files[i].name << "' is not used." << std::endl; if (!seen_opcode) wr_message (where, cat (mc_line, mc_acc_bloat, mc_impact_3)) @@ -543,13 +573,10 @@ check_debug_line::check_debug_line (dwarflint &lint) if (info != NULL) for (std::vector::iterator it = info->cus.begin (); it != info->cus.end (); ++it) - for (size_t i = 0; i < it->line_refs.size; ++i) - { - struct ref *ref = it->line_refs.refs + i; - if (!addr_record_has_addr (&line_tables, ref->addr)) - wr_error (ref->who) - << "unresolved reference to .debug_line table " - << pri::hex (ref->addr) << '.' << std::endl; - } + if (it->stmt_list.addr != (uint64_t)-1 + && !addr_record_has_addr (&line_tables, it->stmt_list.addr)) + wr_error (it->stmt_list.who) + << "unresolved reference to .debug_line table " + << pri::hex (it->stmt_list.addr) << '.' << std::endl; addr_record_free (&line_tables); } diff --git a/src/dwarflint/check_debug_loc_range.cc b/src/dwarflint/check_debug_loc_range.cc index 797bf1754..8759e0822 100644 --- a/src/dwarflint/check_debug_loc_range.cc +++ b/src/dwarflint/check_debug_loc_range.cc @@ -977,7 +977,7 @@ check_location_expression (elf_file const &file, << pri::locexpr_opcode (opcode) << " with operand " << pri::hex (value1) << " on a 32-bit machine." << std::endl; - }; + } } out: diff --git a/src/dwarflint/low.h b/src/dwarflint/low.h index c415310f4..27c336501 100644 --- a/src/dwarflint/low.h +++ b/src/dwarflint/low.h @@ -212,12 +212,13 @@ extern "C" struct cu_head const *head; uint64_t cudie_offset; uint64_t low_pc; // DW_AT_low_pc value of CU DIE, -1 if not present. + struct ref stmt_list; struct addr_record die_addrs; // Addresses where DIEs begin in this CU. struct ref_record die_refs; // DIE references into other CUs from this CU. struct ref_record loc_refs; // references into .debug_loc from this CU. struct ref_record range_refs; // references into .debug_ranges from this CU. - struct ref_record line_refs; // references into .debug_line from this CU. - bool has_arange; // Whether we saw arange section pointing to this CU. + struct ref_record decl_file_refs; // values of DW_AT_decl_file in this CU. + bool has_arange; // Whether we saw arange section pointing at this CU. bool has_pubnames; // Likewise for pubnames. bool has_pubtypes; // Likewise for pubtypes. };