From patchwork Tue Aug 11 01:05:36 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 8128 Received: (qmail 107062 invoked by alias); 11 Aug 2015 01:05:41 -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 107023 invoked by uid 89); 11 Aug 2015 01:05:41 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.7 required=5.0 tests=AWL, BAYES_20, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD, SPF_PASS, UNSUBSCRIBE_BODY autolearn=no version=3.3.2 X-HELO: mail-pd0-f201.google.com Received: from mail-pd0-f201.google.com (HELO mail-pd0-f201.google.com) (209.85.192.201) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Tue, 11 Aug 2015 01:05:38 +0000 Received: by pdav4 with SMTP id v4so15767804pda.0 for ; Mon, 10 Aug 2015 18:05:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:message-id:date:subject:from:to :content-type; bh=LeYpJ6NjKBz9c2iEyBV50W09qvaaeRL1IuQsU2gxLz4=; b=SzDofZG+Tn5XX8XF3IKSlRXPQYzaiXZpdtDnwrMcUtxnDy4FLDVA/6yH0+aK8dElFU y3PZ2Z8srBwDK0hIPc9MQEiicPMRa7p6bnZsWBing6K8dOvs2pQUxtXVdiG1oGcFTrWi fs6sQM0P4wS1+JQzVivMnw+IgEAHzQrJyKY9CjkX5iLpBBs2klp29I8ZFs4QqGW9yMBQ vv97KJ3VofzEo2dL/kAjt4wDiIbqpe4FyNXaHCaOz9U3b0aK2gy/UdpPo1uz8oJCZNcc ObUkVe5T49ohlkWS4AqHW6FflebhZv14nt1yFqkwrw4OqqCIJNuC5vUfZDHCLkaISPtH SoPg== X-Gm-Message-State: ALoCoQlZYLkI3jSrTbNmc2rMHYOvb9pPe+WC4XBcbZVx5zxKN3nO/4FrTFvEiwAVUxIG2+oA4y1td6ZCXtvhE7gBFVFgMZn32rIGVKvQs1KVUwtw6kijwAErRtneBflRgp2z7ys1BsKtJLGyJiJigyQ0/5QLt9gQyh0hpXgk1lqXB97YL4Hp8CQ= MIME-Version: 1.0 X-Received: by 10.66.139.38 with SMTP id qv6mr7336031pab.22.1439255136920; Mon, 10 Aug 2015 18:05:36 -0700 (PDT) Message-ID: <001a11331a8c2dbe71051cfeb348@google.com> Date: Tue, 11 Aug 2015 01:05:36 +0000 Subject: [PATCH] [PR symtab/17391] gdb internal error: assertion fails in regcache.c:178 From: Doug Evans To: gdb-patches@sourceware.org X-IsSubscribed: yes Hi. This patch, I hope, addresses PR 17391. I couldn't recreate 17391 but there is clearly a lack of robustness here: gdbarch_dwarf2_reg_to_regnum can return -1 but not all callers watch for that. Some callers do watch for it but call error themselves. There is already dwarf2_reg_to_regnum_or_error so this patch just changes appropriate callers of gdbarch_dwarf2_reg_to_regnum to use it. Sometimes a register number is stored as a ULONGEST, so I changed dwarf2_reg_to_regnum_or_error to take one. Regression tested on amd64-linux. 2015-08-10 Doug Evans PR symtab/17391 * dwarf2-frame.c (read_addr_from_reg): Call dwarf2_reg_to_regnum_or_error instead of gdbarch_dwarf2_reg_to_regnum. (get_reg_value): Ditto. (dwarf2_fetch_cfa_info): Ditto. (dwarf2_frame_prev_register): Ditto. * dwarf2loc.c (dwarf_expr_read_addr_from_reg): Ditto. (dwarf_expr_get_reg_value): Ditto. (read_pieced_value): Ditto. (write_pieced_value): Ditto. (dwarf2_evaluate_loc_desc_full): Ditto. (dwarf2_reg_to_regnum_or_error): Change to take a ULONGEST regnum. (locexpr_regname): Improve text of bad register number. * dwarf2loc.h (dwarf2_reg_to_regnum_or_error): Update prototype. testsuite/ * lib/gdb.exp (_location): Add support for DW_OP_regx. * gdb.dwarf2/bad-regnum.c: New file. * gdb.dwarf2/bad-regnum.exp: New file. diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index 8fb2ac7..eb9f09c 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -292,7 +292,7 @@ read_addr_from_reg (void *baton, int reg) { struct frame_info *this_frame = (struct frame_info *) baton; struct gdbarch *gdbarch = get_frame_arch (this_frame); - int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg); + int regnum = dwarf2_reg_to_regnum_or_error (gdbarch, reg); return address_from_register (regnum, this_frame); } @@ -304,7 +304,7 @@ get_reg_value (void *baton, struct type *type, int reg) { struct frame_info *this_frame = (struct frame_info *) baton; struct gdbarch *gdbarch = get_frame_arch (this_frame); - int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg); + int regnum = dwarf2_reg_to_regnum_or_error (gdbarch, reg); return value_from_register (type, regnum, this_frame); } @@ -936,11 +936,7 @@ dwarf2_fetch_cfa_info (struct gdbarch *gdbarch, CORE_ADDR pc, { case CFA_REG_OFFSET: { - int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, fs.regs.cfa_reg); - - if (regnum == -1) - error (_("Unable to access DWARF register number %d"), - (int) fs.regs.cfa_reg); /* FIXME */ + int regnum = dwarf2_reg_to_regnum_or_error (gdbarch, fs.regs.cfa_reg); *regnum_out = regnum; if (fs.armcc_cfa_offsets_reversed) @@ -1324,8 +1320,8 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, return frame_unwind_got_memory (this_frame, regnum, addr); case DWARF2_FRAME_REG_SAVED_REG: - realnum - = gdbarch_dwarf2_reg_to_regnum (gdbarch, cache->reg[regnum].loc.reg); + realnum = dwarf2_reg_to_regnum_or_error + (gdbarch, cache->reg[regnum].loc.reg); return frame_unwind_got_register (this_frame, regnum, realnum); case DWARF2_FRAME_REG_SAVED_EXP: @@ -1368,7 +1364,7 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, case DWARF2_FRAME_REG_RA_OFFSET: addr = cache->reg[regnum].loc.offset; - regnum = gdbarch_dwarf2_reg_to_regnum + regnum = dwarf2_reg_to_regnum_or_error (gdbarch, cache->retaddr_reg.loc.reg); addr += get_frame_register_unsigned (this_frame, regnum); return frame_unwind_got_address (this_frame, regnum, addr); diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index d8e432e..b8f172d 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -312,7 +312,7 @@ dwarf_expr_read_addr_from_reg (void *baton, int dwarf_regnum) { struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; struct gdbarch *gdbarch = get_frame_arch (debaton->frame); - int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf_regnum); + int regnum = dwarf2_reg_to_regnum_or_error (gdbarch, dwarf_regnum); return address_from_register (regnum, debaton->frame); } @@ -324,7 +324,7 @@ dwarf_expr_get_reg_value (void *baton, struct type *type, int dwarf_regnum) { struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; struct gdbarch *gdbarch = get_frame_arch (debaton->frame); - int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf_regnum); + int regnum = dwarf2_reg_to_regnum_or_error (gdbarch, dwarf_regnum); return value_from_register (type, regnum, debaton->frame); } @@ -1682,40 +1682,31 @@ read_pieced_value (struct value *v) case DWARF_VALUE_REGISTER: { struct gdbarch *arch = get_frame_arch (frame); - int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->v.regno); + int gdb_regnum = dwarf2_reg_to_regnum_or_error (arch, p->v.regno); + int optim, unavail; + int reg_offset = source_offset; - if (gdb_regnum != -1) + if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG + && this_size < register_size (arch, gdb_regnum)) { - int optim, unavail; - int reg_offset = source_offset; - - if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG - && this_size < register_size (arch, gdb_regnum)) - { - /* Big-endian, and we want less than full size. */ - reg_offset = register_size (arch, gdb_regnum) - this_size; - /* We want the lower-order THIS_SIZE_BITS of the bytes - we extract from the register. */ - source_offset_bits += 8 * this_size - this_size_bits; - } - - if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset, - this_size, buffer, - &optim, &unavail)) - { - /* Just so garbage doesn't ever shine through. */ - memset (buffer, 0, this_size); - - if (optim) - mark_value_bits_optimized_out (v, offset, this_size_bits); - if (unavail) - mark_value_bits_unavailable (v, offset, this_size_bits); - } + /* Big-endian, and we want less than full size. */ + reg_offset = register_size (arch, gdb_regnum) - this_size; + /* We want the lower-order THIS_SIZE_BITS of the bytes + we extract from the register. */ + source_offset_bits += 8 * this_size - this_size_bits; } - else + + if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset, + this_size, buffer, + &optim, &unavail)) { - error (_("Unable to access DWARF register number %s"), - paddress (arch, p->v.regno)); + /* Just so garbage doesn't ever shine through. */ + memset (buffer, 0, this_size); + + if (optim) + mark_value_bits_optimized_out (v, offset, this_size_bits); + if (unavail) + mark_value_bits_unavailable (v, offset, this_size_bits); } } break; @@ -1874,52 +1865,43 @@ write_pieced_value (struct value *to, struct value *from) case DWARF_VALUE_REGISTER: { struct gdbarch *arch = get_frame_arch (frame); - int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->v.regno); + int gdb_regnum = dwarf2_reg_to_regnum_or_error (arch, p->v.regno); + int reg_offset = dest_offset; - if (gdb_regnum != -1) + if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG + && this_size <= register_size (arch, gdb_regnum)) { - int reg_offset = dest_offset; + /* Big-endian, and we want less than full size. */ + reg_offset = register_size (arch, gdb_regnum) - this_size; + } - if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG - && this_size <= register_size (arch, gdb_regnum)) - { - /* Big-endian, and we want less than full size. */ - reg_offset = register_size (arch, gdb_regnum) - this_size; - } + if (need_bitwise) + { + int optim, unavail; - if (need_bitwise) + if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset, + this_size, buffer, + &optim, &unavail)) { - int optim, unavail; - - if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset, - this_size, buffer, - &optim, &unavail)) - { - if (optim) - throw_error (OPTIMIZED_OUT_ERROR, - _("Can't do read-modify-write to " - "update bitfield; containing word " - "has been optimized out")); - if (unavail) - throw_error (NOT_AVAILABLE_ERROR, - _("Can't do read-modify-write to update " - "bitfield; containing word " - "is unavailable")); - } - copy_bitwise (buffer, dest_offset_bits, - contents, source_offset_bits, - this_size_bits, - bits_big_endian); + if (optim) + throw_error (OPTIMIZED_OUT_ERROR, + _("Can't do read-modify-write to " + "update bitfield; containing word " + "has been optimized out")); + if (unavail) + throw_error (NOT_AVAILABLE_ERROR, + _("Can't do read-modify-write to update " + "bitfield; containing word " + "is unavailable")); } - - put_frame_register_bytes (frame, gdb_regnum, reg_offset, - this_size, source_buffer); - } - else - { - error (_("Unable to write to DWARF register number %s"), - paddress (arch, p->v.regno)); + copy_bitwise (buffer, dest_offset_bits, + contents, source_offset_bits, + this_size_bits, + bits_big_endian); } + + put_frame_register_bytes (frame, gdb_regnum, reg_offset, + this_size, source_buffer); } break; case DWARF_VALUE_MEMORY: @@ -2260,30 +2242,28 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, struct gdbarch *arch = get_frame_arch (frame); int dwarf_regnum = longest_to_int (value_as_long (dwarf_expr_fetch (ctx, 0))); - int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_regnum); + int gdb_regnum = dwarf2_reg_to_regnum_or_error + (arch, dwarf_regnum); if (byte_offset != 0) error (_("cannot use offset on synthetic pointer to register")); do_cleanups (value_chain); - if (gdb_regnum == -1) - error (_("Unable to access DWARF register number %d"), - dwarf_regnum); - retval = value_from_register (type, gdb_regnum, frame); - if (value_optimized_out (retval)) - { - struct value *tmp; - - /* This means the register has undefined value / was - not saved. As we're computing the location of some - variable etc. in the program, not a value for - inspecting a register ($pc, $sp, etc.), return a - generic optimized out value instead, so that we show - instead of . */ - do_cleanups (value_chain); - tmp = allocate_value (type); - value_contents_copy (tmp, 0, retval, 0, TYPE_LENGTH (type)); - retval = tmp; - } + retval = value_from_register (type, gdb_regnum, frame); + if (value_optimized_out (retval)) + { + struct value *tmp; + + /* This means the register has undefined value / was + not saved. As we're computing the location of some + variable etc. in the program, not a value for + inspecting a register ($pc, $sp, etc.), return a + generic optimized out value instead, so that we show + instead of . */ + do_cleanups (value_chain); + tmp = allocate_value (type); + value_contents_copy (tmp, 0, retval, 0, TYPE_LENGTH (type)); + retval = tmp; + } } break; @@ -2777,11 +2757,17 @@ unimplemented (unsigned int op) /* See dwarf2loc.h. */ int -dwarf2_reg_to_regnum_or_error (struct gdbarch *arch, int dwarf_reg) +dwarf2_reg_to_regnum_or_error (struct gdbarch *arch, ULONGEST dwarf_reg) { - int reg = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_reg); + int reg; + + if (dwarf_reg > INT_MAX) + error (_("Unable to access DWARF register number %s"), + pulongest (dwarf_reg)); + reg = gdbarch_dwarf2_reg_to_regnum (arch, (int) dwarf_reg); if (reg == -1) - error (_("Unable to access DWARF register number %d"), dwarf_reg); + error (_("Unable to access DWARF register number %s"), + pulongest (dwarf_reg)); return reg; } @@ -3572,7 +3558,17 @@ locexpr_regname (struct gdbarch *gdbarch, int dwarf_regnum) { int regnum; + /* This doesn't use gdbarch_dwarf2_reg_to_regnum_or_error on purpose. + We'd rather print *something* here than throw an error. */ regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf_regnum); + /* gdbarch_register_name may just return "", return something more + descriptive for bad register numbers. */ + if (regnum == -1) + { + /* The text is output as "$bad_register_number". + That is why we use the underscores. */ + return _("bad_register_number"); + } return gdbarch_register_name (gdbarch, regnum); } diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h index f3630ac..41916eb 100644 --- a/gdb/dwarf2loc.h +++ b/gdb/dwarf2loc.h @@ -287,8 +287,12 @@ extern struct call_site_chain *call_site_find_chain (struct gdbarch *gdbarch, ARCH is the architecture. DWARF_REG is the register. This will throw an exception if the DWARF register cannot be - translated to an architecture register. */ + translated to an architecture register. + This takes a ULONGEST instead of an int because some callers actually have + a ULONGEST. Negative values passed as ints will still be flagged as + invalid. */ -extern int dwarf2_reg_to_regnum_or_error (struct gdbarch *arch, int dwarf_reg); +extern int dwarf2_reg_to_regnum_or_error (struct gdbarch *arch, + ULONGEST dwarf_reg); #endif /* dwarf2loc.h */ diff --git a/gdb/testsuite/gdb.dwarf2/bad-regnum.c b/gdb/testsuite/gdb.dwarf2/bad-regnum.c new file mode 100644 index 0000000..35230f2 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/bad-regnum.c @@ -0,0 +1,22 @@ +/* Copyright 2015 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 . */ + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/bad-regnum.exp b/gdb/testsuite/gdb.dwarf2/bad-regnum.exp new file mode 100644 index 0000000..7356adb --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/bad-regnum.exp @@ -0,0 +1,64 @@ +# Copyright 2015 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 . + +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 bad-regnum.c bad-regnum-dw.S + +# Make some DWARF for the test. +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + cu {} { + DW_TAG_compile_unit { + {DW_AT_language @DW_LANG_C} + {DW_AT_name bad-regnum-dw.c} + {DW_AT_comp_dir /tmp} + } { + declare_labels integer_label + + integer_label: DW_TAG_base_type { + {DW_AT_byte_size 4 DW_FORM_sdata} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name integer} + } + + DW_TAG_variable { + {DW_AT_name foo} + {DW_AT_type :$integer_label} + {DW_AT_location { + DW_OP_regx 2147483647 + } SPECIAL_expr} + {external 1 flag} + } + } + } +} + +if { [prepare_for_testing ${testfile}.exp ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +gdb_test "info addr foo" \ + "Symbol \"foo\" is warning: Unmapped DWARF Register #2147483647 encountered.\[\r\n\]+a variable in \\\$bad_register_number." diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index 515334e..df7a36d 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -836,6 +836,10 @@ namespace eval Dwarf { _op .${_cu_addr_size}byte [lindex $line 1] } + DW_OP_regx { + _op .uleb128 [lindex $line 1] + } + DW_OP_pick - DW_OP_const1u - DW_OP_const1s {