public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: "Jose E. Marchesi" <jose.marchesi@oracle.com>
To: Cupertino Miranda <cupertino.miranda@oracle.com>
Cc: gcc-patches@gcc.gnu.org, david.faust@oracle.com,
	elena.zannoni@oracle.com
Subject: Re: [PATCH 3/3] bpf: add line_info support to BTF.ext section.
Date: Wed, 17 Apr 2024 19:55:27 +0200	[thread overview]
Message-ID: <87cyqn6fhs.fsf@oracle.com> (raw)
In-Reply-To: <87mspr6fsq.fsf@oracle.com> (Jose E. Marchesi's message of "Wed, 17 Apr 2024 19:48:53 +0200")


>> Jose E. Marchesi writes:
>>
>>> 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?
>> Maybe BPF would be Ok (not complaining of missing line_info) with just a
>> single entry per function pointing to the entry instruction. That
>> is not what clang does. Don't know if it emits any labels either.
>>
>> It is probably possible to add some logic to compute the offset from
>> the function label and emit with an offset to the instruction
>> location.  In case of inline assembly we could add a symbol after, and
>> restart offset computation.  It will need to add code to compute the
>> instruction encoding size, and increment function label offset each
>> time we emit an instruction.
>>
>> Still, my personal preference is to create those labels to properly
>> compute instruction location then some rather intricate solution that
>> would lead to future complications.  I know BPF is not like all the
>> other targets, but I am thinking of assembly/linker relaxation.
>>
>> WDYT ?
>
> What I meant is: if it is not required to emit a line_info entry for
> _every_ BPF instruction, but only for the instructions that "change" the
> current location, then we better do so?
>
> Then, regarding the labels, I assume their purpose is to get the
> assembler to fill in the `insn_off' field of the bpf_line_info in the
> .BTF.ext section:
>
>     struct bpf_line_info {
>         __u32   insn_off; /* [0, insn_cnt - 1] */
>         __u32   file_name_off; /* offset to string table for the filename */
>         __u32   line_off; /* offset to string table for the source line */
>         __u32   line_col; /* line number and column number */
>     };
>
> Which makes sense, since "instruction offset" is really the business of
> the assembler, not the compiler.  I agree with you making it the
> compiler's business would be overcomplicated, given inline assembly and
> variable-sized BPF instructions...
>
> So, what about moving the task of creating these line_info entries
> entirely to the assembler?  GCC already knows how to emit .file and .loc
> directives to track location info in DWARF.
>
> The BPF assembler could then process these and create entries in
> .BTF.ext for line_info, all the fields above: insn_off, file_name_off,
> line_off and line_col.

Regarding file_name_off, hopefully it will be possible to make the
assembler to simply expand the string table in .BTF (with the strings
read from .file directives) without having to understand/redo the whole
BTF section...

>>>> 	* 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	other threads:[~2024-04-17 17:55 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-11 11:11 [PATCH 1/3] bpf: support more instructions to match CO-RE relocations Cupertino Miranda
2024-04-11 11:11 ` [PATCH 2/3] bpf: remove huge memory waste with string allocation Cupertino Miranda
2024-04-11 16:34   ` David Faust
2024-04-11 17:23     ` Cupertino Miranda
2024-04-11 11:11 ` [PATCH 3/3] bpf: add line_info support to BTF.ext section Cupertino Miranda
2024-04-17 15:14   ` Jose E. Marchesi
2024-04-17 15:47     ` Cupertino Miranda
2024-04-17 17:48       ` Jose E. Marchesi
2024-04-17 17:55         ` Jose E. Marchesi [this message]
2024-04-17 15:07 ` [PATCH 1/3] bpf: support more instructions to match CO-RE relocations Jose E. Marchesi
2024-04-19 10:17   ` Cupertino Miranda

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87cyqn6fhs.fsf@oracle.com \
    --to=jose.marchesi@oracle.com \
    --cc=cupertino.miranda@oracle.com \
    --cc=david.faust@oracle.com \
    --cc=elena.zannoni@oracle.com \
    --cc=gcc-patches@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).