diff mbox series

[v2,3/3] btf: correct generation for extern funcs [PR106773]

Message ID 20221213184426.8861-4-david.faust@oracle.com
State New
Headers show
Series btf: fix BTF for extern items [PR106773] | expand

Commit Message

David Faust Dec. 13, 2022, 6:44 p.m. UTC
[Changes from v1:
 - Add enum btf_func_linkage to include/btf.h and use it.
 - Minor updates to comments based on review. ]

The eBPF loader expects to find entries for functions declared as extern
in the corresponding BTF_KIND_DATASEC record, but we were not generating
these entries.

This patch adds support for the 'extern' linkage of function types in
BTF, and creates entries for for them BTF_KIND_DATASEC records as needed.

	PR target/106773

gcc/

	* btfout.cc (get_section_name): New function.
	(btf_collect_datasec): Use it here. Process functions, marking them
	'extern' and generating DATASEC entries for them as appropriate. Move
	creation of BTF_KIND_FUNC records to here...
	(btf_dtd_emit_preprocess_cb): ... from here.

gcc/testsuite/

	* gcc.dg/debug/btf/btf-datasec-2.c: New test.
	* gcc.dg/debug/btf/btf-function-6.c: New test.

include/

	* btf.h (enum btf_func_linkage): New.
	(struct btf_var_secinfo): Update comments with notes about extern
	functions.
---
 gcc/btfout.cc                                 | 129 ++++++++++++------
 .../gcc.dg/debug/btf/btf-datasec-2.c          |  28 ++++
 .../gcc.dg/debug/btf/btf-function-6.c         |  19 +++
 include/btf.h                                 |  18 ++-
 4 files changed, 148 insertions(+), 46 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-datasec-2.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-function-6.c
diff mbox series

Patch

