public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* Re: [PATCH] Fission support for multiple CUs per DWO file
@ 2017-05-22 18:01 Doug Evans via gdb-patches
  2017-06-01 23:33 ` David Blaikie
  0 siblings, 1 reply; 6+ messages in thread
From: Doug Evans via gdb-patches @ 2017-05-22 18:01 UTC (permalink / raw)
  To: David Blaikie; +Cc: gdb-patches, Pedro Alves

David Blaikie writes:
 > ...

Hi. Review comments inline.
All nits.

First one: Tab instead of spaces throughout (including ChangeLog entries).

The testcase is fine with me.

 > gdb/ChangeLog:
 > 
 > 2017-05-12  David Blaikie  <dblaikie@gmail.com>
 > 
 >         * dwarf2read.c (struct dwo_file): Use a htab of dwo_unit*
 > (rather than a singular dwo_unit*) to support multiple CUs in the same
 > way that multiple TUs are supported.
 >         (static void create_cus_hash_table): Replace create_dwo_cu
 > with a function for parsing multiple CUs from a DWO file.
 >         (open_and_init_dwo_file): Use create_cus_hash_table rather
 > than create_dwo_cu.
 >         (lookup_dwo_cutu): Lookup CU in the hash table in the dwo_file
 > with htab_find, rather than comparing the signature to a singleton CU
 > in the dwo_file.
 > 
 > gdb/testsuite/ChangeLog:
 > 
 > 2017-05-12  David Blaikie  <dblaikie@gmail.com>
 > 
 >         * gdb.dwarf2/fission-multi-cu.S: Test containing multiple CUs
 > in a DWO, built from fission-multi-cu{1,2}.c.
 >         * gdb.dwarf2/fission-multi-cu.exp: Test similar to
 > fission-base.exp, except putting 'main' and 'func' in separate CUs
 > while in the same DWO file.
 >         * gdb.dwarf2/fission-multi-cu1.c: First CU for the
 > multi-CU-single-DWO test.
 >         * gdb.dwarf2/fission-multi-cu2.c: Second CU for the
 > multi-CU-single-DWO test.
 > diff --git gdb/dwarf2read.c gdb/dwarf2read.c
 > index b58d0fc16e..29eb5a14b2 100644
 > --- gdb/dwarf2read.c
 > +++ gdb/dwarf2read.c
 > @@ -852,12 +852,9 @@ struct dwo_file
 >       sections (for lack of a better name).  */
 >    struct dwo_sections sections;
 >  
 > -  /* The CU in the file.
 > -     We only support one because having more than one requires hacking the
 > -     dwo_name of each to match, which is highly unlikely to happen.
 > -     Doing this means all TUs can share comp_dir: We also assume that
 > -     DW_AT_comp_dir across all TUs in a DWO file will be identical.  */
 > -  struct dwo_unit *cu;
 > +  /* The CUs in the file.
 > +     Each element is a struct dwo_unit. */

Since this is currently non-standard, I think it will help some readers
to elaborate on the Why of things here. IOW, add a comment explaining why
we're now supporting multi-CUs in one DWO file.

 > +  htab_t cus;
 >  
 >    /* Table of TUs in the file.
 >       Each element is a struct dwo_unit.  */
 > @@ -9702,72 +9699,75 @@ create_dwo_cu_reader (const struct die_reader_specs *reader,
 >  			hex_string (dwo_unit->signature));
 >  }
 >  
 > -/* Create the dwo_unit for the lone CU in DWO_FILE.
 > -   Note: This function processes DWO files only, not DWP files.  */

Need to keep the function comment (just reword it).
And please keep the note about only being used for DWO files, not DWP files.

 > -
 > -static struct dwo_unit *
 > -create_dwo_cu (struct dwo_file *dwo_file)
 > +static void create_cus_hash_table (struct dwo_file &dwo_file,
 > +                                   dwarf2_section_info &section,
 > +                                   htab_t &cus_htab)
 >  {
 >    struct objfile *objfile = dwarf2_per_objfile->objfile;
 > -  struct dwarf2_section_info *section = &dwo_file->sections.info;
 > +  const struct dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev;
 >    const gdb_byte *info_ptr, *end_ptr;
 > -  struct create_dwo_cu_data create_dwo_cu_data;
 > -  struct dwo_unit *dwo_unit;
 >  
 > -  dwarf2_read_section (objfile, section);
 > -  info_ptr = section->buffer;
 > +  dwarf2_read_section (objfile, &section);
 > +  info_ptr = section.buffer;
 >  
 >    if (info_ptr == NULL)
 > -    return NULL;
 > +    return;
 >  
 >    if (dwarf_read_debug)
 >      {
 >        fprintf_unfiltered (gdb_stdlog, "Reading %s for %s:\n",
 > -			  get_section_name (section),
 > -			  get_section_file_name (section));
 > +			  get_section_name (&section),
 > +			  get_section_file_name (&section));
 >      }
 >  
 > -  create_dwo_cu_data.dwo_file = dwo_file;
 > -  dwo_unit = NULL;
 > -
 > -  end_ptr = info_ptr + section->size;
 > +  end_ptr = info_ptr  + section.size;

extra space

 >    while (info_ptr < end_ptr)
 >      {
 >        struct dwarf2_per_cu_data per_cu;
 > +      struct create_dwo_cu_data create_dwo_cu_data;
 > +      struct dwo_unit *dwo_unit;
 > +      void **slot;
 > +      sect_offset sect_off = (sect_offset) (info_ptr - section.buffer);
 >  
 >        memset (&create_dwo_cu_data.dwo_unit, 0,
 >  	      sizeof (create_dwo_cu_data.dwo_unit));
 >        memset (&per_cu, 0, sizeof (per_cu));
 >        per_cu.objfile = objfile;
 >        per_cu.is_debug_types = 0;
 > -      per_cu.sect_off = sect_offset (info_ptr - section->buffer);
 > -      per_cu.section = section;
 > +      per_cu.sect_off = sect_offset (info_ptr - section.buffer);
 > +      per_cu.section = &section;
 > +      create_dwo_cu_data.dwo_file = &dwo_file;
 >  
 > -      init_cutu_and_read_dies_no_follow (&per_cu, dwo_file,
 > +      init_cutu_and_read_dies_no_follow (&per_cu, &dwo_file,
 >  					 create_dwo_cu_reader,
 >  					 &create_dwo_cu_data);
 > +      info_ptr += per_cu.length;
 >  
 > -      if (create_dwo_cu_data.dwo_unit.dwo_file != NULL)
 > -	{
 > -	  /* If we've already found one, complain.  We only support one
 > -	     because having more than one requires hacking the dwo_name of
 > -	     each to match, which is highly unlikely to happen.  */
 > -	  if (dwo_unit != NULL)
 > -	    {
 > -	      complaint (&symfile_complaints,
 > -			 _("Multiple CUs in DWO file %s [in module %s]"),
 > -			 dwo_file->dwo_name, objfile_name (objfile));
 > -	      break;
 > -	    }

Add a comment explaining why this test is present:

 > +      if (create_dwo_cu_data.dwo_unit.dwo_file == NULL)
 > +        continue;
 >  
 > -	  dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
 > -	  *dwo_unit = create_dwo_cu_data.dwo_unit;
 > -	}
 > +      if (cus_htab == NULL)

Remove the surrounding braces.

 > +        {
 > +          cus_htab = allocate_dwo_unit_table (objfile);
 > +        }
 >  
 > -      info_ptr += per_cu.length;
 > -    }
 > +      dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
 > +      *dwo_unit = create_dwo_cu_data.dwo_unit;
 > +      slot = htab_find_slot (cus_htab, dwo_unit, INSERT);
 > +      gdb_assert (slot != NULL);
 > +      if (*slot != NULL)
 > +        {
 > +          const struct dwo_unit *dup_cu = (const struct dwo_unit *) *slot;
 > +          sect_offset dup_sect_off = dup_cu->sect_off;
 >  
 > -  return dwo_unit;
 > +	  complaint (&symfile_complaints,
 > +		     _("debug cu entry at offset 0x%x is duplicate to"
 > +		       " the entry at offset 0x%x, signature %s"),
 > +		     to_underlying (sect_off), to_underlying (dup_sect_off),
 > +		     hex_string (dwo_unit->signature));
 > +        }
 > +      *slot = (void *) dwo_unit;
 > +    }
 >  }
 >  
 >  /* DWP file .debug_{cu,tu}_index section format:
 > @@ -10772,7 +10772,7 @@ open_and_init_dwo_file (struct dwarf2_per_cu_data *per_cu,
 >    bfd_map_over_sections (dwo_file->dbfd, dwarf2_locate_dwo_sections,
 >  			 &dwo_file->sections);
 >  
 > -  dwo_file->cu = create_dwo_cu (dwo_file);
 > +  create_cus_hash_table (*dwo_file, dwo_file->sections.info, dwo_file->cus);
 >  
 >    create_debug_types_hash_table (dwo_file, dwo_file->sections.types,
 >  				 dwo_file->tus);
 > @@ -11139,10 +11139,13 @@ lookup_dwo_cutu (struct dwarf2_per_cu_data *this_unit,
 >  	      dwo_cutu
 >  		= (struct dwo_unit *) htab_find (dwo_file->tus, &find_dwo_cutu);
 >  	    }
 > -	  else if (!is_debug_types && dwo_file->cu)
 > +	  else if (!is_debug_types && dwo_file->cus)
 >  	    {
 > -	      if (signature == dwo_file->cu->signature)
 > -		dwo_cutu = dwo_file->cu;
 > +              struct dwo_unit find_dwo_cutu;
 > +
 > +              memset (&find_dwo_cutu, 0, sizeof (find_dwo_cutu));
 > +              find_dwo_cutu.signature = signature;
 > +              dwo_cutu = (struct dwo_unit *) htab_find (dwo_file->cus, &find_dwo_cutu);
 >  	    }
 >  
 >  	  if (dwo_cutu != NULL)
 > diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu.S gdb/testsuite/gdb.dwarf2/fission-multi-cu.S
 > new file mode 100644
 > index 0000000000..d09a7e543d
 > --- /dev/null
 > +++ gdb/testsuite/gdb.dwarf2/fission-multi-cu.S
 > @@ -0,0 +1,374 @@
 > +/* This testcase is part of GDB, the GNU debugger.
 > +
 > +   Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.
 > +
 > +   This file was created by doing:
 > +
 > +   clang fission-multi-cu*.c -g -fno-split-dwarf-inlining -emit-llvm -S -c
 > +   llvm-link fission-multi-cu*.ll -S -o fission-multi-cu.ll
 > +   clang-tot fission-multi-cu.ll -gsplit-dwarf -S
 > +
 > +   and then massaging the output.
 > +*/
 > +	.text
 > +	.file	"llvm-link"
 > +	.globl	func
 > +	.p2align	4, 0x90
 > +	.type	func,@function
 > +func:                                   # @func
 > +.Lfunc_begin0:
 > +	.file	1 "fission-multi-cu1.c"
 > +	.loc	1 20 0                  # fission-multi-cu1.c:20:0
 > +	.cfi_startproc
 > +# BB#0:                                 # %entry
 > +	pushq	%rbp
 > +	.cfi_def_cfa_offset 16
 > +	.cfi_offset %rbp, -16
 > +	movq	%rsp, %rbp
 > +	.cfi_def_cfa_register %rbp
 > +	movl	%edi, -4(%rbp)
 > +	.loc	1 21 10 prologue_end    # fission-multi-cu1.c:21:10
 > +	movl	-4(%rbp), %edi
 > +	.loc	1 21 14 is_stmt 0       # fission-multi-cu1.c:21:14
 > +	addl	$1, %edi
 > +	.loc	1 21 3                  # fission-multi-cu1.c:21:3
 > +	movl	%edi, %eax
 > +	popq	%rbp
 > +	retq
 > +.Lfunc_end0:
 > +	.size	func, .Lfunc_end0-func
 > +	.cfi_endproc
 > +
 > +	.globl	main
 > +	.p2align	4, 0x90
 > +	.type	main,@function
 > +main:                                   # @main
 > +.Lfunc_begin1:
 > +	.file	2 "fission-multi-cu2.c"
 > +	.loc	2 23 0 is_stmt 1        # fission-multi-cu2.c:23:0
 > +	.cfi_startproc
 > +# BB#0:                                 # %entry
 > +	pushq	%rbp
 > +	.cfi_def_cfa_offset 16
 > +	.cfi_offset %rbp, -16
 > +	movq	%rsp, %rbp
 > +	.cfi_def_cfa_register %rbp
 > +	movl	$4294967295, %edi       # imm = 0xFFFFFFFF
 > +	.loc	2 24 3 prologue_end     # fission-multi-cu2.c:24:3
 > +	movb	$0, %al
 > +	callq	func
 > +	xorl	%eax, %eax
 > +	.loc	2 25 1                  # fission-multi-cu2.c:25:1
 > +	popq	%rbp
 > +	retq
 > +.Lfunc_end1:
 > +	.size	main, .Lfunc_end1-main
 > +	.cfi_endproc
 > +
 > +	.section	.debug_str,"MS",@progbits,1
 > +.Lskel_string0:
 > +	.asciz	"fission-multi-cu.dwo"  # string offset=0
 > +.Lskel_string1:
 > +	.asciz	"/tmp/src/gdb/testsuite" # string offset=21
 > +	.section	.debug_loc.dwo,"",@progbits
 > +	.section	.debug_abbrev,"",@progbits
 > +	.byte	1                       # Abbreviation Code
 > +	.byte	17                      # DW_TAG_compile_unit
 > +	.byte	0                       # DW_CHILDREN_no
 > +	.byte	16                      # DW_AT_stmt_list
 > +	.byte	23                      # DW_FORM_sec_offset
 > +	.ascii	"\260B"                 # DW_AT_GNU_dwo_name
 > +	.byte	14                      # DW_FORM_strp
 > +	.byte	27                      # DW_AT_comp_dir
 > +	.byte	14                      # DW_FORM_strp
 > +	.ascii	"\261B"                 # DW_AT_GNU_dwo_id
 > +	.byte	7                       # DW_FORM_data8
 > +	.ascii	"\263B"                 # DW_AT_GNU_addr_base
 > +	.byte	23                      # DW_FORM_sec_offset
 > +	.byte	17                      # DW_AT_low_pc
 > +	.byte	1                       # DW_FORM_addr
 > +	.byte	18                      # DW_AT_high_pc
 > +	.byte	6                       # DW_FORM_data4
 > +	.byte	0                       # EOM(1)
 > +	.byte	0                       # EOM(2)
 > +	.byte	0                       # EOM(3)
 > +	.section	.debug_info,"",@progbits
 > +.Lcu_begin0:
 > +	.long	44                      # Length of Unit
 > +	.short	4                       # DWARF version number
 > +	.long	.debug_abbrev           # Offset Into Abbrev. Section
 > +	.byte	8                       # Address Size (in bytes)
 > +	.byte	1                       # Abbrev [1] 0xb:0x25 DW_TAG_compile_unit
 > +	.long	.Lline_table_start0     # DW_AT_stmt_list
 > +	.long	.Lskel_string0          # DW_AT_GNU_dwo_name
 > +	.long	.Lskel_string1          # DW_AT_comp_dir
 > +	.quad	7615852067747431413     # DW_AT_GNU_dwo_id
 > +	.long	.debug_addr             # DW_AT_GNU_addr_base
 > +	.quad	.Lfunc_begin0           # DW_AT_low_pc
 > +	.long	.Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
 > +.Lcu_begin1:
 > +	.long	44                      # Length of Unit
 > +	.short	4                       # DWARF version number
 > +	.long	.debug_abbrev           # Offset Into Abbrev. Section
 > +	.byte	8                       # Address Size (in bytes)
 > +	.byte	1                       # Abbrev [1] 0xb:0x25 DW_TAG_compile_unit
 > +	.long	.Lline_table_start0     # DW_AT_stmt_list
 > +	.long	.Lskel_string0          # DW_AT_GNU_dwo_name
 > +	.long	.Lskel_string1          # DW_AT_comp_dir
 > +	.quad	2037650261599692324     # DW_AT_GNU_dwo_id
 > +	.long	.debug_addr             # DW_AT_GNU_addr_base
 > +	.quad	.Lfunc_begin1           # DW_AT_low_pc
 > +	.long	.Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
 > +	.section	.debug_ranges,"",@progbits
 > +	.section	.debug_macinfo,"",@progbits
 > +.Lcu_macro_begin1:
 > +.Lcu_macro_begin3:
 > +	.byte	0                       # End Of Macro List Mark
 > +	.section	.debug_str.dwo,"MS",@progbits,1
 > +.Linfo_string0:
 > +	.asciz	"fission-multi-cu.dwo"  # string offset=0
 > +.Linfo_string1:
 > +	.asciz	"clang version 5.0.0 (trunk 302855) (llvm/trunk 302853)" # string offset=21
 > +.Linfo_string2:
 > +	.asciz	"fission-multi-cu1.c" # string offset=76
 > +.Linfo_string3:
 > +	.asciz	"fission-multi-cu2.c" # string offset=96
 > +.Linfo_string4:
 > +	.asciz	"func"                  # string offset=116
 > +.Linfo_string5:
 > +	.asciz	"int"                   # string offset=121
 > +.Linfo_string6:
 > +	.asciz	"main"                  # string offset=125
 > +.Linfo_string7:
 > +	.asciz	"arg"                   # string offset=130
 > +	.section	.debug_str_offsets.dwo,"",@progbits
 > +	.long	0
 > +	.long	21
 > +	.long	76
 > +	.long	96
 > +	.long	116
 > +	.long	121
 > +	.long	125
 > +	.long	130
 > +	.section	.debug_info.dwo,"",@progbits
 > +	.long	53                      # Length of Unit
 > +	.short	4                       # DWARF version number
 > +	.long	0                       # Offset Into Abbrev. Section
 > +	.byte	8                       # Address Size (in bytes)
 > +	.byte	1                       # Abbrev [1] 0xb:0x2e DW_TAG_compile_unit
 > +	.byte	0                       # DW_AT_GNU_dwo_name
 > +	.byte	1                       # DW_AT_producer
 > +	.short	12                      # DW_AT_language
 > +	.byte	2                       # DW_AT_name
 > +	.quad	7615852067747431413     # DW_AT_GNU_dwo_id
 > +	.byte	2                       # Abbrev [2] 0x19:0x1b DW_TAG_subprogram
 > +	.byte	0                       # DW_AT_low_pc
 > +	.long	.Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
 > +	.byte	1                       # DW_AT_frame_base
 > +	.byte	86
 > +	.byte	4                       # DW_AT_name
 > +	.byte	1                       # DW_AT_decl_file
 > +	.byte	19                      # DW_AT_decl_line
 > +                                        # DW_AT_prototyped
 > +	.long	52                      # DW_AT_type
 > +                                        # DW_AT_external
 > +	.byte	3                       # Abbrev [3] 0x28:0xb DW_TAG_formal_parameter
 > +	.byte	2                       # DW_AT_location
 > +	.byte	145
 > +	.byte	124
 > +	.byte	7                       # DW_AT_name
 > +	.byte	1                       # DW_AT_decl_file
 > +	.byte	19                      # DW_AT_decl_line
 > +	.long	52                      # DW_AT_type
 > +	.byte	0                       # End Of Children Mark
 > +	.byte	4                       # Abbrev [4] 0x34:0x4 DW_TAG_base_type
 > +	.byte	5                       # DW_AT_name
 > +	.byte	5                       # DW_AT_encoding
 > +	.byte	4                       # DW_AT_byte_size
 > +	.byte	0                       # End Of Children Mark
 > +	.long	41                      # Length of Unit
 > +	.short	4                       # DWARF version number
 > +	.long	0                       # Offset Into Abbrev. Section
 > +	.byte	8                       # Address Size (in bytes)
 > +	.byte	1                       # Abbrev [1] 0xb:0x22 DW_TAG_compile_unit
 > +	.byte	0                       # DW_AT_GNU_dwo_name
 > +	.byte	1                       # DW_AT_producer
 > +	.short	12                      # DW_AT_language
 > +	.byte	3                       # DW_AT_name
 > +	.quad	2037650261599692324     # DW_AT_GNU_dwo_id
 > +	.byte	5                       # Abbrev [5] 0x19:0xf DW_TAG_subprogram
 > +	.byte	1                       # DW_AT_low_pc
 > +	.long	.Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
 > +	.byte	1                       # DW_AT_frame_base
 > +	.byte	86
 > +	.byte	6                       # DW_AT_name
 > +	.byte	2                       # DW_AT_decl_file
 > +	.byte	22                      # DW_AT_decl_line
 > +	.long	40                      # DW_AT_type
 > +                                        # DW_AT_external
 > +	.byte	4                       # Abbrev [4] 0x28:0x4 DW_TAG_base_type
 > +	.byte	5                       # DW_AT_name
 > +	.byte	5                       # DW_AT_encoding
 > +	.byte	4                       # DW_AT_byte_size
 > +	.byte	0                       # End Of Children Mark
 > +	.section	.debug_abbrev.dwo,"",@progbits
 > +	.byte	1                       # Abbreviation Code
 > +	.byte	17                      # DW_TAG_compile_unit
 > +	.byte	1                       # DW_CHILDREN_yes
 > +	.ascii	"\260B"                 # DW_AT_GNU_dwo_name
 > +	.ascii	"\202>"                 # DW_FORM_GNU_str_index
 > +	.byte	37                      # DW_AT_producer
 > +	.ascii	"\202>"                 # DW_FORM_GNU_str_index
 > +	.byte	19                      # DW_AT_language
 > +	.byte	5                       # DW_FORM_data2
 > +	.byte	3                       # DW_AT_name
 > +	.ascii	"\202>"                 # DW_FORM_GNU_str_index
 > +	.ascii	"\261B"                 # DW_AT_GNU_dwo_id
 > +	.byte	7                       # DW_FORM_data8
 > +	.byte	0                       # EOM(1)
 > +	.byte	0                       # EOM(2)
 > +	.byte	2                       # Abbreviation Code
 > +	.byte	46                      # DW_TAG_subprogram
 > +	.byte	1                       # DW_CHILDREN_yes
 > +	.byte	17                      # DW_AT_low_pc
 > +	.ascii	"\201>"                 # DW_FORM_GNU_addr_index
 > +	.byte	18                      # DW_AT_high_pc
 > +	.byte	6                       # DW_FORM_data4
 > +	.byte	64                      # DW_AT_frame_base
 > +	.byte	24                      # DW_FORM_exprloc
 > +	.byte	3                       # DW_AT_name
 > +	.ascii	"\202>"                 # DW_FORM_GNU_str_index
 > +	.byte	58                      # DW_AT_decl_file
 > +	.byte	11                      # DW_FORM_data1
 > +	.byte	59                      # DW_AT_decl_line
 > +	.byte	11                      # DW_FORM_data1
 > +	.byte	39                      # DW_AT_prototyped
 > +	.byte	25                      # DW_FORM_flag_present
 > +	.byte	73                      # DW_AT_type
 > +	.byte	19                      # DW_FORM_ref4
 > +	.byte	63                      # DW_AT_external
 > +	.byte	25                      # DW_FORM_flag_present
 > +	.byte	0                       # EOM(1)
 > +	.byte	0                       # EOM(2)
 > +	.byte	3                       # Abbreviation Code
 > +	.byte	5                       # DW_TAG_formal_parameter
 > +	.byte	0                       # DW_CHILDREN_no
 > +	.byte	2                       # DW_AT_location
 > +	.byte	24                      # DW_FORM_exprloc
 > +	.byte	3                       # DW_AT_name
 > +	.ascii	"\202>"                 # DW_FORM_GNU_str_index
 > +	.byte	58                      # DW_AT_decl_file
 > +	.byte	11                      # DW_FORM_data1
 > +	.byte	59                      # DW_AT_decl_line
 > +	.byte	11                      # DW_FORM_data1
 > +	.byte	73                      # DW_AT_type
 > +	.byte	19                      # DW_FORM_ref4
 > +	.byte	0                       # EOM(1)
 > +	.byte	0                       # EOM(2)
 > +	.byte	4                       # Abbreviation Code
 > +	.byte	36                      # DW_TAG_base_type
 > +	.byte	0                       # DW_CHILDREN_no
 > +	.byte	3                       # DW_AT_name
 > +	.ascii	"\202>"                 # DW_FORM_GNU_str_index
 > +	.byte	62                      # DW_AT_encoding
 > +	.byte	11                      # DW_FORM_data1
 > +	.byte	11                      # DW_AT_byte_size
 > +	.byte	11                      # DW_FORM_data1
 > +	.byte	0                       # EOM(1)
 > +	.byte	0                       # EOM(2)
 > +	.byte	5                       # Abbreviation Code
 > +	.byte	46                      # DW_TAG_subprogram
 > +	.byte	0                       # DW_CHILDREN_no
 > +	.byte	17                      # DW_AT_low_pc
 > +	.ascii	"\201>"                 # DW_FORM_GNU_addr_index
 > +	.byte	18                      # DW_AT_high_pc
 > +	.byte	6                       # DW_FORM_data4
 > +	.byte	64                      # DW_AT_frame_base
 > +	.byte	24                      # DW_FORM_exprloc
 > +	.byte	3                       # DW_AT_name
 > +	.ascii	"\202>"                 # DW_FORM_GNU_str_index
 > +	.byte	58                      # DW_AT_decl_file
 > +	.byte	11                      # DW_FORM_data1
 > +	.byte	59                      # DW_AT_decl_line
 > +	.byte	11                      # DW_FORM_data1
 > +	.byte	73                      # DW_AT_type
 > +	.byte	19                      # DW_FORM_ref4
 > +	.byte	63                      # DW_AT_external
 > +	.byte	25                      # DW_FORM_flag_present
 > +	.byte	0                       # EOM(1)
 > +	.byte	0                       # EOM(2)
 > +	.byte	0                       # EOM(3)
 > +	.section	.debug_line.dwo,"",@progbits
 > +.Ltmp4:
 > +	.long	(.Ltmp5-.Ltmp4)-4
 > +	.short	2
 > +	.long	(.Ltmp6-.Ltmp4)-10
 > +	.byte	1
 > +	.byte	1
 > +	.byte	-5
 > +	.byte	14
 > +	.byte	1
 > +	.byte	0
 > +	.byte	0
 > +.Ltmp6:
 > +.Ltmp5:
 > +	.section	.debug_addr,"",@progbits
 > +	.quad	.Lfunc_begin0
 > +	.quad	.Lfunc_begin1
 > +	.section	.debug_pubnames,"",@progbits
 > +	.long	.LpubNames_end0-.LpubNames_begin0 # Length of Public Names Info
 > +.LpubNames_begin0:
 > +	.short	2                       # DWARF Version
 > +	.long	.Lcu_begin0             # Offset of Compilation Unit Info
 > +	.long	48                      # Compilation Unit Length
 > +	.long	25                      # DIE offset
 > +	.asciz	"func"                  # External Name
 > +	.long	0                       # End Mark
 > +.LpubNames_end0:
 > +	.long	.LpubNames_end1-.LpubNames_begin1 # Length of Public Names Info
 > +.LpubNames_begin1:
 > +	.short	2                       # DWARF Version
 > +	.long	.Lcu_begin1             # Offset of Compilation Unit Info
 > +	.long	48                      # Compilation Unit Length
 > +	.long	25                      # DIE offset
 > +	.asciz	"main"                  # External Name
 > +	.long	0                       # End Mark
 > +.LpubNames_end1:
 > +	.section	.debug_pubtypes,"",@progbits
 > +	.long	.LpubTypes_end0-.LpubTypes_begin0 # Length of Public Types Info
 > +.LpubTypes_begin0:
 > +	.short	2                       # DWARF Version
 > +	.long	.Lcu_begin0             # Offset of Compilation Unit Info
 > +	.long	48                      # Compilation Unit Length
 > +	.long	52                      # DIE offset
 > +	.asciz	"int"                   # External Name
 > +	.long	0                       # End Mark
 > +.LpubTypes_end0:
 > +	.long	.LpubTypes_end1-.LpubTypes_begin1 # Length of Public Types Info
 > +.LpubTypes_begin1:
 > +	.short	2                       # DWARF Version
 > +	.long	.Lcu_begin1             # Offset of Compilation Unit Info
 > +	.long	48                      # Compilation Unit Length
 > +	.long	40                      # DIE offset
 > +	.asciz	"int"                   # External Name
 > +	.long	0                       # End Mark
 > +.LpubTypes_end1:
 > +
 > +	.ident	"clang version 5.0.0 (trunk 302855) (llvm/trunk 302853)"
 > +	.ident	"clang version 5.0.0 (trunk 302855) (llvm/trunk 302853)"
 > +	.section	".note.GNU-stack","",@progbits
 > +	.section	.debug_line,"",@progbits
 > +.Lline_table_start0:
 > diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu.exp gdb/testsuite/gdb.dwarf2/fission-multi-cu.exp
 > new file mode 100644
 > index 0000000000..1f23c5b6ee
 > --- /dev/null
 > +++ gdb/testsuite/gdb.dwarf2/fission-multi-cu.exp
 > @@ -0,0 +1,67 @@
 > +# Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.
 > +
 > +load_lib dwarf.exp
 > +
 > +# We run objcopy locally to split out the .dwo file.
 > +if [is_remote host] {
 > +    return 0
 > +}
 > +
 > +# This test can only be run on targets which support DWARF-2 and use gas.
 > +if ![dwarf2_support] {
 > +    return 0
 > +}
 > +
 > +# This test can only be run on x86-64 targets.
 > +if {![istarget x86_64-*] || ![is_lp64_target]} {
 > +    return 0
 > +}
 > +
 > +standard_testfile .S
 > +
 > +if [build_executable_from_fission_assembler \
 > +	"$testfile.exp" "$binfile" "$srcfile" {nodebug}] {
 > +    return -1
 > +}
 > +
 > +gdb_exit
 > +gdb_start
 > +gdb_reinitialize_dir $srcdir/$subdir
 > +# Make sure we can find the .dwo file, regardless of whether we're
 > +# running in parallel mode.
 > +gdb_test_no_output "set debug-file-directory [file dirname $binfile]" \
 > +    "set debug-file-directory"
 > +gdb_load $binfile
 > +
 > +if ![runto_main] {
 > +    return -1
 > +}
 > +
 > +# Do a few basic things to verify we're finding the DWO debug info.
 > +
 > +gdb_test "ptype main" "type = int \\(\\)"
 > +gdb_test "ptype func" "type = int \\(int\\)"
 > +
 > +gdb_test "frame" "#0 *main \\(\\) at ${testfile}2\\.c:$decimal.*" \
 > +    "frame in main"
 > +
 > +gdb_test "break func" "Breakpoint.*at.* file .*${testfile}1\\.c, line .*"
 > +
 > +gdb_test "continue" "Breakpoint.* func \\(arg=-1\\).*" \
 > +    "continue to func"
 > +
 > +gdb_test "frame" "#0 *func \\(arg=-1\\) at ${testfile}1\\.c:$decimal.*" \
 > +    "frame in func"
 > diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu1.c gdb/testsuite/gdb.dwarf2/fission-multi-cu1.c
 > new file mode 100644
 > index 0000000000..d93e2f912e
 > --- /dev/null
 > +++ gdb/testsuite/gdb.dwarf2/fission-multi-cu1.c
 > @@ -0,0 +1,22 @@
 > +/* This testcase is part of GDB, the GNU debugger.
 > +
 > +   Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.  */
 > +
 > +int
 > +func (int arg)
 > +{
 > +  return arg + 1;
 > +}
 > diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu2.c gdb/testsuite/gdb.dwarf2/fission-multi-cu2.c
 > new file mode 100644
 > index 0000000000..053b3ea141
 > --- /dev/null
 > +++ gdb/testsuite/gdb.dwarf2/fission-multi-cu2.c
 > @@ -0,0 +1,24 @@
 > +/* This testcase is part of GDB, the GNU debugger.
 > +
 > +   Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.  */
 > +
 > +void func ();
 > +
 > +int
 > +main ()
 > +{
 > +  func (-1);
 > +}

-- 
/dje

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Fission support for multiple CUs per DWO file
  2017-05-22 18:01 [PATCH] Fission support for multiple CUs per DWO file Doug Evans via gdb-patches
@ 2017-06-01 23:33 ` David Blaikie
  2017-06-27 18:52   ` David Blaikie
  0 siblings, 1 reply; 6+ messages in thread
From: David Blaikie @ 2017-06-01 23:33 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, Pedro Alves

[-- Attachment #1: Type: text/plain, Size: 8482 bytes --]

gdb/ChangeLog:

2017-05-12  David Blaikie  <dblaikie@gmail.com>

* dwarf2read.c (struct dwo_file): Use a htab of dwo_unit* (rather than
a singular dwo_unit*) to support multiple CUs in the same way that
multiple TUs are supported.
(static void create_cus_hash_table): Replace create_dwo_cu with a
function for parsing multiple CUs from a DWO file.
(open_and_init_dwo_file): Use create_cus_hash_table rather than create_dwo_cu.
(lookup_dwo_cutu): Lookup CU in the hash table in the dwo_file with
htab_find, rather than comparing the signature to a singleton CU in
the dwo_file.

gdb/testsuite/ChangeLog:

2017-05-12  David Blaikie  <dblaikie@gmail.com>

* gdb.dwarf2/fission-multi-cu.S: Test containing multiple CUs in a
DWO, built from fission-multi-cu{1,2}.c.
* gdb.dwarf2/fission-multi-cu.exp: Test similar to fission-base.exp,
except putting 'main' and 'func' in separate CUs while in the same DWO
file.
* gdb.dwarf2/fission-multi-cu1.c: First CU for the multi-CU-single-DWO test.
* gdb.dwarf2/fission-multi-cu2.c: Second CU for the multi-CU-single-DWO test.

On Mon, May 22, 2017 at 11:01 AM, Doug Evans <dje@google.com> wrote:
> David Blaikie writes:
>  > ...
>
> Hi. Review comments inline.

Hi - thanks for the review!

(responses inline, patch addressing the issues is attached)

Do let me know if there's other things that'd be good to address or if
this looks good as-is.

Thanks,
- Dave

> All nits.
>
> First one: Tab instead of spaces throughout (including ChangeLog entries).

Think I got all that addressed - though GMail seems to be getting in
my way of adding tabs into the ChangeLog entries inline in the email.
I'll be sure they're there when I commit it.

>
> The testcase is fine with me.
>
>  > gdb/ChangeLog:
>  >
>  > 2017-05-12  David Blaikie  <dblaikie@gmail.com>
>  >
>  >         * dwarf2read.c (struct dwo_file): Use a htab of dwo_unit*
>  > (rather than a singular dwo_unit*) to support multiple CUs in the same
>  > way that multiple TUs are supported.
>  >         (static void create_cus_hash_table): Replace create_dwo_cu
>  > with a function for parsing multiple CUs from a DWO file.
>  >         (open_and_init_dwo_file): Use create_cus_hash_table rather
>  > than create_dwo_cu.
>  >         (lookup_dwo_cutu): Lookup CU in the hash table in the dwo_file
>  > with htab_find, rather than comparing the signature to a singleton CU
>  > in the dwo_file.
>  >
>  > gdb/testsuite/ChangeLog:
>  >
>  > 2017-05-12  David Blaikie  <dblaikie@gmail.com>
>  >
>  >         * gdb.dwarf2/fission-multi-cu.S: Test containing multiple CUs
>  > in a DWO, built from fission-multi-cu{1,2}.c.
>  >         * gdb.dwarf2/fission-multi-cu.exp: Test similar to
>  > fission-base.exp, except putting 'main' and 'func' in separate CUs
>  > while in the same DWO file.
>  >         * gdb.dwarf2/fission-multi-cu1.c: First CU for the
>  > multi-CU-single-DWO test.
>  >         * gdb.dwarf2/fission-multi-cu2.c: Second CU for the
>  > multi-CU-single-DWO test.
>  > diff --git gdb/dwarf2read.c gdb/dwarf2read.c
>  > index b58d0fc16e..29eb5a14b2 100644
>  > --- gdb/dwarf2read.c
>  > +++ gdb/dwarf2read.c
>  > @@ -852,12 +852,9 @@ struct dwo_file
>  >       sections (for lack of a better name).  */
>  >    struct dwo_sections sections;
>  >
>  > -  /* The CU in the file.
>  > -     We only support one because having more than one requires hacking the
>  > -     dwo_name of each to match, which is highly unlikely to happen.
>  > -     Doing this means all TUs can share comp_dir: We also assume that
>  > -     DW_AT_comp_dir across all TUs in a DWO file will be identical.  */
>  > -  struct dwo_unit *cu;
>  > +  /* The CUs in the file.
>  > +     Each element is a struct dwo_unit. */
>
> Since this is currently non-standard, I think it will help some readers
> to elaborate on the Why of things here. IOW, add a comment explaining why
> we're now supporting multi-CUs in one DWO file.

Commented about the use case here & that it's supported as an extension.

>
>  > +  htab_t cus;
>  >
>  >    /* Table of TUs in the file.
>  >       Each element is a struct dwo_unit.  */
>  > @@ -9702,72 +9699,75 @@ create_dwo_cu_reader (const struct die_reader_specs *reader,
>  >                      hex_string (dwo_unit->signature));
>  >  }
>  >
>  > -/* Create the dwo_unit for the lone CU in DWO_FILE.
>  > -   Note: This function processes DWO files only, not DWP files.  */
>
> Need to keep the function comment (just reword it).
> And please keep the note about only being used for DWO files, not DWP files.

Kept & reworded.

>
>  > -
>  > -static struct dwo_unit *
>  > -create_dwo_cu (struct dwo_file *dwo_file)
>  > +static void create_cus_hash_table (struct dwo_file &dwo_file,
>  > +                                   dwarf2_section_info &section,
>  > +                                   htab_t &cus_htab)
>  >  {
>  >    struct objfile *objfile = dwarf2_per_objfile->objfile;
>  > -  struct dwarf2_section_info *section = &dwo_file->sections.info;
>  > +  const struct dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev;
>  >    const gdb_byte *info_ptr, *end_ptr;
>  > -  struct create_dwo_cu_data create_dwo_cu_data;
>  > -  struct dwo_unit *dwo_unit;
>  >
>  > -  dwarf2_read_section (objfile, section);
>  > -  info_ptr = section->buffer;
>  > +  dwarf2_read_section (objfile, &section);
>  > +  info_ptr = section.buffer;
>  >
>  >    if (info_ptr == NULL)
>  > -    return NULL;
>  > +    return;
>  >
>  >    if (dwarf_read_debug)
>  >      {
>  >        fprintf_unfiltered (gdb_stdlog, "Reading %s for %s:\n",
>  > -                      get_section_name (section),
>  > -                      get_section_file_name (section));
>  > +                      get_section_name (&section),
>  > +                      get_section_file_name (&section));
>  >      }
>  >
>  > -  create_dwo_cu_data.dwo_file = dwo_file;
>  > -  dwo_unit = NULL;
>  > -
>  > -  end_ptr = info_ptr + section->size;
>  > +  end_ptr = info_ptr  + section.size;
>
> extra space

Removed.

>
>  >    while (info_ptr < end_ptr)
>  >      {
>  >        struct dwarf2_per_cu_data per_cu;
>  > +      struct create_dwo_cu_data create_dwo_cu_data;
>  > +      struct dwo_unit *dwo_unit;
>  > +      void **slot;
>  > +      sect_offset sect_off = (sect_offset) (info_ptr - section.buffer);
>  >
>  >        memset (&create_dwo_cu_data.dwo_unit, 0,
>  >            sizeof (create_dwo_cu_data.dwo_unit));
>  >        memset (&per_cu, 0, sizeof (per_cu));
>  >        per_cu.objfile = objfile;
>  >        per_cu.is_debug_types = 0;
>  > -      per_cu.sect_off = sect_offset (info_ptr - section->buffer);
>  > -      per_cu.section = section;
>  > +      per_cu.sect_off = sect_offset (info_ptr - section.buffer);
>  > +      per_cu.section = &section;
>  > +      create_dwo_cu_data.dwo_file = &dwo_file;
>  >
>  > -      init_cutu_and_read_dies_no_follow (&per_cu, dwo_file,
>  > +      init_cutu_and_read_dies_no_follow (&per_cu, &dwo_file,
>  >                                       create_dwo_cu_reader,
>  >                                       &create_dwo_cu_data);
>  > +      info_ptr += per_cu.length;
>  >
>  > -      if (create_dwo_cu_data.dwo_unit.dwo_file != NULL)
>  > -    {
>  > -      /* If we've already found one, complain.  We only support one
>  > -         because having more than one requires hacking the dwo_name of
>  > -         each to match, which is highly unlikely to happen.  */
>  > -      if (dwo_unit != NULL)
>  > -        {
>  > -          complaint (&symfile_complaints,
>  > -                     _("Multiple CUs in DWO file %s [in module %s]"),
>  > -                     dwo_file->dwo_name, objfile_name (objfile));
>  > -          break;
>  > -        }
>
> Add a comment explaining why this test is present:
>
>  > +      if (create_dwo_cu_data.dwo_unit.dwo_file == NULL)
>  > +        continue;

Added a comment & fixed a mistake I introduced by initializing
dwo_file before this call rather than letting the call initialize it.
Looks like the original code was using this for error detection & I
attempted to keep that the same but broke it by initializing the value
early.

>  >
>  > -      dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
>  > -      *dwo_unit = create_dwo_cu_data.dwo_unit;
>  > -    }
>  > +      if (cus_htab == NULL)
>
> Remove the surrounding braces.
>
>  > +        {
>  > +          cus_htab = allocate_dwo_unit_table (objfile);
>  > +        }

Removed & reduced indentation.

[-- Attachment #2: multiple_cus_per_dwo.diff --]
[-- Type: text/plain, Size: 26120 bytes --]

diff --git gdb/dwarf2read.c gdb/dwarf2read.c
index b58d0fc16e..965d74c44f 100644
--- gdb/dwarf2read.c
+++ gdb/dwarf2read.c
@@ -852,12 +852,11 @@ struct dwo_file
      sections (for lack of a better name).  */
   struct dwo_sections sections;
 
-  /* The CU in the file.
-     We only support one because having more than one requires hacking the
-     dwo_name of each to match, which is highly unlikely to happen.
-     Doing this means all TUs can share comp_dir: We also assume that
-     DW_AT_comp_dir across all TUs in a DWO file will be identical.  */
-  struct dwo_unit *cu;
+  /* The CUs in the file.
+     Each element is a struct dwo_unit. Multiple CUs per DWO are supported as
+     an extension to handle LLVM's Link Time Optimization output (where
+     multiple source files may be compiled into a single object/dwo pair). */
+  htab_t cus;
 
   /* Table of TUs in the file.
      Each element is a struct dwo_unit.  */
@@ -9702,72 +9701,75 @@ create_dwo_cu_reader (const struct die_reader_specs *reader,
 			hex_string (dwo_unit->signature));
 }
 
-/* Create the dwo_unit for the lone CU in DWO_FILE.
+/* Create the dwo_units for the CUs in a DWO_FILE.
    Note: This function processes DWO files only, not DWP files.  */
 
-static struct dwo_unit *
-create_dwo_cu (struct dwo_file *dwo_file)
+static void
+create_cus_hash_table (struct dwo_file &dwo_file, dwarf2_section_info &section,
+		       htab_t &cus_htab)
 {
   struct objfile *objfile = dwarf2_per_objfile->objfile;
-  struct dwarf2_section_info *section = &dwo_file->sections.info;
+  const struct dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev;
   const gdb_byte *info_ptr, *end_ptr;
-  struct create_dwo_cu_data create_dwo_cu_data;
-  struct dwo_unit *dwo_unit;
 
-  dwarf2_read_section (objfile, section);
-  info_ptr = section->buffer;
+  dwarf2_read_section (objfile, &section);
+  info_ptr = section.buffer;
 
   if (info_ptr == NULL)
-    return NULL;
+    return;
 
   if (dwarf_read_debug)
     {
       fprintf_unfiltered (gdb_stdlog, "Reading %s for %s:\n",
-			  get_section_name (section),
-			  get_section_file_name (section));
+			  get_section_name (&section),
+			  get_section_file_name (&section));
     }
 
-  create_dwo_cu_data.dwo_file = dwo_file;
-  dwo_unit = NULL;
-
-  end_ptr = info_ptr + section->size;
+  end_ptr = info_ptr + section.size;
   while (info_ptr < end_ptr)
     {
       struct dwarf2_per_cu_data per_cu;
+      struct create_dwo_cu_data create_dwo_cu_data;
+      struct dwo_unit *dwo_unit;
+      void **slot;
+      sect_offset sect_off = (sect_offset) (info_ptr - section.buffer);
 
       memset (&create_dwo_cu_data.dwo_unit, 0,
 	      sizeof (create_dwo_cu_data.dwo_unit));
       memset (&per_cu, 0, sizeof (per_cu));
       per_cu.objfile = objfile;
       per_cu.is_debug_types = 0;
-      per_cu.sect_off = sect_offset (info_ptr - section->buffer);
-      per_cu.section = section;
+      per_cu.sect_off = sect_offset (info_ptr - section.buffer);
+      per_cu.section = &section;
+
+      init_cutu_and_read_dies_no_follow (
+	  &per_cu, &dwo_file, create_dwo_cu_reader, &create_dwo_cu_data);
+      info_ptr += per_cu.length;
+
+      // If the unit could not be parsed, skip it.
+      if (create_dwo_cu_data.dwo_unit.dwo_file == NULL)
+	continue;
 
-      init_cutu_and_read_dies_no_follow (&per_cu, dwo_file,
-					 create_dwo_cu_reader,
-					 &create_dwo_cu_data);
+      if (cus_htab == NULL)
+	cus_htab = allocate_dwo_unit_table (objfile);
 
-      if (create_dwo_cu_data.dwo_unit.dwo_file != NULL)
+      dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
+      *dwo_unit = create_dwo_cu_data.dwo_unit;
+      slot = htab_find_slot (cus_htab, dwo_unit, INSERT);
+      gdb_assert (slot != NULL);
+      if (*slot != NULL)
 	{
-	  /* If we've already found one, complain.  We only support one
-	     because having more than one requires hacking the dwo_name of
-	     each to match, which is highly unlikely to happen.  */
-	  if (dwo_unit != NULL)
-	    {
-	      complaint (&symfile_complaints,
-			 _("Multiple CUs in DWO file %s [in module %s]"),
-			 dwo_file->dwo_name, objfile_name (objfile));
-	      break;
-	    }
+	  const struct dwo_unit *dup_cu = (const struct dwo_unit *)*slot;
+	  sect_offset dup_sect_off = dup_cu->sect_off;
 
-	  dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
-	  *dwo_unit = create_dwo_cu_data.dwo_unit;
+	  complaint (&symfile_complaints,
+		     _("debug cu entry at offset 0x%x is duplicate to"
+		       " the entry at offset 0x%x, signature %s"),
+		     to_underlying (sect_off), to_underlying (dup_sect_off),
+		     hex_string (dwo_unit->signature));
 	}
-
-      info_ptr += per_cu.length;
+      *slot = (void *)dwo_unit;
     }
-
-  return dwo_unit;
 }
 
 /* DWP file .debug_{cu,tu}_index section format:
@@ -10772,7 +10774,7 @@ open_and_init_dwo_file (struct dwarf2_per_cu_data *per_cu,
   bfd_map_over_sections (dwo_file->dbfd, dwarf2_locate_dwo_sections,
 			 &dwo_file->sections);
 
-  dwo_file->cu = create_dwo_cu (dwo_file);
+  create_cus_hash_table (*dwo_file, dwo_file->sections.info, dwo_file->cus);
 
   create_debug_types_hash_table (dwo_file, dwo_file->sections.types,
 				 dwo_file->tus);
@@ -11139,10 +11141,14 @@ lookup_dwo_cutu (struct dwarf2_per_cu_data *this_unit,
 	      dwo_cutu
 		= (struct dwo_unit *) htab_find (dwo_file->tus, &find_dwo_cutu);
 	    }
-	  else if (!is_debug_types && dwo_file->cu)
+	  else if (!is_debug_types && dwo_file->cus)
 	    {
-	      if (signature == dwo_file->cu->signature)
-		dwo_cutu = dwo_file->cu;
+	      struct dwo_unit find_dwo_cutu;
+
+	      memset (&find_dwo_cutu, 0, sizeof (find_dwo_cutu));
+	      find_dwo_cutu.signature = signature;
+	      dwo_cutu = (struct dwo_unit *)htab_find (dwo_file->cus,
+						       &find_dwo_cutu);
 	    }
 
 	  if (dwo_cutu != NULL)
diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu.S gdb/testsuite/gdb.dwarf2/fission-multi-cu.S
new file mode 100644
index 0000000000..d09a7e543d
--- /dev/null
+++ gdb/testsuite/gdb.dwarf2/fission-multi-cu.S
@@ -0,0 +1,374 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.
+
+   This file was created by doing:
+
+   clang fission-multi-cu*.c -g -fno-split-dwarf-inlining -emit-llvm -S -c
+   llvm-link fission-multi-cu*.ll -S -o fission-multi-cu.ll
+   clang-tot fission-multi-cu.ll -gsplit-dwarf -S
+
+   and then massaging the output.
+*/
+	.text
+	.file	"llvm-link"
+	.globl	func
+	.p2align	4, 0x90
+	.type	func,@function
+func:                                   # @func
+.Lfunc_begin0:
+	.file	1 "fission-multi-cu1.c"
+	.loc	1 20 0                  # fission-multi-cu1.c:20:0
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	.loc	1 21 10 prologue_end    # fission-multi-cu1.c:21:10
+	movl	-4(%rbp), %edi
+	.loc	1 21 14 is_stmt 0       # fission-multi-cu1.c:21:14
+	addl	$1, %edi
+	.loc	1 21 3                  # fission-multi-cu1.c:21:3
+	movl	%edi, %eax
+	popq	%rbp
+	retq
+.Lfunc_end0:
+	.size	func, .Lfunc_end0-func
+	.cfi_endproc
+
+	.globl	main
+	.p2align	4, 0x90
+	.type	main,@function
+main:                                   # @main
+.Lfunc_begin1:
+	.file	2 "fission-multi-cu2.c"
+	.loc	2 23 0 is_stmt 1        # fission-multi-cu2.c:23:0
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	$4294967295, %edi       # imm = 0xFFFFFFFF
+	.loc	2 24 3 prologue_end     # fission-multi-cu2.c:24:3
+	movb	$0, %al
+	callq	func
+	xorl	%eax, %eax
+	.loc	2 25 1                  # fission-multi-cu2.c:25:1
+	popq	%rbp
+	retq
+.Lfunc_end1:
+	.size	main, .Lfunc_end1-main
+	.cfi_endproc
+
+	.section	.debug_str,"MS",@progbits,1
+.Lskel_string0:
+	.asciz	"fission-multi-cu.dwo"  # string offset=0
+.Lskel_string1:
+	.asciz	"/tmp/src/gdb/testsuite" # string offset=21
+	.section	.debug_loc.dwo,"",@progbits
+	.section	.debug_abbrev,"",@progbits
+	.byte	1                       # Abbreviation Code
+	.byte	17                      # DW_TAG_compile_unit
+	.byte	0                       # DW_CHILDREN_no
+	.byte	16                      # DW_AT_stmt_list
+	.byte	23                      # DW_FORM_sec_offset
+	.ascii	"\260B"                 # DW_AT_GNU_dwo_name
+	.byte	14                      # DW_FORM_strp
+	.byte	27                      # DW_AT_comp_dir
+	.byte	14                      # DW_FORM_strp
+	.ascii	"\261B"                 # DW_AT_GNU_dwo_id
+	.byte	7                       # DW_FORM_data8
+	.ascii	"\263B"                 # DW_AT_GNU_addr_base
+	.byte	23                      # DW_FORM_sec_offset
+	.byte	17                      # DW_AT_low_pc
+	.byte	1                       # DW_FORM_addr
+	.byte	18                      # DW_AT_high_pc
+	.byte	6                       # DW_FORM_data4
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	0                       # EOM(3)
+	.section	.debug_info,"",@progbits
+.Lcu_begin0:
+	.long	44                      # Length of Unit
+	.short	4                       # DWARF version number
+	.long	.debug_abbrev           # Offset Into Abbrev. Section
+	.byte	8                       # Address Size (in bytes)
+	.byte	1                       # Abbrev [1] 0xb:0x25 DW_TAG_compile_unit
+	.long	.Lline_table_start0     # DW_AT_stmt_list
+	.long	.Lskel_string0          # DW_AT_GNU_dwo_name
+	.long	.Lskel_string1          # DW_AT_comp_dir
+	.quad	7615852067747431413     # DW_AT_GNU_dwo_id
+	.long	.debug_addr             # DW_AT_GNU_addr_base
+	.quad	.Lfunc_begin0           # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+.Lcu_begin1:
+	.long	44                      # Length of Unit
+	.short	4                       # DWARF version number
+	.long	.debug_abbrev           # Offset Into Abbrev. Section
+	.byte	8                       # Address Size (in bytes)
+	.byte	1                       # Abbrev [1] 0xb:0x25 DW_TAG_compile_unit
+	.long	.Lline_table_start0     # DW_AT_stmt_list
+	.long	.Lskel_string0          # DW_AT_GNU_dwo_name
+	.long	.Lskel_string1          # DW_AT_comp_dir
+	.quad	2037650261599692324     # DW_AT_GNU_dwo_id
+	.long	.debug_addr             # DW_AT_GNU_addr_base
+	.quad	.Lfunc_begin1           # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+	.section	.debug_ranges,"",@progbits
+	.section	.debug_macinfo,"",@progbits
+.Lcu_macro_begin1:
+.Lcu_macro_begin3:
+	.byte	0                       # End Of Macro List Mark
+	.section	.debug_str.dwo,"MS",@progbits,1
+.Linfo_string0:
+	.asciz	"fission-multi-cu.dwo"  # string offset=0
+.Linfo_string1:
+	.asciz	"clang version 5.0.0 (trunk 302855) (llvm/trunk 302853)" # string offset=21
+.Linfo_string2:
+	.asciz	"fission-multi-cu1.c" # string offset=76
+.Linfo_string3:
+	.asciz	"fission-multi-cu2.c" # string offset=96
+.Linfo_string4:
+	.asciz	"func"                  # string offset=116
+.Linfo_string5:
+	.asciz	"int"                   # string offset=121
+.Linfo_string6:
+	.asciz	"main"                  # string offset=125
+.Linfo_string7:
+	.asciz	"arg"                   # string offset=130
+	.section	.debug_str_offsets.dwo,"",@progbits
+	.long	0
+	.long	21
+	.long	76
+	.long	96
+	.long	116
+	.long	121
+	.long	125
+	.long	130
+	.section	.debug_info.dwo,"",@progbits
+	.long	53                      # Length of Unit
+	.short	4                       # DWARF version number
+	.long	0                       # Offset Into Abbrev. Section
+	.byte	8                       # Address Size (in bytes)
+	.byte	1                       # Abbrev [1] 0xb:0x2e DW_TAG_compile_unit
+	.byte	0                       # DW_AT_GNU_dwo_name
+	.byte	1                       # DW_AT_producer
+	.short	12                      # DW_AT_language
+	.byte	2                       # DW_AT_name
+	.quad	7615852067747431413     # DW_AT_GNU_dwo_id
+	.byte	2                       # Abbrev [2] 0x19:0x1b DW_TAG_subprogram
+	.byte	0                       # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+	.byte	1                       # DW_AT_frame_base
+	.byte	86
+	.byte	4                       # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	19                      # DW_AT_decl_line
+                                        # DW_AT_prototyped
+	.long	52                      # DW_AT_type
+                                        # DW_AT_external
+	.byte	3                       # Abbrev [3] 0x28:0xb DW_TAG_formal_parameter
+	.byte	2                       # DW_AT_location
+	.byte	145
+	.byte	124
+	.byte	7                       # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	19                      # DW_AT_decl_line
+	.long	52                      # DW_AT_type
+	.byte	0                       # End Of Children Mark
+	.byte	4                       # Abbrev [4] 0x34:0x4 DW_TAG_base_type
+	.byte	5                       # DW_AT_name
+	.byte	5                       # DW_AT_encoding
+	.byte	4                       # DW_AT_byte_size
+	.byte	0                       # End Of Children Mark
+	.long	41                      # Length of Unit
+	.short	4                       # DWARF version number
+	.long	0                       # Offset Into Abbrev. Section
+	.byte	8                       # Address Size (in bytes)
+	.byte	1                       # Abbrev [1] 0xb:0x22 DW_TAG_compile_unit
+	.byte	0                       # DW_AT_GNU_dwo_name
+	.byte	1                       # DW_AT_producer
+	.short	12                      # DW_AT_language
+	.byte	3                       # DW_AT_name
+	.quad	2037650261599692324     # DW_AT_GNU_dwo_id
+	.byte	5                       # Abbrev [5] 0x19:0xf DW_TAG_subprogram
+	.byte	1                       # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+	.byte	1                       # DW_AT_frame_base
+	.byte	86
+	.byte	6                       # DW_AT_name
+	.byte	2                       # DW_AT_decl_file
+	.byte	22                      # DW_AT_decl_line
+	.long	40                      # DW_AT_type
+                                        # DW_AT_external
+	.byte	4                       # Abbrev [4] 0x28:0x4 DW_TAG_base_type
+	.byte	5                       # DW_AT_name
+	.byte	5                       # DW_AT_encoding
+	.byte	4                       # DW_AT_byte_size
+	.byte	0                       # End Of Children Mark
+	.section	.debug_abbrev.dwo,"",@progbits
+	.byte	1                       # Abbreviation Code
+	.byte	17                      # DW_TAG_compile_unit
+	.byte	1                       # DW_CHILDREN_yes
+	.ascii	"\260B"                 # DW_AT_GNU_dwo_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	37                      # DW_AT_producer
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	19                      # DW_AT_language
+	.byte	5                       # DW_FORM_data2
+	.byte	3                       # DW_AT_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.ascii	"\261B"                 # DW_AT_GNU_dwo_id
+	.byte	7                       # DW_FORM_data8
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	2                       # Abbreviation Code
+	.byte	46                      # DW_TAG_subprogram
+	.byte	1                       # DW_CHILDREN_yes
+	.byte	17                      # DW_AT_low_pc
+	.ascii	"\201>"                 # DW_FORM_GNU_addr_index
+	.byte	18                      # DW_AT_high_pc
+	.byte	6                       # DW_FORM_data4
+	.byte	64                      # DW_AT_frame_base
+	.byte	24                      # DW_FORM_exprloc
+	.byte	3                       # DW_AT_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	58                      # DW_AT_decl_file
+	.byte	11                      # DW_FORM_data1
+	.byte	59                      # DW_AT_decl_line
+	.byte	11                      # DW_FORM_data1
+	.byte	39                      # DW_AT_prototyped
+	.byte	25                      # DW_FORM_flag_present
+	.byte	73                      # DW_AT_type
+	.byte	19                      # DW_FORM_ref4
+	.byte	63                      # DW_AT_external
+	.byte	25                      # DW_FORM_flag_present
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	3                       # Abbreviation Code
+	.byte	5                       # DW_TAG_formal_parameter
+	.byte	0                       # DW_CHILDREN_no
+	.byte	2                       # DW_AT_location
+	.byte	24                      # DW_FORM_exprloc
+	.byte	3                       # DW_AT_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	58                      # DW_AT_decl_file
+	.byte	11                      # DW_FORM_data1
+	.byte	59                      # DW_AT_decl_line
+	.byte	11                      # DW_FORM_data1
+	.byte	73                      # DW_AT_type
+	.byte	19                      # DW_FORM_ref4
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	4                       # Abbreviation Code
+	.byte	36                      # DW_TAG_base_type
+	.byte	0                       # DW_CHILDREN_no
+	.byte	3                       # DW_AT_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	62                      # DW_AT_encoding
+	.byte	11                      # DW_FORM_data1
+	.byte	11                      # DW_AT_byte_size
+	.byte	11                      # DW_FORM_data1
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	5                       # Abbreviation Code
+	.byte	46                      # DW_TAG_subprogram
+	.byte	0                       # DW_CHILDREN_no
+	.byte	17                      # DW_AT_low_pc
+	.ascii	"\201>"                 # DW_FORM_GNU_addr_index
+	.byte	18                      # DW_AT_high_pc
+	.byte	6                       # DW_FORM_data4
+	.byte	64                      # DW_AT_frame_base
+	.byte	24                      # DW_FORM_exprloc
+	.byte	3                       # DW_AT_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	58                      # DW_AT_decl_file
+	.byte	11                      # DW_FORM_data1
+	.byte	59                      # DW_AT_decl_line
+	.byte	11                      # DW_FORM_data1
+	.byte	73                      # DW_AT_type
+	.byte	19                      # DW_FORM_ref4
+	.byte	63                      # DW_AT_external
+	.byte	25                      # DW_FORM_flag_present
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	0                       # EOM(3)
+	.section	.debug_line.dwo,"",@progbits
+.Ltmp4:
+	.long	(.Ltmp5-.Ltmp4)-4
+	.short	2
+	.long	(.Ltmp6-.Ltmp4)-10
+	.byte	1
+	.byte	1
+	.byte	-5
+	.byte	14
+	.byte	1
+	.byte	0
+	.byte	0
+.Ltmp6:
+.Ltmp5:
+	.section	.debug_addr,"",@progbits
+	.quad	.Lfunc_begin0
+	.quad	.Lfunc_begin1
+	.section	.debug_pubnames,"",@progbits
+	.long	.LpubNames_end0-.LpubNames_begin0 # Length of Public Names Info
+.LpubNames_begin0:
+	.short	2                       # DWARF Version
+	.long	.Lcu_begin0             # Offset of Compilation Unit Info
+	.long	48                      # Compilation Unit Length
+	.long	25                      # DIE offset
+	.asciz	"func"                  # External Name
+	.long	0                       # End Mark
+.LpubNames_end0:
+	.long	.LpubNames_end1-.LpubNames_begin1 # Length of Public Names Info
+.LpubNames_begin1:
+	.short	2                       # DWARF Version
+	.long	.Lcu_begin1             # Offset of Compilation Unit Info
+	.long	48                      # Compilation Unit Length
+	.long	25                      # DIE offset
+	.asciz	"main"                  # External Name
+	.long	0                       # End Mark
+.LpubNames_end1:
+	.section	.debug_pubtypes,"",@progbits
+	.long	.LpubTypes_end0-.LpubTypes_begin0 # Length of Public Types Info
+.LpubTypes_begin0:
+	.short	2                       # DWARF Version
+	.long	.Lcu_begin0             # Offset of Compilation Unit Info
+	.long	48                      # Compilation Unit Length
+	.long	52                      # DIE offset
+	.asciz	"int"                   # External Name
+	.long	0                       # End Mark
+.LpubTypes_end0:
+	.long	.LpubTypes_end1-.LpubTypes_begin1 # Length of Public Types Info
+.LpubTypes_begin1:
+	.short	2                       # DWARF Version
+	.long	.Lcu_begin1             # Offset of Compilation Unit Info
+	.long	48                      # Compilation Unit Length
+	.long	40                      # DIE offset
+	.asciz	"int"                   # External Name
+	.long	0                       # End Mark
+.LpubTypes_end1:
+
+	.ident	"clang version 5.0.0 (trunk 302855) (llvm/trunk 302853)"
+	.ident	"clang version 5.0.0 (trunk 302855) (llvm/trunk 302853)"
+	.section	".note.GNU-stack","",@progbits
+	.section	.debug_line,"",@progbits
+.Lline_table_start0:
diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu.exp gdb/testsuite/gdb.dwarf2/fission-multi-cu.exp
new file mode 100644
index 0000000000..1f23c5b6ee
--- /dev/null
+++ gdb/testsuite/gdb.dwarf2/fission-multi-cu.exp
@@ -0,0 +1,67 @@
+# Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.
+
+load_lib dwarf.exp
+
+# We run objcopy locally to split out the .dwo file.
+if [is_remote host] {
+    return 0
+}
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if ![dwarf2_support] {
+    return 0
+}
+
+# This test can only be run on x86-64 targets.
+if {![istarget x86_64-*] || ![is_lp64_target]} {
+    return 0
+}
+
+standard_testfile .S
+
+if [build_executable_from_fission_assembler \
+	"$testfile.exp" "$binfile" "$srcfile" {nodebug}] {
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+# Make sure we can find the .dwo file, regardless of whether we're
+# running in parallel mode.
+gdb_test_no_output "set debug-file-directory [file dirname $binfile]" \
+    "set debug-file-directory"
+gdb_load $binfile
+
+if ![runto_main] {
+    return -1
+}
+
+# Do a few basic things to verify we're finding the DWO debug info.
+
+gdb_test "ptype main" "type = int \\(\\)"
+gdb_test "ptype func" "type = int \\(int\\)"
+
+gdb_test "frame" "#0 *main \\(\\) at ${testfile}2\\.c:$decimal.*" \
+    "frame in main"
+
+gdb_test "break func" "Breakpoint.*at.* file .*${testfile}1\\.c, line .*"
+
+gdb_test "continue" "Breakpoint.* func \\(arg=-1\\).*" \
+    "continue to func"
+
+gdb_test "frame" "#0 *func \\(arg=-1\\) at ${testfile}1\\.c:$decimal.*" \
+    "frame in func"
diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu1.c gdb/testsuite/gdb.dwarf2/fission-multi-cu1.c
new file mode 100644
index 0000000000..d93e2f912e
--- /dev/null
+++ gdb/testsuite/gdb.dwarf2/fission-multi-cu1.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.  */
+
+int
+func (int arg)
+{
+  return arg + 1;
+}
diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu2.c gdb/testsuite/gdb.dwarf2/fission-multi-cu2.c
new file mode 100644
index 0000000000..053b3ea141
--- /dev/null
+++ gdb/testsuite/gdb.dwarf2/fission-multi-cu2.c
@@ -0,0 +1,24 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.  */
+
+void func ();
+
+int
+main ()
+{
+  func (-1);
+}

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Fission support for multiple CUs per DWO file
  2017-06-01 23:33 ` David Blaikie
