Hi Cuper.
Thanks for the patch.

> 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 core referenced errors.
>
> gcc/Changelog:
>       * 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 emmidiatelly 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.

Is it actually necessary to emit a label (plus .BTF.ext entry) for every
instruction?

>       * 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/config/bpf/bpf-protos.h                   |   2 +-
>  gcc/config/bpf/bpf.cc                         | 103 ++++++++++++++---
>  gcc/config/bpf/bpf.md                         |   4 +-
>  gcc/config/bpf/btfext-out.cc                  | 108 +++++++++++++++++-
>  gcc/config/bpf/btfext-out.h                   |   4 +
>  .../gcc.target/bpf/btfext-funcinfo.c          |   3 +-
>  6 files changed, 203 insertions(+), 21 deletions(-)
>
> diff --git a/gcc/config/bpf/bpf-protos.h b/gcc/config/bpf/bpf-protos.h
> index b4866d34209..ddaca50af69 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 d9141dd625a..f1a8eb8d62c 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -754,14 +754,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:
>        {
> @@ -774,26 +772,20 @@ 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);
> -       }
> -     else
> -       output_asm_insn ("call\t%0", &target);
> +         operands[target_index] = GEN_INT (TREE_INT_CST_LOW (TREE_VALUE 
> (attr_args)));
>  
> +       }
>       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 *
> @@ -1144,6 +1136,87 @@ 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;
> +  const char *filename = NULL;
> +  unsigned int line = 0;
> +  unsigned int column = 0;
> +
> +  if(!btf_debuginfo_p ())
> +    return;

I think it would be better to put this guard in bpf_asm_out_unwind_emit
instead of bpf_output_line_info.

