From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 7110 invoked by alias); 1 Feb 2011 07:34:19 -0000 Received: (qmail 6777 invoked by uid 22791); 1 Feb 2011 07:34:17 -0000 X-SWARE-Spam-Status: No, hits=-0.8 required=5.0 tests=AWL,BAYES_00,TW_BJ,TW_JC X-Spam-Check-By: sourceware.org Received: from mail.apical.co.uk (HELO srv1.office.apical.co.uk) (213.106.251.44) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 01 Feb 2011 07:34:10 +0000 Received: from [10.250.148.115] (23.nat.acronis.net [91.195.22.23]) (authenticated bits=0) by srv1.office.apical.co.uk (8.14.4/8.14.4) with ESMTP id p117Y2Bv012611 (version=TLSv1/SSLv3 cipher=DHE-RSA-CAMELLIA256-SHA bits=256 verify=NO); Tue, 1 Feb 2011 07:34:02 GMT Message-ID: <4D47B430.4090108@sw.ru> Date: Tue, 01 Feb 2011 07:34:00 -0000 From: Vladimir Simonov User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9) Gecko/20100430 Fedora/3.0.4-2.fc11 Thunderbird/3.0.4 MIME-Version: 1.0 To: ppluzhnikov@google.com, Ian Lance Taylor CC: gdb-patches@sourceware.org Subject: gdb: Incorrect stack unwinding if debug info is compressed References: <1296238472.3009.ezmlm@sourceware.org> In-Reply-To: <1296238472.3009.ezmlm@sourceware.org> Content-Type: multipart/mixed; boundary="------------040200020206020807000108" X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-02/txt/msg00002.txt.bz2 This is a multi-part message in MIME format. --------------040200020206020807000108 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1870 Ian and Paul, Could you please comment below. Executable created with -Wl,compressed-debug-sections=zlib using gold linker or compress debug-info via objcopy. I see problems with local variables and backtraces in gdb. Something like this: gdb: bt .... #11 0xb2356a74 in Core::WorkerImpl::WorkerThread (this=Could not find the frame base for "Core::WorkerImpl::WorkerThread()". ) .... Debug info is kept in separate file linked to executable via --add-gnu-debuglink objcopy option. Environment: gdb-weekly-CVS-7.2.50.20110125, binutils 2.21, gcc 4.4.3, Linux, i686, 32 bit kernel 2.6.32. IMO the problem is in dwarf2_symbol_mark_computed function (dwarf2read.c). Check "DW_UNSND (attr) < dwarf2_per_objfile->loc.size" is incorrect if compressed section is used. In this case loc.size contains compressed section size, not decompressed one. As result large part of symbols are not passed above verification and are left with size==0 and data==NULL after dwarf2_symbol_mark_computed function. The problem observed if the section has not been read via dwarf2_read_section. But dwarf2_locate_sections has been done for the section. The patch introduces uncompressed_size field in struct dwarf2_section_info. And fill it in dwarf2_locate_sections. Check in dwarf2_symbol_mark_computed function takes into account uncompressed_size. Fields "size' and "uncompressed_size" meaning: - "size" - section/compressed section size between dwarf2_locate_sections and dwarf2_read_section calls. After dwarf2_read_section it is uncompressed section size. - "uncompressed_size" - always zero for uncompressed sections. For compressed sections it is uncompressed section size always. The patch is quite large cause I try to avoid code duplication with zlib_decompress section and have to do new field initialization properly. Any comments are welcome Best regards Vladimir Simonov --------------040200020206020807000108 Content-Type: text/plain; name="gdb-7.2-compressed-section.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="gdb-7.2-compressed-section.diff" Content-length: 9433 diff -ruN gdb-weekly-CVS-7.2.50.20110125/gdb/dwarf2read.c gdb-7.2/gdb/dwarf2read.c --- gdb-weekly-CVS-7.2.50.20110125/gdb/dwarf2read.c 2011-01-12 19:16:20.000000000 +0300 +++ ./gdb/dwarf2read.c 2011-01-31 18:03:37.072688100 +0300 @@ -136,6 +136,7 @@ int was_mmapped; /* True if we have tried to read this section. */ int readin; + bfd_size_type uncompressed_size; }; /* All offsets in the index are of this type. It must be @@ -1357,6 +1358,59 @@ && strcmp (section_name + 2, name) == 0))); } +static int +is_compressed_section_name (const char *section_name) +{ + return (section_name[0] == '.' && section_name[1] == 'z'); +} + +static int +parse_zlib_section_header (bfd_byte *compressed_buffer, bfd_size_type *size) +{ + bfd_size_type uncompressed_size; + + /* Read the zlib header. In this case, it should be "ZLIB" followed + by the uncompressed section size, 8 bytes in big-endian order. */ + if (strncmp (compressed_buffer, "ZLIB", 4) != 0) + return FALSE; + uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[11]; + *size = uncompressed_size; + return TRUE; +} + +static int +read_uncompressed_size (bfd *abfd, asection *sec, bfd_size_type *size) +{ + bfd_byte compressed_buffer [12]; + bfd_size_type uncompressed_size; + + if (sec->size < 12 || !bfd_get_section_contents (abfd, sec, + compressed_buffer, 0, 12)) + return FALSE; + return parse_zlib_section_header (compressed_buffer, size); +} + +static void +fill_dwarf2_section_info (struct dwarf2_section_info* info, + bfd *abfd, asection *sectp) +{ + bfd_size_type size; + + info->asection = sectp; + info->size = bfd_get_section_size (sectp); + info->uncompressed_size = 0; + if (!is_compressed_section_name (sectp->name)) + return; + read_uncompressed_size (abfd, sectp, &info->uncompressed_size); +} + /* This function is mapped across the sections and remembers the offset and size of each of the debugging sections we are interested in. */ @@ -1366,38 +1420,31 @@ { if (section_is_p (sectp->name, INFO_SECTION)) { - dwarf2_per_objfile->info.asection = sectp; - dwarf2_per_objfile->info.size = bfd_get_section_size (sectp); + fill_dwarf2_section_info(&dwarf2_per_objfile->info, abfd, sectp); } else if (section_is_p (sectp->name, ABBREV_SECTION)) { - dwarf2_per_objfile->abbrev.asection = sectp; - dwarf2_per_objfile->abbrev.size = bfd_get_section_size (sectp); + fill_dwarf2_section_info(&dwarf2_per_objfile->abbrev, abfd, sectp); } else if (section_is_p (sectp->name, LINE_SECTION)) { - dwarf2_per_objfile->line.asection = sectp; - dwarf2_per_objfile->line.size = bfd_get_section_size (sectp); + fill_dwarf2_section_info(&dwarf2_per_objfile->line, abfd, sectp); } else if (section_is_p (sectp->name, LOC_SECTION)) { - dwarf2_per_objfile->loc.asection = sectp; - dwarf2_per_objfile->loc.size = bfd_get_section_size (sectp); + fill_dwarf2_section_info(&dwarf2_per_objfile->loc, abfd, sectp); } else if (section_is_p (sectp->name, MACINFO_SECTION)) { - dwarf2_per_objfile->macinfo.asection = sectp; - dwarf2_per_objfile->macinfo.size = bfd_get_section_size (sectp); + fill_dwarf2_section_info(&dwarf2_per_objfile->macinfo, abfd, sectp); } else if (section_is_p (sectp->name, STR_SECTION)) { - dwarf2_per_objfile->str.asection = sectp; - dwarf2_per_objfile->str.size = bfd_get_section_size (sectp); + fill_dwarf2_section_info(&dwarf2_per_objfile->str, abfd, sectp); } else if (section_is_p (sectp->name, FRAME_SECTION)) { - dwarf2_per_objfile->frame.asection = sectp; - dwarf2_per_objfile->frame.size = bfd_get_section_size (sectp); + fill_dwarf2_section_info(&dwarf2_per_objfile->frame, abfd, sectp); } else if (section_is_p (sectp->name, EH_FRAME_SECTION)) { @@ -1405,24 +1452,20 @@ if (aflag & SEC_HAS_CONTENTS) { - dwarf2_per_objfile->eh_frame.asection = sectp; - dwarf2_per_objfile->eh_frame.size = bfd_get_section_size (sectp); + fill_dwarf2_section_info(&dwarf2_per_objfile->eh_frame, abfd, sectp); } } else if (section_is_p (sectp->name, RANGES_SECTION)) { - dwarf2_per_objfile->ranges.asection = sectp; - dwarf2_per_objfile->ranges.size = bfd_get_section_size (sectp); + fill_dwarf2_section_info(&dwarf2_per_objfile->ranges, abfd, sectp); } else if (section_is_p (sectp->name, TYPES_SECTION)) { - dwarf2_per_objfile->types.asection = sectp; - dwarf2_per_objfile->types.size = bfd_get_section_size (sectp); + fill_dwarf2_section_info(&dwarf2_per_objfile->types, abfd, sectp); } else if (section_is_p (sectp->name, GDB_INDEX_SECTION)) { - dwarf2_per_objfile->gdb_index.asection = sectp; - dwarf2_per_objfile->gdb_index.size = bfd_get_section_size (sectp); + fill_dwarf2_section_info(&dwarf2_per_objfile->gdb_index, abfd, sectp); } if ((bfd_get_section_flags (abfd, sectp) & SEC_LOAD) @@ -1435,7 +1478,7 @@ static void zlib_decompress_section (struct objfile *objfile, asection *sectp, - gdb_byte **outbuf, bfd_size_type *outsize) + gdb_byte **outbuf) { bfd *abfd = objfile->obfd; #ifndef HAVE_ZLIB_H @@ -1452,26 +1495,19 @@ int rc; int header_size = 12; + if (compressed_size < header_size) + error (_("Dwarf Error: Too small DWARF ZLIB header from '%s'"), + bfd_get_filename (abfd)); + if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 || bfd_bread (compressed_buffer, compressed_size, abfd) != compressed_size) error (_("Dwarf Error: Can't read DWARF data from '%s'"), bfd_get_filename (abfd)); - /* Read the zlib header. In this case, it should be "ZLIB" followed - by the uncompressed section size, 8 bytes in big-endian order. */ - if (compressed_size < header_size - || strncmp (compressed_buffer, "ZLIB", 4) != 0) + if (!parse_zlib_section_header (compressed_buffer, &uncompressed_size)) error (_("Dwarf Error: Corrupt DWARF ZLIB header from '%s'"), bfd_get_filename (abfd)); - uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[11]; /* It is possible the section consists of several compressed buffers concatenated together, so we uncompress in a loop. */ @@ -1505,7 +1541,6 @@ do_cleanups (cleanup); *outbuf = uncompressed_buffer; - *outsize = uncompressed_size; #endif } @@ -1519,29 +1554,23 @@ bfd *abfd = objfile->obfd; asection *sectp = info->asection; gdb_byte *buf, *retbuf; - unsigned char header[4]; if (info->readin) return; info->buffer = NULL; info->was_mmapped = 0; info->readin = 1; + info->uncompressed_size = 0; if (info->asection == NULL || info->size == 0) return; - /* Check if the file has a 4-byte header indicating compression. */ - if (info->size > sizeof (header) - && bfd_seek (abfd, sectp->filepos, SEEK_SET) == 0 - && bfd_bread (header, sizeof (header), abfd) == sizeof (header)) + /* Check if the file has a 12-byte header indicating compression. */ + if (read_uncompressed_size (abfd, sectp, &info->uncompressed_size)) { - /* Upon decompression, update the buffer and its size. */ - if (strncmp (header, "ZLIB", sizeof (header)) == 0) - { - zlib_decompress_section (objfile, sectp, &info->buffer, - &info->size); - return; - } + zlib_decompress_section (objfile, sectp, &info->buffer); + info->size = info->uncompressed_size; + return; } #ifdef HAVE_MMAP @@ -14356,6 +14385,14 @@ baton->base_address = cu->base_address; } +static int +check_attr_location (struct dwarf2_section_info *info, struct attribute *attr) +{ + if (info->uncompressed_size) + return DW_UNSND (attr) < info->uncompressed_size; + return DW_UNSND (attr) < info->size; +} + static void dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu) @@ -14364,7 +14401,7 @@ /* ".debug_loc" may not exist at all, or the offset may be outside the section. If so, fall through to the complaint in the other branch. */ - && DW_UNSND (attr) < dwarf2_per_objfile->loc.size) + && check_attr_location (&dwarf2_per_objfile->loc, attr)) { struct dwarf2_loclist_baton *baton; --------------040200020206020807000108--