Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
-/* TODO: Implement .debug_str handling, and share entries somehow.
- Emit .debug_line header even when there are no functions, since
+/* TODO: Emit .debug_line header even when there are no functions, since
the file numbers are used by .debug_info. Alternately, leave
out locations for types and decls.
Avoid talking about ctors and op= for PODs.
#include "diagnostic.h"
#include "debug.h"
#include "target.h"
+#include "hashtable.h"
#ifdef DWARF2_DEBUGGING_INFO
static void dwarf2out_source_line PARAMS ((unsigned int, const char *));
associated with the current function (body) definition. */
static unsigned current_funcdef_fde;
+struct ht *debug_str_hash;
+
+struct indirect_string_node
+{
+ struct ht_identifier id;
+ unsigned int refcount;
+ unsigned int form;
+ char *label;
+};
+
/* Forward declarations for functions defined in this file. */
static char *stripattributes PARAMS ((const char *));
PARAMS ((dw_cfa_location *));
static void def_cfa_1 PARAMS ((const char *, dw_cfa_location *));
+/* .debug_str support. */
+static hashnode indirect_string_alloc PARAMS ((hash_table *));
+static int output_indirect_string PARAMS ((struct cpp_reader *,
+ hashnode, const PTR));
+
/* How to start an assembler comment. */
#ifndef ASM_COMMENT_START
#define ASM_COMMENT_START ";#"
int external;
} val_die_ref;
unsigned val_fde_index;
- char *val_str;
+ struct indirect_string_node *val_str;
char *val_lbl_id;
unsigned char val_flag;
}
static void add_sibling_attributes PARAMS ((dw_die_ref));
static void build_abbrev_table PARAMS ((dw_die_ref));
static void output_location_lists PARAMS ((dw_die_ref));
-static unsigned long size_of_string PARAMS ((const char *));
static int constant_size PARAMS ((long unsigned));
static unsigned long size_of_die PARAMS ((dw_die_ref));
static void calc_die_sizes PARAMS ((dw_die_ref));
#define TEXT_SECTION_NAME ".text"
#endif
+/* Section flags for .debug_str section. */
+#ifdef HAVE_GAS_SHF_MERGE
+#define DEBUG_STR_SECTION_FLAGS \
+ (SECTION_DEBUG | SECTION_MERGE | SECTION_STRINGS | 1)
+#else
+#define DEBUG_STR_SECTION_FLAGS SECTION_DEBUG
+#endif
+
/* Labels we insert at beginning sections we can reference instead of
the section names themselves. */
const char *str;
{
dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ struct indirect_string_node *node;
+
+ if (! debug_str_hash)
+ {
+ debug_str_hash = ht_create (10);
+ debug_str_hash->alloc_node = indirect_string_alloc;
+ }
+
+ node = (struct indirect_string_node *)
+ ht_lookup (debug_str_hash, (const unsigned char *) str,
+ strlen (str), HT_ALLOC);
+ node->refcount++;
attr->dw_attr_next = NULL;
attr->dw_attr = attr_kind;
attr->dw_attr_val.val_class = dw_val_class_str;
- attr->dw_attr_val.v.val_str = xstrdup (str);
+ attr->dw_attr_val.v.val_str = node;
add_dwarf_attr (die, attr);
}
dw_attr_ref a;
{
if (a && AT_class (a) == dw_val_class_str)
- return a->dw_attr_val.v.val_str;
+ return (const char *) HT_STR (&a->dw_attr_val.v.val_str->id);
+
+ abort ();
+}
+
+/* Find out whether a string should be output inline in DIE
+ or out-of-line in .debug_str section. */
+
+static int AT_string_form PARAMS ((dw_attr_ref));
+static int
+AT_string_form (a)
+ dw_attr_ref a;
+{
+ if (a && AT_class (a) == dw_val_class_str)
+ {
+ struct indirect_string_node *node;
+ unsigned int len;
+ extern int const_labelno;
+ char label[32];
+
+ node = a->dw_attr_val.v.val_str;
+ if (node->form)
+ return node->form;
+
+ len = HT_LEN (&node->id) + 1;
+
+ /* If the string is shorter or equal to the size
+ of the reference, it is always better to put it
+ inline. */
+ if (len <= DWARF_OFFSET_SIZE || node->refcount == 0)
+ return node->form = DW_FORM_string;
+
+ if ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) == 0)
+ {
+ /* If we cannot expect the linker to merge strings
+ in .debug_str section, only put it into .debug_str
+ if it is worth even in this single module. */
+ if ((len - DWARF_OFFSET_SIZE) * node->refcount <= len)
+ return node->form = DW_FORM_string;
+ }
+
+ ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
+ ++const_labelno;
+ node->label = xstrdup (label);
+ return node->form = DW_FORM_strp;
+ }
abort ();
}
switch (AT_class (a))
{
case dw_val_class_str:
+ if (a->dw_attr_val.v.val_str->refcount)
+ a->dw_attr_val.v.val_str->refcount--;
+ break;
+
case dw_val_class_lbl_id:
case dw_val_class_lbl_offset:
- free (a->dw_attr_val.v.val_str);
+ free (a->dw_attr_val.v.val_lbl_id);
break;
case dw_val_class_float:
build_abbrev_table (c);
}
\f
-/* Return the size of a string, including the null byte.
-
- This used to treat backslashes as escapes, and hence they were not included
- in the count. However, that conflicts with what ASM_OUTPUT_ASCII does,
- which treats a backslash as a backslash, escaping it if necessary, and hence
- we must include them in the count. */
-
-static unsigned long
-size_of_string (str)
- const char *str;
-{
- return strlen (str) + 1;
-}
-
/* Return the power-of-two number of bytes necessary to represent VALUE. */
static int
size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_str:
- size += size_of_string (AT_string (a));
+ if (AT_string_form (a) == DW_FORM_strp)
+ size += DWARF_OFFSET_SIZE;
+ else
+ size += HT_LEN (&a->dw_attr_val.v.val_str->id) + 1;
break;
default:
abort ();
for (i = 0; i < pubname_table_in_use; ++i)
{
pubname_ref p = &pubname_table[i];
- size += DWARF_OFFSET_SIZE + size_of_string (p->name);
+ size += DWARF_OFFSET_SIZE + strlen (p->name) + 1;
}
size += DWARF_OFFSET_SIZE;
case dw_val_class_lbl_offset:
return DW_FORM_data;
case dw_val_class_str:
- return DW_FORM_string;
+ return AT_string_form (a);
default:
abort ();
"Location list terminator end (%s)",
list_head->ll_symbol);
}
+
/* Output the DIE and its attributes. Called recursively to generate
the definitions of each child DIE. */
break;
case dw_val_class_str:
- dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
+ if (AT_string_form (a) == DW_FORM_strp)
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+ a->dw_attr_val.v.val_str->label,
+ "%s", name);
+ else
+ dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
break;
default:
}
}
+/* Allocate a string in .debug_str hash table. */
+
+static hashnode
+indirect_string_alloc (tab)
+ hash_table *tab ATTRIBUTE_UNUSED;
+{
+ struct indirect_string_node *node;
+
+ node = xmalloc (sizeof (struct indirect_string_node));
+ node->refcount = 0;
+ node->form = 0;
+ node->label = NULL;
+ return (hashnode) node;
+}
+
+/* A helper function for dwarf2out_finish called through
+ ht_forall. Emit one queued .debug_str string. */
+
+static int
+output_indirect_string (pfile, h, v)
+ struct cpp_reader *pfile ATTRIBUTE_UNUSED;
+ hashnode h;
+ const PTR v ATTRIBUTE_UNUSED;
+{
+ struct indirect_string_node *node;
+
+ node = (struct indirect_string_node *) h;
+ if (node->form == DW_FORM_strp)
+ {
+ named_section_flags (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS);
+ ASM_OUTPUT_LABEL (asm_out_file, node->label);
+ assemble_string ((const char *) HT_STR (&node->id),
+ HT_LEN (&node->id) + 1);
+ }
+ return 1;
+}
+
/* Output stuff that dwarf requires at the end of every file,
and generate the DWARF-2 debugging info. */
named_section_flags (DEBUG_MACINFO_SECTION, SECTION_DEBUG);
dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
}
+
+ /* If we emitted any DW_FORM_strp form attribute, output string
+ table too. */
+ if (debug_str_hash)
+ ht_forall (debug_str_hash, output_indirect_string, NULL);
}
#endif /* DWARF2_DEBUGGING_INFO || DWARF2_UNWIND_INFO */