@ 2017-06-27 18:52   ` David Blaikie
  2017-06-28  0:56     ` Doug Evans via gdb-patches
  0 siblings, 1 reply; 6+ messages in thread
From: David Blaikie @ 2017-06-27 18:52 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, Pedro Alves

Ping (no rush, but trying not to forget it myself (: )

On Thu, Jun 1, 2017 at 4:33 PM, David Blaikie <dblaikie@gmail.com> wrote:
> gdb/ChangeLog:
>
> 2017-05-12  David Blaikie  <dblaikie@gmail.com>
>
> * dwarf2read.c (struct dwo_file): Use a htab of dwo_unit* (rather than
> a singular dwo_unit*) to support multiple CUs in the same way that
> multiple TUs are supported.
> (static void create_cus_hash_table): Replace create_dwo_cu with a
> function for parsing multiple CUs from a DWO file.
> (open_and_init_dwo_file): Use create_cus_hash_table rather than create_dwo_cu.
> (lookup_dwo_cutu): Lookup CU in the hash table in the dwo_file with
> htab_find, rather than comparing the signature to a singleton CU in
> the dwo_file.
>
> gdb/testsuite/ChangeLog:
>
> 2017-05-12  David Blaikie  <dblaikie@gmail.com>
>
> * gdb.dwarf2/fission-multi-cu.S: Test containing multiple CUs in a
> DWO, built from fission-multi-cu{1,2}.c.
> * gdb.dwarf2/fission-multi-cu.exp: Test similar to fission-base.exp,
> except putting 'main' and 'func' in separate CUs while in the same DWO
> file.
> * gdb.dwarf2/fission-multi-cu1.c: First CU for the multi-CU-single-DWO test.
> * gdb.dwarf2/fission-multi-cu2.c: Second CU for the multi-CU-single-DWO test.
>
> On Mon, May 22, 2017 at 11:01 AM, Doug Evans <dje@google.com> wrote:
>> David Blaikie writes:
>>  > ...
>>
>> Hi. Review comments inline.
>
> Hi - thanks for the review!
>
> (responses inline, patch addressing the issues is attached)
>
> Do let me know if there's other things that'd be good to address or if
> this looks good as-is.
>
> Thanks,
> - Dave
>
>> All nits.
>>
>> First one: Tab instead of spaces throughout (including ChangeLog entries).
>
> Think I got all that addressed - though GMail seems to be getting in
> my way of adding tabs into the ChangeLog entries inline in the email.
> I'll be sure they're there when I commit it.
>
>>
>> The testcase is fine with me.
>>
>>  > gdb/ChangeLog:
>>  >
>>  > 2017-05-12  David Blaikie  <dblaikie@gmail.com>
>>  >
>>  >         * dwarf2read.c (struct dwo_file): Use a htab of dwo_unit*
>>  > (rather than a singular dwo_unit*) to support multiple CUs in the same
>>  > way that multiple TUs are supported.
>>  >         (static void create_cus_hash_table): Replace create_dwo_cu
>>  > with a function for parsing multiple CUs from a DWO file.
>>  >         (open_and_init_dwo_file): Use create_cus_hash_table rather
>>  > than create_dwo_cu.
>>  >         (lookup_dwo_cutu): Lookup CU in the hash table in the dwo_file
>>  > with htab_find, rather than comparing the signature to a singleton CU
>>  > in the dwo_file.
>>  >
>>  > gdb/testsuite/ChangeLog:
>>  >
>>  > 2017-05-12  David Blaikie  <dblaikie@gmail.com>
>>  >
>>  >         * gdb.dwarf2/fission-multi-cu.S: Test containing multiple CUs
>>  > in a DWO, built from fission-multi-cu{1,2}.c.
>>  >         * gdb.dwarf2/fission-multi-cu.exp: Test similar to
>>  > fission-base.exp, except putting 'main' and 'func' in separate CUs
>>  > while in the same DWO file.
>>  >         * gdb.dwarf2/fission-multi-cu1.c: First CU for the
>>  > multi-CU-single-DWO test.
>>  >         * gdb.dwarf2/fission-multi-cu2.c: Second CU for the
>>  > multi-CU-single-DWO test.
>>  > diff --git gdb/dwarf2read.c gdb/dwarf2read.c
>>  > index b58d0fc16e..29eb5a14b2 100644
>>  > --- gdb/dwarf2read.c
>>  > +++ gdb/dwarf2read.c
>>  > @@ -852,12 +852,9 @@ struct dwo_file
>>  >       sections (for lack of a better name).  */
>>  >    struct dwo_sections sections;
>>  >
>>  > -  /* The CU in the file.
>>  > -     We only support one because having more than one requires hacking the
>>  > -     dwo_name of each to match, which is highly unlikely to happen.
>>  > -     Doing this means all TUs can share comp_dir: We also assume that
>>  > -     DW_AT_comp_dir across all TUs in a DWO file will be identical.  */
>>  > -  struct dwo_unit *cu;
>>  > +  /* The CUs in the file.
>>  > +     Each element is a struct dwo_unit. */
>>
>> Since this is currently non-standard, I think it will help some readers
>> to elaborate on the Why of things here. IOW, add a comment explaining why
>> we're now supporting multi-CUs in one DWO file.
>
> Commented about the use case here & that it's supported as an extension.
>
>>
>>  > +  htab_t cus;
>>  >
>>  >    /* Table of TUs in the file.
>>  >       Each element is a struct dwo_unit.  */
>>  > @@ -9702,72 +9699,75 @@ create_dwo_cu_reader (const struct die_reader_specs *reader,
>>  >                      hex_string (dwo_unit->signature));
>>  >  }
>>  >
>>  > -/* Create the dwo_unit for the lone CU in DWO_FILE.
>>  > -   Note: This function processes DWO files only, not DWP files.  */
>>
>> Need to keep the function comment (just reword it).
>> And please keep the note about only being used for DWO files, not DWP files.
>
> Kept & reworded.
>
>>
>>  > -
>>  > -static struct dwo_unit *
>>  > -create_dwo_cu (struct dwo_file *dwo_file)
>>  > +static void create_cus_hash_table (struct dwo_file &dwo_file,
>>  > +                                   dwarf2_section_info &section,
>>  > +                                   htab_t &cus_htab)
>>  >  {
>>  >    struct objfile *objfile = dwarf2_per_objfile->objfile;
>>  > -  struct dwarf2_section_info *section = &dwo_file->sections.info;
>>  > +  const struct dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev;
>>  >    const gdb_byte *info_ptr, *end_ptr;
>>  > -  struct create_dwo_cu_data create_dwo_cu_data;
>>  > -  struct dwo_unit *dwo_unit;
>>  >
>>  > -  dwarf2_read_section (objfile, section);
>>  > -  info_ptr = section->buffer;
>>  > +  dwarf2_read_section (objfile, &section);
>>  > +  info_ptr = section.buffer;
>>  >
>>  >    if (info_ptr == NULL)
>>  > -    return NULL;
>>  > +    return;
>>  >
>>  >    if (dwarf_read_debug)
>>  >      {
>>  >        fprintf_unfiltered (gdb_stdlog, "Reading %s for %s:\n",
>>  > -                      get_section_name (section),
>>  > -                      get_section_file_name (section));
>>  > +                      get_section_name (&section),
>>  > +                      get_section_file_name (&section));
>>  >      }
>>  >
>>  > -  create_dwo_cu_data.dwo_file = dwo_file;
>>  > -  dwo_unit = NULL;
>>  > -
>>  > -  end_ptr = info_ptr + section->size;
>>  > +  end_ptr = info_ptr  + section.size;
>>
>> extra space
>
> Removed.
>
>>
>>  >    while (info_ptr < end_ptr)
>>  >      {
>>  >        struct dwarf2_per_cu_data per_cu;
>>  > +      struct create_dwo_cu_data create_dwo_cu_data;
>>  > +      struct dwo_unit *dwo_unit;
>>  > +      void **slot;
>>  > +      sect_offset sect_off = (sect_offset) (info_ptr - section.buffer);
>>  >
>>  >        memset (&create_dwo_cu_data.dwo_unit, 0,
>>  >            sizeof (create_dwo_cu_data.dwo_unit));
>>  >        memset (&per_cu, 0, sizeof (per_cu));
>>  >        per_cu.objfile = objfile;
>>  >        per_cu.is_debug_types = 0;
>>  > -      per_cu.sect_off = sect_offset (info_ptr - section->buffer);
>>  > -      per_cu.section = section;
>>  > +      per_cu.sect_off = sect_offset (info_ptr - section.buffer);
>>  > +      per_cu.section = &section;
>>  > +      create_dwo_cu_data.dwo_file = &dwo_file;
>>  >
>>  > -      init_cutu_and_read_dies_no_follow (&per_cu, dwo_file,
>>  > +      init_cutu_and_read_dies_no_follow (&per_cu, &dwo_file,
>>  >                                       create_dwo_cu_reader,
>>  >                                       &create_dwo_cu_data);
>>  > +      info_ptr += per_cu.length;
>>  >
>>  > -      if (create_dwo_cu_data.dwo_unit.dwo_file != NULL)
>>  > -    {
>>  > -      /* If we've already found one, complain.  We only support one
>>  > -         because having more than one requires hacking the dwo_name of
>>  > -         each to match, which is highly unlikely to happen.  */
>>  > -      if (dwo_unit != NULL)
>>  > -        {
>>  > -          complaint (&symfile_complaints,
>>  > -                     _("Multiple CUs in DWO file %s [in module %s]"),
>>  > -                     dwo_file->dwo_name, objfile_name (objfile));
>>  > -          break;
>>  > -        }
>>
>> Add a comment explaining why this test is present:
>>
>>  > +      if (create_dwo_cu_data.dwo_unit.dwo_file == NULL)
>>  > +        continue;
>
> Added a comment & fixed a mistake I introduced by initializing
> dwo_file before this call rather than letting the call initialize it.
> Looks like the original code was using this for error detection & I
> attempted to keep that the same but broke it by initializing the value
> early.
>
>>  >
>>  > -      dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
>>  > -      *dwo_unit = create_dwo_cu_data.dwo_unit;
>>  > -    }
>>  > +      if (cus_htab == NULL)
>>
>> Remove the surrounding braces.
>>
>>  > +        {
>>  > +          cus_htab = allocate_dwo_unit_table (objfile);
>>  > +        }
>
> Removed & reduced indentation.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Fission support for multiple CUs per DWO file
  2017-06-27 18:52   ` David Blaikie
@ 2017-06-28  0:56     ` Doug Evans via gdb-patches
  2017-07-14 17:10       ` Yao Qi
  0 siblings, 1 reply; 6+ messages in thread
From: Doug Evans via gdb-patches @ 2017-06-28  0:56 UTC (permalink / raw)
  To: David Blaikie; +Cc: gdb-patches, Pedro Alves

Once more with feeling (err, not text/html ...).

On Tue, Jun 27, 2017 at 11:52 AM, David Blaikie <dblaikie@gmail.com> wrote:
>
> Ping (no rush, but trying not to forget it myself (: )
>
> On Thu, Jun 1, 2017 at 4:33 PM, David Blaikie <dblaikie@gmail.com> wrote:
> > gdb/ChangeLog:
> >
> > 2017-05-12  David Blaikie  <dblaikie@gmail.com>
> >
> > * dwarf2read.c (struct dwo_file): Use a htab of dwo_unit* (rather than
> > a singular dwo_unit*) to support multiple CUs in the same way that
> > multiple TUs are supported.
> > (static void create_cus_hash_table): Replace create_dwo_cu with a
> > function for parsing multiple CUs from a DWO file.
> > (open_and_init_dwo_file): Use create_cus_hash_table rather than create_dwo_cu.
> > (lookup_dwo_cutu): Lookup CU in the hash table in the dwo_file with
> > htab_find, rather than comparing the signature to a singleton CU in
> > the dwo_file.
> >
> > gdb/testsuite/ChangeLog:
> >
> > 2017-05-12  David Blaikie  <dblaikie@gmail.com>
> >
> > * gdb.dwarf2/fission-multi-cu.S: Test containing multiple CUs in a
> > DWO, built from fission-multi-cu{1,2}.c.
> > * gdb.dwarf2/fission-multi-cu.exp: Test similar to fission-base.exp,
> > except putting 'main' and 'func' in separate CUs while in the same DWO
> > file.
> > * gdb.dwarf2/fission-multi-cu1.c: First CU for the multi-CU-single-DWO test.
> > * gdb.dwarf2/fission-multi-cu2.c: Second CU for the multi-CU-single-DWO test.
> >
> > On Mon, May 22, 2017 at 11:01 AM, Doug Evans <dje@google.com> wrote:
> >> David Blaikie writes:
> >>  > ...
> >>
> >> Hi. Review comments inline.
> >
> > Hi - thanks for the review!
> >
> > (responses inline, patch addressing the issues is attached)
> >
> > Do let me know if there's other things that'd be good to address or if
> > this looks good as-is.

LGTM

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Fission support for multiple CUs per DWO file
  2017-06-28  0:56     ` Doug Evans via gdb-patches
@ 2017-07-14 17:10       ` Yao Qi
  0 siblings, 0 replies; 6+ messages in thread
From: Yao Qi @ 2017-07-14 17:10 UTC (permalink / raw)
  To: Doug Evans; +Cc: David Blaikie, gdb-patches, Pedro Alves

"Doug Evans via gdb-patches" <gdb-patches@sourceware.org> writes:

Hi David,
This patch causes some regressions, found by buildbot,
https://sourceware.org/ml/gdb-testers/2017-q3/msg00186.html
I can reproduce the fail on my machine too.

(gdb) file /home/yao.qi/SourceCode/gnu/build/gdb/testsuite/outputs/gdb.dwarf2/fission-reread/fission-reread^M
Reading symbols from /home/yao.qi/SourceCode/gnu/build/gdb/testsuite/outputs/gdb.dwarf2/fission-reread/fission-reread...Dwarf Error: bad offset (0x0) in compilation unit header (offset 0x0 + 6) [in module /home/yao.qi/SourceCode/gnu/build/gdb/testsuite/outputs/gdb.dwarf2/fission-reread/fission-reread.dwo]^M
(no debugging symbols found)...done.^M
(gdb) break main^M
Breakpoint 1 at 0x4004d6^M
(gdb) PASS: gdb.dwarf2/fission-reread.exp: break main
ptype baz^M
type = <data variable, no debug info>^M
(gdb) FAIL: gdb.dwarf2/fission-reread.exp: ptype baz

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] Fission support for multiple CUs per DWO file
@ 2017-05-14 16:20 David Blaikie
  0 siblings, 0 replies; 6+ messages in thread
From: David Blaikie @ 2017-05-14 16:20 UTC (permalink / raw)
  To: gdb-patches, dje, Pedro Alves

[-- Attachment #1: Type: text/plain, Size: 2895 bytes --]

(previous thread: https://sourceware.org/ml/gdb-patches/2017-04/msg00749.html )

LLVM LTO (ThinLTO, full LTO, any other situation where two LLVM
modules with debug info are merged into one/cross imported, etc)
produces multiple CUs in a single object file.

The best guess at how this should be combined with Fission (though it
seem there's any particular plan/spec for this, so it's a bit
off-label, for sure), is that multiple skeletons and dwo CUs should be
produced - but all dwo CUs in one .dwo file (matching (actually
objcopy'd out of) the .o file produced) and all the skeleton CUs
providing that one/same file name as the dwo_name.

Here's a patch to support that and seems to work well with LLVM's output here.

[An extra wrinkle is that LLVM would normally try to use
DW_FORM_ref_addr to refer to entities across the CU boundary (types,
to avoid duplicating type information in each CU, abstract
subprograms/variables to avoid duplication and accurately reflect
cross-CU inlining (eg: a file-local function (namespace static, or
anonymous namespace) in one CU might end inlined into a function in
another CU)). The problem with this is that the DWP format doesn't
carry enough information currently to make this possible (the INFO
column contains only the contribution of a single CU, even if it came
from a multi-CU DWO file - so there's no way to know where to resolve
the ref_addr relative to). So for now I've added a workaround to LLVM
to duplicate rather than using ref_addr in this case. But I hope/plan
to fix this as soon as possible once a reasonable format can be
decided on (see dwarf-discuss mailing list thread) and DWP tool and
GDB are fixed to address that. But for now, multiple CUs in a DWO
without cross-CU references is still valuable]


gdb/ChangeLog:

2017-05-12  David Blaikie  <dblaikie@gmail.com>

        * dwarf2read.c (struct dwo_file): Use a htab of dwo_unit*
(rather than a singular dwo_unit*) to support multiple CUs in the same
way that multiple TUs are supported.
        (static void create_cus_hash_table): Replace create_dwo_cu
with a function for parsing multiple CUs from a DWO file.
        (open_and_init_dwo_file): Use create_cus_hash_table rather
than create_dwo_cu.
        (lookup_dwo_cutu): Lookup CU in the hash table in the dwo_file
with htab_find, rather than comparing the signature to a singleton CU
in the dwo_file.

gdb/testsuite/ChangeLog:

2017-05-12  David Blaikie  <dblaikie@gmail.com>

        * gdb.dwarf2/fission-multi-cu.S: Test containing multiple CUs
in a DWO, built from fission-multi-cu{1,2}.c.
        * gdb.dwarf2/fission-multi-cu.exp: Test similar to
fission-base.exp, except putting 'main' and 'func' in separate CUs
while in the same DWO file.
        * gdb.dwarf2/fission-multi-cu1.c: First CU for the
multi-CU-single-DWO test.
        * gdb.dwarf2/fission-multi-cu2.c: Second CU for the
multi-CU-single-DWO test.

[-- Attachment #2: multiple_cus_per_dwo.diff --]
[-- Type: text/plain, Size: 25983 bytes --]

diff --git gdb/dwarf2read.c gdb/dwarf2read.c
index b58d0fc16e..29eb5a14b2 100644
--- gdb/dwarf2read.c
+++ gdb/dwarf2read.c
@@ -852,12 +852,9 @@ struct dwo_file
      sections (for lack of a better name).  */
   struct dwo_sections sections;
 
-  /* The CU in the file.
-     We only support one because having more than one requires hacking the
-     dwo_name of each to match, which is highly unlikely to happen.
-     Doing this means all TUs can share comp_dir: We also assume that
-     DW_AT_comp_dir across all TUs in a DWO file will be identical.  */
-  struct dwo_unit *cu;
+  /* The CUs in the file.
+     Each element is a struct dwo_unit. */
+  htab_t cus;
 
   /* Table of TUs in the file.
      Each element is a struct dwo_unit.  */
@@ -9702,72 +9699,75 @@ create_dwo_cu_reader (const struct die_reader_specs *reader,
 			hex_string (dwo_unit->signature));
 }
 
-/* Create the dwo_unit for the lone CU in DWO_FILE.
-   Note: This function processes DWO files only, not DWP files.  */
-
-static struct dwo_unit *
-create_dwo_cu (struct dwo_file *dwo_file)
+static void create_cus_hash_table (struct dwo_file &dwo_file,
+                                   dwarf2_section_info &section,
+                                   htab_t &cus_htab)
 {
   struct objfile *objfile = dwarf2_per_objfile->objfile;
-  struct dwarf2_section_info *section = &dwo_file->sections.info;
+  const struct dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev;
   const gdb_byte *info_ptr, *end_ptr;
-  struct create_dwo_cu_data create_dwo_cu_data;
-  struct dwo_unit *dwo_unit;
 
-  dwarf2_read_section (objfile, section);
-  info_ptr = section->buffer;
+  dwarf2_read_section (objfile, &section);
+  info_ptr = section.buffer;
 
   if (info_ptr == NULL)
-    return NULL;
+    return;
 
   if (dwarf_read_debug)
     {
       fprintf_unfiltered (gdb_stdlog, "Reading %s for %s:\n",
-			  get_section_name (section),
-			  get_section_file_name (section));
+			  get_section_name (&section),
+			  get_section_file_name (&section));
     }
 
-  create_dwo_cu_data.dwo_file = dwo_file;
-  dwo_unit = NULL;
-
-  end_ptr = info_ptr + section->size;
+  end_ptr = info_ptr  + section.size;
   while (info_ptr < end_ptr)
     {
       struct dwarf2_per_cu_data per_cu;
+      struct create_dwo_cu_data create_dwo_cu_data;
+      struct dwo_unit *dwo_unit;
+      void **slot;
+      sect_offset sect_off = (sect_offset) (info_ptr - section.buffer);
 
       memset (&create_dwo_cu_data.dwo_unit, 0,
 	      sizeof (create_dwo_cu_data.dwo_unit));
       memset (&per_cu, 0, sizeof (per_cu));
       per_cu.objfile = objfile;
       per_cu.is_debug_types = 0;
-      per_cu.sect_off = sect_offset (info_ptr - section->buffer);
-      per_cu.section = section;
+      per_cu.sect_off = sect_offset (info_ptr - section.buffer);
+      per_cu.section = &section;
+      create_dwo_cu_data.dwo_file = &dwo_file;
 
-      init_cutu_and_read_dies_no_follow (&per_cu, dwo_file,
+      init_cutu_and_read_dies_no_follow (&per_cu, &dwo_file,
 					 create_dwo_cu_reader,
 					 &create_dwo_cu_data);
+      info_ptr += per_cu.length;
 
-      if (create_dwo_cu_data.dwo_unit.dwo_file != NULL)
-	{
-	  /* If we've already found one, complain.  We only support one
-	     because having more than one requires hacking the dwo_name of
-	     each to match, which is highly unlikely to happen.  */
-	  if (dwo_unit != NULL)
-	    {
-	      complaint (&symfile_complaints,
-			 _("Multiple CUs in DWO file %s [in module %s]"),
-			 dwo_file->dwo_name, objfile_name (objfile));
-	      break;
-	    }
+      if (create_dwo_cu_data.dwo_unit.dwo_file == NULL)
+        continue;
 
-	  dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
-	  *dwo_unit = create_dwo_cu_data.dwo_unit;
-	}
+      if (cus_htab == NULL)
+        {
+          cus_htab = allocate_dwo_unit_table (objfile);
+        }
 
-      info_ptr += per_cu.length;
-    }
+      dwo_unit = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwo_unit);
+      *dwo_unit = create_dwo_cu_data.dwo_unit;
+      slot = htab_find_slot (cus_htab, dwo_unit, INSERT);
+      gdb_assert (slot != NULL);
+      if (*slot != NULL)
+        {
+          const struct dwo_unit *dup_cu = (const struct dwo_unit *) *slot;
+          sect_offset dup_sect_off = dup_cu->sect_off;
 
-  return dwo_unit;
+	  complaint (&symfile_complaints,
+		     _("debug cu entry at offset 0x%x is duplicate to"
+		       " the entry at offset 0x%x, signature %s"),
+		     to_underlying (sect_off), to_underlying (dup_sect_off),
+		     hex_string (dwo_unit->signature));
+        }
+      *slot = (void *) dwo_unit;
+    }
 }
 
 /* DWP file .debug_{cu,tu}_index section format:
@@ -10772,7 +10772,7 @@ open_and_init_dwo_file (struct dwarf2_per_cu_data *per_cu,
   bfd_map_over_sections (dwo_file->dbfd, dwarf2_locate_dwo_sections,
 			 &dwo_file->sections);
 
-  dwo_file->cu = create_dwo_cu (dwo_file);
+  create_cus_hash_table (*dwo_file, dwo_file->sections.info, dwo_file->cus);
 
   create_debug_types_hash_table (dwo_file, dwo_file->sections.types,
 				 dwo_file->tus);
@@ -11139,10 +11139,13 @@ lookup_dwo_cutu (struct dwarf2_per_cu_data *this_unit,
 	      dwo_cutu
 		= (struct dwo_unit *) htab_find (dwo_file->tus, &find_dwo_cutu);
 	    }
-	  else if (!is_debug_types && dwo_file->cu)
+	  else if (!is_debug_types && dwo_file->cus)
 	    {
-	      if (signature == dwo_file->cu->signature)
-		dwo_cutu = dwo_file->cu;
+              struct dwo_unit find_dwo_cutu;
+
+              memset (&find_dwo_cutu, 0, sizeof (find_dwo_cutu));
+              find_dwo_cutu.signature = signature;
+              dwo_cutu = (struct dwo_unit *) htab_find (dwo_file->cus, &find_dwo_cutu);
 	    }
 
 	  if (dwo_cutu != NULL)
diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu.S gdb/testsuite/gdb.dwarf2/fission-multi-cu.S
new file mode 100644
index 0000000000..d09a7e543d
--- /dev/null
+++ gdb/testsuite/gdb.dwarf2/fission-multi-cu.S
@@ -0,0 +1,374 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.
+
+   This file was created by doing:
+
+   clang fission-multi-cu*.c -g -fno-split-dwarf-inlining -emit-llvm -S -c
+   llvm-link fission-multi-cu*.ll -S -o fission-multi-cu.ll
+   clang-tot fission-multi-cu.ll -gsplit-dwarf -S
+
+   and then massaging the output.
+*/
+	.text
+	.file	"llvm-link"
+	.globl	func
+	.p2align	4, 0x90
+	.type	func,@function
+func:                                   # @func
+.Lfunc_begin0:
+	.file	1 "fission-multi-cu1.c"
+	.loc	1 20 0                  # fission-multi-cu1.c:20:0
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	.loc	1 21 10 prologue_end    # fission-multi-cu1.c:21:10
+	movl	-4(%rbp), %edi
+	.loc	1 21 14 is_stmt 0       # fission-multi-cu1.c:21:14
+	addl	$1, %edi
+	.loc	1 21 3                  # fission-multi-cu1.c:21:3
+	movl	%edi, %eax
+	popq	%rbp
+	retq
+.Lfunc_end0:
+	.size	func, .Lfunc_end0-func
+	.cfi_endproc
+
+	.globl	main
+	.p2align	4, 0x90
+	.type	main,@function
+main:                                   # @main
+.Lfunc_begin1:
+	.file	2 "fission-multi-cu2.c"
+	.loc	2 23 0 is_stmt 1        # fission-multi-cu2.c:23:0
+	.cfi_startproc
+# BB#0:                                 # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	$4294967295, %edi       # imm = 0xFFFFFFFF
+	.loc	2 24 3 prologue_end     # fission-multi-cu2.c:24:3
+	movb	$0, %al
+	callq	func
+	xorl	%eax, %eax
+	.loc	2 25 1                  # fission-multi-cu2.c:25:1
+	popq	%rbp
+	retq
+.Lfunc_end1:
+	.size	main, .Lfunc_end1-main
+	.cfi_endproc
+
+	.section	.debug_str,"MS",@progbits,1
+.Lskel_string0:
+	.asciz	"fission-multi-cu.dwo"  # string offset=0
+.Lskel_string1:
+	.asciz	"/tmp/src/gdb/testsuite" # string offset=21
+	.section	.debug_loc.dwo,"",@progbits
+	.section	.debug_abbrev,"",@progbits
+	.byte	1                       # Abbreviation Code
+	.byte	17                      # DW_TAG_compile_unit
+	.byte	0                       # DW_CHILDREN_no
+	.byte	16                      # DW_AT_stmt_list
+	.byte	23                      # DW_FORM_sec_offset
+	.ascii	"\260B"                 # DW_AT_GNU_dwo_name
+	.byte	14                      # DW_FORM_strp
+	.byte	27                      # DW_AT_comp_dir
+	.byte	14                      # DW_FORM_strp
+	.ascii	"\261B"                 # DW_AT_GNU_dwo_id
+	.byte	7                       # DW_FORM_data8
+	.ascii	"\263B"                 # DW_AT_GNU_addr_base
+	.byte	23                      # DW_FORM_sec_offset
+	.byte	17                      # DW_AT_low_pc
+	.byte	1                       # DW_FORM_addr
+	.byte	18                      # DW_AT_high_pc
+	.byte	6                       # DW_FORM_data4
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	0                       # EOM(3)
+	.section	.debug_info,"",@progbits
+.Lcu_begin0:
+	.long	44                      # Length of Unit
+	.short	4                       # DWARF version number
+	.long	.debug_abbrev           # Offset Into Abbrev. Section
+	.byte	8                       # Address Size (in bytes)
+	.byte	1                       # Abbrev [1] 0xb:0x25 DW_TAG_compile_unit
+	.long	.Lline_table_start0     # DW_AT_stmt_list
+	.long	.Lskel_string0          # DW_AT_GNU_dwo_name
+	.long	.Lskel_string1          # DW_AT_comp_dir
+	.quad	7615852067747431413     # DW_AT_GNU_dwo_id
+	.long	.debug_addr             # DW_AT_GNU_addr_base
+	.quad	.Lfunc_begin0           # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+.Lcu_begin1:
+	.long	44                      # Length of Unit
+	.short	4                       # DWARF version number
+	.long	.debug_abbrev           # Offset Into Abbrev. Section
+	.byte	8                       # Address Size (in bytes)
+	.byte	1                       # Abbrev [1] 0xb:0x25 DW_TAG_compile_unit
+	.long	.Lline_table_start0     # DW_AT_stmt_list
+	.long	.Lskel_string0          # DW_AT_GNU_dwo_name
+	.long	.Lskel_string1          # DW_AT_comp_dir
+	.quad	2037650261599692324     # DW_AT_GNU_dwo_id
+	.long	.debug_addr             # DW_AT_GNU_addr_base
+	.quad	.Lfunc_begin1           # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+	.section	.debug_ranges,"",@progbits
+	.section	.debug_macinfo,"",@progbits
+.Lcu_macro_begin1:
+.Lcu_macro_begin3:
+	.byte	0                       # End Of Macro List Mark
+	.section	.debug_str.dwo,"MS",@progbits,1
+.Linfo_string0:
+	.asciz	"fission-multi-cu.dwo"  # string offset=0
+.Linfo_string1:
+	.asciz	"clang version 5.0.0 (trunk 302855) (llvm/trunk 302853)" # string offset=21
+.Linfo_string2:
+	.asciz	"fission-multi-cu1.c" # string offset=76
+.Linfo_string3:
+	.asciz	"fission-multi-cu2.c" # string offset=96
+.Linfo_string4:
+	.asciz	"func"                  # string offset=116
+.Linfo_string5:
+	.asciz	"int"                   # string offset=121
+.Linfo_string6:
+	.asciz	"main"                  # string offset=125
+.Linfo_string7:
+	.asciz	"arg"                   # string offset=130
+	.section	.debug_str_offsets.dwo,"",@progbits
+	.long	0
+	.long	21
+	.long	76
+	.long	96
+	.long	116
+	.long	121
+	.long	125
+	.long	130
+	.section	.debug_info.dwo,"",@progbits
+	.long	53                      # Length of Unit
+	.short	4                       # DWARF version number
+	.long	0                       # Offset Into Abbrev. Section
+	.byte	8                       # Address Size (in bytes)
+	.byte	1                       # Abbrev [1] 0xb:0x2e DW_TAG_compile_unit
+	.byte	0                       # DW_AT_GNU_dwo_name
+	.byte	1                       # DW_AT_producer
+	.short	12                      # DW_AT_language
+	.byte	2                       # DW_AT_name
+	.quad	7615852067747431413     # DW_AT_GNU_dwo_id
+	.byte	2                       # Abbrev [2] 0x19:0x1b DW_TAG_subprogram
+	.byte	0                       # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+	.byte	1                       # DW_AT_frame_base
+	.byte	86
+	.byte	4                       # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	19                      # DW_AT_decl_line
+                                        # DW_AT_prototyped
+	.long	52                      # DW_AT_type
+                                        # DW_AT_external
+	.byte	3                       # Abbrev [3] 0x28:0xb DW_TAG_formal_parameter
+	.byte	2                       # DW_AT_location
+	.byte	145
+	.byte	124
+	.byte	7                       # DW_AT_name
+	.byte	1                       # DW_AT_decl_file
+	.byte	19                      # DW_AT_decl_line
+	.long	52                      # DW_AT_type
+	.byte	0                       # End Of Children Mark
+	.byte	4                       # Abbrev [4] 0x34:0x4 DW_TAG_base_type
+	.byte	5                       # DW_AT_name
+	.byte	5                       # DW_AT_encoding
+	.byte	4                       # DW_AT_byte_size
+	.byte	0                       # End Of Children Mark
+	.long	41                      # Length of Unit
+	.short	4                       # DWARF version number
+	.long	0                       # Offset Into Abbrev. Section
+	.byte	8                       # Address Size (in bytes)
+	.byte	1                       # Abbrev [1] 0xb:0x22 DW_TAG_compile_unit
+	.byte	0                       # DW_AT_GNU_dwo_name
+	.byte	1                       # DW_AT_producer
+	.short	12                      # DW_AT_language
+	.byte	3                       # DW_AT_name
+	.quad	2037650261599692324     # DW_AT_GNU_dwo_id
+	.byte	5                       # Abbrev [5] 0x19:0xf DW_TAG_subprogram
+	.byte	1                       # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+	.byte	1                       # DW_AT_frame_base
+	.byte	86
+	.byte	6                       # DW_AT_name
+	.byte	2                       # DW_AT_decl_file
+	.byte	22                      # DW_AT_decl_line
+	.long	40                      # DW_AT_type
+                                        # DW_AT_external
+	.byte	4                       # Abbrev [4] 0x28:0x4 DW_TAG_base_type
+	.byte	5                       # DW_AT_name
+	.byte	5                       # DW_AT_encoding
+	.byte	4                       # DW_AT_byte_size
+	.byte	0                       # End Of Children Mark
+	.section	.debug_abbrev.dwo,"",@progbits
+	.byte	1                       # Abbreviation Code
+	.byte	17                      # DW_TAG_compile_unit
+	.byte	1                       # DW_CHILDREN_yes
+	.ascii	"\260B"                 # DW_AT_GNU_dwo_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	37                      # DW_AT_producer
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	19                      # DW_AT_language
+	.byte	5                       # DW_FORM_data2
+	.byte	3                       # DW_AT_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.ascii	"\261B"                 # DW_AT_GNU_dwo_id
+	.byte	7                       # DW_FORM_data8
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	2                       # Abbreviation Code
+	.byte	46                      # DW_TAG_subprogram
+	.byte	1                       # DW_CHILDREN_yes
+	.byte	17                      # DW_AT_low_pc
+	.ascii	"\201>"                 # DW_FORM_GNU_addr_index
+	.byte	18                      # DW_AT_high_pc
+	.byte	6                       # DW_FORM_data4
+	.byte	64                      # DW_AT_frame_base
+	.byte	24                      # DW_FORM_exprloc
+	.byte	3                       # DW_AT_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	58                      # DW_AT_decl_file
+	.byte	11                      # DW_FORM_data1
+	.byte	59                      # DW_AT_decl_line
+	.byte	11                      # DW_FORM_data1
+	.byte	39                      # DW_AT_prototyped
+	.byte	25                      # DW_FORM_flag_present
+	.byte	73                      # DW_AT_type
+	.byte	19                      # DW_FORM_ref4
+	.byte	63                      # DW_AT_external
+	.byte	25                      # DW_FORM_flag_present
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	3                       # Abbreviation Code
+	.byte	5                       # DW_TAG_formal_parameter
+	.byte	0                       # DW_CHILDREN_no
+	.byte	2                       # DW_AT_location
+	.byte	24                      # DW_FORM_exprloc
+	.byte	3                       # DW_AT_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	58                      # DW_AT_decl_file
+	.byte	11                      # DW_FORM_data1
+	.byte	59                      # DW_AT_decl_line
+	.byte	11                      # DW_FORM_data1
+	.byte	73                      # DW_AT_type
+	.byte	19                      # DW_FORM_ref4
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	4                       # Abbreviation Code
+	.byte	36                      # DW_TAG_base_type
+	.byte	0                       # DW_CHILDREN_no
+	.byte	3                       # DW_AT_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	62                      # DW_AT_encoding
+	.byte	11                      # DW_FORM_data1
+	.byte	11                      # DW_AT_byte_size
+	.byte	11                      # DW_FORM_data1
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	5                       # Abbreviation Code
+	.byte	46                      # DW_TAG_subprogram
+	.byte	0                       # DW_CHILDREN_no
+	.byte	17                      # DW_AT_low_pc
+	.ascii	"\201>"                 # DW_FORM_GNU_addr_index
+	.byte	18                      # DW_AT_high_pc
+	.byte	6                       # DW_FORM_data4
+	.byte	64                      # DW_AT_frame_base
+	.byte	24                      # DW_FORM_exprloc
+	.byte	3                       # DW_AT_name
+	.ascii	"\202>"                 # DW_FORM_GNU_str_index
+	.byte	58                      # DW_AT_decl_file
+	.byte	11                      # DW_FORM_data1
+	.byte	59                      # DW_AT_decl_line
+	.byte	11                      # DW_FORM_data1
+	.byte	73                      # DW_AT_type
+	.byte	19                      # DW_FORM_ref4
+	.byte	63                      # DW_AT_external
+	.byte	25                      # DW_FORM_flag_present
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	0                       # EOM(3)
+	.section	.debug_line.dwo,"",@progbits
+.Ltmp4:
+	.long	(.Ltmp5-.Ltmp4)-4
+	.short	2
+	.long	(.Ltmp6-.Ltmp4)-10
+	.byte	1
+	.byte	1
+	.byte	-5
+	.byte	14
+	.byte	1
+	.byte	0
+	.byte	0
+.Ltmp6:
+.Ltmp5:
+	.section	.debug_addr,"",@progbits
+	.quad	.Lfunc_begin0
+	.quad	.Lfunc_begin1
+	.section	.debug_pubnames,"",@progbits
+	.long	.LpubNames_end0-.LpubNames_begin0 # Length of Public Names Info
+.LpubNames_begin0:
+	.short	2                       # DWARF Version
+	.long	.Lcu_begin0             # Offset of Compilation Unit Info
+	.long	48                      # Compilation Unit Length
+	.long	25                      # DIE offset
+	.asciz	"func"                  # External Name
+	.long	0                       # End Mark
+.LpubNames_end0:
+	.long	.LpubNames_end1-.LpubNames_begin1 # Length of Public Names Info
+.LpubNames_begin1:
+	.short	2                       # DWARF Version
+	.long	.Lcu_begin1             # Offset of Compilation Unit Info
+	.long	48                      # Compilation Unit Length
+	.long	25                      # DIE offset
+	.asciz	"main"                  # External Name
+	.long	0                       # End Mark
+.LpubNames_end1:
+	.section	.debug_pubtypes,"",@progbits
+	.long	.LpubTypes_end0-.LpubTypes_begin0 # Length of Public Types Info
+.LpubTypes_begin0:
+	.short	2                       # DWARF Version
+	.long	.Lcu_begin0             # Offset of Compilation Unit Info
+	.long	48                      # Compilation Unit Length
+	.long	52                      # DIE offset
+	.asciz	"int"                   # External Name
+	.long	0                       # End Mark
+.LpubTypes_end0:
+	.long	.LpubTypes_end1-.LpubTypes_begin1 # Length of Public Types Info
+.LpubTypes_begin1:
+	.short	2                       # DWARF Version
+	.long	.Lcu_begin1             # Offset of Compilation Unit Info
+	.long	48                      # Compilation Unit Length
+	.long	40                      # DIE offset
+	.asciz	"int"                   # External Name
+	.long	0                       # End Mark
+.LpubTypes_end1:
+
+	.ident	"clang version 5.0.0 (trunk 302855) (llvm/trunk 302853)"
+	.ident	"clang version 5.0.0 (trunk 302855) (llvm/trunk 302853)"
+	.section	".note.GNU-stack","",@progbits
+	.section	.debug_line,"",@progbits
+.Lline_table_start0:
diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu.exp gdb/testsuite/gdb.dwarf2/fission-multi-cu.exp
new file mode 100644
index 0000000000..1f23c5b6ee
--- /dev/null
+++ gdb/testsuite/gdb.dwarf2/fission-multi-cu.exp
@@ -0,0 +1,67 @@
+# Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.
+
+load_lib dwarf.exp
+
+# We run objcopy locally to split out the .dwo file.
+if [is_remote host] {
+    return 0
+}
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if ![dwarf2_support] {
+    return 0
+}
+
+# This test can only be run on x86-64 targets.
+if {![istarget x86_64-*] || ![is_lp64_target]} {
+    return 0
+}
+
+standard_testfile .S
+
+if [build_executable_from_fission_assembler \
+	"$testfile.exp" "$binfile" "$srcfile" {nodebug}] {
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+# Make sure we can find the .dwo file, regardless of whether we're
+# running in parallel mode.
+gdb_test_no_output "set debug-file-directory [file dirname $binfile]" \
+    "set debug-file-directory"
+gdb_load $binfile
+
+if ![runto_main] {
+    return -1
+}
+
+# Do a few basic things to verify we're finding the DWO debug info.
+
+gdb_test "ptype main" "type = int \\(\\)"
+gdb_test "ptype func" "type = int \\(int\\)"
+
+gdb_test "frame" "#0 *main \\(\\) at ${testfile}2\\.c:$decimal.*" \
+    "frame in main"
+
+gdb_test "break func" "Breakpoint.*at.* file .*${testfile}1\\.c, line .*"
+
+gdb_test "continue" "Breakpoint.* func \\(arg=-1\\).*" \
+    "continue to func"
+
+gdb_test "frame" "#0 *func \\(arg=-1\\) at ${testfile}1\\.c:$decimal.*" \
+    "frame in func"
diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu1.c gdb/testsuite/gdb.dwarf2/fission-multi-cu1.c
new file mode 100644
index 0000000000..d93e2f912e
--- /dev/null
+++ gdb/testsuite/gdb.dwarf2/fission-multi-cu1.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.  */
+
+int
+func (int arg)
+{
+  return arg + 1;
+}
diff --git gdb/testsuite/gdb.dwarf2/fission-multi-cu2.c gdb/testsuite/gdb.dwarf2/fission-multi-cu2.c
new file mode 100644
index 0000000000..053b3ea141
--- /dev/null
+++ gdb/testsuite/gdb.dwarf2/fission-multi-cu2.c
@@ -0,0 +1,24 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2017 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 <http://www.gnu.org/licenses/>.  */
+
+void func ();
+
+int
+main ()
+{
+  func (-1);
+}

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-07-14 17:10 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-22 18:01 [PATCH] Fission support for multiple CUs per DWO file Doug Evans via gdb-patches
2017-06-01 23:33 ` David Blaikie
2017-06-27 18:52   ` David Blaikie
2017-06-28  0:56     ` Doug Evans via gdb-patches
2017-07-14 17:10       ` Yao Qi
  -- strict thread matches above, loose matches on Subject: below --
2017-05-14 16:20 David Blaikie

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).