diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index 4318b26b9cda..ea47e3a8dbfb 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -385,6 +385,18 @@ bpf_compute_frame_layout (void)
 #undef TARGET_COMPUTE_FRAME_LAYOUT
 #define TARGET_COMPUTE_FRAME_LAYOUT bpf_compute_frame_layout
 
+/* Defined to initialize data for func_info region in .BTF.ext section.  */
+
+static void
+bpf_function_prologue (FILE *f ATTRIBUTE_UNUSED)
+{
+  if (btf_debuginfo_p ())
+    btf_add_func_info_for (cfun->decl, current_function_func_begin_label);
+}
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE bpf_function_prologue
+
 /* Expand to the instructions in a function prologue.  This function
    is called when expanding the 'prologue' pattern in bpf.md.  */
 
diff --git a/gcc/config/bpf/coreout.cc b/gcc/config/bpf/coreout.cc
index 2f06ec2a0f29..31b2abc3151b 100644
--- a/gcc/config/bpf/coreout.cc
+++ b/gcc/config/bpf/coreout.cc
@@ -31,6 +31,7 @@
 #include "btf.h"
 #include "rtl.h"
 #include "tree-pretty-print.h"
+#include "cgraph.h"
 
 #include "coreout.h"
 
@@ -95,64 +96,193 @@
    result, a single .BTF.ext section can contain CO-RE relocations for multiple
    programs in distinct sections.  */
 
-/* Internal representation of a BPF CO-RE relocation record.  */
+/* BTF.ext debug info section.  */
+static GTY (()) section * btf_ext_info_section;
+
+#ifndef BTF_EXT_INFO_SECTION_NAME
+#define BTF_EXT_INFO_SECTION_NAME ".BTF.ext"
+#endif
+#define BTF_EXT_INFO_SECTION_FLAGS (SECTION_DEBUG)
+
+#ifndef BTF_EXT_INFO_SECTION_LABEL
+#define BTF_EXT_INFO_SECTION_LABEL "Lbtfext"
+#endif
+
+#define MAX_BTF_EXT_LABEL_BYTES 40
+static char btf_ext_info_section_label[MAX_BTF_EXT_LABEL_BYTES];
+
+/* A funcinfo record, in the .BTF.ext funcinfo section.  */
+struct GTY ((chain_next ("%h.next"))) btf_ext_funcinfo
+{
+  uint32_t type;     /* Type ID of a BTF_KIND_FUNC type.  */
+  const char *fnname;
+  const char *label;
+
+  struct btf_ext_funcinfo *next; /* Linked list to collect func_info elems.  */
+};
+
+/* 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.  */
+  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).  */
 
-typedef struct GTY (()) bpf_core_reloc {
+  struct btf_ext_lineinfo *next; /* Linked list to collect line_info elems.  */
+};
+
+/* Internal representation of a BPF CO-RE relocation record.  */
+struct GTY ((chain_next ("%h.next"))) btf_ext_core_reloc {
   unsigned int bpfcr_type;		/* BTF type ID of container.  */
   unsigned int  bpfcr_astr_off;		/* Offset of access string in .BTF
 					   string table.  */
   rtx_code_label * bpfcr_insn_label;	/* RTX label attached to instruction
 					   to patch.  */
   enum btf_core_reloc_kind bpfcr_kind;	/* Kind of relocation to perform.  */
-} bpf_core_reloc_t;
 
-typedef bpf_core_reloc_t * bpf_core_reloc_ref;
+  struct {
+    const char *accessor_str;
+    tree type;
+  } info;
 
-/* Internal representation of a CO-RE relocation (sub)section of the
-   .BTF.ext information. One such section is generated for each ELF section
-   in the output object having relocations that a BPF loader must resolve.  */
+  struct btf_ext_core_reloc *next;
+};
 
