[PATCH,RFC,V4 6/8] readelf/objdump: support for CTF Frame section

Indu Bhagat indu.bhagat@oracle.com
Mon Jun 27 23:47:17 GMT 2022


[Changes from V3]
 - Add a string "[m]" to mark FDE of type
   CTF_FRAME_DESCRIPTOR_ENTRY_TYPE_ADDRMASK as shown here:

    func idx [1]: pc = 0x401030, size = 64 bytes
    STARTPC[m]        CFA       FP        RA
    0000000000000000  sp+8      u         u
    000000000000000b  sp+16     u         u

[End of changes from V3]

[Changes from V2]
 - consistent use of terminology around CTF Frame and its components.
[End of changes from V2]

[Changes from V1]
 - readelf/objdump: spit out an introduction message - "Contents of the
   CTF Frame section XX"
 - readelf/objdump: use spaces instead of tabs for alignment of the
   textual dump.
[End of changes from V1]

This patch adds support for CTF Frame in readelf and objdump.

include/ChangeLog:

	* ctf-frame-api.h (dump_ctf_frame): New function declaration.

ChangeLog:

	* binutils/Makefile.am: Add dependency on libctfframe for
	readelf and objdump.
	* binutils/Makefile.in: Regenerate.
	* binutils/doc/binutils.texi: Document --ctf-frame=[section].
	* binutils/doc/ctfframe.options.texi: New file.
	* binutils/objdump.c: Add support for CTF Frame format.
	* binutils/readelf.c: Likewise.
	* include/ctf-frame-api.h: Add new API for dumping .ctf_frame
	section.
	* libctfframe/Makefile.am: Add ctf-frame-dump.c.
	* libctfframe/Makefile.in: Regenerate.
	* libctfframe/ctf-frame-dump.c: New file.
---
 binutils/Makefile.am               |   8 +-
 binutils/Makefile.in               |   9 +-
 binutils/doc/binutils.texi         |   4 +
 binutils/doc/ctfframe.options.texi |  10 ++
 binutils/objdump.c                 |  76 ++++++++++++
 binutils/readelf.c                 |  46 ++++++++
 include/ctf-frame-api.h            |   3 +
 libctfframe/Makefile.am            |   2 +-
 libctfframe/Makefile.in            |  11 +-
 libctfframe/ctf-frame-dump.c       | 181 +++++++++++++++++++++++++++++
 10 files changed, 340 insertions(+), 10 deletions(-)
 create mode 100644 binutils/doc/ctfframe.options.texi
 create mode 100644 libctfframe/ctf-frame-dump.c

diff --git a/binutils/Makefile.am b/binutils/Makefile.am
index 17dcc27fc86..7cebe055d55 100644
--- a/binutils/Makefile.am
+++ b/binutils/Makefile.am
@@ -228,7 +228,7 @@ installcheck-local:
 # which depends on libintl, since we don't know whether LIBINTL_DEP will be
 # non-empty until configure time.  Ugh!
 size_DEPENDENCIES =      $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
-objdump_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB) $(OPCODES) $(LIBCTF) $(OBJDUMP_PRIVATE_OFILES)
+objdump_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB) $(OPCODES) $(LIBCTF) $(OBJDUMP_PRIVATE_OFILES) $(LIBCTFFRAME)
 nm_new_DEPENDENCIES =    $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 ar_DEPENDENCIES =        $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 strings_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
@@ -243,7 +243,7 @@ dlltool_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 windres_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 windmc_DEPENDENCIES =    $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 addr2line_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
-readelf_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(LIBCTF_NOBFD)
+readelf_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(LIBCTF_NOBFD) $(LIBCTFFRAME)
 elfedit_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
 dllwrap_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY)
 bfdtest1_DEPENDENCIES =  $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
@@ -258,7 +258,7 @@ objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 strings_SOURCES = strings.c $(BULIBS)
 
 readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c demanguse.c $(ELFLIBS)
