* [PATCH 1/4] Write CodeView information about enregistered optimized variables
@ 2024-08-19 1:15 Mark Harmstone
2024-08-19 1:15 ` [PATCH 2/4] Write CodeView information about optimized stack variables Mark Harmstone
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Mark Harmstone @ 2024-08-19 1:15 UTC (permalink / raw)
To: gcc-patches; +Cc: Mark Harmstone
Enable variable tracking when outputting CodeView debug information, and make
it so that we issue debug symbols for optimized variables in registers. This
consists of S_LOCAL symbols, which give the name and the type of local
variables, followed by S_DEFRANGE_REGISTER symbols for the register and the
code for which this applies.
gcc/
* dwarf2codeview.cc (enum cv_sym_type): Add S_LOCAL and
S_DEFRANGE_REGISTER.
(write_s_local): New function.
(write_defrange_register): New function.
(write_optimized_local_variable_loc): New function.
(write_optimized_local_variable): New function.
(write_optimized_function_vars): New function.
(write_function): Call write_optimized_function_vars if variable
tracking enabled.
* dwarf2out.cc (typedef var_loc_view): Move to dwarf2out.h.
(struct dw_loc_list_struct): Likewise.
* dwarf2out.h (typedef var_loc_view): Move from dwarf2out.cc.
(struct dw_loc_list_struct): Likewise.
* opts.cc (finish_options): Enable variable tracking for CodeView.
---
gcc/dwarf2codeview.cc | 316 +++++++++++++++++++++++++++++++++++++++++-
gcc/dwarf2out.cc | 37 -----
gcc/dwarf2out.h | 37 +++++
gcc/opts.cc | 2 +-
4 files changed, 353 insertions(+), 39 deletions(-)
diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index e01515a0ec4..15253978968 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -77,6 +77,8 @@ enum cv_sym_type {
S_GDATA32 = 0x110d,
S_REGREL32 = 0x1111,
S_COMPILE3 = 0x113c,
+ S_LOCAL = 0x113e,
+ S_DEFRANGE_REGISTER = 0x1141,
S_LPROC32_ID = 0x1146,
S_GPROC32_ID = 0x1147,
S_PROC_ID_END = 0x114f
@@ -1946,6 +1948,56 @@ end:
free (s->data_symbol.name);
}
+/* Write an S_LOCAL symbol, representing an optimized variable. This is then
+ followed by various S_DEFRANGE_* symbols, which describe how to find the
+ value of a variable and the range for which this is valid. */
+
+static void
+write_s_local (dw_die_ref die)
+{
+ unsigned int label_num = ++sym_label_num;
+ const char *name = get_AT_string (die, DW_AT_name);
+ uint32_t type;
+
+ /* This is struct LOCALSYM in Microsoft's cvinfo.h:
+
+ struct LOCALSYM {
+ uint16_t reclen;
+ uint16_t rectyp;
+ uint32_t typind;
+ uint16_t flags;
+ char name[];
+ };
+ */
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ asm_fprintf (asm_out_file,
+ "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n",
+ label_num, label_num);
+
+ targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ fprint_whex (asm_out_file, S_LOCAL);
+ putc ('\n', asm_out_file);
+
+ type = get_type_num (get_AT_ref (die, DW_AT_type), false, false);
+
+ fputs (integer_asm_op (4, false), asm_out_file);
+ fprint_whex (asm_out_file, type);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ fprint_whex (asm_out_file, 0);
+ putc ('\n', asm_out_file);
+
+ ASM_OUTPUT_ASCII (asm_out_file, name, strlen (name) + 1);
+
+ ASM_OUTPUT_ALIGN (asm_out_file, 2);
+
+ targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
+}
+
/* Write an S_LDATA32 symbol, representing a static variable within a function.
This symbol can also appear outside of a function block - see
write_data_symbol. */
@@ -2278,6 +2330,194 @@ write_fbreg_variable (dw_die_ref die, dw_loc_descr_ref loc_ref,
targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
}
+/* Write an S_DEFRANGE_REGISTER symbol, which describes a range for which an
+ S_LOCAL variable is held in a certain register. */
+
+static void
+write_defrange_register (dw_loc_descr_ref expr, rtx range_start, rtx range_end)
+{
+ unsigned int label_num = ++sym_label_num;
+ uint16_t regno;
+
+ /* This is defrange_register in binutils and DEFRANGESYMREGISTER in
+ Microsoft's cvinfo.h:
+
+ struct lvar_addr_range
+ {
+ uint32_t offset;
+ uint16_t section;
+ uint16_t length;
+ } ATTRIBUTE_PACKED;
+
+ struct lvar_addr_gap {
+ uint16_t offset;
+ uint16_t length;
+ } ATTRIBUTE_PACKED;
+
+ struct defrange_register
+ {
+ uint16_t size;
+ uint16_t kind;
+ uint16_t reg;
+ uint16_t attributes;
+ struct lvar_addr_range range;
+ struct lvar_addr_gap gaps[];
+ } ATTRIBUTE_PACKED;
+ */
+
+ if (expr->dw_loc_opc == DW_OP_regx)
+ regno = dwarf_reg_to_cv (expr->dw_loc_oprnd1.v.val_int);
+ else
+ regno = dwarf_reg_to_cv (expr->dw_loc_opc - DW_OP_reg0);
+
+ if (regno == 0)
+ return;
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ asm_fprintf (asm_out_file,
+ "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n",
+ label_num, label_num);
+
+ targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ fprint_whex (asm_out_file, S_DEFRANGE_REGISTER);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ fprint_whex (asm_out_file, regno);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ fprint_whex (asm_out_file, 0);
+ putc ('\n', asm_out_file);
+
+ asm_fprintf (asm_out_file, "\t.secrel32 ");
+ output_addr_const (asm_out_file, range_start);
+ fputc ('\n', asm_out_file);
+
+ asm_fprintf (asm_out_file, "\t.secidx ");
+ output_addr_const (asm_out_file, range_start);
+ fputc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ output_addr_const (asm_out_file, range_end);
+ fputs (" - ", asm_out_file);
+ output_addr_const (asm_out_file, range_start);
+ putc ('\n', asm_out_file);
+
+ targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
+}
+
+/* Try to write an S_DEFRANGE_* symbol for the given DWARF location. */
+
+static void
+write_optimized_local_variable_loc (dw_loc_descr_ref expr, rtx range_start,
+ rtx range_end)
+{
+ if (expr->dw_loc_next)
+ return;
+
+ if (!range_start)
+ return;
+
+ if (!range_end)
+ return;
+
+ switch (expr->dw_loc_opc)
+ {
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ case DW_OP_regx:
+ write_defrange_register (expr, range_start, range_end);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Write an optimized local variable, given by an S_LOCAL symbol followed by
+ any number of S_DEFRANGE_* symbols. We can't mix and match optimized and
+ unoptimized variables in the same function, so even if it stays in the same
+ place for the whole block we need to write an S_LOCAL. */
+
+static void
+write_optimized_local_variable (dw_die_ref die, rtx block_start, rtx block_end)
+{
+ dw_attr_node *loc;
+ dw_loc_list_ref loc_list;
+
+ loc = get_AT (die, DW_AT_location);
+ if (!loc)
+ return;
+
+ switch (loc->dw_attr_val.val_class)
+ {
+ case dw_val_class_loc_list:
+ loc_list = loc->dw_attr_val.v.val_loc_list;
+
+ write_s_local (die);
+
+ while (loc_list)
+ {
+ rtx range_start = NULL, range_end = NULL;
+
+ if (loc_list->begin)
+ range_start = gen_rtx_SYMBOL_REF (Pmode, loc_list->begin);
+
+ if (loc_list->end)
+ range_end = gen_rtx_SYMBOL_REF (Pmode, loc_list->end);
+
+ write_optimized_local_variable_loc (loc_list->expr, range_start,
+ range_end);
+
+ loc_list = loc_list->dw_loc_next;
+ }
+ break;
+
+ case dw_val_class_loc:
+ write_s_local (die);
+
+ write_optimized_local_variable_loc (loc->dw_attr_val.v.val_loc,
+ block_start, block_end);
+ break;
+
+ default:
+ break;
+ }
+}
+
/* Write a symbol representing an unoptimized variable within a function, if
we're able to translate the DIE's DW_AT_location into its CodeView
equivalent. */
@@ -2517,6 +2757,77 @@ write_unoptimized_function_vars (dw_die_ref die, dw_loc_descr_ref fbloc)
while (c != first_child);
}
+/* Write the variables in an optimized function or block. There's no S_BLOCK32s
+ here, with the range determining the lifetime of a variable. Unfortunately
+ for us CodeView is much less expressive than DWARF when it comes to variable
+ locations, so some degree of "optimized out"s is inevitable. */
+
+static void
+write_optimized_function_vars (dw_die_ref die, rtx block_start, rtx block_end)
+{
+ dw_die_ref first_child, c;
+
+ first_child = dw_get_die_child (die);
+
+ if (!first_child)
+ return;
+
+ c = first_child;
+ do
+ {
+ c = dw_get_die_sib (c);
+
+ switch (dw_get_die_tag (c))
+ {
+ case DW_TAG_formal_parameter:
+ case DW_TAG_variable:
+ write_optimized_local_variable (c, block_start, block_end);
+ break;
+
+ case DW_TAG_lexical_block:
+ {
+ dw_attr_node *loc_low, *loc_high;
+ const char *label_low, *label_high;
+ rtx rtx_low, rtx_high;
+
+ loc_low = get_AT (die, DW_AT_low_pc);
+ if (!loc_low)
+ break;
+
+ if (loc_low->dw_attr_val.val_class != dw_val_class_lbl_id)
+ break;
+
+ label_low = loc_low->dw_attr_val.v.val_lbl_id;
+ if (!label_low)
+ break;
+
+ rtx_low = gen_rtx_SYMBOL_REF (Pmode, label_low);
+
+ loc_high = get_AT (die, DW_AT_high_pc);
+ if (!loc_high)
+ break;
+
+ if (loc_high->dw_attr_val.val_class != dw_val_class_high_pc)
+ break;
+
+ label_high = loc_high->dw_attr_val.v.val_lbl_id;
+ if (!label_high)
+ break;
+
+ rtx_high = gen_rtx_SYMBOL_REF (Pmode, label_high);
+
+ write_optimized_function_vars (c, rtx_low, rtx_high);
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ while (c != first_child);
+}
+
/* Write an S_GPROC32_ID symbol, representing a global function, or an
S_LPROC32_ID symbol, for a static function. */
@@ -2648,7 +2959,10 @@ write_function (codeview_symbol *s)
if (frame_base && frame_base->dw_attr_val.val_class == dw_val_class_loc)
fbloc = frame_base->dw_attr_val.v.val_loc;
- write_unoptimized_function_vars (s->function.die, fbloc);
+ if (flag_var_tracking)
+ write_optimized_function_vars (s->function.die, rtx_low, rtx_high);
+ else
+ write_unoptimized_function_vars (s->function.die, fbloc);
/* Output the S_PROC_ID_END record. */
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index d5144714c6e..79f76935121 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -1362,43 +1362,6 @@ struct GTY((for_user)) addr_table_entry {
GTY ((desc ("%1.kind"))) addr;
};
-typedef unsigned int var_loc_view;
-
-/* Location lists are ranges + location descriptions for that range,
- so you can track variables that are in different places over
- their entire life. */
-typedef struct GTY(()) dw_loc_list_struct {
- dw_loc_list_ref dw_loc_next;
- const char *begin; /* Label and addr_entry for start of range */
- addr_table_entry *begin_entry;
- const char *end; /* Label for end of range */
- addr_table_entry *end_entry;
- char *ll_symbol; /* Label for beginning of location list.
- Only on head of list. */
- char *vl_symbol; /* Label for beginning of view list. Ditto. */
- const char *section; /* Section this loclist is relative to */
- dw_loc_descr_ref expr;
- var_loc_view vbegin, vend;
- hashval_t hash;
- /* True if all addresses in this and subsequent lists are known to be
- resolved. */
- bool resolved_addr;
- /* True if this list has been replaced by dw_loc_next. */
- bool replaced;
- /* True if it has been emitted into .debug_loc* / .debug_loclists*
- section. */
- unsigned char emitted : 1;
- /* True if hash field is index rather than hash value. */
- unsigned char num_assigned : 1;
- /* True if .debug_loclists.dwo offset has been emitted for it already. */
- unsigned char offset_emitted : 1;
- /* True if note_variable_value_in_expr has been called on it. */
- unsigned char noted_variable_value : 1;
- /* True if the range should be emitted even if begin and end
- are the same. */
- bool force;
-} dw_loc_list_node;
-
static dw_loc_descr_ref int_loc_descriptor (poly_int64);
static dw_loc_descr_ref uint_loc_descriptor (unsigned HOST_WIDE_INT);
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index a424981b911..f8270c8601f 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -235,6 +235,43 @@ struct GTY(()) dw_discr_value {
struct addr_table_entry;
+typedef unsigned int var_loc_view;
+
+/* Location lists are ranges + location descriptions for that range,
+ so you can track variables that are in different places over
+ their entire life. */
+typedef struct GTY(()) dw_loc_list_struct {
+ dw_loc_list_ref dw_loc_next;
+ const char *begin; /* Label and addr_entry for start of range */
+ addr_table_entry *begin_entry;
+ const char *end; /* Label for end of range */
+ addr_table_entry *end_entry;
+ char *ll_symbol; /* Label for beginning of location list.
+ Only on head of list. */
+ char *vl_symbol; /* Label for beginning of view list. Ditto. */
+ const char *section; /* Section this loclist is relative to */
+ dw_loc_descr_ref expr;
+ var_loc_view vbegin, vend;
+ hashval_t hash;
+ /* True if all addresses in this and subsequent lists are known to be
+ resolved. */
+ bool resolved_addr;
+ /* True if this list has been replaced by dw_loc_next. */
+ bool replaced;
+ /* True if it has been emitted into .debug_loc* / .debug_loclists*
+ section. */
+ unsigned char emitted : 1;
+ /* True if hash field is index rather than hash value. */
+ unsigned char num_assigned : 1;
+ /* True if .debug_loclists.dwo offset has been emitted for it already. */
+ unsigned char offset_emitted : 1;
+ /* True if note_variable_value_in_expr has been called on it. */
+ unsigned char noted_variable_value : 1;
+ /* True if the range should be emitted even if begin and end
+ are the same. */
+ bool force;
+} dw_loc_list_node;
+
/* The dw_val_node describes an attribute's value, as it is
represented internally. */
diff --git a/gcc/opts.cc b/gcc/opts.cc
index 0b7b137c376..317b586be58 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -1408,7 +1408,7 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
/* We know which debug output will be used so we can set flag_var_tracking
and flag_var_tracking_uninit if the user has not specified them. */
if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL
- || !dwarf_debuginfo_p (opts)
+ || (!dwarf_debuginfo_p (opts) && !codeview_debuginfo_p ())
/* We have not yet initialized debug hooks so match that to check
whether we're only doing DWARF2_LINENO_DEBUGGING_INFO. */
#ifndef DWARF2_DEBUGGING_INFO
--
2.44.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/4] Write CodeView information about optimized stack variables
2024-08-19 1:15 [PATCH 1/4] Write CodeView information about enregistered optimized variables Mark Harmstone
@ 2024-08-19 1:15 ` Mark Harmstone
2024-08-19 1:15 ` [PATCH 3/4] Write CodeView S_FRAMEPROC symbols Mark Harmstone
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Mark Harmstone @ 2024-08-19 1:15 UTC (permalink / raw)
To: gcc-patches; +Cc: Mark Harmstone
Outputs S_DEFRANGE_REGISTER_REL symbols for optimized local variables that are
on the stack, consisting of the stack register, the offset, and the code range
for which this applies.
gcc/
* dwarf2codeview.cc (enum cv_sym_type): Add S_DEFRANGE_REGISTER_REL.
(write_defrange_register_rel): New function.
(write_optimized_local_variable_loc): Add fbloc param, and call
write_defrange_register_rel.
(write_optimized_local_variable): Add fbloc param.
(write_optimized_function_vars): Add fbloc param.
---
gcc/dwarf2codeview.cc | 128 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 119 insertions(+), 9 deletions(-)
diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 15253978968..74bbf6bc1d7 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -79,6 +79,7 @@ enum cv_sym_type {
S_COMPILE3 = 0x113c,
S_LOCAL = 0x113e,
S_DEFRANGE_REGISTER = 0x1141,
+ S_DEFRANGE_REGISTER_REL = 0x1145,
S_LPROC32_ID = 0x1146,
S_GPROC32_ID = 0x1147,
S_PROC_ID_END = 0x114f
@@ -2409,10 +2410,113 @@ write_defrange_register (dw_loc_descr_ref expr, rtx range_start, rtx range_end)
targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
}
+/* Write an S_DEFRANGE_REGISTER_REL symbol, which describes a range for which
+ an S_LOCAL variable is held in memory given by the value of a certain
+ register plus an offset. */
+
+static void
+write_defrange_register_rel (dw_loc_descr_ref expr, dw_loc_descr_ref fbloc,
+ rtx range_start, rtx range_end)
+{
+ unsigned int label_num = ++sym_label_num;
+ uint16_t regno;
+ int offset;
+
+ /* This is defrange_register_rel in binutils and DEFRANGESYMREGISTERREL in
+ Microsoft's cvinfo.h:
+
+ struct lvar_addr_range
+ {
+ uint32_t offset;
+ uint16_t section;
+ uint16_t length;
+ } ATTRIBUTE_PACKED;
+
+ struct lvar_addr_gap {
+ uint16_t offset;
+ uint16_t length;
+ } ATTRIBUTE_PACKED;
+
+ struct defrange_register_rel
+ {
+ uint16_t size;
+ uint16_t kind;
+ uint16_t reg;
+ uint16_t offset_parent;
+ uint32_t offset_register;
+ struct lvar_addr_range range;
+ struct lvar_addr_gap gaps[];
+ } ATTRIBUTE_PACKED;
+ */
+
+ if (!fbloc)
+ return;
+
+ if (fbloc->dw_loc_opc >= DW_OP_breg0 && fbloc->dw_loc_opc <= DW_OP_breg31)
+ {
+ regno = dwarf_reg_to_cv (fbloc->dw_loc_opc - DW_OP_breg0);
+ offset = fbloc->dw_loc_oprnd1.v.val_int;
+ }
+ else if (fbloc->dw_loc_opc == DW_OP_bregx)
+ {
+ regno = dwarf_reg_to_cv (fbloc->dw_loc_oprnd1.v.val_int);
+ offset = fbloc->dw_loc_oprnd2.v.val_int;
+ }
+ else
+ {
+ return;
+ }
+
+ if (expr->dw_loc_oprnd1.val_class != dw_val_class_unsigned_const)
+ return;
+
+ offset += expr->dw_loc_oprnd1.v.val_int;
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ asm_fprintf (asm_out_file,
+ "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n",
+ label_num, label_num);
+
+ targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ fprint_whex (asm_out_file, S_DEFRANGE_REGISTER_REL);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ fprint_whex (asm_out_file, regno);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ fprint_whex (asm_out_file, 0);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (4, false), asm_out_file);
+ fprint_whex (asm_out_file, offset);
+ putc ('\n', asm_out_file);
+
+ asm_fprintf (asm_out_file, "\t.secrel32 ");
+ output_addr_const (asm_out_file, range_start);
+ fputc ('\n', asm_out_file);
+
+ asm_fprintf (asm_out_file, "\t.secidx ");
+ output_addr_const (asm_out_file, range_start);
+ fputc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ output_addr_const (asm_out_file, range_end);
+ fputs (" - ", asm_out_file);
+ output_addr_const (asm_out_file, range_start);
+ putc ('\n', asm_out_file);
+
+ targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
+}
+
/* Try to write an S_DEFRANGE_* symbol for the given DWARF location. */
static void
-write_optimized_local_variable_loc (dw_loc_descr_ref expr, rtx range_start,
+write_optimized_local_variable_loc (dw_loc_descr_ref expr,
+ dw_loc_descr_ref fbloc, rtx range_start,
rtx range_end)
{
if (expr->dw_loc_next)
@@ -2462,6 +2566,10 @@ write_optimized_local_variable_loc (dw_loc_descr_ref expr, rtx range_start,
write_defrange_register (expr, range_start, range_end);
break;
+ case DW_OP_fbreg:
+ write_defrange_register_rel (expr, fbloc, range_start, range_end);
+ break;
+
default:
break;
}
@@ -2473,7 +2581,8 @@ write_optimized_local_variable_loc (dw_loc_descr_ref expr, rtx range_start,
place for the whole block we need to write an S_LOCAL. */
static void
-write_optimized_local_variable (dw_die_ref die, rtx block_start, rtx block_end)
+write_optimized_local_variable (dw_die_ref die, dw_loc_descr_ref fbloc,
+ rtx block_start, rtx block_end)
{
dw_attr_node *loc;
dw_loc_list_ref loc_list;
@@ -2499,8 +2608,8 @@ write_optimized_local_variable (dw_die_ref die, rtx block_start, rtx block_end)
if (loc_list->end)
range_end = gen_rtx_SYMBOL_REF (Pmode, loc_list->end);
- write_optimized_local_variable_loc (loc_list->expr, range_start,
- range_end);
+ write_optimized_local_variable_loc (loc_list->expr, fbloc,
+ range_start, range_end);
loc_list = loc_list->dw_loc_next;
}
@@ -2509,7 +2618,7 @@ write_optimized_local_variable (dw_die_ref die, rtx block_start, rtx block_end)
case dw_val_class_loc:
write_s_local (die);
- write_optimized_local_variable_loc (loc->dw_attr_val.v.val_loc,
+ write_optimized_local_variable_loc (loc->dw_attr_val.v.val_loc, fbloc,
block_start, block_end);
break;
@@ -2763,7 +2872,8 @@ write_unoptimized_function_vars (dw_die_ref die, dw_loc_descr_ref fbloc)
locations, so some degree of "optimized out"s is inevitable. */
static void
-write_optimized_function_vars (dw_die_ref die, rtx block_start, rtx block_end)
+write_optimized_function_vars (dw_die_ref die, dw_loc_descr_ref fbloc,
+ rtx block_start, rtx block_end)
{
dw_die_ref first_child, c;
@@ -2781,7 +2891,7 @@ write_optimized_function_vars (dw_die_ref die, rtx block_start, rtx block_end)
{
case DW_TAG_formal_parameter:
case DW_TAG_variable:
- write_optimized_local_variable (c, block_start, block_end);
+ write_optimized_local_variable (c, fbloc, block_start, block_end);
break;
case DW_TAG_lexical_block:
@@ -2816,7 +2926,7 @@ write_optimized_function_vars (dw_die_ref die, rtx block_start, rtx block_end)
rtx_high = gen_rtx_SYMBOL_REF (Pmode, label_high);
- write_optimized_function_vars (c, rtx_low, rtx_high);
+ write_optimized_function_vars (c, fbloc, rtx_low, rtx_high);
break;
}
@@ -2960,7 +3070,7 @@ write_function (codeview_symbol *s)
fbloc = frame_base->dw_attr_val.v.val_loc;
if (flag_var_tracking)
- write_optimized_function_vars (s->function.die, rtx_low, rtx_high);
+ write_optimized_function_vars (s->function.die, fbloc, rtx_low, rtx_high);
else
write_unoptimized_function_vars (s->function.die, fbloc);
--
2.44.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/4] Write CodeView S_FRAMEPROC symbols
2024-08-19 1:15 [PATCH 1/4] Write CodeView information about enregistered optimized variables Mark Harmstone
2024-08-19 1:15 ` [PATCH 2/4] Write CodeView information about optimized stack variables Mark Harmstone
@ 2024-08-19 1:15 ` Mark Harmstone
2024-08-19 1:15 ` [PATCH 4/4] Write CodeView information about static locals in optimized code Mark Harmstone
2024-08-25 15:26 ` [PATCH 1/4] Write CodeView information about enregistered optimized variables Jeff Law
3 siblings, 0 replies; 5+ messages in thread
From: Mark Harmstone @ 2024-08-19 1:15 UTC (permalink / raw)
To: gcc-patches; +Cc: Mark Harmstone
Write S_FRAMEPROC symbols, which aren't very useful but seem to be necessary
for Microsoft debuggers to function properly. These symbols come after S_LOCAL
symbols for optimized variables, but before S_REGISTER and S_REGREL32 for
unoptimized variables.
gcc/
* dwarf2codeview.cc (enum cv_sym_type): Add S_FRAMEPROC.
(write_s_frameproc): New function.
(write_function): Call write_s_frameproc.
---
gcc/dwarf2codeview.cc | 80 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 78 insertions(+), 2 deletions(-)
diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 74bbf6bc1d7..88310504cf7 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -71,6 +71,7 @@ along with GCC; see the file COPYING3. If not see
enum cv_sym_type {
S_END = 0x0006,
+ S_FRAMEPROC = 0x1012,
S_BLOCK32 = 0x1103,
S_REGISTER = 0x1106,
S_LDATA32 = 0x110c,
@@ -2822,6 +2823,74 @@ write_s_end (void)
targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
}
+/* Write the S_FRAMEPROC symbol, which is supposed to give information about
+ the function frame. It doesn't seem to be really used in modern versions of
+ MSVC, which is why we zero-out everything here. You still need to write it
+ though, otherwise windbg won't necessarily show all the local variables. */
+
+static void
+write_s_frameproc (void)
+{
+ unsigned int label_num = ++sym_label_num;
+
+ /* This is struct FRAMEPROCSYM in Microsoft's cvinfo.h:
+
+ struct frameprocsym
+ {
+ uint16_t size;
+ uint16_t kind;
+ uint32_t frame_size;
+ uint32_t padding_size;
+ uint32_t padding_offset;
+ uint32_t saved_registers_size;
+ uint32_t exception_handler_offset;
+ uint16_t exception_handler_section;
+ uint32_t flags;
+ } ATTRIBUTE_PACKED;
+ */
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ asm_fprintf (asm_out_file,
+ "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n",
+ label_num, label_num);
+
+ targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ fprint_whex (asm_out_file, S_FRAMEPROC);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (4, false), asm_out_file);
+ fprint_whex (asm_out_file, 0);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (4, false), asm_out_file);
+ fprint_whex (asm_out_file, 0);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (4, false), asm_out_file);
+ fprint_whex (asm_out_file, 0);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (4, false), asm_out_file);
+ fprint_whex (asm_out_file, 0);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (4, false), asm_out_file);
+ fprint_whex (asm_out_file, 0);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (2, false), asm_out_file);
+ fprint_whex (asm_out_file, 0);
+ putc ('\n', asm_out_file);
+
+ fputs (integer_asm_op (4, false), asm_out_file);
+ fprint_whex (asm_out_file, 0);
+ putc ('\n', asm_out_file);
+
+ targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
+}
+
/* Loop through the DIEs in an unoptimized function, writing out any variables
or blocks that we encounter. */
@@ -3070,9 +3139,16 @@ write_function (codeview_symbol *s)
fbloc = frame_base->dw_attr_val.v.val_loc;
if (flag_var_tracking)
- write_optimized_function_vars (s->function.die, fbloc, rtx_low, rtx_high);
+ {
+ write_optimized_function_vars (s->function.die, fbloc, rtx_low,
+ rtx_high);
+ write_s_frameproc ();
+ }
else
- write_unoptimized_function_vars (s->function.die, fbloc);
+ {
+ write_s_frameproc ();
+ write_unoptimized_function_vars (s->function.die, fbloc);
+ }
/* Output the S_PROC_ID_END record. */
--
2.44.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 4/4] Write CodeView information about static locals in optimized code
2024-08-19 1:15 [PATCH 1/4] Write CodeView information about enregistered optimized variables Mark Harmstone
2024-08-19 1:15 ` [PATCH 2/4] Write CodeView information about optimized stack variables Mark Harmstone
2024-08-19 1:15 ` [PATCH 3/4] Write CodeView S_FRAMEPROC symbols Mark Harmstone
@ 2024-08-19 1:15 ` Mark Harmstone
2024-08-25 15:26 ` [PATCH 1/4] Write CodeView information about enregistered optimized variables Jeff Law
3 siblings, 0 replies; 5+ messages in thread
From: Mark Harmstone @ 2024-08-19 1:15 UTC (permalink / raw)
To: gcc-patches; +Cc: Mark Harmstone
Write CodeView S_LDATA32 symbols for static locals in optimized code. We have
to handle these separately, as they come after the S_FRAMEPROC, plus you can't
have S_BLOCK32 symbols like you can in unoptimized code.
gcc/
* dwarf2codeview.cc (write_optimized_static_local_vars): New function.
(write_function): Call write_optimized_static_local_vars.
---
gcc/dwarf2codeview.cc | 57 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 88310504cf7..e4c67f921cd 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -3007,6 +3007,62 @@ write_optimized_function_vars (dw_die_ref die, dw_loc_descr_ref fbloc,
while (c != first_child);
}
+/* There's no way to mark the range of a static local variable in an optimized
+ function: there's no S_DEFRANGE_* symbol for this, and you can't have
+ S_BLOCK32 symbols. So instead we have to loop through after the S_FRAMEPROC
+ has been written, and write the S_LDATA32s at the end. */
+
+static void
+write_optimized_static_local_vars (dw_die_ref die)
+{
+ dw_die_ref first_child, c;
+
+ first_child = dw_get_die_child (die);
+
+ if (!first_child)
+ return;
+
+ c = first_child;
+ do
+ {
+ c = dw_get_die_sib (c);
+
+ switch (dw_get_die_tag (c))
+ {
+ case DW_TAG_variable:
+ {
+ dw_attr_node *loc;
+ dw_loc_descr_ref loc_ref;
+
+ loc = get_AT (c, DW_AT_location);
+ if (!loc)
+ break;
+
+ if (loc->dw_attr_val.val_class != dw_val_class_loc)
+ break;
+
+ loc_ref = loc->dw_attr_val.v.val_loc;
+ if (!loc_ref)
+ break;
+
+ if (loc_ref->dw_loc_opc != DW_OP_addr)
+ break;
+
+ write_local_s_ldata32 (c, loc_ref);
+ break;
+ }
+
+ case DW_TAG_lexical_block:
+ write_optimized_static_local_vars (c);
+ break;
+
+ default:
+ break;
+ }
+ }
+ while (c != first_child);
+}
+
/* Write an S_GPROC32_ID symbol, representing a global function, or an
S_LPROC32_ID symbol, for a static function. */
@@ -3143,6 +3199,7 @@ write_function (codeview_symbol *s)
write_optimized_function_vars (s->function.die, fbloc, rtx_low,
rtx_high);
write_s_frameproc ();
+ write_optimized_static_local_vars (s->function.die);
}
else
{
--
2.44.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/4] Write CodeView information about enregistered optimized variables
2024-08-19 1:15 [PATCH 1/4] Write CodeView information about enregistered optimized variables Mark Harmstone
` (2 preceding siblings ...)
2024-08-19 1:15 ` [PATCH 4/4] Write CodeView information about static locals in optimized code Mark Harmstone
@ 2024-08-25 15:26 ` Jeff Law
3 siblings, 0 replies; 5+ messages in thread
From: Jeff Law @ 2024-08-25 15:26 UTC (permalink / raw)
To: Mark Harmstone, gcc-patches
On 8/18/24 7:15 PM, Mark Harmstone wrote:
> Enable variable tracking when outputting CodeView debug information, and make
> it so that we issue debug symbols for optimized variables in registers. This
> consists of S_LOCAL symbols, which give the name and the type of local
> variables, followed by S_DEFRANGE_REGISTER symbols for the register and the
> code for which this applies.
>
> gcc/
> * dwarf2codeview.cc (enum cv_sym_type): Add S_LOCAL and
> S_DEFRANGE_REGISTER.
> (write_s_local): New function.
> (write_defrange_register): New function.
> (write_optimized_local_variable_loc): New function.
> (write_optimized_local_variable): New function.
> (write_optimized_function_vars): New function.
> (write_function): Call write_optimized_function_vars if variable
> tracking enabled.
> * dwarf2out.cc (typedef var_loc_view): Move to dwarf2out.h.
> (struct dw_loc_list_struct): Likewise.
> * dwarf2out.h (typedef var_loc_view): Move from dwarf2out.cc.
> (struct dw_loc_list_struct): Likewise.
> * opts.cc (finish_options): Enable variable tracking for CodeView.
All four patches in this series are fine.
Thanks,
Jeff
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-08-25 15:26 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-08-19 1:15 [PATCH 1/4] Write CodeView information about enregistered optimized variables Mark Harmstone
2024-08-19 1:15 ` [PATCH 2/4] Write CodeView information about optimized stack variables Mark Harmstone
2024-08-19 1:15 ` [PATCH 3/4] Write CodeView S_FRAMEPROC symbols Mark Harmstone
2024-08-19 1:15 ` [PATCH 4/4] Write CodeView information about static locals in optimized code Mark Harmstone
2024-08-25 15:26 ` [PATCH 1/4] Write CodeView information about enregistered optimized variables Jeff Law
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).