-typedef struct GTY (()) bpf_core_section {
-  /* Name of ELF section to which these CO-RE relocations apply.  */
-  const char * name;
+/* Main data structure to keep .BTF.ext section data.  */
+struct GTY ((chain_next ("%h.next"))) btf_ext_info_sec {
+  const char *sec_name;
+  uint32_t   sec_name_off; /* offset to section name.  */
+
+  struct {
+    uint32_t num_info;
+    struct btf_ext_funcinfo *head;
+  } func_info;
+  struct {
+    uint32_t num_info;
+    struct btf_ext_lineinfo *head;
+  } line_info;
+  struct {
+    uint32_t num_info;
+    struct btf_ext_core_reloc *head;
+  } core_info;
+
+  struct btf_ext_info_sec *next;
+};
 
-  /* Offset of section name in .BTF string table.  */
-  uint32_t name_offset;
+static GTY (()) struct btf_ext_info_sec *btf_ext = NULL;
 
-  /* Relocations in the section.  */
-  vec <bpf_core_reloc_ref, va_gc> * GTY (()) relocs;
-} bpf_core_section_t;
+/* Helper function to add a section structure to the linked list with entry
+   point in info static variable.  */
 
-typedef bpf_core_section_t * bpf_core_section_ref;
+static struct btf_ext_info_sec *
+btfext_info_sec_find_or_add (const char *sec_name, bool add)
+{
+  struct btf_ext_info_sec **tmp = &btf_ext;
 
-/* BTF.ext debug info section.  */
+  while (*tmp != NULL)
+    {
+      if (strcmp ((*tmp)->sec_name, sec_name) == 0)
+	return *tmp;
+      tmp = &((*tmp)->next);
+    }
 
-static GTY (()) section * btf_ext_info_section;
+  if (add == false)
+    return NULL;
 
-static int btf_ext_label_num;
+  struct btf_ext_info_sec *ret = ggc_cleared_alloc<struct btf_ext_info_sec> ();
+  *tmp = ret;
 
-#ifndef BTF_EXT_INFO_SECTION_NAME
-#define BTF_EXT_INFO_SECTION_NAME ".BTF.ext"
-#endif
+  /* Set data for section info.  */
+  ret->sec_name = sec_name;
+  ret->sec_name_off = btf_ext_add_string (sec_name);
 
-#define BTF_EXT_INFO_SECTION_FLAGS (SECTION_DEBUG)
+  return ret;
+}
 
-#define MAX_BTF_EXT_LABEL_BYTES 40
+#define SEARCH_NODE_AND_RETURN(TYPE, FIELD, CONDITION) ({ \
+  TYPE **head = &(FIELD); \
+  while (*head != NULL) \
+    { \
+      if (CONDITION) \
+	return (*head); \
+      head = &((*head)->next); \
+    } \
+  head; \
+})
+
+/* Function to create or find a funcinfo node in info.  */
+
+static struct btf_ext_funcinfo *
+bpf_create_or_find_funcinfo (const char *fnname, 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);
 
-static char btf_ext_info_section_label[MAX_BTF_EXT_LABEL_BYTES];
+  if (in_sec != NULL)
+    *in_sec = sec_elem;
 
-#ifndef BTF_EXT_INFO_SECTION_LABEL
-#define BTF_EXT_INFO_SECTION_LABEL "Lbtfext"
-#endif
+  struct btf_ext_funcinfo **head =
+    SEARCH_NODE_AND_RETURN(struct btf_ext_funcinfo,
+			   sec_elem->func_info.head,
+			   strcmp ((*head)->fnname, fnname) == 0);
 
-static GTY (()) vec<bpf_core_section_ref, va_gc> *bpf_core_sections;
+  *head = ggc_cleared_alloc<struct btf_ext_funcinfo> ();
+  (*head)->fnname = fnname;
+  (*head)->label = NULL;
 
-struct GTY(()) bpf_core_extra {
-  const char *accessor_str;
-  tree type;
+  return *head;
+}
+
+/* Function to create a core_reloc node in info.  */
+
+static struct btf_ext_core_reloc *
+bpf_create_core_reloc (const char *sec_name,
+		       struct 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_core_reloc **head =
+    SEARCH_NODE_AND_RETURN(struct btf_ext_core_reloc,
+			   sec_elem->core_info.head,
+			   false);
+
+  *head = ggc_cleared_alloc<struct btf_ext_core_reloc> ();
+
+  return *head;
+}
+
+/* String caching to avoid repeated strings added to BTF string table.  */
+struct GTY((chain_next ("%h.next"))) string_cache {
+  const char *str;
+  unsigned int offset;
+  struct string_cache *next;
 };