diff --git a/gcc/btfout.cc b/gcc/btfout.cc
index 204b11d4e9f..a423fabc0b5 100644
--- a/gcc/btfout.cc
+++ b/gcc/btfout.cc
@@ -290,7 +290,35 @@  btf_datasec_push_entry (ctf_container_ref ctfc, const char *secname,
   ds.entries.safe_push (info);
 
   datasecs.safe_push (ds);
-  num_types_created++;
+}
+
+
+/* Return the section name, as of interest to btf_collect_datasec, for the
+   given symtab node.  Note that this deliberately returns NULL for objects
+   which do not go in a section btf_collect_datasec cares about.  */
+static const char *
+get_section_name (symtab_node *node)
+{
+  const char *section_name = node->get_section ();
+
+  if (section_name == NULL)
+    {
+      switch (categorize_decl_for_section (node->decl, 0))
+	{
+	case SECCAT_BSS:
+	  section_name = ".bss";
+	  break;
+	case SECCAT_DATA:
+	  section_name = ".data";
+	  break;
+	case SECCAT_RODATA:
+	  section_name = ".rodata";
+	  break;
+	default:;
+	}
+    }
+
+  return section_name;
 }
 
 /* Construct all BTF_KIND_DATASEC records for CTFC. One such record is created
@@ -301,7 +329,60 @@  btf_datasec_push_entry (ctf_container_ref ctfc, const char *secname,
 static void
 btf_collect_datasec (ctf_container_ref ctfc)
 {
-  /* See cgraph.h struct symtab_node, which varpool_node extends.  */
+  cgraph_node *func;
+  FOR_EACH_FUNCTION (func)
+    {
+      dw_die_ref die = lookup_decl_die (func->decl);
+      if (die == NULL)
+	continue;
+
+      ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
+      if (dtd == NULL)
+	continue;
+
+      /* Functions actually get two types: a BTF_KIND_FUNC_PROTO, and
+	 also a BTF_KIND_FUNC.  But the CTF container only allocates one
+	 type per function, which matches closely with BTF_KIND_FUNC_PROTO.
+	 For each such function, also allocate a BTF_KIND_FUNC entry.
+	 These will be output later.  */
+      ctf_dtdef_ref func_dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
+      func_dtd->dtd_data = dtd->dtd_data;
+      func_dtd->dtd_data.ctti_type = dtd->dtd_type;
+      func_dtd->linkage = dtd->linkage;
+      func_dtd->dtd_type = num_types_added + num_types_created;
+
+      /* Only the BTF_KIND_FUNC type actually references the name. The
+	 BTF_KIND_FUNC_PROTO is always anonymous.  */
+      dtd->dtd_data.ctti_name = 0;
+
+      vec_safe_push (funcs, func_dtd);
+      num_types_created++;
+
+      /* Mark any 'extern' funcs and add DATASEC entries for them.  */
+      if (DECL_EXTERNAL (func->decl))
+	{
+	  func_dtd->linkage = BTF_FUNC_EXTERN;
+
+	  const char *section_name = get_section_name (func);
+	  /* Note: get_section_name () returns NULL for functions in text
+	     section.  This is intentional, since we do not want to generate
+	     DATASEC entries for them.  */
+	  if (section_name == NULL)
+	    continue;
+
+	  struct btf_var_secinfo info;
+
+	  /* +1 for the sentinel type not in the types map.  */
+	  info.type = func_dtd->dtd_type + 1;
+
+	  /* Both zero at compile time.  */
+	  info.size = 0;
+	  info.offset = 0;
+
+	  btf_datasec_push_entry (ctfc, section_name, info);
+	}
+    }
+
   varpool_node *node;
   FOR_EACH_VARIABLE (node)
     {
@@ -313,28 +394,13 @@  btf_collect_datasec (ctf_container_ref ctfc)
       if (dvd == NULL)
 	continue;
 
-      const char *section_name = node->get_section ();
       /* Mark extern variables.  */
       if (DECL_EXTERNAL (node->decl))
 	dvd->dvd_visibility = BTF_VAR_GLOBAL_EXTERN;
 
+      const char *section_name = get_section_name (node);
       if (section_name == NULL)
-	{
-	  switch (categorize_decl_for_section (node->decl, 0))
-	    {
-	    case SECCAT_BSS:
-	      section_name = ".bss";
-	      break;
-	    case SECCAT_DATA:
-	      section_name = ".data";
-	      break;
-	    case SECCAT_RODATA:
-	      section_name = ".rodata";
-	      break;
-	    default:
-	      continue;
-	    }
-	}
+	continue;
 
       struct btf_var_secinfo info;
 
@@ -359,6 +425,8 @@  btf_collect_datasec (ctf_container_ref ctfc)
 
       btf_datasec_push_entry (ctfc, section_name, info);
     }
