Cheers,
Cupertino
Changes from v1:
- Corrected typos.
- Fixed line_col encoding and created macros.
- Added a test case for line_info.
- Improved line and column info repetition detection.
Previous patch was generating multiple entries for the same line and
column data for consecutive labels.
This patch adds line_info debug information support to .BTF.ext
sections.
Line info information is used by the BPF verifier to improve error
reporting and give more precise source code referenced errors.
gcc/ChangeLog:
PR target/113453
* config/bpf/bpf-protos.h (bpf_output_call): Change prototype.
* config/bpf/bpf.cc (bpf_output_call): Change to adapt operands
and return
the instruction template instead of immediately emit asm and
not allow proper final expected execution flow.
(bpf_output_line_info): Add function to introduce line info
entries in respective structures
(bpf_asm_out_unwind_emit): Add function as hook to
TARGET_ASM_UNWIND_EMIT. This hook is called before any
instruction is emitted.
* config/bpf/bpf.md: Change calls to bpf_output_call.
* config/bpf/btfext-out.cc (struct btf_ext_lineinfo): Add fields
to struct.
(bpf_create_lineinfo, btf_add_line_info_for): Add support
function to insert line_info data in respective structures.
(output_btfext_line_info): Function to emit line_info data in
.BTF.ext section.
(btf_ext_output): Call output_btfext_line_info.
* config/bpf/btfext-out.h: Add prototype for
btf_add_line_info_for.
gcc/testsuite/ChangeLog:
PR target/113453
* gcc.target/bpf/btfext-funcinfo.c: Adapt test.
* gcc.target/bpf/btfext-lineinfo.c: New test.
---
gcc/config/bpf/bpf-protos.h | 2 +-
gcc/config/bpf/bpf.cc | 105 +++++++++++++---
gcc/config/bpf/bpf.md | 4 +-
gcc/config/bpf/btfext-out.cc | 114 +++++++++++++++++-
gcc/config/bpf/btfext-out.h | 4 +
.../gcc.target/bpf/btfext-funcinfo.c | 3 +-
.../gcc.target/bpf/btfext-lineinfo.c | 51 ++++++++
7 files changed, 262 insertions(+), 21 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/bpf/btfext-lineinfo.c
diff --git a/gcc/config/bpf/bpf-protos.h b/gcc/config/bpf/bpf-protos.h
index 4a4799e9bf22..1113cc3e6d17 100644
--- a/gcc/config/bpf/bpf-protos.h
+++ b/gcc/config/bpf/bpf-protos.h
@@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see
/* Routines implemented in bpf.cc. */
extern HOST_WIDE_INT bpf_initial_elimination_offset (int, int);
-extern const char *bpf_output_call (rtx);
+extern const char *bpf_output_call (const char *templ, rtx *, int
target_index);
extern void bpf_target_macros (cpp_reader *);
extern void bpf_print_operand (FILE *, rtx, int);
extern void bpf_print_operand_address (FILE *, rtx);
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index d91013ad140b..4773d789d8e3 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -745,14 +745,12 @@ bpf_output_destructor (rtx symbol, int priority
ATTRIBUTE_UNUSED)
bpf.md. */
const char *
-bpf_output_call (rtx target)
+bpf_output_call (const char *templ, rtx *operands, int target_index)
{
- rtx xops[1];
-
+ rtx target = operands[target_index];
switch (GET_CODE (target))
{
case CONST_INT:
- output_asm_insn ("call\t%0", &target);
break;
case SYMBOL_REF:
{
@@ -765,26 +763,21 @@ bpf_output_call (rtx target)
{
tree attr_args = TREE_VALUE (attr);
- xops[0] = GEN_INT (TREE_INT_CST_LOW (TREE_VALUE (attr_args)));
- output_asm_insn ("call\t%0", xops);
+ operands[target_index] =
+ GEN_INT (TREE_INT_CST_LOW (TREE_VALUE (attr_args)));
}
- else
- output_asm_insn ("call\t%0", &target);
-
break;
}
default:
- if (TARGET_XBPF)
- output_asm_insn ("call\t%0", &target);
- else
+ if (!TARGET_XBPF)
{
error ("indirect call in function, which are not supported by eBPF");
- output_asm_insn ("call 0", NULL);
+ operands[target_index] = GEN_INT (0);
}
break;
}
- return "";
+ return templ;
}
const char *
@@ -1145,6 +1138,90 @@ bpf_debug_unwind_info ()
#undef TARGET_DEBUG_UNWIND_INFO
#define TARGET_DEBUG_UNWIND_INFO bpf_debug_unwind_info
+/* Create a BTF.ext line_info entry. */
+
+static void
+bpf_output_line_info (FILE *asm_out_file, rtx_insn *insn)
+{
+ static unsigned int line_info_label = 1;
+ static tree cfun_decl = NULL_TREE;
+ static bool func_start_added = false;
+ const char *label = NULL;
+ unsigned int loc = 0;
+ expanded_location exploc = {NULL, 0, 0, NULL, false};
+ static expanded_location prev_exploc = {NULL, 0, 0, NULL, false};
+
+ if(!btf_debuginfo_p () || flag_building_libgcc)
+ return;
+
+ gcc_assert (insn != NULL_RTX);
+
+ if (current_function_decl != cfun_decl
+ && GET_CODE (insn) == NOTE)
+ {
+ label = current_function_func_begin_label;
+ loc = DECL_SOURCE_LOCATION (current_function_decl);
+ exploc = expand_location (loc);
+ func_start_added = true;
+ prev_exploc = exploc;
+ }
+ else
+ {
+ if (GET_CODE (insn) == NOTE)
+ return;
+
+ /* Already added a label for this location. This might not be fully
+ accurate but it is better then adding 2 entries on the same location,
+ which is incompatible with the verifier expectations. */
+ if (func_start_added == true)
+ {
+ func_start_added = false;
+ return;
+ }
+
+
+ if (!INSN_HAS_LOCATION (insn))
+ return;
+
+ exploc = insn_location (insn);
+
+ if (exploc.file == NULL || exploc.line == 0
+ || (exploc.line == prev_exploc.line
+ && exploc.column == prev_exploc.column))
+ return;
+
+ prev_exploc = exploc;
+
+ char tmp_label[25];
+ sprintf (tmp_label, "LI%u", line_info_label);
+ ASM_OUTPUT_LABEL (asm_out_file, tmp_label);
+ line_info_label += 1;
+ label = const_cast<char *> (ggc_strdup (tmp_label));
+ }
+
+ cfun_decl = current_function_decl;
+
+ if (exploc.file != NULL && exploc.line != 0)
+ btf_add_line_info_for (label, exploc.file, exploc.line, exploc.column);
+}
+
+
+/* This hook is defined as a way for BPF target to create a label before each
+ emitted instruction and emit line_info information. This data is later
+ output in .BTF.ext section.
+ This approach expects TARGET_EMIT_BEFORE_INSN to be returning TRUE as
+ this function needs to be called before the instruction is emitted. Current
+ default behaviour returns TRUE and the hook is left undefined. */
+
+static void
+bpf_asm_out_unwind_emit (FILE *asm_out_file, rtx_insn *insn)
+{
+ bpf_output_line_info (asm_out_file, insn);
+}
+
+#undef TARGET_ASM_UNWIND_EMIT
+#define TARGET_ASM_UNWIND_EMIT bpf_asm_out_unwind_emit
+
/* Output assembly directives to assemble data of various sized and
alignments. */
diff --git a/gcc/config/bpf/bpf.md b/gcc/config/bpf/bpf.md
index 0eec006d3cfe..bc739f2746c0 100644
--- a/gcc/config/bpf/bpf.md
+++ b/gcc/config/bpf/bpf.md
@@ -545,7 +545,7 @@
;; operands[2] is next_arg_register
;; operands[3] is struct_value_size_rtx.
""
- { return bpf_output_call (operands[0]); }
+ { return bpf_output_call ("call\t%0", operands, 0); }
[(set_attr "type" "jmp")])
(define_expand "call_value"
@@ -568,7 +568,7 @@
;; operands[3] is next_arg_register
;; operands[4] is struct_value_size_rtx.
""
- { return bpf_output_call (operands[1]); }
+ { return bpf_output_call ("call\t%1", operands, 1); }
[(set_attr "type" "jmp")])
(define_insn "sibcall"
diff --git a/gcc/config/bpf/btfext-out.cc b/gcc/config/bpf/btfext-out.cc
index 04bc60d69b0e..9a7e34aeb634 100644
--- a/gcc/config/bpf/btfext-out.cc
+++ b/gcc/config/bpf/btfext-out.cc
@@ -32,6 +32,7 @@
#include "rtl.h"
#include "tree-pretty-print.h"
#include "cgraph.h"
+#include "toplev.h" /* get_src_pwd */
#include "btfext-out.h"
@@ -124,14 +125,19 @@ struct GTY ((chain_next ("%h.next"))) btf_ext_funcinfo
/* A lineinfo record, in the .BTF.ext lineinfo section. */
struct GTY ((chain_next ("%h.next"))) btf_ext_lineinfo
{
- uint32_t insn_off; /* Offset of the instruction. */
+ const char *insn_label; /* Instruction label. */
+ const char *file_name; /* Source-code file name. */
uint32_t file_name_off; /* Offset of file name in BTF string table. */
uint32_t line_off; /* Offset of source line in BTF string table. */
- uint32_t line_col; /* Line number (bits 31-11) and column (11-0). */
+ uint32_t line_col; /* Line number (bits 31-10) and column (9-0). */
struct btf_ext_lineinfo *next; /* Linked list to collect line_info elems. */
};
+#define BTF_LINE_INFO_LINE(line_col) ((line_col) >> 10)
+#define BTF_LINE_INFO_COLUMN(line_col) ((line_col) & 0x3ff)
+#define BTF_LINE_INFO_LINE_COL(line, column) (line << 10 | (column & 0x3ff))
+
/* Internal representation of a BPF CO-RE relocation record. */
struct GTY ((chain_next ("%h.next"))) btf_ext_core_reloc {
ctf_dtdef_ref bpfcr_type; /* BTF type involved in relocation. */
@@ -235,6 +241,26 @@ bpf_create_or_find_funcinfo (const char *fnname, const
char *sec_name,
return *head;
}
+/* Function to create a lineinfo node in info. */
+
+static struct btf_ext_lineinfo *
+bpf_create_lineinfo (const char *sec_name, btf_ext_info_sec **in_sec = NULL)
+{
+ struct btf_ext_info_sec *sec_elem =
+ btfext_info_sec_find_or_add (sec_name, true);
+
+ if (in_sec != NULL)
+ *in_sec = sec_elem;
+
+ struct btf_ext_lineinfo **head =
+ SEARCH_NODE_AND_RETURN(struct btf_ext_lineinfo,
+ sec_elem->line_info.head,
+ false);
+ *head = ggc_cleared_alloc<struct btf_ext_lineinfo> ();
+
+ return *head;
+}
+
/* Function to create a core_reloc node in info. */
static struct btf_ext_core_reloc *
@@ -438,6 +464,47 @@ btf_validate_funcinfo (btf_ext_info_sec *sec)
}
}
+#define STR_BUFF_SIZE 256
+
+struct btf_ext_lineinfo *
+btf_add_line_info_for (const char *label, const char *filename,
+ unsigned int line, unsigned int column)
+{
+ const char *sec_name = decl_section_name (current_function_decl);
+
+ if (sec_name == NULL)
+ sec_name = ".text";
+
+ struct btf_ext_info_sec *sec = NULL;
+ struct btf_ext_lineinfo *info =
+ bpf_create_lineinfo (sec_name, &sec);
+
+ info->insn_label = label;
+
+ if (!IS_DIR_SEPARATOR (filename[0]))
+ {
+ char full_filename[STR_BUFF_SIZE];
+
+ /* Filename is a relative path. */
+ const char * cu_pwd = get_src_pwd ();
+ gcc_assert (strlen (cu_pwd) + strlen (filename) + 2 < STR_BUFF_SIZE);
+
+ sprintf (full_filename, "%s%c%s", cu_pwd, DIR_SEPARATOR, filename);