-typedef struct bpf_core_extra *bpf_core_extra_ref;
-static GTY(()) hash_map<bpf_core_reloc_ref, bpf_core_extra_ref> *bpf_comment_info;
+static GTY(()) struct string_cache *btf_ext_strings = NULL;
+
+unsigned int
+btf_ext_add_string (const char *str)
+{
+  ctf_container_ref ctfc = ctf_get_tu_ctfc ();
+  struct string_cache **tmp = &btf_ext_strings;
+  while (*tmp != NULL)
+    {
+      if (strcmp ((*tmp)->str, str) == 0)
+	return (*tmp)->offset;
+      tmp = &((*tmp)->next);
+    }
+
+  *tmp = ggc_cleared_alloc<struct string_cache> ();
+  (*tmp)->str = ggc_strdup (str);
+  ctf_add_string (ctfc, (*tmp)->str, &((*tmp)->offset), CTF_AUX_STRTAB);
+
+  return (*tmp)->offset;
+}
 
 /* Create a new BPF CO-RE relocation record, and add it to the appropriate
    CO-RE section.  */
@@ -162,42 +292,23 @@ bpf_core_reloc_add (const tree type, const char * section_name,
 		    rtx_code_label *label,
 		    enum btf_core_reloc_kind kind)
 {
-  bpf_core_reloc_ref bpfcr = ggc_cleared_alloc<bpf_core_reloc_t> ();
-  bpf_core_extra_ref info = ggc_cleared_alloc<struct bpf_core_extra> ();
+  struct btf_ext_info_sec *sec = NULL;
+  struct btf_ext_core_reloc *bpfcr = bpf_create_core_reloc (section_name, &sec);
+
   ctf_container_ref ctfc = ctf_get_tu_ctfc ();
 
   /* Buffer the access string in the auxiliary strtab.  */
-  ctf_add_string (ctfc, accessor, &(bpfcr->bpfcr_astr_off), CTF_AUX_STRTAB);
+  bpfcr->bpfcr_astr_off = 0;
+  if (accessor != NULL)
+    bpfcr->bpfcr_astr_off = btf_ext_add_string (accessor);
   bpfcr->bpfcr_type = get_btf_id (ctf_lookup_tree_type (ctfc, type));
   bpfcr->bpfcr_insn_label = label;
   bpfcr->bpfcr_kind = kind;
 
-  info->accessor_str = accessor;
-  info->type = type;
-  bpf_comment_info->put (bpfcr, info);
-
-  /* Add the CO-RE reloc to the appropriate section.  */
-  bpf_core_section_ref sec;
-  int i;
-  FOR_EACH_VEC_ELT (*bpf_core_sections, i, sec)
-    if (strcmp (sec->name, section_name) == 0)
-      {
-	vec_safe_push (sec->relocs, bpfcr);
-	return;
-      }
+  bpfcr->info.accessor_str = accessor;
+  bpfcr->info.type = type;
 
-  /* If the CO-RE section does not yet exist, create it.  */
-  sec = ggc_cleared_alloc<bpf_core_section_t> ();
-
-  ctf_add_string (ctfc, section_name, &sec->name_offset, CTF_AUX_STRTAB);
-  if (strcmp (section_name, ""))
-    ctfc->ctfc_aux_strlen += strlen (section_name) + 1;
-
-  sec->name = section_name;
-  vec_alloc (sec->relocs, 1);
-  vec_safe_push (sec->relocs, bpfcr);
-
-  vec_safe_push (bpf_core_sections, sec);
+  sec->core_info.num_info += 1;
 }
 
 /* Return the 0-based index of the field NODE in its containing struct or union
@@ -243,6 +354,113 @@ bpf_core_get_sou_member_index (ctf_container_ref ctfc, const tree node)
   return -1;
 }
 
+/* Helper function to check if a particular named function exists as a
+   BTF_KIND_FUNC type record.  */
+
+static bool
+btf_funcinfo_type_callback (ctf_dtdef_ref func, void *data)
+{
+  struct btf_ext_funcinfo *info = (struct btf_ext_funcinfo *) data;
+  if (strcmp (func->dtd_name, info->fnname) == 0)
+    {
+      uint32_t type = func->dtd_type;
+      info->type = type;
+      return true;
+    }
+  return false;
+}
+
+/* Entry point function to add a func_info  in local data structures
+   represented by info static variable.
+   This function is used in bpf.cc.  */
+
+struct btf_ext_funcinfo *
+btf_add_func_info_for (tree decl, const char *label)
+{
+  const char *fnname = IDENTIFIER_POINTER (DECL_NAME (decl));
+  const char *sec_name = decl_section_name (decl);
+
+  /* Finding suffixed function names, due to the function cloning base on
+     optimizations.
+     This is required to recover the original function name that is the one
+     used in BTF_KIND_FUNC type records.  */
+  const char *cp_ptr = strstr (fnname, ".");
+  if (cp_ptr != NULL)
+    {
+      char new_name[100];
+      strcpy (new_name, fnname);
+      int pos = cp_ptr - fnname;
+      new_name[pos] = 0;
+      fnname = ggc_strdup (new_name);
+    }
+
+  if (sec_name == NULL)
+    sec_name = ".text";
+
+  struct btf_ext_info_sec *sec = NULL;
+  struct btf_ext_funcinfo *info =
+    bpf_create_or_find_funcinfo (fnname, sec_name, &sec);
+
+  info->label = label;
+  return info;
+}
+
+/* This function traverses all func_info entries and verified they do have a
+   BTF_KIND_FUNC type record associated.  If they do not it is marked as
+   invalided by clearing the associated label.  */
+
+static void
+btf_validate_funcinfo (btf_ext_info_sec *sec)
+{
+  while (sec != NULL)
+    {
+      struct btf_ext_funcinfo *funcinfo = sec->func_info.head;
+      while (funcinfo != NULL)
+	{
+	  bool found = traverse_btf_func_types (btf_funcinfo_type_callback,
+						funcinfo);
+	  if (found == true)
+	    sec->func_info.num_info += 1;
+	  else
+	    funcinfo->label = NULL;
+
+	  funcinfo = funcinfo->next;
+	}
+      sec = sec->next;
+    }
+}
+
+/* Compute the section size in section for func_info, line_info and core_info
+   regions of .BTF.ext.  */
+
+static void
+btf_ext_info_len (uint32_t *fi_len, uint32_t *li_len, uint32_t *cr_len)
+{
+  *fi_len = *li_len = *cr_len = 0;
+  struct btf_ext_info_sec *tmp = btf_ext;
+  if (tmp != NULL)
+  while (tmp != NULL)
+    {
+      /* Size computation does 8 bytes per section entry plus num_info of the
+       * respective structure size:
+	  - 8 bytes for func_info,
+	  - 16 bytes for both line_info and core_info.  */
+      if (tmp->func_info.num_info > 0)
+	*fi_len +=  8 + (8 * tmp->func_info.num_info);
+      if (tmp->line_info.num_info > 0)
+	*li_len +=  8 + (16 * tmp->line_info.num_info);
+      if (tmp->core_info.num_info > 0)
+	*cr_len +=  8 + (16 * tmp->core_info.num_info);
+      tmp = tmp->next;
+    }
+
+  /* If there are entries within the regions, add 4 bytes to set the header of
+     the respective sections that contains the size for each of the entry.  */
+  *fi_len += *fi_len != 0 ? 4 : 0;
+  *li_len += *li_len != 0 ? 4 : 0;
+  *cr_len += *cr_len != 0 ? 4 : 0;
+}
+
 /* Compute and output the header of a .BTF.ext debug info section.  */
 
 static void