+
+  num_types_created += datasecs.length ();
 }
 
 /* Return true if the type ID is that of a type which will not be emitted (for
@@ -463,29 +531,6 @@  btf_dtd_emit_preprocess_cb (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
   if (!btf_emit_id_p (dtd->dtd_type))
     return;
 
-  uint32_t btf_kind
-    = get_btf_kind (CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info));
-
-  if (btf_kind == BTF_KIND_FUNC_PROTO)
-    {
-      /* Functions actually get two types: a BTF_KIND_FUNC_PROTO, and
-	 also a BTF_KIND_FUNC. But the CTF container only allocates one
-	 type per function, which matches closely with BTF_KIND_FUNC_PROTO.
-	 For each such function, also allocate a BTF_KIND_FUNC entry.
-	 These will be output later.  */
-      ctf_dtdef_ref func_dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
-      func_dtd->dtd_data = dtd->dtd_data;
-      func_dtd->dtd_data.ctti_type = dtd->dtd_type;
-      func_dtd->linkage = dtd->linkage;
-
-      vec_safe_push (funcs, func_dtd);
-      num_types_created++;
-
-      /* Only the BTF_KIND_FUNC type actually references the name. The
-	 BTF_KIND_FUNC_PROTO is always anonymous.  */
-      dtd->dtd_data.ctti_name = 0;
-    }
-
   ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (dtd);
 }
 
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-datasec-2.c b/gcc/testsuite/gcc.dg/debug/btf/btf-datasec-2.c
new file mode 100644
index 00000000000..f4b298cf019
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-datasec-2.c
@@ -0,0 +1,28 @@ 
+/* Test BTF generation of DATASEC records for extern functions.
+
+   Only functions declared extern should have entries in DATASEC records.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+/* Expect one DATASEC with vlen=1 (.foo_sec) and one with vlen=2 (.bar_sec) */
+/* { dg-final { scan-assembler-times "0xf000002\[\t \]+\[^\n\]*btt_info" 1 } } */
+/* { dg-final { scan-assembler-times "0xf000001\[\t \]+\[^\n\]*btt_info" 1 } } */
+
+/* Function entries should have offset and size of 0 at compile time.  */
+/* { dg-final { scan-assembler-times "0\[\t \]+\[^\n\]*bts_offset" 3 } } */
+/* { dg-final { scan-assembler-times "0\[\t \]+\[^\n\]*bts_size" 3 } } */
+
+extern int foo (int a) __attribute__((section(".foo_sec")));
+
+
+extern int bar (int b) __attribute__((section(".bar_sec")));
+extern void chacha (void) __attribute__((section(".bar_sec")));
+
+__attribute__((section(".foo_sec")))
+void baz (int *x)
+{
+  chacha ();
+
+  *x = foo (bar (*x));
+}
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-function-6.c b/gcc/testsuite/gcc.dg/debug/btf/btf-function-6.c
new file mode 100644
index 00000000000..48a946ab14b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-function-6.c
@@ -0,0 +1,19 @@ 
+/* Test BTF extern linkage for functions.
+
+   We expect to see one BTF_KIND_FUNC type with global linkage (foo), and
+   one BTF_KIND_FUNC type with extern linkage (extfunc).  */
+
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+/* { dg-final { scan-assembler-times "btt_info: kind=12, kflag=0, linkage=2" 1 } } */
+/* { dg-final { scan-assembler-times "btt_info: kind=12, kflag=0, linkage=1" 1 } } */
+
+extern int extfunc(int a, int b);
+
+int foo (int x) {
+
+  int y = extfunc (x, x+1);
+
+  return y;
+}
diff --git a/include/btf.h b/include/btf.h
index da621353aa1..2f8f6f68b27 100644
--- a/include/btf.h
+++ b/include/btf.h
@@ -178,6 +178,15 @@  struct btf_param
   uint32_t type;	/* Type of parameter.  */
 };
 
+/* BTF_KIND_FUNC records encode linkage information in the VLEN bits
+   of the type record.  These are the supported values.  */
+enum btf_func_linkage
+{
+  BTF_FUNC_STATIC = 0,
+  BTF_FUNC_GLOBAL = 1,
+  BTF_FUNC_EXTERN = 2,
+};
+
 /* BTF_KIND_VAR records encode linkage information in a single
    trailing struct btf_var.  These are the supported values.  */
 enum btf_var_linkage
@@ -195,12 +204,13 @@  struct btf_var
 };
 
 /* BTF_KIND_DATASEC is followed by VLEN struct btf_var_secinfo entries,
-   which describe all BTF_KIND_VAR types contained in the section.  */
+   which describe all BTF_KIND_VAR or extern BTF_KIND_FUNC types contained
+   in the section.  */
 struct btf_var_secinfo
 {
-  uint32_t type;	/* Type of variable.  */
-  uint32_t offset;	/* In-section offset of variable (in bytes).  */
-  uint32_t size;	/* Size (in bytes) of variable.  */
+  uint32_t type;	/* Type of BTF_KIND_VAR or BTF_KIND_FUNC item.  */
+  uint32_t offset;	/* In-section offset (in bytes) of item.  */
+  uint32_t size;	/* Size (in bytes) of item.  */
 };
 
 /* BTF_KIND_ENUM64 is followed by VLEN struct btf_enum64 entries,