-readelf_LDADD   = $(LIBCTF_NOBFD) $(LIBINTL) $(LIBIBERTY) $(ZLIB) $(DEBUGINFOD_LIBS) $(MSGPACK_LIBS)
+readelf_LDADD   = $(LIBCTF_NOBFD) $(LIBINTL) $(LIBIBERTY) $(ZLIB) $(DEBUGINFOD_LIBS) $(MSGPACK_LIBS) $(LIBCTFFRAME)
 
 elfedit_SOURCES = elfedit.c version.c $(ELFLIBS)
 elfedit_LDADD = $(LIBINTL) $(LIBIBERTY)
@@ -269,7 +269,7 @@ nm_new_SOURCES = nm.c demanguse.c $(BULIBS)
 
 objdump_SOURCES = objdump.c dwarf.c prdbg.c demanguse.c $(DEBUG_SRCS) $(BULIBS) $(ELFLIBS)
 EXTRA_objdump_SOURCES = od-xcoff.c
-objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(LIBCTF) $(BFDLIB) $(LIBIBERTY) $(LIBINTL) $(DEBUGINFOD_LIBS)
+objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(LIBCTF) $(BFDLIB) $(LIBIBERTY) $(LIBINTL) $(DEBUGINFOD_LIBS) $(LIBCTFFRAME)
 
 objdump.@OBJEXT@:objdump.c
 if am__fastdepCC
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index 2ed7f05bf37..4876b6c711b 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -618,6 +618,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -763,7 +764,7 @@ CC_FOR_TARGET = ` \
 # which depends on libintl, since we don't know whether LIBINTL_DEP will be
 # non-empty until configure time.  Ugh!
 size_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
-objdump_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB) $(OPCODES) $(LIBCTF) $(OBJDUMP_PRIVATE_OFILES)
+objdump_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB) $(OPCODES) $(LIBCTF) $(OBJDUMP_PRIVATE_OFILES) $(LIBCTFFRAME)
 nm_new_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 ar_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 strings_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
@@ -778,7 +779,7 @@ dlltool_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 windres_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 windmc_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 addr2line_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
-readelf_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(LIBCTF_NOBFD)
+readelf_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(LIBCTF_NOBFD) $(LIBCTFFRAME)
 elfedit_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
 dllwrap_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
 bfdtest1_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
@@ -788,14 +789,14 @@ size_SOURCES = size.c $(BULIBS)
 objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 strings_SOURCES = strings.c $(BULIBS)
 readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c demanguse.c $(ELFLIBS)
-readelf_LDADD = $(LIBCTF_NOBFD) $(LIBINTL) $(LIBIBERTY) $(ZLIB) $(DEBUGINFOD_LIBS) $(MSGPACK_LIBS)
+readelf_LDADD = $(LIBCTF_NOBFD) $(LIBINTL) $(LIBIBERTY) $(ZLIB) $(DEBUGINFOD_LIBS) $(MSGPACK_LIBS) $(LIBCTFFRAME)
 elfedit_SOURCES = elfedit.c version.c $(ELFLIBS)
 elfedit_LDADD = $(LIBINTL) $(LIBIBERTY)
 strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 nm_new_SOURCES = nm.c demanguse.c $(BULIBS)
 objdump_SOURCES = objdump.c dwarf.c prdbg.c demanguse.c $(DEBUG_SRCS) $(BULIBS) $(ELFLIBS)
 EXTRA_objdump_SOURCES = od-xcoff.c
-objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(LIBCTF) $(BFDLIB) $(LIBIBERTY) $(LIBINTL) $(DEBUGINFOD_LIBS)
+objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(LIBCTF) $(BFDLIB) $(LIBIBERTY) $(LIBINTL) $(DEBUGINFOD_LIBS) $(LIBCTFFRAME)
 cxxfilt_SOURCES = cxxfilt.c $(BULIBS)
 ar_SOURCES = arparse.y arlex.l ar.c not-ranlib.c arsup.c rename.c binemul.c \
 	emul_$(EMULATION).c $(BULIBS)
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 81be746a17b..19b9102e934 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -2260,6 +2260,7 @@ objdump [@option{-a}|@option{--archive-headers}]
         [@option{-wE}|@option{--dwarf=do-not-use-debuginfod}]
         [@option{-L}|@option{--process-links}]
         [@option{--ctf=}@var{section}]
+        [@option{--ctf-frame=}@var{section}]
         [@option{-G}|@option{--stabs}]
         [@option{-t}|@option{--syms}]
         [@option{-T}|@option{--dynamic-syms}]
@@ -2837,6 +2838,8 @@ Enable additional checks for consistency of Dwarf information.
 
 @include ctf.options.texi
 
+@include ctfframe.options.texi
+
 @item -G
 @itemx --stabs
 @cindex stab
@@ -4912,6 +4915,7 @@ readelf [@option{-a}|@option{--all}]
         [@option{--dwarf-depth=@var{n}}]
         [@option{--dwarf-start=@var{n}}]
         [@option{--ctf=}@var{section}]
+        [@option{--ctf-frame=}@var{section}]
         [@option{--ctf-parent=}@var{section}]
         [@option{--ctf-symbols=}@var{section}]
         [@option{--ctf-strings=}@var{section}]
diff --git a/binutils/doc/ctfframe.options.texi b/binutils/doc/ctfframe.options.texi
new file mode 100644
index 00000000000..bc74e891005
--- /dev/null
+++ b/binutils/doc/ctfframe.options.texi
@@ -0,0 +1,10 @@
+@c This file contains the entry for the --ctfframe option that is
+@c common to both readeld and objdump.
+
+@item --ctf-frame[=@var{section}]
+@cindex CTF Frame
+
+Display the contents of the specified CTF Frame section.
+
+By default, display the name of the section named @var{.ctf_frame}, which is the
+name emitted by @command{ld}.
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 67824053527..5aedce8274b 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -58,6 +58,7 @@
 #include "demanguse.h"
 #include "dwarf.h"
 #include "ctf-api.h"
+#include "ctf-frame-api.h"
 #include "getopt.h"
 #include "safe-ctype.h"
 #include "dis-asm.h"
@@ -104,6 +105,8 @@ static int dump_stab_section_info;	/* --stabs */
 static int dump_ctf_section_info;       /* --ctf */
 static char *dump_ctf_section_name;
 static char *dump_ctf_parent_name;	/* --ctf-parent */
+static int dump_ctf_frame_section_info; /* --ctf-frame */
+static char *dump_ctf_frame_section_name;
 static int do_demangle;			/* -C, --demangle */
 static bool disassemble;		/* -d */
 static bool disassemble_all;		/* -D */
@@ -306,6 +309,9 @@ usage (FILE *stream, int status)
   fprintf (stream, _("\
       --ctf[=SECTION]      Display CTF info from SECTION, (default `.ctf')\n"));
 #endif