@@ -256,23 +474,19 @@ output_btfext_header (void)
   dw2_asm_output_data (1, 0, "btfext_flags");
   dw2_asm_output_data (4, sizeof (struct btf_ext_header), "btfext_hdr_len");
 
-  uint32_t func_info_off = 0, func_info_len = 0;
-  uint32_t line_info_off = 0, line_info_len = 0;
-  uint32_t core_relo_off = 0, core_relo_len = 0;
+  btf_validate_funcinfo (btf_ext);
 
-  /* Header core_relo_len is the sum total length in bytes of all CO-RE
-     relocation sections, plus the 4 byte record size.  */
-  size_t i;
-  bpf_core_section_ref sec;
-  core_relo_len += vec_safe_length (bpf_core_sections)
-    * sizeof (struct btf_ext_section_header);
+  uint32_t func_info_len = 0;
+  uint32_t line_info_len = 0;
+  uint32_t core_info_len = 0;
+  btf_ext_info_len (&func_info_len, &line_info_len, &core_info_len);
 
-  FOR_EACH_VEC_ELT (*bpf_core_sections, i, sec)
-    core_relo_len +=
-      vec_safe_length (sec->relocs) * sizeof (struct btf_ext_reloc);
+  if (!TARGET_BPF_CORE)
+    core_info_len = 0;
 
