This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [google/gcc-4_9] Add -ftwo-level-line-tables and -gline-tables-only options


On Sun, Jan 25, 2015 at 6:06 PM, Cary Coutant <ccoutant@google.com> wrote:
> Add -ftwo-level-line-tables and -gline-tables-only options.
>
> With -ftwo-level-line-tables, GCC will generate two-level line tables,
> which adds inline call information to the line tables, obviating the
> need to keep bulky debug info around for the purposes of generating
> stack traces.
>
> The -gline-tables-only option suppresses all other debug info except
> the single DW_AT_compilation_unit DIE that points to the line table
> for that compilation unit, and any .debug_ranges entries needed for
> that DIE.
>
> Two-level line tables are being proposed for the DWARF version 6
> standard, and are described here:
>
>   http://dwarfstd.org/ShowIssue.php?issue=140906.1
>
>   http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables
>
> In order to generate two-level line tables, GCC requires support
> from the assembler, in the form of new .subprog and .lloc pseudo-ops.
>
> This patch is for the google/gcc-4_9 branch. I plan to propose it
> for trunk after we gain more experience with it.
>
> -cary
>
>
> 2015-01-23  Cary Coutant  <ccoutant@google.com>
>
> gcc/
>         * common.opt (-ftwo-level-line-tables): New option.
>         (-gline-tables-only): New option.
>         * dwarf2out.c (struct dw_line_info_table_struct): Add subprog_num
>         and context fields.
>         (dwarf2out_abstract_function): Check for line tables only.
>         (dwarf2out_decl): Likewise.
>         (block_stack): New variable.
>         (dwarf2out_begin_block): For two-level line tables, keep a stack of
>         current blocks.
>         (dwarf2out_end_block): Likewise.
>         (dwarf2out_var_location): Check for line tables only.
>         (new_line_info_table): Initialize subprog_num and context fields.
>         (struct subprog_entry): New type.
>         (struct subprog_hasher): New type.
>         (subprog_hasher::hash): New function.
>         (subprog_hasher::equal): New function.
>         (subprog_table): New variable.
>         (last_subprog_num): New variable.
>         (add_subprog_entry): New function.
>         (struct block_entry): New type.
>         (struct block_hasher): New type.
>         (block_hasher::hash): New function.
>         (block_hasher::equal): New function.
>         (block_table): New variable.
>         (struct logical_entry): New type.
>         (struct logical_hasher): New type.
>         (logical_hasher::hash): New function.
>         (logical_hasher::equal): New function.
>         (logical_table): New variable.
>         (last_logical_num): New variable.
>         (scan_blocks_for_inlined_calls): New function.
>         (dwarf2out_begin_function): For two-level line tables, build map
>         of blocks to inlined call stacks.
>         (out_subprog_directive): New function.
>         (out_logical_entry): New function.
>         (dwarf2out_source_line): Add support for two-level line tables.
>         (dwarf2out_init): Create subprog_table, block_table, and logical_table.
>         (dwarf2out_finish): When -gline-tables-only is set, always output
>         the compilation_unit DIE; don't output aranges table.
>         * final.c (final_start_function): Move call to number blocks...
>         (rest_of_handle_final): ... to here.
>         * opts.c (common_handle_option): Add -gline-tables-only.
>         (set_debug_level): Clear debug_line_tables_only flag.
>
>
> Index: common.opt
> ===================================================================
> --- common.opt  (revision 220070)
> +++ common.opt  (working copy)
> @@ -1213,6 +1213,10 @@ fdwarf2-cfi-asm
>  Common Report Var(flag_dwarf2_cfi_asm) Init(HAVE_GAS_CFI_DIRECTIVE)
>  Enable CFI tables via GAS assembler directives.
>
> +ftwo-level-line-tables
> +Common Report Var(flag_two_level_line_tables) Init(0)
> +Use two-level line tables in DWARF (experimental).
> +
>  fripa
>  Common Report Var(flag_dyn_ipa)
>  Perform Dynamic Inter-Procedural Analysis.
> @@ -2657,6 +2661,10 @@ ggdb
>  Common JoinedOrMissing
>  Generate debug information in default extended format
>
> +gline-tables-only
> +Common RejectNegative Var(debug_line_tables_only) Init(0)
> +Generate DWARF line number tables and no other debug sections
> +
>  gno-pubnames
>  Common Negative(gpubnames) Var(debug_generate_pub_sections, 0) Init(-1)
>  Don't generate DWARF pubnames and pubtypes sections.
> Index: dwarf2out.c
> ===================================================================
> --- dwarf2out.c (revision 220070)
> +++ dwarf2out.c (working copy)
> @@ -2552,6 +2552,8 @@ typedef struct GTY(()) dw_line_info_tabl
>    unsigned int line_num;
>    unsigned int column_num;
>    int discrim_num;
> +  unsigned int subprog_num;
> +  unsigned int context;
>    bool is_stmt;
>    bool in_use;
>
> @@ -17777,6 +17779,9 @@ dwarf2out_abstract_function (tree decl)
>    int old_call_site_count, old_tail_call_site_count;
>    struct call_arg_loc_node *old_call_arg_locations;
>
> +  if (debug_line_tables_only)
> +    return;
> +
>    /* Make sure we have the actual abstract inline, not a clone.  */
>    decl = DECL_ORIGIN (decl);
>
> @@ -20716,6 +20721,9 @@ dwarf2out_decl (tree decl)
>  {
>    dw_die_ref context_die;
>
> +  if (debug_line_tables_only)
> +    return;
> +
>    /* In LIPO mode, we may output some functions whose type is defined
>       in another function that will not be output. This can result in
>       undefined location list symbols in the debug type info.
> @@ -20895,6 +20903,10 @@ dwarf2out_function_decl (tree decl)
>    htab_empty (cached_dw_loc_list_table);
>  }
>
> +/* For two-level line tables, we need to remember which block we're in.  */
> +
> +static vec<unsigned int> block_stack;
> +
>  /* Output a marker (i.e. a label) for the beginning of the generated code for
>     a lexical block.  */
>
> @@ -20904,6 +20916,8 @@ dwarf2out_begin_block (unsigned int line
>  {
>    switch_to_section (current_function_section ());
>    ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
> +  if (flag_two_level_line_tables && DWARF2_ASM_LINE_DEBUG_INFO)
> +    block_stack.safe_push (blocknum);
>  }
>
>  /* Output a marker (i.e. a label) for the end of the generated code for a
> @@ -20914,6 +20928,8 @@ dwarf2out_end_block (unsigned int line A
>  {
>    switch_to_section (current_function_section ());
>    ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
> +  if (flag_two_level_line_tables && DWARF2_ASM_LINE_DEBUG_INFO)
> +    block_stack.pop ();
>  }
>
>  /* Returns nonzero if it is appropriate not to emit any debugging
> @@ -21168,6 +21184,9 @@ dwarf2out_var_location (rtx loc_note)
>    tree decl;
>    bool var_loc_p;
>
> +  if (debug_line_tables_only)
> +    return;
> +
>    if (!NOTE_P (loc_note))
>      {
>        if (CALL_P (loc_note))
> @@ -21380,6 +21399,8 @@ new_line_info_table (void)
>    table = ggc_alloc_cleared_dw_line_info_table_struct ();
>    table->file_num = 1;
>    table->line_num = 1;
> +  table->subprog_num = 0;
> +  table->context = 0;
>    table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
>
>    return table;
> @@ -21436,6 +21457,232 @@ set_cur_line_info_table (section *sec)
>    cur_line_info_table = table;
>  }
>
> +/* For two-level line tables, a table of subprograms, keyed by
> +   the function decl node.  We number each subprogram when we
> +   output the .subprog opcode.  */
> +
> +struct subprog_entry
> +{
> +  tree decl;
> +  bool is_inlined;
> +  unsigned int subprog_num;
> +};
> +
> +struct subprog_hasher : typed_free_remove <subprog_entry>
> +{
> +  typedef subprog_entry value_type;
> +  typedef tree_node compare_type;
> +  static hashval_t hash (const value_type *);
> +  static bool equal (const value_type *, const compare_type *);
> +};
> +
> +inline hashval_t
> +subprog_hasher::hash (const value_type *p)
> +{
> +  return DECL_UID (p->decl);
> +}
> +
> +inline bool
> +subprog_hasher::equal (const value_type *p1, const compare_type *p2)
> +{
> +  return p1->decl == p2;
> +}
> +
> +static hash_table<subprog_hasher> *subprog_table;
> +static unsigned int last_subprog_num = 0;
> +
> +static subprog_entry *
> +add_subprog_entry (tree decl, bool is_inlined)
> +{
> +  subprog_entry **slot;
> +  subprog_entry *entry;
> +
> +  slot = subprog_table->find_slot_with_hash (decl, DECL_UID (decl), INSERT);
> +  if (*slot == HTAB_EMPTY_ENTRY)
> +    {
> +      entry = XCNEW (struct subprog_entry);
> +      entry->decl = decl;
> +      entry->is_inlined = is_inlined;
> +      entry->subprog_num = 0;
> +      *slot = entry;
> +    }
> +  else if (is_inlined)

When will the logic go into else branch?

> +    (*slot)->is_inlined = true;
> +  return *slot;
> +}
> +
> +/* For two-level line tables, a map from block number to an
> +   inlined call chain.  */
> +
> +struct block_entry
> +{
> +  unsigned int block_num;
> +  struct subprog_entry *subprog;
> +  struct block_entry *caller;
> +  location_t caller_loc;
> +};
> +
> +struct block_hasher : typed_free_remove <block_entry>
> +{
> +  typedef block_entry value_type;
> +  typedef unsigned int compare_type;
> +  static hashval_t hash (const value_type *);
> +  static bool equal (const value_type *, const compare_type *);
> +};
> +
> +inline hashval_t
> +block_hasher::hash (const value_type *p)
> +{
> +  return (hashval_t) p->block_num;
> +}
> +
> +inline bool
> +block_hasher::equal (const value_type *p1, const compare_type *p2)
> +{
> +  return p1->block_num == *p2;
> +}
> +
> +static hash_table<block_hasher> *block_table;

Not quite clear why we need block_table. This table is not gonna be
emitted. And we can easily get subprog_entry through block->block_num


> +
> +/* For two-level line tables, a table of logical statements.
> +   We number each logical statement when we output the .lloc opcode.  */
> +
> +struct logical_entry
> +{
> +  unsigned int file_num;
> +  unsigned int line_num;
> +  int discrim;
> +  unsigned int subprog_num;
> +  logical_entry *context;
> +  unsigned int logical_num;
> +};
> +
> +struct logical_hasher : typed_free_remove <logical_entry>
> +{
> +  typedef logical_entry value_type;
> +  typedef logical_entry compare_type;
> +  static hashval_t hash (const value_type *);
> +  static bool equal (const value_type *, const compare_type *);
> +};
> +
> +inline hashval_t
> +logical_hasher::hash (const value_type *p)
> +{
> +  hashval_t h = p->file_num;
> +  h = iterative_hash_object (p->line_num, h);
> +  h = iterative_hash_object (p->discrim, h);
> +  h = iterative_hash_object (p->subprog_num, h);
> +  h = iterative_hash_object (p->context, h);
> +  return h;
> +}
> +
> +inline bool
> +logical_hasher::equal (const value_type *p1, const compare_type *p2)
> +{
> +  return (p1->file_num == p2->file_num
> +         && p1->line_num == p2->line_num
> +         && p1->discrim == p2->discrim
> +         && p1->subprog_num == p2->subprog_num
> +         && p1->context == p2->context);
> +}
> +
> +static hash_table<logical_hasher> *logical_table;
> +static unsigned int last_logical_num = 0;
> +
> +/* Map BLOCK to the SUBPROG it belongs to, adding a block entry to block_table.
> +   If BLOCK has been inlined, CALLER points to the block entry for the calling
> +   context, and CALLER_LOC is the source location for the call.  Process all
> +   the subblocks recursively, so that we can map each block in a function to
> +   the call chain leading to it.  */
> +
> +static void
> +scan_blocks_for_inlined_calls (tree block, subprog_entry *subprog,
> +                              block_entry *caller, location_t caller_loc)
> +{
> +  unsigned int block_num;
> +  block_entry **slot;
> +  block_entry *entry;
> +  tree subblock;
> +#ifdef DEBUG_TWO_LEVEL
> +  static unsigned int level = 0;
> +#endif
> +
> +  if (block == NULL)
> +    return;
> +
> +#ifdef DEBUG_TWO_LEVEL

Shall this be controlled by dump options with TDF_DETAILS dump_flag?

> +  if (level < 6)
> +    {
> +      unsigned int i;
> +
> +      for (i = 0; i < level; i++)
> +       fprintf(stderr, "  ");
> +      fprintf (stderr, "SCAN: block %d, subprog %s", BLOCK_NUMBER (block), dwarf2_name (subprog->decl, 0));
> +      if (caller != NULL)
> +       {
> +         expanded_location loc = expand_location (caller_loc);
> +         fprintf (stderr, ", caller %d (file %s line %d discrim %d)",
> +                  caller->block_num, loc.file, loc.line,
> +                  get_discriminator_from_locus (caller_loc));
> +       }
> +      fprintf (stderr, "\n");
> +    }
> +#endif
> +
> +  block_num = BLOCK_NUMBER (block);
> +  slot = block_table->find_slot_with_hash (&block_num, (hashval_t) block_num, INSERT);
> +  if (*slot != HTAB_EMPTY_ENTRY)

Instead of return, can you assert that the data stored in *slot is
consistent with the new data? Or should *slot never be
HTAB_EMPTY_ENTRY?

> +    return;
> +  entry = XCNEW (struct block_entry);
> +  entry->block_num = block_num;
> +  entry->subprog = subprog;
> +  entry->caller = caller;
> +  entry->caller_loc = caller_loc;
> +  *slot = entry;
> +
> +#ifdef DEBUG_TWO_LEVEL
> +  level++;
> +#endif
> +
> +  for (subblock = BLOCK_SUBBLOCKS (block);
> +       subblock != NULL;
> +       subblock = BLOCK_CHAIN (subblock))
> +    {
> +      if (! BLOCK_ABSTRACT (subblock)
> +         && inlined_function_outer_scope_p (subblock))
> +       {
> +         tree origin = block_ultimate_origin (subblock);
> +         location_t loc = LOCATION_LOCUS (BLOCK_SOURCE_LOCATION (subblock));
> +
> +         scan_blocks_for_inlined_calls (subblock,
> +                                        add_subprog_entry (origin, true),
> +                                        entry, loc);
> +       }
> +      else
> +       scan_blocks_for_inlined_calls (subblock, subprog, caller, caller_loc);
> +    }
> +
> +#ifdef DEBUG_TWO_LEVEL
> +  level--;
> +#endif
> +
> +  for (subblock = BLOCK_FRAGMENT_CHAIN (block);
> +       subblock != NULL;
> +       subblock = BLOCK_FRAGMENT_CHAIN (subblock))
> +    {
> +      block_num = BLOCK_NUMBER (subblock);
> +      slot = block_table->find_slot_with_hash (&block_num, (hashval_t) block_num, INSERT);
> +      if (*slot == HTAB_EMPTY_ENTRY)
> +       {
> +         entry = XCNEW (struct block_entry);
> +         entry->block_num = block_num;
> +         entry->subprog = subprog;
> +         entry->caller = caller;
> +         entry->caller_loc = caller_loc;
> +         *slot = entry;
> +       }
> +    }
> +}
>
>  /* We need to reset the locations at the beginning of each
>     function. We can't do this in the end_function hook, because the
> @@ -21464,6 +21711,19 @@ dwarf2out_begin_function (tree fun)
>    tail_call_site_count = 0;
>
>    set_cur_line_info_table (sec);
> +
> +  if (flag_two_level_line_tables && DWARF2_ASM_LINE_DEBUG_INFO)
> +    {
> +      subprog_entry *subprog;
> +
> +      block_table->empty ();
> +#ifdef DEBUG_TWO_LEVEL
> +      fprintf (stderr, "Begin function %s\n", dwarf2_name (fun, 0));
> +#endif
> +      subprog = add_subprog_entry (fun, false);
> +      scan_blocks_for_inlined_calls (DECL_INITIAL (fun), subprog,
> +                                    NULL, UNKNOWN_LOCATION);
> +    }
>  }
>
>  /* Helper function of dwarf2out_end_function, called only after emitting
> @@ -21531,6 +21791,147 @@ push_dw_line_info_entry (dw_line_info_ta
>    vec_safe_push (table->entries, e);
>  }
>
> +/* Two-level line tables:  Output a .subprog directive.  */
> +
> +static void
> +out_subprog_directive (subprog_entry *subprog)
> +{
> +  tree decl = subprog->decl;
> +  tree decl_name = DECL_NAME (decl);
> +  const char *name;
> +  unsigned int file_num = 0;
> +  unsigned int line_num = 0;
> +
> +  if (decl_name == NULL || IDENTIFIER_POINTER (decl_name) == NULL)
> +    return;
> +
> +  /* For inlined subroutines, use the linkage name.  */
> +  if (subprog->is_inlined && DECL_ASSEMBLER_NAME (decl))
> +    {
> +      name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
> +      if (name[0] == '*')
> +        name++;
> +    }
> +  else
> +    name = dwarf2_name (decl, 0);
> +
> +  if (LOCATION_LOCUS (DECL_SOURCE_LOCATION (decl)) != UNKNOWN_LOCATION)
> +    {
> +      expanded_location s;
> +
> +      s = expand_location (DECL_SOURCE_LOCATION (decl));
> +      file_num = maybe_emit_file (lookup_filename (s.file));
> +      line_num = s.line;
> +    }
> +
> +  subprog->subprog_num = ++last_subprog_num;
> +  fprintf (asm_out_file, "\t.subprog %d \"%s\" %d %d\n",
> +          subprog->subprog_num, name, file_num, line_num);
> +}
> +
> +/* Two-level line tables:  Look for an entry in logical_table for a
> +   logical row with the given attributes.  Insert a new entry if not
> +   present, recursively adding entries for caller contexts as necessary.
> +   Output any necessary .lloc directives.  */
> +
> +static logical_entry *
> +out_logical_entry (dw_line_info_table *table, unsigned int file_num,
> +                  unsigned int line_num, int discriminator,
> +                  block_entry *block, bool is_stmt, bool is_context)
> +{
> +  subprog_entry *subprog = NULL;
> +  unsigned int subprog_num = 0;
> +  logical_entry probe;
> +  logical_entry **slot;
> +  logical_entry *entry;
> +  logical_entry *context = NULL;
> +
> +  /* Find the logical statement for the calling context, generating a new one
> +     if necessary.  */
> +  if (block != NULL && block->caller != NULL)
> +    {
> +      expanded_location s = expand_location (block->caller_loc);
> +      unsigned int caller_file_num = maybe_emit_file (lookup_filename (s.file));
> +      int caller_discrim = get_discriminator_from_locus (block->caller_loc);
> +
> +      context = out_logical_entry (table, caller_file_num, s.line,
> +                                  caller_discrim, block->caller, false, true);
> +    }
> +
> +  /* Declare the subprogram if it hasn't already been declared.  */
> +  if (block != NULL)
> +    subprog = block->subprog;
> +  if (subprog != NULL && subprog->subprog_num == 0 && context != NULL)
> +    out_subprog_directive (subprog);
> +  if (subprog != NULL)
> +    subprog_num = subprog->subprog_num;
> +
> +  probe.file_num = file_num;
> +  probe.line_num = line_num;
> +  probe.discrim = discriminator;
> +  probe.subprog_num = subprog_num;
> +  probe.context = context;
> +  probe.logical_num = 0;
> +  slot = logical_table->find_slot (&probe, INSERT);
> +
> +  if (*slot == HTAB_EMPTY_ENTRY)
> +    {
> +      entry = XCNEW (struct logical_entry);
> +      *entry = probe;
> +      entry->logical_num = ++last_logical_num;
> +      *slot = entry;
> +
> +      /* Declare a new logical statement.  */
> +      fputs ("\t.lloc ", asm_out_file);
> +      fprint_ul (asm_out_file, entry->logical_num);
> +      putc (' ', asm_out_file);
> +      fprint_ul (asm_out_file, file_num);
> +      putc (' ', asm_out_file);
> +      fprint_ul (asm_out_file, line_num);
> +      if (discriminator > 0)
> +       {
> +         fputs (" discriminator ", asm_out_file);
> +         fprint_ul (asm_out_file, (unsigned long) discriminator);
> +       }
> +      if (subprog_num != 0)
> +       {
> +         fputs (" subprog ", asm_out_file);
> +         fprint_ul (asm_out_file, subprog_num);
> +       }
> +      if (context != NULL)
> +       {
> +         fputs (" context ", asm_out_file);
> +         fprint_ul (asm_out_file, context->logical_num);
> +       }
> +      if (is_stmt != table->is_stmt)
> +       {
> +         fputs (" is_stmt ", asm_out_file);
> +         putc (is_stmt ? '1' : '0', asm_out_file);
> +       }
> +      putc ('\n', asm_out_file);
> +    }
> +  else
> +    {
> +      entry = *slot;
> +
> +      /* Switch to a previously-defined logical statement.  */
> +      if (!is_context)
> +       {
> +         fputs ("\t.lloc ", asm_out_file);
> +         fprint_ul (asm_out_file, entry->logical_num);
> +         putc ('\n', asm_out_file);
> +       }
> +    }
> +
> +  table->file_num = file_num;
> +  table->line_num = line_num;
> +  table->discrim_num = discriminator;
> +  table->is_stmt = is_stmt;
> +  table->in_use = true;
> +
> +  return entry;
> +}
> +
>  /* Output a label to mark the beginning of a source code line entry
>     and record information relating to this source line, in
>     'line_info_table' for later output of the .debug_line section.  */
> @@ -21580,6 +21981,28 @@ dwarf2out_source_line (unsigned int line
>    if (flag_debug_asm)
>      fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START, filename, line);
>
> +  /* Two-level line tables.  */
> +  if (flag_two_level_line_tables && DWARF2_ASM_LINE_DEBUG_INFO)
> +    {
> +      unsigned int block_num = 0;
> +      block_entry **slot;
> +      block_entry *block = NULL;
> +
> +      /* Find the block_entry we created in the begin_function hook,
> +         and get the subprogram and caller info.  */
> +      if (!block_stack.is_empty ())
> +        block_num = block_stack.last ();
> +      slot = block_table->find_slot_with_hash (&block_num,
> +                                              (hashval_t) block_num,
> +                                              NO_INSERT);
> +      if (slot != NULL)
> +       block = *slot;
> +
> +      out_logical_entry (table, file_num, line, discriminator, block, is_stmt,
> +                        false);
> +      return;
> +    }
> +
>    if (DWARF2_ASM_LINE_DEBUG_INFO)
>      {
>        /* Emit the .loc directive understood by GNU as.  */
> @@ -22160,6 +22583,17 @@ dwarf2out_init (const char *filename ATT
>
>    vec_alloc (used_rtx_array, 32);
>
> +  /* Allocate the subprogram table and block-to-logical map.  */
> +  if (flag_two_level_line_tables && DWARF2_ASM_LINE_DEBUG_INFO)
> +    {
> +      subprog_table = new hash_table<subprog_hasher> ();
> +      subprog_table->create (10);
> +      block_table = new hash_table<block_hasher> ();
> +      block_table->create (10);
> +      logical_table = new hash_table<logical_hasher> ();
> +      logical_table->create (10);
> +    }
> +
>    if (!dwarf_split_debug_info)
>      {
>        debug_info_section = get_section (DEBUG_INFO_SECTION,
> @@ -24349,8 +24783,8 @@ dwarf2out_finish (const char *filename)
>      }
>
>    /* Output the main compilation unit if non-empty or if .debug_macinfo
> -     or .debug_macro will be emitted.  */
> -  output_comp_unit (comp_unit_die (), have_macinfo);
> +     or .debug_macro will be emitted or if -gline-tables-only is set.  */
> +  output_comp_unit (comp_unit_die (), have_macinfo || debug_line_tables_only);
>
>    if (dwarf_split_debug_info && info_section_emitted)
>      output_skeleton_debug_sections (main_comp_unit_die);
> @@ -24379,7 +24813,7 @@ dwarf2out_finish (const char *filename)
>       to put in it.  This because the consumer has no way to tell the
>       difference between an empty table that we omitted and failure to
>       generate a table that would have contained data.  */
> -  if (info_section_emitted)
> +  if (info_section_emitted && !debug_line_tables_only)
>      {
>        unsigned long aranges_length = size_of_aranges ();
>
> Index: final.c
> ===================================================================
> --- final.c     (revision 220070)
> +++ final.c     (working copy)
> @@ -1802,18 +1802,6 @@ final_start_function (rtx first, FILE *f
>         profile_function (file);
>      }
>
> -  /* If debugging, assign block numbers to all of the blocks in this
> -     function.  */
> -  if (write_symbols)
> -    {
> -      reemit_insn_block_notes ();
> -      number_blocks (current_function_decl);
> -      /* We never actually put out begin/end notes for the top-level
> -        block in the function.  But, conceptually, that block is
> -        always needed.  */
> -      TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
> -    }
> -
>    if (warn_frame_larger_than
>      && get_frame_size () > frame_larger_than_size)
>    {
> @@ -4498,6 +4486,18 @@ rest_of_handle_final (void)
>
>    has_cold_section_p = false;
>
> +  /* If debugging, assign block numbers to all of the blocks in this
> +     function.  */
> +  if (write_symbols)
> +    {
> +      reemit_insn_block_notes ();
> +      number_blocks (current_function_decl);
> +      /* We never actually put out begin/end notes for the top-level
> +        block in the function.  But, conceptually, that block is
> +        always needed.  */
> +      TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
> +    }
> +
>    assemble_start_function (current_function_decl, fnname);
>    final_start_function (get_insns (), asm_out_file, optimize);
>    final (get_insns (), asm_out_file, optimize);
> Index: opts.c
> ===================================================================
> --- opts.c      (revision 220070)
> +++ opts.c      (working copy)
> @@ -2050,6 +2050,12 @@ common_handle_option (struct gcc_options
>        set_debug_level (DWARF2_DEBUG, false, "", opts, opts_set, loc);
>        break;
>
> +    case OPT_gline_tables_only:
> +      set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, "1", opts, opts_set,
> +                      loc);
> +      opts->x_debug_line_tables_only = 1;
> +      break;
> +
>      case OPT_gsplit_dwarf:
>        set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, "", opts, opts_set,
>                        loc);
> @@ -2247,6 +2253,7 @@ set_debug_level (enum debug_info_type ty
>                  struct gcc_options *opts, struct gcc_options *opts_set,
>                  location_t loc)
>  {
> +  opts->x_debug_line_tables_only = 0;
>    opts->x_use_gnu_debug_info_extensions = extended;
>
>    if (type == NO_DEBUG)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]