+  fprintf (stream, _("\
+      --ctf-frame[=SECTION]\n\
+                           Display CTF info from SECTION, (default `.ctf_frame)\n"));
   fprintf (stream, _("\
   -t, --syms               Display the contents of the symbol table(s)\n"));
   fprintf (stream, _("\
@@ -450,6 +456,7 @@ enum option_values
     OPTION_CTF,
     OPTION_CTF_PARENT,
 #endif
+    OPTION_CTF_FRAME,
     OPTION_VISUALIZE_JUMPS,
     OPTION_DISASSEMBLER_COLOR
   };
@@ -464,6 +471,7 @@ static struct option long_options[]=
   {"ctf", optional_argument, NULL, OPTION_CTF},
   {"ctf-parent", required_argument, NULL, OPTION_CTF_PARENT},
 #endif
+  {"ctf-frame", optional_argument, NULL, OPTION_CTF_FRAME},
   {"debugging", no_argument, NULL, 'g'},
   {"debugging-tags", no_argument, NULL, 'e'},
   {"demangle", optional_argument, NULL, 'C'},
@@ -4593,6 +4601,66 @@ dump_ctf (bfd *abfd ATTRIBUTE_UNUSED, const char *sect_name ATTRIBUTE_UNUSED,
 	  const char *parent_name ATTRIBUTE_UNUSED) {}
 #endif
 
+static bfd_byte*
+read_section_ctf_frame (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr,
+			bfd_vma *ctf_frame_vma)
+{
+  asection *ctf_frame_sect;
+  bfd_byte *contents;
+
+  ctf_frame_sect = bfd_get_section_by_name (abfd, sect_name);
+  if (ctf_frame_sect == NULL)
+    {
+      printf (_("No %s section present\n\n"),
+	      sanitize_string (sect_name));
+      return false;
+    }
+
+  if (!bfd_malloc_and_get_section (abfd, ctf_frame_sect, &contents))
+    {
+      non_fatal (_("reading %s section of %s failed: %s"),
+		 sect_name, bfd_get_filename (abfd),
+		 bfd_errmsg (bfd_get_error ()));
+      exit_status = 1;
+      free (contents);
+      return NULL;
+    }
+
+  *size_ptr = bfd_section_size (ctf_frame_sect);
+  *ctf_frame_vma = bfd_section_vma (ctf_frame_sect);
+
+  return contents;
+}
+
+static void
+dump_section_ctf_frame (bfd *abfd ATTRIBUTE_UNUSED,
+			const char * sect_name)
+{
+  ctf_frame_decoder_ctx	  *cfd_ctx = NULL;
+  size_t cf_size;
+  bfd_byte *ctf_frame_data = NULL;
+  bfd_vma cf_vma;
+  int err = 0;
+
+  if (sect_name == NULL)
+    sect_name = ".ctf_frame";
+
+  ctf_frame_data = read_section_ctf_frame (abfd, sect_name, &cf_size, &cf_vma);
+
+  if (ctf_frame_data == NULL)
+    bfd_fatal (bfd_get_filename (abfd));
+
+  /* Decode the contents of the section.  */
+  cfd_ctx = ctf_frame_decode ((const char*)ctf_frame_data, cf_size, &err);
+  if (!cfd_ctx)
+    bfd_fatal (bfd_get_filename (abfd));
+
+  printf (_("Contents of the CTF Frame section %s:"),
+	  sanitize_string (sect_name));
+  /* Dump the contents as text.  */
+  dump_ctf_frame (cfd_ctx, cf_vma);
+}
+
 
 static void
 dump_bfd_private_header (bfd *abfd)
@@ -5346,6 +5414,8 @@ dump_bfd (bfd *abfd, bool is_mainfile)
     {
       if (dump_ctf_section_info)
 	dump_ctf (abfd, dump_ctf_section_name, dump_ctf_parent_name);
+      if (dump_ctf_frame_section_info)
+	dump_section_ctf_frame (abfd, dump_ctf_frame_section_name);
       if (dump_stab_section_info)
 	dump_stabs (abfd);
       if (dump_reloc_info && ! disassemble)
@@ -5843,6 +5913,12 @@ main (int argc, char **argv)
 	  dump_ctf_parent_name = xstrdup (optarg);
 	  break;
 #endif
+	case OPTION_CTF_FRAME:
+	  dump_ctf_frame_section_info = true;
+	  if (optarg)
+	    dump_ctf_frame_section_name = xstrdup (optarg);
+	  seenflag = true;
+	  break;
 	case 'G':
 	  dump_stab_section_info = true;
 	  seenflag = true;
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 5a60ef9dddb..c7d64542bb9 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -64,6 +64,7 @@
 #include "demanguse.h"
 #include "dwarf.h"
 #include "ctf-api.h"
+#include "ctf-frame-api.h"
 #include "demangle.h"
 
 #include "elf/common.h"
@@ -191,6 +192,7 @@ typedef struct elf_section_list
 #define STRING_DUMP     (1 << 3)	/* The -p command line switch.  */
 #define RELOC_DUMP      (1 << 4)	/* The -R command line switch.  */
 #define CTF_DUMP	(1 << 5)	/* The --ctf command line switch.  */
+#define CTF_FRAME_DUMP	(1 << 6)	/* The --ctf-frame command line switch.  */
 
 typedef unsigned char dump_type;
 
@@ -234,6 +236,7 @@ static bool do_version = false;
 static bool do_histogram = false;
 static bool do_debugging = false;
 static bool do_ctf = false;
+static bool do_ctf_frame = false;
 static bool do_arch = false;
 static bool do_notes = false;
 static bool do_archive_index = false;
@@ -5114,6 +5117,7 @@ enum long_option_values
   OPTION_CTF_PARENT,
   OPTION_CTF_SYMBOLS,
   OPTION_CTF_STRINGS,
+  OPTION_CTF_FRAME_DUMP,
   OPTION_WITH_SYMBOL_VERSIONS,
   OPTION_RECURSE_LIMIT,
   OPTION_NO_RECURSE_LIMIT,
@@ -5176,6 +5180,7 @@ static struct option options[] =
   {"ctf-strings",      required_argument, 0, OPTION_CTF_STRINGS},
   {"ctf-parent",       required_argument, 0, OPTION_CTF_PARENT},
 #endif
+  {"ctf-frame",	       required_argument, 0, OPTION_CTF_FRAME_DUMP},
   {"sym-base",	       optional_argument, 0, OPTION_SYM_BASE},
 
   {0,		       no_argument, 0, 0}
@@ -5316,6 +5321,8 @@ usage (FILE * stream)
   --ctf-strings=<number|name>\n\
                          Use section <number|name> as the CTF external strtab\n"));
 #endif
+  fprintf (stream, _("\
+  --ctf-frame=<name>     Display CTF Frame info from section name\n"));
 
 #ifdef SUPPORT_DISASSEMBLY
   fprintf (stream, _("\
@@ -5589,6 +5596,10 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
 	  free (dump_ctf_parent_name);
 	  dump_ctf_parent_name = strdup (optarg);
 	  break;
+	case OPTION_CTF_FRAME_DUMP:
+	  do_ctf_frame = true;
+	  request_dump (dumpdata, CTF_FRAME_DUMP);
+	  break;
 	case OPTION_DYN_SYMS:
 	  do_dyn_syms = true;
 	  break;
@@ -15826,6 +15837,36 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
 }
 #endif
 
+static bool
+dump_section_as_ctf_frame (Elf_Internal_Shdr * section, Filedata * filedata)
+{
+  void *		  data = NULL;
+  ctf_frame_decoder_ctx	  *cfd_ctx = NULL;
+  const char *print_name = printable_section_name (filedata, section);
+
+  bool ret = true;
+  size_t cf_size;
+  int err = 0;
+
+  data = get_section_contents (section, filedata);
+  cf_size = section->sh_size;
+  /* Decode the contents of the section.  */
+  cfd_ctx = ctf_frame_decode ((const char*)data, cf_size, &err);
+  if (!cfd_ctx)
+    {
+      ret = false;
+      goto fail;
+    }
+
+  printf (_("Contents of the CTF Frame section %s:"), print_name);
+  /* Dump the contents as text.  */
+  dump_ctf_frame (cfd_ctx, section->sh_addr);
+
+ fail:
+  free (data);
+  return ret;
+}
+
 static bool
 load_specific_debug_section (enum dwarf_section_display_enum  debug,
 			     const Elf_Internal_Shdr *        sec,
@@ -16325,6 +16366,11 @@ process_section_contents (Filedata * filedata)
 	    res = false;
 	}
 #endif
+      if (dump & CTF_FRAME_DUMP)
+	{
+	  if (! dump_section_as_ctf_frame (section, filedata))
+	    res = false;
+	}
     }
 
   if (! filedata->is_separate)
diff --git a/include/ctf-frame-api.h b/include/ctf-frame-api.h
index c3a39ac0317..ceda5ca1ea6 100644
--- a/include/ctf-frame-api.h
+++ b/include/ctf-frame-api.h
@@ -144,6 +144,9 @@ ctf_frame_decoder_get_funcdesc (ctf_frame_decoder_ctx *ctx,
 				int32_t *func_start_address,
 				unsigned char *func_info);
 
+/* CTF Frame textual dump.  */
+extern void
+dump_ctf_frame (ctf_frame_decoder_ctx *decoder, uint64_t addr);
 
 /* Get the base reg id from the FRE info.  Sets errp if fails.  */
 extern unsigned int
diff --git a/libctfframe/Makefile.am b/libctfframe/Makefile.am
index bb82f34d2d4..712b5b8e773 100644
--- a/libctfframe/Makefile.am
+++ b/libctfframe/Makefile.am
@@ -35,7 +35,7 @@ include_HEADERS =
 noinst_LTLIBRARIES = libctfframe.la
 endif
 
-libctfframe_la_SOURCES = ctf-frame.c ctf-frame-error.c
+libctfframe_la_SOURCES = ctf-frame.c ctf-frame-dump.c ctf-frame-error.c
 libctfframe_la_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include \
                           -I$(srcdir)/../libctf
 
diff --git a/libctfframe/Makefile.in b/libctfframe/Makefile.in
index 3814dbb4d47..2fe55ad39d4 100644
--- a/libctfframe/Makefile.in
+++ b/libctfframe/Makefile.in
@@ -161,6 +161,7 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
 LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
 libctfframe_la_LIBADD =
 am_libctfframe_la_OBJECTS = libctfframe_la-ctf-frame.lo \
+	libctfframe_la-ctf-frame-dump.lo \
 	libctfframe_la-ctf-frame-error.lo
 libctfframe_la_OBJECTS = $(am_libctfframe_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -391,7 +392,7 @@ AM_CFLAGS = -std=gnu99 @ac_libctfframe_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANT
 @INSTALL_LIBBFD_FALSE@include_HEADERS = 
 @INSTALL_LIBBFD_TRUE@include_HEADERS = $(INCDIR)/ctf-frame.h $(INCDIR)/ctf-frame-api.h
 @INSTALL_LIBBFD_FALSE@noinst_LTLIBRARIES = libctfframe.la
-libctfframe_la_SOURCES = ctf-frame.c ctf-frame-error.c
+libctfframe_la_SOURCES = ctf-frame.c ctf-frame-dump.c ctf-frame-error.c
 libctfframe_la_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include \
                           -I$(srcdir)/../libctf
 
@@ -524,6 +525,7 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctfframe_la-ctf-frame-dump.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctfframe_la-ctf-frame-error.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctfframe_la-ctf-frame.Plo@am__quote@
 
@@ -555,6 +557,13 @@ libctfframe_la-ctf-frame.lo: ctf-frame.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctfframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libctfframe_la-ctf-frame.lo `test -f 'ctf-frame.c' || echo '$(srcdir)/'`ctf-frame.c
 
+libctfframe_la-ctf-frame-dump.lo: ctf-frame-dump.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctfframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libctfframe_la-ctf-frame-dump.lo -MD -MP -MF $(DEPDIR)/libctfframe_la-ctf-frame-dump.Tpo -c -o libctfframe_la-ctf-frame-dump.lo `test -f 'ctf-frame-dump.c' || echo '$(srcdir)/'`ctf-frame-dump.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libctfframe_la-ctf-frame-dump.Tpo $(DEPDIR)/libctfframe_la-ctf-frame-dump.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ctf-frame-dump.c' object='libctfframe_la-ctf-frame-dump.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctfframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libctfframe_la-ctf-frame-dump.lo `test -f 'ctf-frame-dump.c' || echo '$(srcdir)/'`ctf-frame-dump.c
+
 libctfframe_la-ctf-frame-error.lo: ctf-frame-error.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctfframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libctfframe_la-ctf-frame-error.lo -MD -MP -MF $(DEPDIR)/libctfframe_la-ctf-frame-error.Tpo -c -o libctfframe_la-ctf-frame-error.lo `test -f 'ctf-frame-error.c' || echo '$(srcdir)/'`ctf-frame-error.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libctfframe_la-ctf-frame-error.Tpo $(DEPDIR)/libctfframe_la-ctf-frame-error.Plo
diff --git a/libctfframe/ctf-frame-dump.c b/libctfframe/ctf-frame-dump.c
new file mode 100644
index 00000000000..e6db7186cf0
--- /dev/null
+++ b/libctfframe/ctf-frame-dump.c
@@ -0,0 +1,181 @@
+/* ctf-frame-dump.c - Textual dump of .ctf_frame.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   his file is part of libctfframe.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "ctf-frame-impl.h"
+
+#define CTF_FRAME_HEADER_FLAGS_STR_MAX_LEN 50
+
+static void
+dump_ctf_frame_header (ctf_frame_decoder_ctx *cfd_ctx)
+{
+  const char *verstr = NULL;
+  const ctf_frame_header *header = &(cfd_ctx->cfd_header);
+
+  /* Prepare CTF Frame section version string.  */
+  const char *version_names[]
+    = { "NULL",
+	"CTF_FRAME_VERSION_1" };
+  unsigned char ver = header->cth_frame_preamble.ctfp_version;
+  if (ver <= CTF_FRAME_VERSION)
+    verstr = version_names[ver];
+
+  /* Prepare CTF Frame section flags string.  */
+  unsigned char flags = header->cth_frame_preamble.ctfp_flags;
+  char *flags_str 
+    = (char*) calloc (sizeof (char), CTF_FRAME_HEADER_FLAGS_STR_MAX_LEN);
+  if (flags)
+    {
+      const char *flag_names[]
+	= { "CTF_FRAME_F_FDE_SORTED",
+	    "CTF_FRAME_F_FRAME_POINTER" };
+      unsigned char flags = header->cth_frame_preamble.ctfp_flags;
+      if (flags & CTF_FRAME_F_FDE_SORTED)
+	strcpy (flags_str, flag_names[0]);
+      if (flags & CTF_FRAME_F_FRAME_POINTER)
+	{
+	  if (strlen (flags_str) > 0)
+	    strcpy (flags_str, ",");
+	  strcpy (flags_str, flag_names[1]);
+	}
+    }
+  else
+    strcpy (flags_str, "NONE");
+
+  const char* subsec_name = "Header";
+  printf ("\n");
+  printf ("  %s :\n", subsec_name);
+  printf ("\n");
+  printf ("    Version: %s\n", verstr);
+  printf ("    Flags: %s\n", flags_str);
+  printf ("    Num FDEs: %d\n", header->cth_num_fdes);
+  printf ("    Num FREs: %d\n", header->cth_num_fres);
+
+  free (flags_str);
+}
+
+static void
+dump_ctf_frame_func_with_fres (ctf_frame_decoder_ctx *cfd_ctx,
+			       unsigned int funcidx,
+			       uint64_t sec_addr)
+{
+  uint32_t j = 0;
+  uint32_t num_fres = 0;
+  uint32_t func_size = 0;
+  int32_t func_start_address = 0;
+  unsigned char func_info = 0;
+
+  uint64_t func_start_pc_vma = 0;
+  uint64_t fre_start_pc_vma = 0;
+  const char *base_reg_str[] = {"fp", "sp"};
+  int32_t cfa_offset = 0;
+  int32_t fp_offset = 0;
+  int32_t ra_offset = 0;
+  unsigned int base_reg_id = 0;
+  int err[3] = {0, 0, 0};
+
+  ctf_frame_row_entry fre;
+
+  /* Get the CTF Frame function descriptor.  */
+  ctf_frame_decoder_get_funcdesc (cfd_ctx, funcidx, &num_fres,
+				  &func_size, &func_start_address, &func_info);
+  ctf_frame_assert (func_info);
+  /* Calculate the virtual memory address for function start pc.  */
+  func_start_pc_vma = func_start_address + sec_addr;
+
+  /* Mark FDEs with [m] where the FRE start address is interpreted as a
+     mask.  */
+  int fde_type_addrmask_p = (CTF_FRAME_V1_FUNC_FDE_TYPE (func_info)
+			    == CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCMASK);
+  const char *fde_type_marker
+    = (fde_type_addrmask_p ? "[m]" : "   ");
+
+  printf ("\n    func idx [%d]: pc = 0x%lx, size = %d bytes",
+	  funcidx,
+	  func_start_pc_vma,
+	  func_size);
+
+  char temp[100];
+  memset (temp, 0, 100);
+
+  printf ("\n    %-7s%-8s %-10s%-10s%-10s", "STARTPC", fde_type_marker, "CFA", "FP", "RA");
+  for (j = 0; j < num_fres; j++)
+    {
+      ctf_frame_decoder_get_fre (cfd_ctx, funcidx, j, &fre);
+
+      fre_start_pc_vma = (fde_type_addrmask_p
+			  ? fre.fre_start_addr
+			  : func_start_pc_vma + fre.fre_start_addr);
+
+      /* FIXME - fixup the err caching in array.
+	 assert no error for base reg id.  */
+      base_reg_id = ctf_frame_fre_get_base_reg_id (&fre, &err[0]);
+      cfa_offset = ctf_frame_fre_get_cfa_offset (&fre, &err[0]);
+      fp_offset = ctf_frame_fre_get_fp_offset (&fre, &err[1]);
+      ra_offset = ctf_frame_fre_get_ra_offset (&fre, &err[2]);
+
+      /* Dump CFA info.  */
+      printf ("\n");
+      printf ("    %016lx", fre_start_pc_vma);
+      sprintf (temp, "%s+%d", base_reg_str[base_reg_id], cfa_offset);
+      printf ("  %-10s", temp);
+
+      /* Dump SP/FP info.  */
+      memset (temp, 0, 100);
+      if (err[1] == 0)
+	sprintf (temp, "c%+d", fp_offset);
+      else
+	strcpy (temp, "u");
+      printf ("%-10s", temp);
+
+      /* Dump RA info.  */
+      memset (temp, 0, 100);
+      if (err[2] == 0)
+	sprintf (temp, "c%+d", ra_offset);
+      else
+	strcpy (temp, "u");
+      printf ("%-10s", temp);
+    }
+}
+
+static void
+dump_ctf_frame_functions (ctf_frame_decoder_ctx *cfd_ctx, uint64_t sec_addr)
+{
+  uint32_t i;
+  uint32_t num_fdes;
+
+  const char* subsec_name = "Function Index";
+  printf ("\n  %s :\n", subsec_name);
+
+  num_fdes = ctf_frame_decoder_get_num_fidx (cfd_ctx);
+  for (i = 0; i < num_fdes; i++)
+    {
+      dump_ctf_frame_func_with_fres (cfd_ctx, i, sec_addr);
+      printf ("\n");
+    }
+}
+
+void
+dump_ctf_frame (ctf_frame_decoder_ctx *cfd_ctx, uint64_t sec_addr)
+{
+  dump_ctf_frame_header (cfd_ctx);
+  dump_ctf_frame_functions (cfd_ctx, sec_addr);
+}
-- 
2.31.1



More information about the Binutils mailing list