-  if (core_relo_len)
-    core_relo_len += sizeof (uint32_t);
+  uint32_t func_info_off = 0;
+  uint32_t line_info_off = func_info_len;
+  uint32_t core_info_off = line_info_off + line_info_len;
 
   dw2_asm_output_data (4, func_info_off, "func_info_offset");
   dw2_asm_output_data (4, func_info_len, "func_info_len");
@@ -280,47 +494,47 @@ output_btfext_header (void)
   dw2_asm_output_data (4, line_info_off, "line_info_offset");
   dw2_asm_output_data (4, line_info_len, "line_info_len");
 
-  dw2_asm_output_data (4, core_relo_off, "core_relo_offset");
-  dw2_asm_output_data (4, core_relo_len, "core_relo_len");
+  dw2_asm_output_data (4, core_info_off, "core_relo_offset");
+  dw2_asm_output_data (4, core_info_len, "core_relo_len");
 }
 
-/* Output a single CO-RE relocation record.  */
+/* Outputs func_info region on .BTF.ext.  */
 
 static void
-output_asm_btfext_core_reloc (bpf_core_reloc_ref bpfcr)
+output_btfext_func_info (struct btf_ext_info_sec *sec)
 {
-  bpf_core_extra_ref *info = bpf_comment_info->get (bpfcr);
-  gcc_assert (info != NULL);
-
-  bpfcr->bpfcr_astr_off += ctfc_get_strtab_len (ctf_get_tu_ctfc (),
-						CTF_STRTAB);
-
-  dw2_assemble_integer (4, gen_rtx_LABEL_REF (Pmode, bpfcr->bpfcr_insn_label));
-  fprintf (asm_out_file, "\t%s%s\n",
-	   flag_debug_asm ? ASM_COMMENT_START : "",
-	   (flag_debug_asm ? " bpfcr_insn" : ""));
-
-  /* Extract the pretty print for the type expression.  */
-  pretty_printer pp;
-  dump_generic_node (&pp, (*info)->type, 0, TDF_VOPS|TDF_MEMSYMS|TDF_SLIM,
-		     false);
-  char *str = xstrdup (pp_formatted_text (&pp));
-
-  dw2_asm_output_data (4, bpfcr->bpfcr_type, "bpfcr_type (%s)", str);
-  dw2_asm_output_data (4, bpfcr->bpfcr_astr_off, "bpfcr_astr_off (\"%s\")",
-			  (*info)->accessor_str);
-  dw2_asm_output_data (4, bpfcr->bpfcr_kind, "bpfcr_kind");
-}
-
-/* Output all CO-RE relocation records for a section.  */
-
-static void
-output_btfext_core_relocs (bpf_core_section_ref sec)
-{
-  size_t i;
-  bpf_core_reloc_ref bpfcr;
-  FOR_EACH_VEC_ELT (*(sec->relocs), i, bpfcr)
-    output_asm_btfext_core_reloc (bpfcr);
+  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->func_info.num_info > 0)
+	{
+	  if (executed == false && (executed = true))
+	    dw2_asm_output_data (4, 8, "FuncInfo entry size");
+	  dw2_asm_output_data (4, sec->sec_name_off + str_aux_off,
+			       "FuncInfo section string for %s",
+			       sec->sec_name);
+	  dw2_asm_output_data (4, sec->func_info.num_info, "Number of entries");
+
+	  struct btf_ext_funcinfo *elem = sec->func_info.head;
+	  while (elem != NULL)
+	    {
+	      if (elem->label != NULL)
+		{
+		  count += 1;
+		  dw2_asm_output_offset (4, elem->label,
+		       NULL, "label for function %s", elem->fnname);
+		  dw2_asm_output_data (4, elem->type, "btf_type_id");
+		}
+	      elem = elem->next;
+	    }
+	}
+
+      gcc_assert (count == sec->func_info.num_info);
+      sec = sec->next;
+    }
 }
 
 /* Output all CO-RE relocation sections.  */
