From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gnu.wildebeest.org (wildebeest.demon.nl [212.238.236.112]) by sourceware.org (Postfix) with ESMTPS id 1A3CF3857C5B for ; Mon, 12 Oct 2020 19:07:32 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 1A3CF3857C5B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=klomp.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mark@klomp.org Received: from tarox.wildebeest.org (tarox.wildebeest.org [172.31.17.39]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id CDB103000661; Mon, 12 Oct 2020 21:07:30 +0200 (CEST) Received: by tarox.wildebeest.org (Postfix, from userid 1000) id C72C64000CA2; Mon, 12 Oct 2020 21:07:30 +0200 (CEST) From: Mark Wielaard To: dwz@sourceware.org Cc: Mark Wielaard Subject: [PATCH 2/2] Write DWARF5 multifile .debug_line if possible. Date: Mon, 12 Oct 2020 21:06:49 +0200 Message-Id: <20201012190649.17808-2-mark@klomp.org> X-Mailer: git-send-email 2.18.4 In-Reply-To: <20201012190649.17808-1-mark@klomp.org> References: <20201012190649.17808-1-mark@klomp.org> X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: dwz@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Dwz mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Oct 2020 19:07:33 -0000 This write version 5 .debug_line into the multifile if all .debug_line segments seen before are also version 5. This is more efficient than version 2, if we don't have to write out the time and size of the files. But only if there are more than ~25 files because the header is bigger and there is some overhead for having to handle zero entry dir and file entries (those do have to exist, but are not directly referenced by anything). ChangeLog: * dwz.c (lowest_line_version): New static unsigned int, set to 5 initially. (read_debug_line): Check version and set lowest_line_version. (struct line_stats): New. (list_line_entries): Update data as struct line_stats. (write_multifile_line): Collect time and size stats and write out version 5 .debug_line data if lowest_line_version is 5. --- dwz.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 129 insertions(+), 16 deletions(-) diff --git a/dwz.c b/dwz.c index 9345e6c..e517a47 100644 --- a/dwz.c +++ b/dwz.c @@ -484,6 +484,12 @@ typedef struct with a single pointer size are handled. */ static int ptr_size; +/* Lowest debug_line version we have seen. When writing out the multi + file .debug_line we'll only use a DWARF5 version when there is no + lower line table seen (since the debug_line dir and file table is + shared between all CUs). */ +static unsigned int lowest_line_version = 5; + /* Utility functions and macros for reading/writing values in given ELF endianity, which might be different from host endianity. No specific alignment is expected. */ @@ -1503,6 +1509,9 @@ read_debug_line (DSO *dso, dw_cu_ref cu, uint32_t off) } version = value; + if (version < lowest_line_version) + lowest_line_version = version; + if (version >= 5) { int addr_size, seg_size; @@ -14371,18 +14380,34 @@ write_multifile_strp (void) return ret; } -/* Helper to record all strp_entry entries from strp_htab. +/* Hold some statistics on the line entries so we know whether to emit + time and/or sizes. Used by list_line_entries used by + write_multifile_line. */ +struct line_stats +{ + struct line_entry ***end; + bool has_time; + bool has_size; +}; + +/* Helper to find the end of the line_htab entries and other stats. Called through htab_traverse. */ static int list_line_entries (void **slot, void *data) { - struct line_entry ***end = (struct line_entry ***) data; - **end = (struct line_entry *) *slot; + struct line_stats *stats = (struct line_stats *) data; + struct line_entry *entry = (struct line_entry *) *slot; + struct line_entry ***end = stats->end; + **end = entry; (*end)++; + if (entry->file->time != 0) + stats->has_time = true; + if (entry->file->size != 0) + stats->has_size = true; return 1; } -/* Helper function for write_multifile_strp to sort strp_entry +/* Helper function for write_multifile_strp to sort line_entry by increasing new_id. */ static int line_id_cmp (const void *p, const void *q) @@ -14405,13 +14430,15 @@ static int write_multifile_line (void) { unsigned int filecnt = 0, dircnt = 0, filetbllen = 0, dirtbllen = 0; - unsigned int len, i, j; + unsigned int header_len, len, i, j; unsigned char *line, *ptr; struct line_entry **filearr = NULL; + struct line_stats line_stats; unsigned int *diridx = NULL, *dirarr = NULL; unsigned char buf[17]; int ret = 0; + line_stats.has_time = line_stats.has_size = false; if (line_htab) { struct line_entry **end; @@ -14419,7 +14446,8 @@ write_multifile_line (void) filearr = (struct line_entry **) obstack_alloc (&ob, filecnt * sizeof (*filearr)); end = filearr; - htab_traverse (line_htab, list_line_entries, (void *) &end); + line_stats.end = &end; + htab_traverse (line_htab, list_line_entries, (void *) &line_stats); assert (filearr + filecnt == end); diridx = (unsigned int *) obstack_alloc (&ob, filecnt * sizeof (*diridx)); @@ -14476,13 +14504,45 @@ write_multifile_line (void) } filetbllen += strlen (file) + 1; filetbllen += size_of_uleb128 (diridx[i]); - filetbllen += size_of_uleb128 (filearr[i]->file->time); - filetbllen += size_of_uleb128 (filearr[i]->file->size); + if (lowest_line_version < 5 || line_stats.has_time) + filetbllen += size_of_uleb128 (filearr[i]->file->time); + if (lowest_line_version < 5 || line_stats.has_size) + filetbllen += size_of_uleb128 (filearr[i]->file->size); } dirarr = (unsigned int *) obstack_finish (&ob); } - len = 17 + filetbllen + dirtbllen; + /* standard .debug_line "header" length (both version 2 and 5): + unit_length (4) + version (2) + header_length (4) + + min_instr_length (1) + default_is_stmt (1) + line_base (1) + + line_range (1) + opcode_base (1) = 15 + + version 2 adds 2 bytes, one zero byte to terminate dir and file lists. + + version 5 adds at least 11 bytes, max_ops_per_instr (1) + + address_size (1) + segment_size (1) + dir_entry_format_cnt (1) + + format_pair (2), file_entry_format_cnt (1) + file_format_pairs + (4). Plus dircnt (uleb128) + format_pair (2) if has_time + + format_pair (2) if has_size) + filecnt (uleb128). + + version 5 also has 2 extra 6 byte "" string entries for dir + and file entry zero, plus one for the zero file entry dir idx. + */ + header_len = 15; + if (lowest_line_version < 5) + header_len += 2; + else + { + header_len += 11; + header_len += size_of_uleb128 (dircnt + 1); + header_len += size_of_uleb128 (filecnt + 1); + if (line_stats.has_time) + header_len += 2; + if (line_stats.has_size) + header_len += 2; + header_len += 2 * 6 + 1; + } + len = header_len + filetbllen + dirtbllen; if (unlikely (op_multifile)) { debug_sections[DEBUG_LINE].new_size = len; @@ -14500,20 +14560,41 @@ write_multifile_line (void) return 1; } - if (len == 17) + if (len == header_len) line = buf; else line = (unsigned char *) obstack_alloc (&ob, len); } ptr = line; write_32 (ptr, len - 4); /* Total length. */ - write_16 (ptr, 2); /* DWARF version. */ - write_32 (ptr, len - 10); /* Header length. */ + if (lowest_line_version < 5) + write_16 (ptr, 2); /* DWARF version. */ + else + { + write_16 (ptr, 5); /* DWARF version. */ + write_8 (ptr, multi_ptr_size); /* Address size. */ + write_8 (ptr, 0); /* Segment size. */ + } + write_32 (ptr, /* Header length. */ + len - (lowest_line_version < 5 ? 10 : 12)); write_8 (ptr, 1); /* Minimum insn length. */ + if (lowest_line_version >= 5) + write_8 (ptr, 1); /* Maximum ops per instr. */ write_8 (ptr, 1); /* Default is_stmt. */ write_8 (ptr, 0); /* Line base. */ write_8 (ptr, 1); /* Line range. */ write_8 (ptr, 1); /* Opcode base. */ + + if (lowest_line_version >= 5) + { + write_8 (ptr, 1); /* Dir entry format count. */ + write_uleb128 (ptr, DW_LNCT_path); + write_uleb128 (ptr, DW_FORM_string); + write_uleb128 (ptr, dircnt + 1); /* Dir cnt. */ + memcpy (ptr, "", 6); /* Zero entry empty dir path. */ + ptr += 6; + } + for (i = 0; i < dircnt; i++) { unsigned int l; @@ -14535,7 +14616,36 @@ write_multifile_line (void) } ptr += l; } - write_8 (ptr, 0); /* Terminate dir table. */ + if (lowest_line_version < 5) + write_8 (ptr, 0); /* Terminate dir table. */ + else + { + unsigned int format_cnt = 2 + line_stats.has_size + line_stats.has_time; + write_8 (ptr, format_cnt); /* File entry format count. */ + write_uleb128 (ptr, DW_LNCT_path); + write_uleb128 (ptr, DW_FORM_string); + write_uleb128 (ptr, DW_LNCT_directory_index); + write_uleb128 (ptr, DW_FORM_udata); + if (line_stats.has_time) + { + write_uleb128 (ptr, DW_LNCT_timestamp); + write_uleb128 (ptr, DW_FORM_udata); + } + if (line_stats.has_size) + { + write_uleb128 (ptr, DW_LNCT_size); + write_uleb128 (ptr, DW_FORM_udata); + } + write_uleb128 (ptr, filecnt + 1); /* File names cnt. */ + memcpy (ptr, "", 6); /* Zero entry empty file path. */ + ptr += 6; + write_8 (ptr, 0); /* Zero entry zero diridx. */ + if (line_stats.has_time) + write_8 (ptr, 0); + if (line_stats.has_size) + write_8 (ptr, 0); + } + for (i = 0; i < filecnt; i++) { const char *file = filearr[i]->file->file; @@ -14546,10 +14656,13 @@ write_multifile_line (void) memcpy (ptr, file, l); ptr += l; write_uleb128 (ptr, diridx[i]); - write_uleb128 (ptr, filearr[i]->file->time); - write_uleb128 (ptr, filearr[i]->file->size); + if (lowest_line_version < 5 || line_stats.has_time) + write_uleb128 (ptr, filearr[i]->file->time); + if (lowest_line_version < 5 || line_stats.has_size) + write_uleb128 (ptr, filearr[i]->file->size); } - write_8 (ptr, 0); /* Terminate file table. */ + if (lowest_line_version < 5) + write_8 (ptr, 0); /* Terminate file table. */ assert (ptr == line + len); if (likely (!op_multifile)) -- 2.18.4