> +
> +  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);
> +      filename = LOCATION_FILE (loc);
> +      line = LOCATION_LINE (loc);
> +      column = LOCATION_COLUMN (loc);
> +      func_start_added = true;
> +    }
> +  else
> +    {
> +      if (GET_CODE (insn) == NOTE)
> +     return;
> +
> +      /* Already added a label for this location. This might not be fully
> +      acurate but it is better then adding 2 entries on the same location,
> +      which is imcompatible with the verifier expectations.  */
> +      if (func_start_added == true)
> +     {
> +       func_start_added = false;
> +       return;
> +     }
> +
> +      loc = INSN_LOCATION (insn);
> +      filename = LOCATION_FILE (loc);
> +      line = LOCATION_LINE (loc);
> +      column = LOCATION_COLUMN (loc);
> +
> +      if (filename == NULL || line == 0)
> +     return;
> +
> +      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 (filename != NULL && line != 0)
> +    btf_add_line_info_for (label, filename, line, 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 returing 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 95859328d25..3fdf81b86a6 100644
> --- a/gcc/config/bpf/bpf.md
> +++ b/gcc/config/bpf/bpf.md
> @@ -546,7 +546,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"
> @@ -569,7 +569,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 ff1fd0739f1..42ec48e394e 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,7 +125,8 @@ 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).  */
> @@ -235,6 +237,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 *
> @@ -429,6 +451,47 @@ btf_validate_funcinfo (btf_ext_info_sec *sec)
>      }
>  }
>  
> +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);
> +
> +  unsigned int line_column = ((0x000fffff & line) << 12)
> +                          | (0x00000fff & column);
> +
> +  info->insn_label = label;
> +
> +  if (!IS_DIR_SEPARATOR (filename[0]))
> +    {
> +      char full_filename[256];
> +
> +      /* Filename is a relative path.  */
> +      const char * cu_pwd = get_src_pwd ();
> +      gcc_assert (strlen (cu_pwd) + strlen (filename) + 2 < 256);
> +
> +      sprintf(full_filename, "%s%c%s", cu_pwd, DIR_SEPARATOR, filename);
> +      info->file_name = ggc_strdup (full_filename);
> +    }
> +  else
> +    /* Filename is an absolute path.  */
> +    info->file_name = ggc_strdup (filename);
> +
> +  info->file_name_off = btf_ext_add_string (info->file_name);
> +  info->line_off = 0;
> +  info->line_col = line_column;
> +
> +  sec->line_info.num_info += 1;
> +  return info;
> +}
> +
>  /* Compute the section size in section for func_info, line_info and core_info
>     regions of .BTF.ext.  */
>  
> @@ -537,6 +600,48 @@ output_btfext_func_info (struct btf_ext_info_sec *sec)
>      }
>  }
>  
> +/* Outputs line_info region on .BTF.ext.  */
> +
> +static void
> +output_btfext_line_info (struct btf_ext_info_sec *sec)
> +{
> +  unsigned int str_aux_off = ctfc_get_strtab_len (ctf_get_tu_ctfc (),
> +                                               CTF_STRTAB);
> +  bool executed = false;
> +  while (sec != NULL)
> +    {
> +      uint32_t count = 0;
> +      if (sec->line_info.num_info > 0)
> +     {
> +       if (executed == false && (executed = true))
> +         dw2_asm_output_data (4, 16, "LineInfo entry size");
> +       dw2_asm_output_data (4, sec->sec_name_off + str_aux_off,
> +                            "LineInfo section string for %s",
> +                            sec->sec_name);
> +       dw2_asm_output_data (4, sec->line_info.num_info, "Number of entries");
> +
> +       struct btf_ext_lineinfo *elem = sec->line_info.head;
> +       while (elem != NULL)
> +         {
> +           count += 1;
> +           dw2_asm_output_offset (4, elem->insn_label, NULL, "insn_label");
> +
> +           unsigned int file_name_off = btf_ext_add_string (elem->file_name);
> +           dw2_asm_output_data (4, file_name_off + str_aux_off,
> +                                "file_name_off");
> +           dw2_asm_output_data (4, elem->line_off, "line_off");
> +           dw2_asm_output_data (4, elem->line_col, "(line, col) (%u, %u)",
> +                                elem->line_col >> 12,
> +                                elem->line_col & 0x00000fff);
> +           elem = elem->next;
> +         }
> +     }
> +
> +      gcc_assert (count == sec->line_info.num_info);
> +      sec = sec->next;
> +    }
> +}
> +
>  /* Output all CO-RE relocation sections.  */
>  
>  static void
> @@ -609,6 +714,7 @@ btf_ext_output (void)
>  {
>    output_btfext_header ();
>    output_btfext_func_info (btf_ext);
> +  output_btfext_line_info (btf_ext);
>    if (TARGET_BPF_CORE)
>      output_btfext_core_sections ();
>  
> diff --git a/gcc/config/bpf/btfext-out.h b/gcc/config/bpf/btfext-out.h
> index b36309475c9..9c6848324e7 100644
> --- a/gcc/config/bpf/btfext-out.h
> +++ b/gcc/config/bpf/btfext-out.h
> @@ -99,6 +99,10 @@ extern int bpf_core_get_sou_member_index 
> (ctf_container_ref, const tree);
>  
>  struct btf_ext_funcinfo *btf_add_func_info_for (tree decl,
>                                               const char *label);
> +struct btf_ext_lineinfo *
> +btf_add_line_info_for (const char *label, const char *filename,
> +                    unsigned int line, unsigned int column);
> +
>  unsigned int btf_ext_add_string (const char *str);
>  
>  #ifdef       __cplusplus
> diff --git a/gcc/testsuite/gcc.target/bpf/btfext-funcinfo.c 
> b/gcc/testsuite/gcc.target/bpf/btfext-funcinfo.c
> index 6fdd14574ec..0f1e0ad1e89 100644
> --- a/gcc/testsuite/gcc.target/bpf/btfext-funcinfo.c
> +++ b/gcc/testsuite/gcc.target/bpf/btfext-funcinfo.c
> @@ -39,6 +39,5 @@ int bar_func (struct T *t)
>  /* { dg-final { scan-assembler-times "ascii \"bar_sec.0\"\[\t 
> \]+\[^\n\]*btf_aux_string" 1 } } */
>  /* { dg-final { scan-assembler-times "FuncInfo entry size" 1 } } */
>  
> -/* { dg-final { scan-assembler-times ".4byte\t0x1\t# Number of entries" 3 } 
> } */
> -/* { dg-final { scan-assembler-times ".4byte\t0x2\t# Number of entries" 1 } 
> } */
> +/* { dg-final { scan-assembler-times "FuncInfo 
> section\[^\n\]*\n\[^0\]*0x1\t# Number of entries" 2 } } */
>  /* { dg-final { scan-assembler-times "Required padding" 1 } } */

Reply via email to