@@ -328,28 +542,51 @@ output_btfext_core_relocs (bpf_core_section_ref sec)
 static void
 output_btfext_core_sections (void)
 {
-  size_t i;
-  bpf_core_section_ref sec;
-
-  /* BTF Ext section info. */
-  dw2_asm_output_data (4, sizeof (struct btf_ext_reloc),
-		       "btfext_core_info_rec_size");
-
-  FOR_EACH_VEC_ELT (*bpf_core_sections, i, sec)
+  struct btf_ext_info_sec *sec = btf_ext;
+  unsigned int str_aux_off = ctfc_get_strtab_len (ctf_get_tu_ctfc (),
+						  CTF_STRTAB);
+  bool executed = false;
+  while (sec != NULL)
     {
-      /* Section name offset, refers to the offset of a string with the name of
-	 the section to which these CORE relocations refer, e.g. '.text'.
-	 The string is buffered in the BTF strings table.  */
-
-      /* BTF specific strings are in CTF_AUX_STRTAB, which is concatenated
-	 after CTF_STRTAB. Add the length of STRTAB to the final offset.  */
-      sec->name_offset += ctfc_get_strtab_len (ctf_get_tu_ctfc (), CTF_STRTAB);
-
-      dw2_asm_output_data (4, sec->name_offset,  "btfext_secinfo_sec_name_off");
-      dw2_asm_output_data (4, vec_safe_length (sec->relocs),
-			   "btfext_secinfo_num_recs");
-
-      output_btfext_core_relocs (sec);
+      uint32_t count = 0;
+      if (sec->core_info.num_info > 0)
+	{
+	  if (executed == false && (executed = true))
+	    dw2_asm_output_data (4, 16, "CoreInfo entry size");
+	  dw2_asm_output_data (4, sec->sec_name_off + str_aux_off,
+			       "CoreInfo section string for %s",
+			       sec->sec_name);
+	  dw2_asm_output_data (4, sec->core_info.num_info, "Number of entries");
+
+	  struct btf_ext_core_reloc *bpfcr = sec->core_info.head;
+	  while (bpfcr != NULL)
+	    {
+	      count += 1;
+	      dw2_assemble_integer (4,
+			gen_rtx_LABEL_REF (Pmode, bpfcr->bpfcr_insn_label));
+	      fprintf (asm_out_file, "\t%s%s\n",
+		       flag_debug_asm ? ASM_COMMENT_START : "",
+		       (flag_debug_asm ? " bpfcr_insn" : ""));
+
+	      /* Extract the pretty print for the type expression.  */
+	      pretty_printer pp;
+	      dump_generic_node (&pp, bpfcr->info.type, 0,
+				 TDF_VOPS|TDF_MEMSYMS|TDF_SLIM,
+				 false);
+	      char *str = xstrdup (pp_formatted_text (&pp));
+
+	      dw2_asm_output_data (4, bpfcr->bpfcr_type, "bpfcr_type (%s)",
+				   str);
+	      dw2_asm_output_data (4, bpfcr->bpfcr_astr_off + str_aux_off,
+				   "bpfcr_astr_off (\"%s\")",
+				   bpfcr->info.accessor_str);
+	      dw2_asm_output_data (4, bpfcr->bpfcr_kind, "bpfcr_kind");
+	      bpfcr = bpfcr->next;
+	    }
+	}
+
+      gcc_assert (count == sec->core_info.num_info);
+      sec = sec->next;
     }
 }
 
@@ -362,22 +599,23 @@ btf_ext_init (void)
 				      BTF_EXT_INFO_SECTION_FLAGS, NULL);
 
   ASM_GENERATE_INTERNAL_LABEL (btf_ext_info_section_label,
-			       BTF_EXT_INFO_SECTION_LABEL,
-			       btf_ext_label_num++);
-
-  vec_alloc (bpf_core_sections, 1);
-  bpf_comment_info = hash_map<bpf_core_reloc_ref, bpf_core_extra_ref>::create_ggc ();
+			       "Lbtfext", 0);
 }
 
