From patchwork Tue Oct 23 21:28:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 29854 Received: (qmail 41928 invoked by alias); 23 Oct 2018 21:28:55 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 41911 invoked by uid 89); 23 Oct 2018 21:28:54 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.3 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=s12, S12, UD:infcmd.c, infcmdc X-HELO: mail-wr1-f68.google.com Received: from mail-wr1-f68.google.com (HELO mail-wr1-f68.google.com) (209.85.221.68) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 23 Oct 2018 21:28:51 +0000 Received: by mail-wr1-f68.google.com with SMTP id r10-v6so2358386wrv.6 for ; Tue, 23 Oct 2018 14:28:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=from:to:cc:subject:date:message-id; bh=84IdL8BrWIxj7QgqyvyU0s3FH2Ghih7j/xRcy3pmN/c=; b=Cd9aD/PHyTLpttMRVpDT6ihRx064yXV+QzApgYo6U0nLDB/iYdr2EcKjU4qQJGKegg 29WHsC2PYjTMBzeCmi6wYifY0Rwk8Xq9sYrhkXtfag7CyTiI/hHXz9r2GOVUFj5VRv5c kROJcrN/IN74+wrzp/Nq7oTFFoxq5pHxxI1MBEG+apfl0UT94dh5HVmFwpn1DvOJ/5Dl k6Gr+g7OKdofYCz9oHAI0si0VRJFGaYf7IFtPuKJEb+D8Fd4yKyLDs4aPdSa+7380uBz HYQ7f6axH3ZUqk7eFxyQOifXYIxJBLwJewk3Txzqe3LF4/F9bWZLSZGHAHviClKdlKLr kZdQ== Return-Path: Received: from localhost (host86-164-85-193.range86-164.btcentralplus.com. [86.164.85.193]) by smtp.gmail.com with ESMTPSA id l195-v6sm3819107wmd.37.2018.10.23.14.28.47 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 23 Oct 2018 14:28:48 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH] gdb: Handle ICC's unexpected void return type Date: Tue, 23 Oct 2018 22:28:43 +0100 Message-Id: <20181023212843.4774-1-andrew.burgess@embecosm.com> X-IsSubscribed: yes I encountered a binary compiled with Intel's C Compiler version 14.0.5.212, which seemed to contain some non-standard DWARF. The DWARF spec (V5 3.3.2) says: Debugging information entries for C void functions should not have an attribute for the return type. However, what I observed in the DWARF from this ICC compiled binary was this: ... <0><857>: Abbrev Number: 1 (DW_TAG_compile_unit) <858> DW_AT_comp_dir : (indirect string, offset: 0x48d): /tmp/ <85c> DW_AT_language : 1 (ANSI C) <85d> DW_AT_name : (indirect string, offset: 0x77c): filename.c <861> DW_AT_producer : (indirect string, offset: 0x520): Intel(R) C Intel(R) 64 Compiler ... <865> DW_AT_low_pc : 0x4378d0 <86d> DW_AT_high_pc : 0x4378f0 <875> DW_AT_stmt_list : 0xa37 ... <1><7ea>: Abbrev Number: 2 (DW_TAG_base_type) <7eb> DW_AT_byte_size : 0 <7ec> DW_AT_encoding : 5 (signed) <7ed> DW_AT_name : (indirect string, offset: 0x58f): void ... <1><7f1>: Abbrev Number: 3 (DW_TAG_subprogram) <7f2> DW_AT_decl_line : 268 <7f4> DW_AT_decl_column : 30 <7f5> DW_AT_decl_file : 1 <7f6> DW_AT_type : <0x7ea> <7fa> DW_AT_prototyped : 1 <7fb> DW_AT_name : (indirect string, offset: 0x761): function_foo <7ff> DW_AT_MIPS_linkage_name: (indirect string, offset: 0x761): function_foo <803> DW_AT_low_pc : 0x4378a0 <80b> DW_AT_high_pc : 0x4378d0 <813> DW_AT_external : 1 ... So function 'function_foo' has void return type, but still has a DW_AT_type attribute for a 0 sized, type called void. What was found was that when the 'finish' command was used to leave 'function_foo', GDB would crash. The problem is that in infcmd.c:print_return_value GDB tries to filter out void return types, by looking for the TYPE_CODE_VOID, this fails for the 'void' type as it has code TYPE_CODE_INT and GDB then tries to print the 'void' type. This eventually ends in a call to valprint.c:maybe_negate_by_bytes, however, the len (length) of the value being negated is 0, which is not detected or expected by this code, and invalid memory accesses occur, some of which might cause GDB to crash. The above DWARF was seen on version 14.0.5.212 of Intel's C compliler. I don't have access to any other versions in order to see when this issue might have appeared, or if it has been fixed. In this patch I have added an assertion to maybe_negate_by_bytes. This is nothing to do with the actual fix, but should detect incorrect use of this function in the future, without relying on undefined behaviour to crash GDB. We already have a predicate in the DWARF parser to detect versions of ICC prior to 14, however, this issue was spotted on a later veresion. As a result I've added a new predicate that is true for any version of ICC. Using the new predicate I convert synthetic void types into GDB's precreated void type. A test confirms that the issue is fixed. gdb/ChangeLog: * dwarf2read.c (struct dwarf2_cu): Add producer_is_icc field. (producer_is_icc): New function. (check_producer): Set producer_is_icc field on dwarf2_cu. (read_base_type): Spot ICC's unexpected void type, and convert to GDB's expected void type. (dwarf2_cu::dwarf2_cu): Initialise producer_is_icc field. * valprint.c (maybe_negate_by_bytes): Add an assertion that the LEN is greater than 0. gdb/testsuite/ChangeLog: * gdb.dwarf2/void-return-type.c: New file. * gdb.dwarf2/void-return-type.exp: New file. --- gdb/ChangeLog | 11 +++ gdb/dwarf2read.c | 26 ++++++- gdb/testsuite/ChangeLog | 5 ++ gdb/testsuite/gdb.dwarf2/void-return-type.c | 32 ++++++++ gdb/testsuite/gdb.dwarf2/void-return-type.exp | 103 ++++++++++++++++++++++++++ gdb/valprint.c | 1 + 6 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 gdb/testsuite/gdb.dwarf2/void-return-type.c create mode 100644 gdb/testsuite/gdb.dwarf2/void-return-type.exp diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 2a1b805c9a7..7d9026a59d7 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -551,6 +551,7 @@ struct dwarf2_cu unsigned int checked_producer : 1; unsigned int producer_is_gxx_lt_4_6 : 1; unsigned int producer_is_gcc_lt_4_3 : 1; + unsigned int producer_is_icc : 1; unsigned int producer_is_icc_lt_14 : 1; bool producer_is_codewarrior : 1; @@ -11368,6 +11369,19 @@ producer_is_icc_lt_14 (struct dwarf2_cu *cu) return cu->producer_is_icc_lt_14; } +/* ICC generates a DW_AT_type for C void functions. This was observed on + ICC 14.0.5.212, and appears to be against the DWARF spec (V5 3.3.2) + which says that void functions should not have a DW_AT_type. */ + +static int +producer_is_icc (struct dwarf2_cu *cu) +{ + if (!cu->checked_producer) + check_producer (cu); + + return cu->producer_is_icc; +} + /* Check for possibly missing DW_AT_comp_dir with relative .debug_line directory paths. GCC SVN r127613 (new option -fdebug-prefix-map) fixed this, it was first present in GCC release 4.3.0. */ @@ -14902,7 +14916,10 @@ check_producer (struct dwarf2_cu *cu) cu->producer_is_gcc_lt_4_3 = major < 4 || (major == 4 && minor < 3); } else if (producer_is_icc (cu->producer, &major, &minor)) - cu->producer_is_icc_lt_14 = major < 14; + { + cu->producer_is_icc = true; + cu->producer_is_icc_lt_14 = major < 14; + } else if (startswith (cu->producer, "CodeWarrior S12/L-ISA")) cu->producer_is_codewarrior = true; else @@ -17548,7 +17565,11 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu) type = dwarf2_init_float_type (objfile, bits, name, name); break; case DW_ATE_signed: - type = init_integer_type (objfile, bits, 0, name); + if (bits == 0 && producer_is_icc (cu) + && strcmp (name, "void") == 0) + type = objfile_type (objfile)->builtin_void; + else + type = init_integer_type (objfile, bits, 0, name); break; case DW_ATE_unsigned: if (cu->language == language_fortran @@ -25134,6 +25155,7 @@ dwarf2_cu::dwarf2_cu (struct dwarf2_per_cu_data *per_cu_) checked_producer (0), producer_is_gxx_lt_4_6 (0), producer_is_gcc_lt_4_3 (0), + producer_is_icc (0), producer_is_icc_lt_14 (0), producer_is_codewarrior (false), processing_has_namespace_info (0) diff --git a/gdb/testsuite/gdb.dwarf2/void-return-type.c b/gdb/testsuite/gdb.dwarf2/void-return-type.c new file mode 100644 index 00000000000..42a6d4a1a46 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/void-return-type.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +__attribute__((noinline)) void +func () +{ + asm ("func_label: .globl func_label"); + asm ("" ::: "memory"); + return; +} + +int +main () +{ + asm ("main_label: .globl main_label"); + func (); + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/void-return-type.exp b/gdb/testsuite/gdb.dwarf2/void-return-type.exp new file mode 100644 index 00000000000..ec93ebe764d --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/void-return-type.exp @@ -0,0 +1,103 @@ +# Copyright 2018 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This tests some non-standard DWARF spotted in an Intel C Compiler +# generated binary. +# +# The DWARF standard (V5 3.3.2) says that a void C function should not +# have a DW_AT_type attribute, however, an ICC compiled binary was +# found to have a DW_AT_type that referenced a signed integer type, of +# size 0, with the name 'void'. +# +# This 'void' integer type would cause GDB to crash in some cases, one +# that was seen was when using 'finish' to leave the void function. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +standard_testfile void-return-type.c void-return-type.S + +# Make some DWARF for the test. +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + global srcdir subdir srcfile + + set func_result [function_range func ${srcdir}/${subdir}/${srcfile}] + set func_start [lindex $func_result 0] + set func_length [lindex $func_result 1] + + set main_result [function_range main ${srcdir}/${subdir}/${srcfile}] + set main_start [lindex $main_result 0] + set main_length [lindex $main_result 1] + + cu {} { + DW_TAG_compile_unit { + {DW_AT_producer "Intel(R) C Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 14.0.5.212 Build 20150212"} + {DW_AT_language @DW_LANG_C} + {DW_AT_name void-return-type.c} + {DW_AT_comp_dir /tmp} + } { + declare_labels main_type func_type + + main_type: DW_TAG_base_type { + {DW_AT_byte_size 4 DW_FORM_sdata} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name int} + } + + func_type: DW_TAG_base_type { + {DW_AT_byte_size 0 DW_FORM_sdata} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name void} + } + + DW_TAG_subprogram { + {name func} + {low_pc $func_start addr} + {high_pc "$func_start + $func_length" addr} + {type :$func_type} + } + DW_TAG_subprogram { + {name main} + {low_pc $main_start addr} + {high_pc "$main_start + $main_length" addr} + {type :$main_type} + } + } + } +} + +if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +# Place a breakpoint in 'func' and continue to there. +gdb_breakpoint func +gdb_continue_to_breakpoint "func" + +# Now finish, returning to main. +gdb_test "finish" [multi_line \ + "Run till exit from #0 $hex in func \\\(\\\)" \ + "$hex in main \\\(\\\)"] \ + "check that finish completes" diff --git a/gdb/valprint.c b/gdb/valprint.c index 2b63a91e8df..b2236f89318 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -1604,6 +1604,7 @@ maybe_negate_by_bytes (const gdb_byte *bytes, unsigned len, gdb::byte_vector *out_vec) { gdb_byte sign_byte; + gdb_assert (len > 0); if (byte_order == BFD_ENDIAN_BIG) sign_byte = bytes[0]; else