+
 /* Output the entire .BTF.ext section.  */
 
 void
 btf_ext_output (void)
 {
   output_btfext_header ();
-  output_btfext_core_sections ();
+  output_btfext_func_info (btf_ext);
+  if (TARGET_BPF_CORE)
+    output_btfext_core_sections ();
 
-  bpf_core_sections = NULL;
+  /* Extra padding required by BPF code, just in case all structures are empty.
+  */
+  dw2_asm_output_data (4, 0, "Required padding by libbpf structs");
 }
 
 #include "gt-coreout.h"
diff --git a/gcc/config/bpf/coreout.h b/gcc/config/bpf/coreout.h
index 8a209f26e94b..1c26b9274739 100644
--- a/gcc/config/bpf/coreout.h
+++ b/gcc/config/bpf/coreout.h
@@ -38,22 +38,6 @@ struct btf_ext_section_header
   uint32_t num_records;
 };
 
-/* A funcinfo record, in the .BTF.ext funcinfo section.  */
-struct btf_ext_funcinfo
-{
-  uint32_t insn_off; /* Offset of the first instruction of the function.  */
-  uint32_t type;     /* Type ID of a BTF_KIND_FUNC type.  */
-};
-
-/* A lineinfo record, in the .BTF.ext lineinfo section.  */
-struct btf_ext_lineinfo
-{
-  uint32_t insn_off;      /* Offset of the instruction.  */
-  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).  */
-};
-
 enum btf_core_reloc_kind
 {
   BPF_RELO_INVALID = -1,
@@ -113,6 +97,10 @@ bpf_core_reloc_add (const tree type, const char * section_name,
 
 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);
+unsigned int btf_ext_add_string (const char *str);
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/gcc/testsuite/gcc.target/bpf/btfext-funcinfo-nocore.c b/gcc/testsuite/gcc.target/bpf/btfext-funcinfo-nocore.c
new file mode 100644
index 000000000000..09d3acc8c2d4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/bpf/btfext-funcinfo-nocore.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -dA -gbtf -mno-co-re" } */
+
+struct T {
+  int a;
+  int b;
+  struct U {
+    int c;
+    struct V {
+      int d;
+      int e[4];
+      int f;
+    } v;
+  } u;
+} __attribute__((preserve_access_index));
+
+__attribute__((section("foo_sec"), used))
+int foo_func (struct T *t)
+{
+  t->u.c = 5;
+  return t->u.v.e[3];
+}
+
+__attribute__((section("bar_sec"), used))
+int bar_func (struct T *t)
+{
+  int *x = &(t->u.v.f);
+  int old = *x;
+  *x = 4;
+  return old;
+}
+
+/* { dg-final { scan-assembler-times "FuncInfo section string for foo_sec" 1 } } */
+/* { dg-final { scan-assembler-times "FuncInfo section string for bar_sec" 1 } } */
+/* { dg-final { scan-assembler-times "label for function foo_func" 1 } } */
+/* { dg-final { scan-assembler-times "label for function bar_func" 1 } } */
+/* { dg-final { scan-assembler-times ".4byte\t0x1\t# Number of entries" 2 } } */
+/* { dg-final { scan-assembler-times "Required padding" 1 } } */
+
+/* { dg-final { scan-assembler-times "ascii \"foo_sec.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
+/* { dg-final { scan-assembler-times "ascii \"bar_sec.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
+
diff --git a/gcc/testsuite/gcc.target/bpf/btfext-funcinfo.c b/gcc/testsuite/gcc.target/bpf/btfext-funcinfo.c
new file mode 100644
index 000000000000..a59c5bd37eb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/bpf/btfext-funcinfo.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -dA -gbtf" } */
+
+struct T {
+  int a;
+  int b;
+  struct U {
+    int c;
+    struct V {
+      int d;
+      int e[4];
+      int f;
+    } v;
+  } u;
+} __attribute__((preserve_access_index));
+
+__attribute__((section("foo_sec"), used))
+int foo_func (struct T *t)
+{
+  t->u.c = 5;
+  return t->u.v.e[3];
+}
+
+__attribute__((section("bar_sec"), used))
+int bar_func (struct T *t)
+{
+  int *x = &(t->u.v.f);
+  int old = *x;
+  *x = 4;
+  return old;
+}
+
+/* { dg-final { scan-assembler-times "FuncInfo section string for foo_sec" 1 } } */
+/* { dg-final { scan-assembler-times "FuncInfo section string for bar_sec" 1 } } */
+/* { dg-final { scan-assembler-times "label for function foo_func" 1 } } */
+/* { dg-final { scan-assembler-times "label for function bar_func" 1 } } */
+
+/* { dg-final { scan-assembler-times "ascii \"0:2:1:1:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
+/* { dg-final { scan-assembler-times "ascii \"0:2:1:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
+/* { dg-final { scan-assembler-times "ascii \"foo_sec.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
+/* { 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 "Required padding" 1 } } */
diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-5.c b/gcc/testsuite/gcc.target/bpf/core-attr-5.c
index c0dc15fbb271..e71901d0d4d1 100644
--- a/gcc/testsuite/gcc.target/bpf/core-attr-5.c
+++ b/gcc/testsuite/gcc.target/bpf/core-attr-5.c
@@ -55,8 +55,13 @@ func (struct T *t, int i)
 /* { dg-final { scan-assembler-times "ascii \"0:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "ascii \"0:1:1:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "ascii \"0:1:1:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
-/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 2 } } */
+/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:1:3\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:4\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:3\"\\)" 2 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:2\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:1:1\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:0\"\\)" 1 } } */
 /* { dg-final { scan-assembler-times "bpfcr_type \\(struct T \\*\\)" 4 } } */
 /* { dg-final { scan-assembler-times "bpfcr_type \\(struct U \\*\\)" 4 { xfail *-*-* } } } */
-
diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-6.c b/gcc/testsuite/gcc.target/bpf/core-attr-6.c
index 858ae627cb8b..34a4c367e528 100644
--- a/gcc/testsuite/gcc.target/bpf/core-attr-6.c
+++ b/gcc/testsuite/gcc.target/bpf/core-attr-6.c
@@ -37,10 +37,14 @@ func (struct T *t, int i)
   mset (&t->a);
 }
 
-/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 2 } } */
+/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "ascii \"0:1:1:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "ascii \"0:1:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:1:1\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:3\"\\)" 2 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:2\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:0\"\\)" 1 } } */
 /* { dg-final { scan-assembler-times "bpfcr_type \\(struct T \\*\\)" 3 } } */
 /* { dg-final { scan-assembler-times "bpfcr_type \\(struct U \\*\\)" 2 } } */
 
diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c
index a4af9a53282a..27654205287d 100644
--- a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c
+++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c
@@ -52,9 +52,18 @@ unsigned int foo (struct T *t)
 /* { dg-final { scan-assembler-times "ascii \"0:1:0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "ascii \"0:1:0:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "ascii \"0:1:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
-/* { dg-final { scan-assembler-times "ascii \"0:1:1:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 2 } } */
+/* { dg-final { scan-assembler-times "ascii \"0:1:1:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "ascii \"0:1:1:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
-/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 2 } } */
+/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
+
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:0:0\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:0:3\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:0:4\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:1:0\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:1:3\"\\)" 2 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:1:4\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:2\"\\)" 1 } } */
+/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:3\"\\)" 2 } } */
 
 /* { dg-final { scan-assembler-times "0\[\t \]+\[^\n\]*bpfcr_kind" 10 } } */
diff --git a/gcc/testsuite/gcc.target/bpf/core-section-1.c b/gcc/testsuite/gcc.target/bpf/core-section-1.c
index 4f16b087c1a2..c2bac46cee78 100644
--- a/gcc/testsuite/gcc.target/bpf/core-section-1.c
+++ b/gcc/testsuite/gcc.target/bpf/core-section-1.c
@@ -35,4 +35,4 @@ int bar_func (struct T *t)
 /* { dg-final { scan-assembler-times "ascii \"foo_sec.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "ascii \"bar_sec.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */
 /* { dg-final { scan-assembler-times "bpfcr_type" 2 } } */
-/* { dg-final { scan-assembler-times "btfext_core_info_rec_size" 1 } } */
+/* { dg-final { scan-assembler-times "CoreInfo entry size" 1 } } */
