public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH,V6 00/10] Definition and Implementation of CTF Frame format
@ 2022-08-02  8:04 Indu Bhagat
  2022-08-02  8:04 ` [PATCH,V6 01/10] ctf-frame.h: Add CTF Frame format definition Indu Bhagat
                   ` (11 more replies)
  0 siblings, 12 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-08-02  8:04 UTC (permalink / raw)
  To: binutils; +Cc: amodra, weimin.pan, Indu Bhagat

Hi,

This is version 6 of the previously sent RFC series.

Initial (V1) posting contains necessary introductions:
https://sourceware.org/pipermail/binutils/2022-May/120731.html
V2 posting with some improvements:
https://sourceware.org/pipermail/binutils/2022-May/120899.html
V3 posting with further improvements:
https://sourceware.org/pipermail/binutils/2022-June/121245.html
V4 posting with further improvements and bugfixes:
https://sourceware.org/pipermail/binutils/2022-June/121478.html
V5 posting testsuite additions:
https://sourceware.org/pipermail/binutils/2022-July/121839.html

The commit log of each patch in the current patch series specifies the changes
from the version V5 of the respective patch.  Briefly, this patch series has
improved testsuites/infrastructure.

1. libctfframe/testsuite now uses recursive makefiles for building test programs.
2. Unwinder tests are still present in libctfframe/testsuite/libctfframe.unwind.
The code for the unwinding library for backtracing using CTF Frame (a.k.a.
libctfbacktrace) still sits in the libctfframe/ folder.

Testing notes:
- Tested natively on x86_64-linux, aarch64-linux
- Cross builds for various targets on x86_64 host.  Ran a regression script
that checks for failures in gas, ld, binutils, libctf with no reported
regressions. libctfframe tests ran as expected. libctfbacktrace/unwinder
tests (which are present in libctfframe/testsuite/libctfframe.unwind) have been
disabled when host != target.

Important note: libctfframe/configure has NOT been included in the patch
series, as it causes the size of some patches to go beyond the allowed limit.
Please regenerate the libctfframe/configure after applying the series.

Thanks,

Indu Bhagat (7):
  ctf-frame.h: Add CTF Frame format definition
  gas: add new command line option --gctf-frame
  gas: generate .ctf_frame
  libctfframe: add GNU poke pickles for CTF Frame
  bfd: linker: merge .ctf_frame sections
  readelf/objdump: support for CTF Frame section
  gdb: sim: buildsystem changes to accommodate libctfframe

Weimin Pan (3):
  libctfframe: add the CTF Frame library
  unwinder: generate backtrace using CTF Frame format
  unwinder: Add CTF Frame unwinder tests

 Makefile.def                                  |    5 +
 Makefile.in                                   | 1289 ++++++++++++-
 bfd/Makefile.am                               |    6 +-
 bfd/Makefile.in                               |    7 +-
 bfd/bfd-in2.h                                 |    1 +
 bfd/configure                                 |    2 +-
 bfd/configure.ac                              |    2 +-
 bfd/elf-bfd.h                                 |   55 +
 bfd/elf-ctf-frame.c                           |  529 ++++++
 bfd/elf.c                                     |   32 +
 bfd/elf64-x86-64.c                            |   97 +-
 bfd/elflink.c                                 |   52 +
 bfd/elfxx-x86.c                               |  379 +++-
 bfd/elfxx-x86.h                               |   46 +
 bfd/section.c                                 |    1 +
 binutils/Makefile.am                          |   10 +-
 binutils/Makefile.in                          |   10 +-
 binutils/doc/binutils.texi                    |    4 +
 binutils/doc/ctfframe.options.texi            |   10 +
 binutils/objdump.c                            |   76 +
 binutils/readelf.c                            |   47 +
 config/ctf-frame.m4                           |   16 +
 configure                                     |    2 +-
 configure.ac                                  |    2 +-
 gas/Makefile.am                               |    3 +
 gas/Makefile.in                               |   23 +-
 gas/as.c                                      |   10 +-
 gas/as.h                                      |   13 +-
 gas/config/tc-aarch64.c                       |   42 +
 gas/config/tc-aarch64.h                       |   29 +
 gas/config/tc-i386.c                          |   46 +
 gas/config/tc-i386.h                          |   26 +
 gas/config/tc-xtensa.c                        |    1 +
 gas/ctf-frame-opt.c                           |  158 ++
 gas/doc/as.texi                               |   19 +-
 gas/dw2gencfi.c                               |   30 +
 gas/dw2gencfi.h                               |    1 +
 gas/gen-ctf-frame.c                           | 1297 ++++++++++++++
 gas/gen-ctf-frame.h                           |  142 ++
 gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.d |   20 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.s |   61 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.d  |   17 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.s  |    3 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.d  |   17 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.s  |    2 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.d  |   17 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.s  |    4 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.d  |   21 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.s  |    8 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.d  |   21 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.s  |    7 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.d  |   21 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.s  |    7 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.d  |   21 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.s  |    7 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.d  |   20 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.s  |   12 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.d  |   22 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.s  |   30 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf.exp         |   58 +
 gas/testsuite/gas/cfi-ctf/common-empty-1.d    |   14 +
 gas/testsuite/gas/cfi-ctf/common-empty-1.s    |    5 +
 gas/testsuite/gas/cfi-ctf/common-empty-2.d    |   14 +
 gas/testsuite/gas/cfi-ctf/common-empty-2.s    |    8 +
 gas/testsuite/gas/cfi-ctf/common-empty-3.d    |   14 +
 gas/testsuite/gas/cfi-ctf/common-empty-3.s    |    9 +
 gas/testsuite/gas/cfi-ctf/common-empty-4.d    |   14 +
 gas/testsuite/gas/cfi-ctf/common-empty-4.s    |   18 +
 gas/write.c                                   |   13 +
 gdb/Makefile.in                               |    8 +-
 gdb/acinclude.m4                              |    4 +-
 gdb/configure                                 |   35 +-
 gdb/configure.ac                              |   11 +
 include/ctf-backtrace-api.h                   |   57 +
 include/ctf-frame-api.h                       |  213 +++
 include/ctf-frame.h                           |  281 +++
 include/elf/common.h                          |    1 +
 include/elf/internal.h                        |    1 +
 ld/Makefile.am                                |    2 +
 ld/Makefile.in                                |    2 +
 ld/configure                                  |    8 +-
 ld/configure.ac                               |    3 +
 ld/ld.texi                                    |    4 +-
 ld/scripttempl/elf.sc                         |    2 +
 ld/testsuite/ld-aarch64/aarch64-elf.exp       |    2 +
 ld/testsuite/ld-aarch64/ctf-frame-bar.s       |    7 +
 ld/testsuite/ld-aarch64/ctf-frame-foo.s       |   10 +
 ld/testsuite/ld-aarch64/ctf-frame-simple-1.d  |   26 +
 ld/testsuite/ld-bootstrap/bootstrap.exp       |    8 +-
 ld/testsuite/ld-ctf-frame/ctf-frame-empty.d   |   10 +
 ld/testsuite/ld-ctf-frame/ctf-frame-empty.s   |    2 +
 ld/testsuite/ld-ctf-frame/ctf-frame.exp       |   47 +
 ld/testsuite/ld-ctf-frame/discard.d           |   10 +
 ld/testsuite/ld-ctf-frame/discard.ld          |    9 +
 ld/testsuite/ld-ctf-frame/discard.s           |   13 +
 ld/testsuite/ld-x86-64/ctf-frame-bar.s        |   31 +
 ld/testsuite/ld-x86-64/ctf-frame-foo.s        |   37 +
 ld/testsuite/ld-x86-64/ctf-frame-plt-1.d      |   29 +
 ld/testsuite/ld-x86-64/ctf-frame-simple-1.d   |   35 +
 ld/testsuite/ld-x86-64/x86-64.exp             |    2 +
 ld/testsuite/lib/ld-lib.exp                   |   45 +
 libctfframe/Makefile.am                       |   52 +
 libctfframe/Makefile.in                       | 1099 ++++++++++++
 libctfframe/aclocal.m4                        | 1242 +++++++++++++
 libctfframe/config.h.in                       |  144 ++
 libctfframe/configure.ac                      |   97 +
 libctfframe/ctf-backtrace-err.c               |   46 +
 libctfframe/ctf-backtrace.c                   |  619 +++++++
 libctfframe/ctf-frame-dump.c                  |  181 ++
 libctfframe/ctf-frame-dump.pk                 |   68 +
 libctfframe/ctf-frame-error.c                 |   49 +
 libctfframe/ctf-frame-impl.h                  |   55 +
 libctfframe/ctf-frame.c                       | 1587 +++++++++++++++++
 libctfframe/ctf-frame.pk                      |  200 +++
 libctfframe/testsuite/Makefile.am             |   23 +
 libctfframe/testsuite/Makefile.in             |  684 +++++++
 libctfframe/testsuite/config/default.exp      |   57 +
 libctfframe/testsuite/lib/ctfframe-lib.exp    |  180 ++
 .../testsuite/libctfframe.decode/DATA1        |  Bin 0 -> 59 bytes
 .../testsuite/libctfframe.decode/DATA2        |  Bin 0 -> 91 bytes
 .../testsuite/libctfframe.decode/DATA_BIGE    |  Bin 0 -> 59 bytes
 .../testsuite/libctfframe.decode/Makefile.am  |   14 +
 .../testsuite/libctfframe.decode/Makefile.in  |  663 +++++++
 .../libctfframe.decode/bigendian_data.c       |  107 ++
 .../testsuite/libctfframe.decode/decode.exp   |   41 +
 .../testsuite/libctfframe.decode/frecnt_1.c   |   99 +
 .../testsuite/libctfframe.decode/frecnt_2.c   |  103 ++
 .../testsuite/libctfframe.encode/Makefile.am  |    6 +
 .../testsuite/libctfframe.encode/Makefile.in  |  610 +++++++
 .../testsuite/libctfframe.encode/encode.exp   |   25 +
 .../testsuite/libctfframe.encode/encode_1.c   |  182 ++
 .../testsuite/libctfframe.unwind/backtrace.c  |  145 ++
 .../testsuite/libctfframe.unwind/backtrace.lk |    3 +
 .../libctfframe.unwind/inline-cmds.c          |  135 ++
 .../libctfframe.unwind/inline-cmds.lk         |    3 +
 .../testsuite/libctfframe.unwind/inline.c     |   97 +
 .../testsuite/libctfframe.unwind/inline.lk    |    3 +
 .../testsuite/libctfframe.unwind/solib-lib1.c |    8 +
 .../testsuite/libctfframe.unwind/solib-lib2.c |   51 +
 .../testsuite/libctfframe.unwind/solib-main.c |   47 +
 .../testsuite/libctfframe.unwind/solib-main.d |    3 +
 .../testsuite/libctfframe.unwind/solib.exp    |   75 +
 .../testsuite/libctfframe.unwind/solib_lib1.h |    3 +
 .../testsuite/libctfframe.unwind/solib_lib2.h |    3 +
 .../testsuite/libctfframe.unwind/tailcall.c   |  103 ++
 .../testsuite/libctfframe.unwind/tailcall.lk  |    3 +
 .../testsuite/libctfframe.unwind/ttest.c      |  127 ++
 .../testsuite/libctfframe.unwind/ttest.lk     |    3 +
 .../testsuite/libctfframe.unwind/unwind.exp   |  200 +++
 libctfframe/ttest.c                           |   78 +
 sim/common/Make-common.in                     |    7 +-
 151 files changed, 15252 insertions(+), 58 deletions(-)
 create mode 100644 bfd/elf-ctf-frame.c
 create mode 100644 binutils/doc/ctfframe.options.texi
 create mode 100644 config/ctf-frame.m4
 create mode 100644 gas/ctf-frame-opt.c
 create mode 100644 gas/gen-ctf-frame.c
 create mode 100644 gas/gen-ctf-frame.h
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf.exp
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-1.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-1.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-2.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-2.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-3.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-3.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-4.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-4.s
 create mode 100644 include/ctf-backtrace-api.h
 create mode 100644 include/ctf-frame-api.h
 create mode 100644 include/ctf-frame.h
 create mode 100644 ld/testsuite/ld-aarch64/ctf-frame-bar.s
 create mode 100644 ld/testsuite/ld-aarch64/ctf-frame-foo.s
 create mode 100644 ld/testsuite/ld-aarch64/ctf-frame-simple-1.d
 create mode 100644 ld/testsuite/ld-ctf-frame/ctf-frame-empty.d
 create mode 100644 ld/testsuite/ld-ctf-frame/ctf-frame-empty.s
 create mode 100644 ld/testsuite/ld-ctf-frame/ctf-frame.exp
 create mode 100644 ld/testsuite/ld-ctf-frame/discard.d
 create mode 100644 ld/testsuite/ld-ctf-frame/discard.ld
 create mode 100644 ld/testsuite/ld-ctf-frame/discard.s
 create mode 100644 ld/testsuite/ld-x86-64/ctf-frame-bar.s
 create mode 100644 ld/testsuite/ld-x86-64/ctf-frame-foo.s
 create mode 100644 ld/testsuite/ld-x86-64/ctf-frame-plt-1.d
 create mode 100644 ld/testsuite/ld-x86-64/ctf-frame-simple-1.d
 create mode 100644 libctfframe/Makefile.am
 create mode 100644 libctfframe/Makefile.in
 create mode 100644 libctfframe/aclocal.m4
 create mode 100644 libctfframe/config.h.in
 create mode 100644 libctfframe/configure.ac
 create mode 100644 libctfframe/ctf-backtrace-err.c
 create mode 100644 libctfframe/ctf-backtrace.c
 create mode 100644 libctfframe/ctf-frame-dump.c
 create mode 100644 libctfframe/ctf-frame-dump.pk
 create mode 100644 libctfframe/ctf-frame-error.c
 create mode 100644 libctfframe/ctf-frame-impl.h
 create mode 100644 libctfframe/ctf-frame.c
 create mode 100644 libctfframe/ctf-frame.pk
 create mode 100644 libctfframe/testsuite/Makefile.am
 create mode 100644 libctfframe/testsuite/Makefile.in
 create mode 100644 libctfframe/testsuite/config/default.exp
 create mode 100644 libctfframe/testsuite/lib/ctfframe-lib.exp
 create mode 100644 libctfframe/testsuite/libctfframe.decode/DATA1
 create mode 100644 libctfframe/testsuite/libctfframe.decode/DATA2
 create mode 100644 libctfframe/testsuite/libctfframe.decode/DATA_BIGE
 create mode 100644 libctfframe/testsuite/libctfframe.decode/Makefile.am
 create mode 100644 libctfframe/testsuite/libctfframe.decode/Makefile.in
 create mode 100644 libctfframe/testsuite/libctfframe.decode/bigendian_data.c
 create mode 100644 libctfframe/testsuite/libctfframe.decode/decode.exp
 create mode 100644 libctfframe/testsuite/libctfframe.decode/frecnt_1.c
 create mode 100644 libctfframe/testsuite/libctfframe.decode/frecnt_2.c
 create mode 100644 libctfframe/testsuite/libctfframe.encode/Makefile.am
 create mode 100644 libctfframe/testsuite/libctfframe.encode/Makefile.in
 create mode 100644 libctfframe/testsuite/libctfframe.encode/encode.exp
 create mode 100644 libctfframe/testsuite/libctfframe.encode/encode_1.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/backtrace.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/backtrace.lk
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/inline-cmds.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/inline-cmds.lk
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/inline.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/inline.lk
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib-lib1.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib-lib2.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib-main.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib-main.d
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib.exp
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib_lib1.h
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib_lib2.h
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/tailcall.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/tailcall.lk
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/ttest.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/ttest.lk
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/unwind.exp
 create mode 100644 libctfframe/ttest.c

-- 
2.37.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V6 01/10] ctf-frame.h: Add CTF Frame format definition
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
@ 2022-08-02  8:04 ` Indu Bhagat
  2022-08-15 12:04   ` Nick Clifton
  2022-08-02  8:04 ` [PATCH,V6 02/10] gas: add new command line option --gctf-frame Indu Bhagat
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-08-02  8:04 UTC (permalink / raw)
  To: binutils; +Cc: amodra, weimin.pan, Indu Bhagat

[Changes from V5]
 - Fix minor typos.
[End of changes from V5]

[Changes from V4]
 - Fix minor typos.
[End of changes from V4]

[Changes from V3]
  - CTF Format differentiates between the two possible FDE types using a
    bit in the fde_func_info byte - CTF_FRAME_DESCRIPTOR_ENTRY_TYPE_ADDRINC
    or CTF_FRAME_DESCRIPTOR_ENTRY_TYPE_ADDRMASK.
    The new CTF FDE type (CTF_FRAME_DESCRIPTOR_ENTRY_TYPE_ADDRMASK) is ideal
    for representing unwind information for regular, repetitive instruction
    patterns like plt entries.
[End of changes from V3]

[Changes from V2]
  - Consistent use of terminology.
[End of changes from V2]

[Changes from V1]
  - Make use of uint8_t, uint16_t consistently.  Removed the usage of
    unsigned char, unsigned short.
[End of changes from V1]

The header ctf-frame.h defines the CTF Frame format.

The CTF Frame format is a simple, compact format for representing
unwind information.  This information can be used for generating
backtraces.  The current version supports AMD64 and AARCH64.

More details of the CTF Frame format are included in the documentation
of the header file in this patch.

include/ChangeLog:
	* ctf-frame.h: New file.
---
 include/ctf-frame.h | 281 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 281 insertions(+)
 create mode 100644 include/ctf-frame.h

diff --git a/include/ctf-frame.h b/include/ctf-frame.h
new file mode 100644
index 00000000000..fc46b8a06d1
--- /dev/null
+++ b/include/ctf-frame.h
@@ -0,0 +1,281 @@
+/* CTF Frame format description.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of libctfframe.
+
+   libctfframe 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, 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_CTF_FRAME_H
+#define	_CTF_FRAME_H
+
+#include <sys/types.h>
+#include <limits.h>
+#include <stdint.h>
+
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+/* CTF Frame format.
+
+   CTF Frame format can be used to compactly represent the information needed
+   for virtual stack unwinding.  CTF Frame format keeps track of the minimal
+   necessary information needed for stack unwinding:
+     - Canonical Frame Address (CFA)
+     - Frame Pointer (FP)
+     - Return Address (RA)
+
+   The CTF Frame section itself has the following structure:
+
+       +--------+------------+---------+
+       |  file  |  function  | frame   |
+       | header | descriptor |  row    |
+       |        |   entries  | entries |
+       +--------+------------+---------+
+
+   The file header stores a magic number and version information, flags, and
+   the byte offset of each of the sections relative to the end of the header
+   itself.  The file header also specifies the total number of Function
+   Descriptor Entries, Frame Row Entries and length of the FRE sub-section.
+
+   Following the header is a list of Function Descriptor Entries (FDEs).
+   This list may be sorted if the flags in the file header indicate it to be
+   so.  The sort order, if applicable, is the order of functions in the
+   .text.* sections in the resulting binary artifact.  Each Function
+   Descriptor Entry specifies the start PC of a function, the size in bytes
+   of the function and an offset to its first Frame Row Entry (FRE).  Each FDE
+   additionally also specifies the type of FRE it uses to encode the unwind
+   information.
+
+   Next, the Frame Row Entry section is a list of variable size records,
+   each of which represent CTF Frame unwind information for a set of PCs.  A
+   singular Frame Row Entry is a self-sufficient record with information on
+   how to virtually unwind the stack for the applicable set of PCs.
+
+   */
+
+
+/* CTF Frame format versions.  */
+#define CTF_FRAME_VERSION_1	1
+/* CTF Frame magic number.  */
+#define CTF_FRAME_MAGIC		0xdee2
+/* Current version of CTF Frame format.  */
+#define CTF_FRAME_VERSION	CTF_FRAME_VERSION_1
+
+/* Various flags for CTF Frame.  */
+
+/* Function Descriptor Entries are sorted on PC.  */
+#define CTF_FRAME_F_FDE_SORTED	0x1
+/* Frame-pointer based unwinding.  */
+#define CTF_FRAME_F_FRAME_POINTER 0x2
+
+#define CTF_FRAME_CFA_FIXED_FP_INVALID 0
+#define CTF_FRAME_CFA_FIXED_RA_INVALID 0
+
+/* Supported ABIs/Arch.  */
+#define CTF_FRAME_ABI_AARCH64_ENDIAN_BIG      1 /* AARCH64 big endian.  */
+#define CTF_FRAME_ABI_AARCH64_ENDIAN_LITTLE   2 /* AARCH64 little endian.  */
+#define CTF_FRAME_ABI_AMD64_ENDIAN_LITTLE     3 /* AMD64 little endian.  */
+
+/* CTF Frame FRE types.  */
+#define CTF_FRAME_ROW_ENTRY_TYPE_ADDR1  1
+#define CTF_FRAME_ROW_ENTRY_TYPE_ADDR2  2
+#define CTF_FRAME_ROW_ENTRY_TYPE_ADDR4	3
+
+/* CTF Frame Function Descriptor Entry types.
+
+   The CTF Frame format has two possible representations for functions.  The
+   choice of which type to use is made according to the instruction patterns
+   in the relevant program stub.
+
+   A CTF FDE of type CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCINC is an indication
+   that the PCs in the FREs should be treated as increments in bytes.  This is
+   used for a bulk of the executable code of a program, which contains
+   instructions with no specific pattern.
+
+   A CTF FDE of type CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCMASK is an indication
+   that the PCs in the FREs should be treated as masks.  This type is useful
+   for the cases when a small pattern of instructions in a program stub is
+   repeatedly to cover a specific functionality.  Typical usescases are pltN
+   entries, trampolines etc.  */
+
+/* Unwinders perform a (PC >= FRE_START_ADDR) to look up a matching FRE.  */
+#define CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCINC   0
+/* Unwinders perform a (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK)
+   to look up a matching FRE.  */
+#define CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCMASK  1
+
+typedef struct ctf_frame_preamble
+{
+  uint16_t ctfp_magic;	/* Magic number (CTF_FRAME_MAGIC).  */
+  uint8_t ctfp_version;	/* Data format version number (CTF_FRAME_VERSION).  */
+  uint8_t ctfp_flags;	/* Flags.  */
+} __attribute__ ((packed)) ctf_frame_preamble;
+
+typedef struct ctf_frame_header
+{
+  ctf_frame_preamble cth_frame_preamble;
+  /* Information about the arch (endianness) and ABI.  */
+  uint8_t cth_frame_abi_arch;
+  /* Offset for the Frame Pointer (FP) from CFA may be fixed for some
+     ABIs (e.g, in AMD64 when -fno-omit-frame-pointer is used).  When fixed,
+     this field specifies the fixed stack frame offset and the individual
+     FREs do not need to track it.  When not fixed, it is set to
+     CTF_FRAME_CFA_FIXED_FP_INVALID, and the individual FREs may provide
+     the applicable stack frame offset, if any.  */
+  int8_t cth_cfa_fixed_fp_offset;
+  /* Offset for the Return Address from CFA is fixed for some ABIs
+     (e.g., AMD64 has it as CFA-8).  When fixed, the header specifies the
+     fixed stack frame offset and the individual FREs do not track it.  When
+     not fixed, it is set to CTF_FRAME_CFA_FIXED_RA_INVALID, and individual
+     FREs provide the applicable stack frame offset, if any.  */
+  int8_t cth_cfa_fixed_ra_offset;
+  /* Number of CTF FDEs in this CTF Frame section.  May be useful for
+     debugging.  */
+  uint32_t cth_num_fdes;
+  /* Number of CTF Frame row entries.  */
+  uint32_t cth_num_fres;
+  /* Number of bytes in the CTF Frame Row Entry section. */
+  uint32_t cth_fre_len;
+  /* Offset of CTF function descriptor entry section.  */
+  uint32_t cth_fdeoff;
+  /* Offset of CTF Frame Row Entry section.  */
+  uint32_t cth_freoff;
+} __attribute__ ((packed)) ctf_frame_header;
+
+typedef struct ctf_frame_func_desc_entry
+{
+  /* Function start address.  Encoded as a signed offset, relative to the
+     beginning of the current FDE.  */
+  int32_t ctf_func_start_address;
+  /* Size of the function in bytes.  */
+  uint32_t ctf_func_size;
+  /* Offset of the first CTF Frame Row Entry of the function, relative to the
+     beginning of the CTF Frame Row Entry sub-section.  */
+  uint32_t ctf_func_start_fre_off;
+  /* Number of frame row entries for the function.  */
+  uint32_t ctf_func_num_fres;
+  /* Additional information for deciphering the unwind information for the
+     function.
+     - 4-bits: Identify the FRE type used for the function.
+     - 1-bit: Identify the FDE type of the function - mask or inc.
+     - 3-bits: Unused.
+     --------------------------------------------
+     |     Unused    |  FDE type |   FRE type   |
+     --------------------------------------------
+     8               5           4              0     */
+  uint8_t ctf_func_info;
+} __attribute__ ((packed)) ctf_frame_func_desc_entry;
+
+/* Macros to compose and decompose function info in FDE.  */
+
+#define CTF_FRAME_V1_FUNC_INFO(fde_type, fre_enc_type) \
+  (((fde_type) & 0x1) << 4 | (fre_enc_type))
+
+#define CTF_FRAME_V1_FUNC_FRE_TYPE(data)	  ((data) & 0xf)
+#define CTF_FRAME_V1_FUNC_FDE_TYPE(data)	  ((data >> 4) & 0x1)
+
+/* Size of stack frame offsets in a CTF Frame Row Entry.  A single CTF Frame
+   row entry has all offsets of the same size.  Offset size may vary across
+   frame row entries.  */
+#define CTF_FRAME_FRE_OFFSET_1B	  0
+#define CTF_FRAME_FRE_OFFSET_2B	  1
+#define CTF_FRAME_FRE_OFFSET_4B	  2
+
+/* A CTF Frame Row Entry can be SP or FP based.  */
+#define CTF_FRAME_BASE_REG_FP	0
+#define CTF_FRAME_BASE_REG_SP	1
+
+/* The index at which a specific offset is presented in the variable length
+   bytes of an FRE.  */
+#define CTF_FRAME_FRE_CFA_OFFSET_IDX  0
+#define CTF_FRAME_FRE_FP_OFFSET_IDX   1
+#define CTF_FRAME_FRE_RA_OFFSET_IDX   2
+
+typedef struct ctf_frame_fre_info
+{
+  /* Information about
+     - 1 bit: base reg for CFA
+     - 4 bits: Number of offsets (N).  A value of upto 3 is allowed to track
+     all three of CFA, FP and RA (fixed implicit order).
+     - 2 bits: information about size of the offsets (S) in bytes.
+     Valid values are CTF_FRAME_FRE_OFFSET_1B, CTF_FRAME_FRE_OFFSET_2B,
+     CTF_FRAME_FRE_OFFSET_4B
+     - 1 bit: Unused.
+     -----------------------------------------------------------------------
+     |  Unused  |  Size of offsets   |   Number of offsets    |   base_reg |
+     -----------------------------------------------------------------------
+     8          7                    5                        1            0
+
+     */
+  uint8_t fre_info;
+} ctf_frame_fre_info;
+
+/* Macros to compose and decompose FRE info.  */
+
+#define CTF_FRAME_V1_FRE_INFO(base_reg_id, offset_num, offset_size) \
+  ((offset_size << 5) | (offset_num << 1) | (base_reg_id))
+
+#define CTF_FRAME_V1_FRE_CFA_BASE_REG_ID(data)	  ((data) & 0x1)
+#define CTF_FRAME_V1_FRE_OFFSET_COUNT(data)	  (((data) >> 1) & 0xf)
+#define CTF_FRAME_V1_FRE_OFFSET_SIZE(data)	  (((data) >> 5) & 0x3)
+
+/* CTF Frame Row Entry definitions.
+
+   Used for both AMD64 and AARCH64.
+
+   A CTF Frame Row Entry is a self-sufficient record containing CTF Frame
+   unwind info for a range of addresses, starting at the specified offset in
+   the function.  Each CTF Frame Row Entry is followed by S*N bytes, where:
+     S is the size of the stack frame offset for the FRE, and
+     N is the number of stack frame offsets in the FRE
+
+   The offsets are interpreted in order as follows:
+   offset1 (interpreted as CFA = BASE_REG + offset1)
+   offset2 (interpreted as FP = CFA + offset2)
+   offset3 (interpreted as RA = CFA + offset3)
+*/
+
+typedef struct ctf_frame_row_entry_addr1
+{
+  /* Start address of the frame row entry.  Encoded as an 1-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint8_t ctf_fre_start_address;
+  ctf_frame_fre_info ctf_fre_info;
+} __attribute__ ((packed)) ctf_frame_row_entry_addr1;
+
+typedef struct ctf_frame_row_entry_addr2
+{
+  /* Start address of the frame row entry.  Encoded as an 2-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint16_t ctf_fre_start_address;
+  ctf_frame_fre_info ctf_fre_info;
+} __attribute__ ((packed)) ctf_frame_row_entry_addr2;
+
+typedef struct ctf_frame_row_entry_addr4
+{
+  /* Start address of the frame row entry.  Encoded as a 4-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint32_t ctf_fre_start_address;
+  ctf_frame_fre_info ctf_fre_info;
+} __attribute__ ((packed)) ctf_frame_row_entry_addr4;
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _CTF_FRAME_H */
-- 
2.37.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V6 02/10] gas: add new command line option --gctf-frame
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
  2022-08-02  8:04 ` [PATCH,V6 01/10] ctf-frame.h: Add CTF Frame format definition Indu Bhagat
@ 2022-08-02  8:04 ` Indu Bhagat
  2022-08-15 12:07   ` Nick Clifton
  2022-08-02  8:04 ` [PATCH,V6 03/10] gas: generate .ctf_frame Indu Bhagat
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-08-02  8:04 UTC (permalink / raw)
  To: binutils; +Cc: amodra, weimin.pan, Indu Bhagat

[No changes from V5, V4, V3]

When --gctf-frame is specified, the assembler will generate a .ctf_frame
section from the CFI directives in the assembly.

ChangeLog:
	* gas/as.c (parse_args): Parse args and set flag_gen_ctf_frame.
	* gas/as.h: Introduce skeleton for --gctf-frame.
	* gas/doc/as.texi: document --gctf-frame.
---
 gas/as.c        | 10 +++++++++-
 gas/as.h        |  3 +++
 gas/doc/as.texi |  5 +++++
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/gas/as.c b/gas/as.c
index 6268779cf90..cacf5d6aa48 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -318,6 +318,8 @@ Options:\n\
 #endif
   fprintf (stream, _("\
                           generate GNU Build notes if none are present in the input\n"));
+  fprintf (stream, _("\
+  --gctf-frame            generate CTF Frame unwind info\n"));
 #endif /* OBJ_ELF */
 
   fprintf (stream, _("\
@@ -491,7 +493,8 @@ parse_args (int * pargc, char *** pargv)
       OPTION_COMPRESS_DEBUG,
       OPTION_NOCOMPRESS_DEBUG,
       OPTION_NO_PAD_SECTIONS,
-      OPTION_MULTIBYTE_HANDLING  /* = STD_BASE + 40 */
+      OPTION_MULTIBYTE_HANDLING,  /* = STD_BASE + 40 */
+      OPTION_CTF_FRAME
     /* When you add options here, check that they do
        not collide with OPTION_MD_BASE.  See as.h.  */
     };
@@ -522,6 +525,7 @@ parse_args (int * pargc, char *** pargv)
     ,{"elf-stt-common", required_argument, NULL, OPTION_ELF_STT_COMMON}
     ,{"sectname-subst", no_argument, NULL, OPTION_SECTNAME_SUBST}
     ,{"generate-missing-build-notes", required_argument, NULL, OPTION_ELF_BUILD_NOTES}
+    ,{"gctf-frame", no_argument, NULL, OPTION_CTF_FRAME}
 #endif
     ,{"fatal-warnings", no_argument, NULL, OPTION_WARN_FATAL}
     ,{"gdwarf-2", no_argument, NULL, OPTION_GDWARF_2}
@@ -987,6 +991,10 @@ This program has absolutely no warranty.\n"));
 		      optarg);
 	  break;
 
+	case OPTION_CTF_FRAME:
+	  flag_gen_ctf_frame = 1;
+	  break;
+
 #endif /* OBJ_ELF */
 
 	case 'Z':
diff --git a/gas/as.h b/gas/as.h
index ff665c75812..92e039b163a 100644
--- a/gas/as.h
+++ b/gas/as.h
@@ -337,6 +337,9 @@ COMMON int flag_execstack;
 /* TRUE if .note.GNU-stack section with SEC_CODE should be created */
 COMMON int flag_noexecstack;
 
+/* TRUE if .ctf_frame section should be created.  */
+COMMON int flag_gen_ctf_frame;
+
 /* name of emitted object file */
 COMMON const char *out_file_name;
 
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index 09b0ca5f565..c74b9eee3d6 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -245,6 +245,7 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
  [@b{--sectname-subst}] [@b{--size-check=[error|warning]}]
  [@b{--elf-stt-common=[no|yes]}]
  [@b{--generate-missing-build-notes=[no|yes]}]
+ [@b{--gctf-frame}]
  [@b{--multibyte-handling=[allow|warn|warn-sym-only]}]
  [@b{--target-help}] [@var{target-options}]
  [@b{--}|@var{files} @dots{}]
@@ -825,6 +826,10 @@ attribute notes if none are present in the input sources.
 The default can be controlled by the @option{--enable-generate-build-notes}
 configure option.
 
+@item --gctf-frame
+@itemx --gctf-frame
+Create @var{.ctf_frame} section from CFI directives.
+
 @end ifset
 
 @item --help
-- 
2.37.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V6 03/10] gas: generate .ctf_frame
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
  2022-08-02  8:04 ` [PATCH,V6 01/10] ctf-frame.h: Add CTF Frame format definition Indu Bhagat
  2022-08-02  8:04 ` [PATCH,V6 02/10] gas: add new command line option --gctf-frame Indu Bhagat
@ 2022-08-02  8:04 ` Indu Bhagat
  2022-08-15 12:22   ` Nick Clifton
  2022-08-02  8:04 ` [PATCH,V6 04/10] libctfframe: add the CTF Frame library Indu Bhagat
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-08-02  8:04 UTC (permalink / raw)
  To: binutils; +Cc: amodra, weimin.pan, Indu Bhagat

[No changes from V5]

[Changes from V4]
 - bugfix: Disabling CTF_FRE_TYPE_SELECTION_OPT causes gas to crash
 - Tested various cfi_* directives in isolation and in combination with
   each other to ensure graceful handling in all scenarios.  Added
   further testcases in gas testsuite.
[End of changes from V4]

[Changes from V3]
 - Do not err out if .ctf_frame is not supported for a target, just warn
   instead.
 - Other changes around API ctf_frame_fde_func_info () as it now
   includes an fde_type along with the earlier lone argument of
   fre_type.
[End of changes from V3]

[Changes from V2]
 - consistent use of terminology.
 - updated documentation in code comments around FRE start address
   optimization (fragment fixup).  Also renamed the type rs_ctf_fre to
   rs_ctf_frame.
 - added gas testsuite.
[End of changes from V2]

[Changes from V1]
 - generate .ctf_frame if --gctf-frame is specified OR if .cfi_sections
   .ctf_frame is specified.
 - bugfix: use startswith in .cfi_sections. Earlier, strcmp was being
   used incorrectly.
 - generate .ctf_frame section even if there are no FDEs (no functions
   with unwind information).  A .ctf_frame section with no FDEs is valid.
   Such a CTF Frame section will have a valid header with other fields
   set to appropriate values.
 - Support conditional compilation on the basis of support_ctf_frame_p.
   Compile in the CTF Frame generation APIs only when the tagets support
   CTF Frame.  Currently, gas emits CTF Frame unwind information for x86_64
    and aarch64 only.
 - doc: update documentation for .cfi_sections to include .ctf_frame
   section in the list.
[End of changes from V1]

[PS: Currently, the compiler has not been adapted to generate
".cfi_sections" with ".ctf_frame" in it.  The newly added command line
option of --gctf-frame provides an easy way to try out .ctf_frame support
in the toolchain.]

gas interprets the CFI directives to generate DWARF-based .eh_frame
info.  These internal DWARF structures are now consumed by
gen-ctf-frame.[ch] sub-system to, in turn, create the CTF Frame unwind
information.  These internal DWARF structures are read-only for the
purpose of CTF Frame unwind info generation.

CTF Frame unwind info generation does not impact .eh_frame unwind info
generation.  Both .eh_frame and .ctf_frame can co-exist in an ELF file,
if so desired by the user.

Recall that CTF Frame unwind information only contains the minimal
necessary information to generate backtraces and does not provide
information to recover all callee-saved registers.  The reason being
that callee-saved registers other than FP are not needed for stack
unwinding, and hence are not included in the .ctf_frame section.

Consequently, gen-ctf-frame.[ch] only needs to interpret a subset of
DWARF opcodes in gas.  More details follow.

[Set 1, Interpreted] The following opcodes are interpreted:
- DW_CFA_advance_loc
- DW_CFA_def_cfa
- DW_CFA_def_cfa_register
- DW_CFA_def_cfa_offset
- DW_CFA_offset
- DW_CFA_remember_state
- DW_CFA_restore_state
- DW_CFA_restore

[Set 2, Bypassed] The following opcodes are acknowledged but are not
necessary for generating CTF Frame unwind info:
- DW_CFA_undefined
- DW_CFA_same_value

Anything else apart from the two above-mentioned sets is skipped altogether.
This means that any function containing a CFI directive not in Set 1 or Set 2
above, will not have any CTF Frame unwind information generated for them.
Holes in instructions covered by FREs are not representable in the CTF
unwind format.

As few examples, following opcodes are not processed for .ctf_frame
generation, and are skipped:
- .cfi_personality*
- .cfi_*lsda
- .cfi_escape
- .cfi_negate_ra_state
- ...

Not processing .cfi_escape, .cfi_negate_ra_state will cause CTF Frame
unwind information to be absent for CTF FDEs that contain these CFI
directives, hence affecting the asynchronicity.

x86-64 and aarch64 backends need to have a few new definitions and functions
for .ctf_frame generation to provide gas with architecture specific
information like SP/FP/RA register numbers and a CTF Frame specific ABI
marker.

Lastly, the patch also implements an optimization for size, where
specific fragments containing CTF FRE start address and CTF FDE function
info are fixed up.  This is similar to other similar optimizations in
gas, where fragments are sized and fixed up when the associated symbols
can be resolved.  This optimization is controlled by a #define
CTF_FRE_START_ADDR_OPT and should be easy to turn off if needed.  The
optimization is on by default for both x86_64 and aarch64.

ChangeLog:

	* gas/Makefile.am: Include gen-ctf-frame.c and ctf-frame-opt.c.
	* gas/Makefile.in: Regenerated.
	* gas/as.h (enum _relax_state): Add new state rs_ctf_fre.
	(ctf_frame_estimate_size_before_relax): New function.
	(ctf_frame_relax_frag): Likewise.
	(ctf_frame_convert_frag): Likewise.
	* gas/config/tc-aarch64.c (enum aarch64_abi_type): New
	declaration.
	(aarch64_support_ctf_frame_p): Likewise.
	(aarch64_ctf_frame_ra_tracking_p): Likewise.
	(aarch64_ctf_frame_cfa_ra_offset): Likewise.
	(aarch64_ctf_frame_get_abi_arch): Likewise.
	(md_begin): Set values of sp/fp/ra registers.
	* gas/config/tc-aarch64.h (aarch64_support_ctf_frame_p): New
	declaration.
	(support_ctf_frame_p): Likewise.
	(CTF_FRAME_CFA_SP_REG): Likewise.
	(CTF_FRAME_CFA_FP_REG): Likewise.
	(CTF_FRAME_CFA_RA_REG): Likewise.
	(aarch64_ctf_frame_ra_tracking_p): Likewise.
	(ctf_frame_ra_tracking_p): Likewise.
	(aarch64_ctf_frame_cfa_ra_offset): Likewise.
	(ctf_frame_cfa_ra_offset): Likewise.
	(aarch64_ctf_frame_get_abi_arch): Likewise.
	(ctf_frame_get_abi_arch): Likewise.
	* gas/config/tc-i386.c (md_begin): Set values of sp/fp/ra.
	(x86_support_ctf_frame_p): New definition.
	(x86_ctf_frame_ra_tracking_p): Likewise.
	(x86_ctf_frame_cfa_ra_offset): Likewise.
	(x86_ctf_frame_get_abi_arch): Likewise.
	* gas/config/tc-i386.h (x86_support_ctf_frame_p): New
	declaration.
	(support_ctf_frame_p): Likewise.
	(CTF_FRAME_CFA_SP_REG): Likewise.
	(CTF_FRAME_CFA_FP_REG): Likewise.
	(x86_ctf_frame_ra_tracking_p): Likewise.
	(ctf_frame_ra_tracking_p): Likewise.
	(x86_ctf_frame_cfa_ra_offset): Likewise.
	(ctf_frame_cfa_ra_offset): Likewise.
	(x86_ctf_frame_get_abi_arch): Likewise.
	(ctf_frame_get_abi_arch): Likewise.
	* gas/config/tc-xtensa.c (unrelaxed_frag_max_size): Add case for
	rs_ctf_fre.
	* gas/dw2gencfi.c (cfi_finish): Create a .ctf_frame section.
	* gas/dw2gencfi.h (CFI_EMIT_ctf_frame): New definition.
	* gas/write.c (cvt_frag_to_fill): Handle rs_ctf_fre.
	(relax_segment): Handle rs_ctf_fre.
	* gas/ctf-frame-opt.c: New file.
	* gas/gen-ctf-frame.c: New file.
	* gas/gen-ctf-frame.h: New file.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.d: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.s: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.d: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.s: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.d: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.s: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.d: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.s: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.d: Likewise..
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.s: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.d: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.s: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.d: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.s: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.d: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.s: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.d: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.s: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.d: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.s: Likewise.
	* gas/testsuite/gas/cfi-ctf/cfi-ctf.exp: Testsuite for CTF Frame.
---
 gas/Makefile.am                               |    3 +
 gas/Makefile.in                               |   23 +-
 gas/as.h                                      |   10 +-
 gas/config/tc-aarch64.c                       |   42 +
 gas/config/tc-aarch64.h                       |   29 +
 gas/config/tc-i386.c                          |   46 +
 gas/config/tc-i386.h                          |   26 +
 gas/config/tc-xtensa.c                        |    1 +
 gas/ctf-frame-opt.c                           |  158 ++
 gas/doc/as.texi                               |   14 +-
 gas/dw2gencfi.c                               |   30 +
 gas/dw2gencfi.h                               |    1 +
 gas/gen-ctf-frame.c                           | 1297 +++++++++++++++++
 gas/gen-ctf-frame.h                           |  142 ++
 gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.d |   20 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.s |   61 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.d  |   17 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.s  |    3 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.d  |   17 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.s  |    2 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.d  |   17 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.s  |    4 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.d  |   21 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.s  |    8 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.d  |   21 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.s  |    7 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.d  |   21 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.s  |    7 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.d  |   21 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.s  |    7 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.d  |   20 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.s  |   12 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.d  |   22 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.s  |   30 +
 gas/testsuite/gas/cfi-ctf/cfi-ctf.exp         |   58 +
 gas/testsuite/gas/cfi-ctf/common-empty-1.d    |   14 +
 gas/testsuite/gas/cfi-ctf/common-empty-1.s    |    5 +
 gas/testsuite/gas/cfi-ctf/common-empty-2.d    |   14 +
 gas/testsuite/gas/cfi-ctf/common-empty-2.s    |    8 +
 gas/testsuite/gas/cfi-ctf/common-empty-3.d    |   14 +
 gas/testsuite/gas/cfi-ctf/common-empty-3.s    |    9 +
 gas/testsuite/gas/cfi-ctf/common-empty-4.d    |   14 +
 gas/testsuite/gas/cfi-ctf/common-empty-4.s    |   18 +
 gas/write.c                                   |   13 +
 44 files changed, 2313 insertions(+), 14 deletions(-)
 create mode 100644 gas/ctf-frame-opt.c
 create mode 100644 gas/gen-ctf-frame.c
 create mode 100644 gas/gen-ctf-frame.h
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/cfi-ctf.exp
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-1.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-1.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-2.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-2.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-3.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-3.s
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-4.d
 create mode 100644 gas/testsuite/gas/cfi-ctf/common-empty-4.s

diff --git a/gas/Makefile.am b/gas/Makefile.am
index bd597398671..58f28930c64 100644
--- a/gas/Makefile.am
+++ b/gas/Makefile.am
@@ -70,6 +70,8 @@ GAS_CFILES = \
 	atof-generic.c \
 	compress-debug.c \
 	cond.c \
+	ctf-frame-opt.c \
+	gen-ctf-frame.c \
 	depend.c \
 	dwarf2dbg.c \
 	dw2gencfi.c \
@@ -105,6 +107,7 @@ HFILES = \
 	bit_fix.h \
 	cgen.h \
 	compress-debug.h \
+	gen-ctf-frame.h \
 	dwarf2dbg.h \
 	dw2gencfi.h \
 	ecoff.h \
diff --git a/gas/Makefile.in b/gas/Makefile.in
index c57d78f82c4..7ae8859b0a6 100644
--- a/gas/Makefile.in
+++ b/gas/Makefile.in
@@ -160,14 +160,16 @@ CONFIG_CLEAN_FILES = gdb.ini .gdbinit po/Makefile.in
 CONFIG_CLEAN_VPATH_FILES =
 PROGRAMS = $(noinst_PROGRAMS)
 am__objects_1 = app.$(OBJEXT) as.$(OBJEXT) atof-generic.$(OBJEXT) \
-	compress-debug.$(OBJEXT) cond.$(OBJEXT) depend.$(OBJEXT) \
-	dwarf2dbg.$(OBJEXT) dw2gencfi.$(OBJEXT) ecoff.$(OBJEXT) \
-	ehopt.$(OBJEXT) expr.$(OBJEXT) flonum-copy.$(OBJEXT) \
-	flonum-konst.$(OBJEXT) flonum-mult.$(OBJEXT) frags.$(OBJEXT) \
-	hash.$(OBJEXT) input-file.$(OBJEXT) input-scrub.$(OBJEXT) \
-	listing.$(OBJEXT) literal.$(OBJEXT) macro.$(OBJEXT) \
-	messages.$(OBJEXT) output-file.$(OBJEXT) read.$(OBJEXT) \
-	remap.$(OBJEXT) sb.$(OBJEXT) stabs.$(OBJEXT) subsegs.$(OBJEXT) \
+	compress-debug.$(OBJEXT) cond.$(OBJEXT) \
+	ctf-frame-opt.$(OBJEXT) gen-ctf-frame.$(OBJEXT) \
+	depend.$(OBJEXT) dwarf2dbg.$(OBJEXT) dw2gencfi.$(OBJEXT) \
+	ecoff.$(OBJEXT) ehopt.$(OBJEXT) expr.$(OBJEXT) \
+	flonum-copy.$(OBJEXT) flonum-konst.$(OBJEXT) \
+	flonum-mult.$(OBJEXT) frags.$(OBJEXT) hash.$(OBJEXT) \
+	input-file.$(OBJEXT) input-scrub.$(OBJEXT) listing.$(OBJEXT) \
+	literal.$(OBJEXT) macro.$(OBJEXT) messages.$(OBJEXT) \
+	output-file.$(OBJEXT) read.$(OBJEXT) remap.$(OBJEXT) \
+	sb.$(OBJEXT) stabs.$(OBJEXT) subsegs.$(OBJEXT) \
 	symbols.$(OBJEXT) write.$(OBJEXT)
 am_as_new_OBJECTS = $(am__objects_1)
 am__dirstamp = $(am__leading_dot)dirstamp
@@ -549,6 +551,8 @@ GAS_CFILES = \
 	atof-generic.c \
 	compress-debug.c \
 	cond.c \
+	ctf-frame-opt.c \
+	gen-ctf-frame.c \
 	depend.c \
 	dwarf2dbg.c \
 	dw2gencfi.c \
@@ -583,6 +587,7 @@ HFILES = \
 	bit_fix.h \
 	cgen.h \
 	compress-debug.h \
+	gen-ctf-frame.h \
 	dwarf2dbg.h \
 	dw2gencfi.h \
 	ecoff.h \
@@ -1285,6 +1290,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgen.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compress-debug.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cond.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctf-frame-opt.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/depend.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dw2gencfi.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf2dbg.Po@am__quote@
@@ -1295,6 +1301,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flonum-konst.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flonum-mult.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/frags.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen-ctf-frame.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/input-file.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/input-scrub.Po@am__quote@
diff --git a/gas/as.h b/gas/as.h
index 92e039b163a..f0bb3bd66bf 100644
--- a/gas/as.h
+++ b/gas/as.h
@@ -261,7 +261,10 @@ enum _relax_state
   rs_cfa,
 
   /* Cross-fragment dwarf2 line number optimization.  */
-  rs_dwarf2dbg
+  rs_dwarf2dbg,
+
+  /* CTF Frame FRE type selection optimization.  */
+  rs_ctf_frame
 };
 
 typedef enum _relax_state relax_stateT;
@@ -527,6 +530,11 @@ int eh_frame_relax_frag (fragS *);
 void eh_frame_convert_frag (fragS *);
 int generic_force_reloc (struct fix *);
 
+/* CTF Frame FRE optimization.  */
+int ctf_frame_estimate_size_before_relax (fragS *);
+int ctf_frame_relax_frag (fragS *);
+void ctf_frame_convert_frag (fragS *);
+
 #include "expr.h"		/* Before targ-*.h */
 
 /* This one starts the chain of target dependent headers.  */
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index f023e5b0a28..8c78ed3a173 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -31,6 +31,7 @@
 #ifdef OBJ_ELF
 #include "elf/aarch64.h"
 #include "dw2gencfi.h"
+#include "gen-ctf-frame.h"
 #endif
 
 #include "dwarf2dbg.h"
@@ -70,6 +71,11 @@ enum aarch64_abi_type
   AARCH64_ABI_ILP32 = 2
 };
 
+unsigned int aarch64_ctf_frame_cfa_sp_reg;
+/* The other CFA base register for CTF Frame unwind info.  */
+unsigned int aarch64_ctf_frame_cfa_fp_reg;
+unsigned int aarch64_ctf_frame_cfa_ra_reg;
+
 #ifndef DEFAULT_ARCH
 #define DEFAULT_ARCH "aarch64"
 #endif
@@ -8406,6 +8412,36 @@ tc_aarch64_frame_initial_instructions (void)
 {
   cfi_add_CFA_def_cfa (REG_SP, 0);
 }
+
+bool
+aarch64_support_ctf_frame_p (void)
+{
+  if (aarch64_abi == AARCH64_ABI_LP64)
+    return 1;
+  return 0;
+}
+
+bool
+aarch64_ctf_frame_ra_tracking_p (void)
+{
+  return 1;
+}
+
+offsetT
+aarch64_ctf_frame_cfa_ra_offset (void)
+{
+  return (offsetT)0;
+}
+
+unsigned char
+aarch64_ctf_frame_get_abi_arch (void)
+{
+  if (aarch64_support_ctf_frame_p ())
+    return ctf_frame_get_abi_arch_callback ("aarch64", target_big_endian);
+  else
+    return 0;
+}
+
 #endif /* OBJ_ELF */
 
 /* Convert REGNAME to a DWARF-2 register number.  */
@@ -9669,6 +9705,12 @@ md_begin (void)
   mach = ilp32_p ? bfd_mach_aarch64_ilp32 : bfd_mach_aarch64;
 
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
+#ifdef OBJ_ELF
+  // FIXME - is there a better way to do it ? 
+  aarch64_ctf_frame_cfa_sp_reg = 31;
+  aarch64_ctf_frame_cfa_fp_reg = 29; /* x29.  */
+  aarch64_ctf_frame_cfa_ra_reg = 30;
+#endif
 }
 
 /* Command line processing.  */
diff --git a/gas/config/tc-aarch64.h b/gas/config/tc-aarch64.h
index f5c17523796..f1274a2d3aa 100644
--- a/gas/config/tc-aarch64.h
+++ b/gas/config/tc-aarch64.h
@@ -235,6 +235,35 @@ struct aarch64_segment_info_type
 /* We want .cfi_* pseudo-ops for generating unwind info.  */
 #define TARGET_USE_CFIPOP              1
 
+/* Whether CTF Frame unwind info is supported.  */
+extern bool aarch64_support_ctf_frame_p (void);
+#define support_ctf_frame_p aarch64_support_ctf_frame_p
+
+/* The stack-pointer register number for CTF Frame unwind info.  */
+extern unsigned int aarch64_ctf_frame_cfa_sp_reg;
+#define CTF_FRAME_CFA_SP_REG aarch64_ctf_frame_cfa_sp_reg
+
+/* The base-pointer register number for CFA unwind info.  */
+extern unsigned int aarch64_ctf_frame_cfa_fp_reg;
+#define CTF_FRAME_CFA_FP_REG aarch64_ctf_frame_cfa_fp_reg
+
+/* The return address register number for CFA unwind info.  */
+extern unsigned int aarch64_ctf_frame_cfa_ra_reg;
+#define CTF_FRAME_CFA_RA_REG aarch64_ctf_frame_cfa_ra_reg
+
+/* Specify if RA tracking is needed.  */
+extern bool aarch64_ctf_frame_ra_tracking_p (void);
+#define ctf_frame_ra_tracking_p aarch64_ctf_frame_ra_tracking_p
+
+/* Specify the fixed offset to recover RA from CFA.
+   (useful only when RA tracking is not needed).  */
+extern offsetT aarch64_ctf_frame_cfa_ra_offset (void);
+#define ctf_frame_cfa_ra_offset aarch64_ctf_frame_cfa_ra_offset
+
+/* The abi/arch indentifier for CTF Frame.  */
+unsigned char aarch64_ctf_frame_get_abi_arch (void);
+#define ctf_frame_get_abi_arch aarch64_ctf_frame_get_abi_arch
+
 /* CFI hooks.  */
 #define tc_regname_to_dw2regnum            tc_aarch64_regname_to_dw2regnum
 #define tc_cfi_frame_initial_instructions  tc_aarch64_frame_initial_instructions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index d40a71a492a..7181dfddb83 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -30,6 +30,7 @@
 #include "subsegs.h"
 #include "dwarf2dbg.h"
 #include "dw2gencfi.h"
+#include "gen-ctf-frame.h"
 #include "elf/x86-64.h"
 #include "opcodes/i386-init.h"
 #include <limits.h>
@@ -586,6 +587,12 @@ static int use_big_obj = 0;
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 /* 1 if generating code for a shared library.  */
 static int shared = 0;
+
+unsigned int x86_ctf_frame_cfa_sp_reg;
+/* The other CFA base register for CTF Frame unwind info.  */
+unsigned int x86_ctf_frame_cfa_fp_reg;
+unsigned int x86_ctf_frame_cfa_ra_reg;
+
 #endif
 
 /* 1 for intel syntax,
@@ -3080,6 +3087,10 @@ md_begin (void)
       x86_dwarf2_return_column = 16;
 #endif
       x86_cie_data_alignment = -8;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+      x86_ctf_frame_cfa_sp_reg = 7;
+      x86_ctf_frame_cfa_fp_reg = 6;
+#endif
     }
   else
     {
@@ -9147,6 +9158,41 @@ x86_cleanup (void)
   if (seg && subseg)
     subseg_set (seg, subseg);
 }
+
+bool
+x86_support_ctf_frame_p (void)
+{
+  /* At this time, CTF Frame unwind is supported for AMD64 ABI only.  */
+  if (x86_elf_abi == X86_64_ABI)
+    return true;
+  return false;
+}
+
+bool
+x86_ctf_frame_ra_tracking_p (void)
+{
+  /* In AMD64, return address is always stored on the stack at a fixed offset
+     from the CFA (provided via x86_ctf_frame_cfa_ra_offset ()).
+     Do not track explicitly via a CTF Frame Row Entry.  */
+  return false;
+}
+
+offsetT
+x86_ctf_frame_cfa_ra_offset (void)
+{
+  gas_assert (x86_elf_abi == X86_64_ABI);
+  return (offsetT)-8;
+}
+
+unsigned char
+x86_ctf_frame_get_abi_arch (void)
+{
+  if (x86_support_ctf_frame_p ())
+    return ctf_frame_get_abi_arch_callback ("x86-64", target_big_endian);
+  else
+    return 0;
+}
+
 #endif
 
 static unsigned int
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
index a6e096ee110..1607ef6cfd2 100644
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -362,6 +362,32 @@ extern bfd_vma x86_64_section_letter (int, const char **);
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 extern void x86_cleanup (void);
 #define md_cleanup() x86_cleanup ()
+
+/* Whether CTF Frame unwind info is supported.  */
+extern bool x86_support_ctf_frame_p (void);
+#define support_ctf_frame_p x86_support_ctf_frame_p
+
+/* The stack-pointer register number for CTF Frame unwind info.  */
+extern unsigned int x86_ctf_frame_cfa_sp_reg;
+#define CTF_FRAME_CFA_SP_REG x86_ctf_frame_cfa_sp_reg
+
+/* The frame-pointer register number for CFA unwind info.  */
+extern unsigned int x86_ctf_frame_cfa_fp_reg;
+#define CTF_FRAME_CFA_FP_REG x86_ctf_frame_cfa_fp_reg
+
+/* Specify if RA tracking is needed.  */
+extern bool x86_ctf_frame_ra_tracking_p (void);
+#define ctf_frame_ra_tracking_p x86_ctf_frame_ra_tracking_p
+
+/* Specify the fixed offset to recover RA from CFA.
+   (useful only when RA tracking is not needed).  */
+extern offsetT x86_ctf_frame_cfa_ra_offset (void);
+#define ctf_frame_cfa_ra_offset x86_ctf_frame_cfa_ra_offset
+
+/* The abi/arch indentifier for CTF Frame.  */
+extern unsigned char x86_ctf_frame_get_abi_arch (void);
+#define ctf_frame_get_abi_arch x86_ctf_frame_get_abi_arch
+
 #endif
 
 #ifdef TE_PE
diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
index b7403ac45d4..9b909cfffba 100644
--- a/gas/config/tc-xtensa.c
+++ b/gas/config/tc-xtensa.c
@@ -8616,6 +8616,7 @@ unrelaxed_frag_max_size (fragS *fragP)
     case rs_leb128:
     case rs_cfa:
     case rs_dwarf2dbg:
+    case rs_ctf_frame:
       /* No further adjustments needed.  */
       break;
     case rs_machine_dependent:
diff --git a/gas/ctf-frame-opt.c b/gas/ctf-frame-opt.c
new file mode 100644
index 00000000000..a3a4561cc89
--- /dev/null
+++ b/gas/ctf-frame-opt.c
@@ -0,0 +1,158 @@
+/* ctf-frame-opt.c - optimize FRE and FDE information in CTF Frame.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS 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, or (at your option)
+   any later version.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#include "as.h"
+#include "ctf-frame.h"
+
+/* The function estimates the size of a rs_ctf_frame variant frag based on
+   the current values of the symbols.  It is called before the
+   relaxation loop.  We set fr_subtype{0:2} to the expected length.  */
+
+int
+ctf_frame_estimate_size_before_relax (fragS *frag)
+{
+  offsetT width;
+  expressionS *exp;
+  symbolS *widthS;
+  int ret;
+
+  /* We are dealing with two different kind of fragments here which need
+     to be fixed up:
+       - first, FRE start address in each FRE, and
+       - second, Function info in each FDE (function info stores the FRE type)
+     The two kind of fragments can be differentiated based on the opcode
+     of the symbol.  */
+  exp = symbol_get_value_expression (frag->fr_symbol);
+  gas_assert ((exp->X_op == O_subtract) || (exp->X_op == O_absent));
+  /* Fragment for function info in a CTF Frame FDE will always write
+     only one byte.  */
+  if (exp->X_op == O_subtract)
+    ret = 1;
+  /* Fragment for the start address in a CTF Frame FRE may write out
+     1/2/4 bytes depending on the value of the diff.  */
+  else
+    {
+      /* Get the width expression from the symbol.  */
+      widthS = exp->X_op_symbol;
+      width = resolve_symbol_value (widthS);
+
+      if (width < 0x100)
+	ret = 1;
+      else if (width < 0x10000)
+	ret = 2;
+      else
+	ret = 4;
+    }
+
+  frag->fr_subtype = (frag->fr_subtype & ~7) | (ret & 7);
+
+  return ret;
+}
+
+/* This function relaxes a rs_ctf_frame variant frag based on the current
+   values of the symbols.  fr_subtype{0:2} is the current length of
+   the frag.  This returns the change in frag length.  */
+
+int
+ctf_frame_relax_frag (fragS *frag)
+{
+  int oldsize, newsize;
+
+  oldsize = frag->fr_subtype & 7;
+  if (oldsize == 7)
+    oldsize = -1;
+  newsize = ctf_frame_estimate_size_before_relax (frag);
+  return newsize - oldsize;
+}
+
+/* This function converts a rs_ctf_frame variant frag into a normal fill
+   frag.  This is called after all relaxation has been done.
+   fr_subtype{0:2} will be the desired length of the frag.  */
+
+void
+ctf_frame_convert_frag (fragS *frag)
+{
+  offsetT fsize;
+  offsetT diff;
+  offsetT value;
+  unsigned char func_info = CTF_FRAME_ROW_ENTRY_TYPE_ADDR4;
+  expressionS *exp;
+  symbolS *fsizeS, *diffS;
+
+  /* We are dealing with two different kind of fragments here which need
+     to be fixed up:
+       - first, FRE start address in each FRE, and
+       - second, Function info in each FDE (function info stores the FRE type)
+     The two kind of fragments can be differentiated based on the opcode
+     of the symbol.  */
+  exp = symbol_get_value_expression (frag->fr_symbol);
+  gas_assert ((exp->X_op == O_subtract) || (exp->X_op == O_absent));
+  /* Fragment for function info in a CTF Frame FDE.  */
+  if (exp->X_op == O_subtract)
+    {
+      fsizeS = frag->fr_symbol;
+      fsize = resolve_symbol_value (fsizeS);
+      if (fsize < 0x100)
+	func_info = CTF_FRAME_ROW_ENTRY_TYPE_ADDR1;
+      else if (fsize < 0x10000)
+	func_info = CTF_FRAME_ROW_ENTRY_TYPE_ADDR2;
+      else
+	func_info = CTF_FRAME_ROW_ENTRY_TYPE_ADDR4;
+      value = func_info;
+
+      frag->fr_literal[frag->fr_fix] = value;
+    }
+  /* Fragment for the start address in a CTF Frame FRE.  */
+  else
+    {
+      /* Get the fsize expression from the symbol.  */
+      fsizeS = exp->X_op_symbol;
+      fsize = resolve_symbol_value (fsizeS);
+      /* Get the diff expression from the symbol.  */
+      diffS= exp->X_add_symbol;
+      diff = resolve_symbol_value (diffS);
+      value = diff;
+
+      switch (frag->fr_subtype & 7)
+	{
+	case 1:
+	  gas_assert (fsize < 0x100);
+	  frag->fr_literal[frag->fr_fix] = diff;
+	  break;
+	case 2:
+	  gas_assert (fsize < 0x10000);
+	  md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2);
+	  break;
+	case 4:
+	  md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4);
+	  break;
+	default:
+	  abort ();
+	}
+    }
+
+  frag->fr_fix += frag->fr_subtype & 7;
+  frag->fr_type = rs_fill;
+  frag->fr_subtype = 0;
+  frag->fr_offset = 0;
+  /* FIXME do this now because we have evaluated and fixed up the fragments
+     manually ?  */
+  frag->fr_symbol = 0;
+}
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index c74b9eee3d6..c1c3233ece6 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -4846,11 +4846,15 @@ Each expression is assembled into the next byte.
 @subsection @code{.cfi_sections @var{section_list}}
 @cindex @code{cfi_sections} directive
 @code{.cfi_sections} may be used to specify whether CFI directives
-should emit @code{.eh_frame} section and/or @code{.debug_frame} section.
-If @var{section_list} is @code{.eh_frame}, @code{.eh_frame} is emitted,
-if @var{section_list} is @code{.debug_frame}, @code{.debug_frame} is emitted.
-To emit both use @code{.eh_frame, .debug_frame}.  The default if this
-directive is not used is @code{.cfi_sections .eh_frame}.
+should emit @code{.eh_frame} section, @code{.debug_frame} section and/or
+@code{.ctf_frame} section.  If @var{section_list} contains @code{.eh_frame},
+@code{.eh_frame} is emitted, if @var{section_list} contains
+@code{.debug_frame}, @code{.debug_frame} is emitted, and finally, if
+@var{section_list} contains @code{.ctf_frame}, @code{.ctf_frame} is emitted.
+To emit multiple sections, specify them together in a list.  For example, to
+emit both @code{.eh_frame} and @code{.debug_frame}, use
+@code{.eh_frame, .debug_frame}.  The default if this directive is not used
+is @code{.cfi_sections .eh_frame}.
 
 On targets that support compact unwinding tables these can be generated
 by specifying @code{.eh_frame_entry} instead of @code{.eh_frame}.
diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c
index 6be8cb50495..b2882ff527d 100644
--- a/gas/dw2gencfi.c
+++ b/gas/dw2gencfi.c
@@ -23,6 +23,7 @@
 #include "dw2gencfi.h"
 #include "subsegs.h"
 #include "dwarf2dbg.h"
+#include "gen-ctf-frame.h"
 
 #ifdef TARGET_USE_CFIPOP
 
@@ -1231,6 +1232,8 @@ dot_cfi_sections (int ignored ATTRIBUTE_UNUSED)
 	else if (strcmp (name, tc_cfi_section_name) == 0)
 	  sections |= CFI_EMIT_target;
 #endif
+	else if (startswith (name, ".ctf_frame"))
+	    sections |= CFI_EMIT_ctf_frame;
 	else
 	  {
 	    *input_line_pointer = c;
@@ -2471,6 +2474,33 @@ cfi_finish (void)
       flag_traditional_format = save_flag_traditional_format;
     }
 
+  cfi_sections_set = true;
+  // FIXME - remove this commented line once the compiler can specify
+  // .ctf_frame for .cfi_sections directive
+  // if ((all_cfi_sections & CFI_EMIT_ctf_frame) != 0)
+  if (flag_gen_ctf_frame || (all_cfi_sections & CFI_EMIT_ctf_frame) != 0)
+    {
+#ifdef support_ctf_frame_p
+      if (support_ctf_frame_p ())
+	{
+	  segT ctf_frame_seg;
+	  int alignment = ffs (DWARF2_ADDR_SIZE (stdoutput)) - 1;
+
+	  if (!SUPPORT_FRAME_LINKONCE)
+	    ctf_frame_seg = get_cfi_seg (NULL, ".ctf_frame",
+					 (SEC_ALLOC | SEC_LOAD | SEC_DATA
+					  | DWARF2_EH_FRAME_READ_ONLY),
+					 alignment);
+	  output_ctf_frame (ctf_frame_seg);
+	}
+      else
+	as_warn (_(".ctf_frame not supported for target"));
+
+#else
+	as_warn (_(".ctf_frame not supported for target"));
+#endif
+    }
+
   cfi_sections_set = true;
   if ((all_cfi_sections & CFI_EMIT_debug_frame) != 0)
     {
diff --git a/gas/dw2gencfi.h b/gas/dw2gencfi.h
index d570cdb8db3..02ef27af7ca 100644
--- a/gas/dw2gencfi.h
+++ b/gas/dw2gencfi.h
@@ -200,5 +200,6 @@ extern struct fde_entry *all_fde_data;
 #define CFI_EMIT_debug_frame            (1 << 1)
 #define CFI_EMIT_target                 (1 << 2)
 #define CFI_EMIT_eh_frame_compact       (1 << 3)
+#define CFI_EMIT_ctf_frame              (1 << 4)
 
 #endif /* DW2GENCFI_H */
diff --git a/gas/gen-ctf-frame.c b/gas/gen-ctf-frame.c
new file mode 100644
index 00000000000..251699166bc
--- /dev/null
+++ b/gas/gen-ctf-frame.c
@@ -0,0 +1,1297 @@
+/* gen-ctf-frame.c - Support for generating CTF Frame section.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS 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, or (at your option)
+   any later version.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#include "as.h"
+#include "subsegs.h"
+#include "ctf-frame.h"
+#include "gen-ctf-frame.h"
+#include "dw2gencfi.h"
+
+#ifdef support_ctf_frame_p
+
+/* By default, use 32-bit relocations from .ctf_frame into .text.  */
+#ifndef CTF_FRAME_RELOC_SIZE
+# define CTF_FRAME_RELOC_SIZE 4
+#endif
+
+/* Whether frame row entries track RA.
+
+   A target may not need return address tracking for stack unwinding.  If it
+   does need the same, CTF_FRAME_CFA_RA_REG must be defined with the return
+   address register number.  */
+
+#if defined (ctf_frame_ra_tracking_p) && defined (CTF_FRAME_CFA_RA_REG)
+# ifndef CTFF_ROW_ENTRY_RA_TRACKING
+# define CTFF_ROW_ENTRY_RA_TRACKING 1
+# endif
+#endif
+
+/* CTF FRE type selection optimization is an optimization for size.
+
+   There are three flavors of CTF FRE representation in the binary format:
+     - ctf_frame_row_entry_addr1 where the FRE start address is 1 byte.
+     - ctf_frame_row_entry_addr2 where the FRE start address is 2 bytes.
+     - ctf_frame_row_entry_addr4 where the FRE start address is 4 bytes.
+
+   Note that in the CTF Frame format, all CTF FREs of a function use one
+   single representation.  The CTF FRE type itself is identified via the
+   information in the CTF FDE function info.
+
+   Now, to select the minimum required one from the list above, one needs to
+   make a decision based on the size (in bytes) of the function.
+
+   As a result, for this optimization, some fragments (generated with a new
+   type rs_ctf_frame) for the CTF Frame section are fixed up later.
+
+   This optimization (for size) is enabled by default.  */
+
+#ifndef CTF_FRE_TYPE_SELECTION_OPT
+# define CTF_FRE_TYPE_SELECTION_OPT 1
+#endif
+
+/* Emit a single byte into the current segment.  */
+
+static inline void
+out_one (int byte)
+{
+  FRAG_APPEND_1_CHAR (byte);
+}
+
+/* Emit a two-byte word into the current segment.  */
+
+static inline void
+out_two (int data)
+{
+  md_number_to_chars (frag_more (2), data, 2);
+}
+
+/* Emit a four byte word into the current segment.  */
+
+static inline void
+out_four (int data)
+{
+  md_number_to_chars (frag_more (4), data, 4);
+}
+
+/* Get the start address symbol from the DWARF FDE.  */
+
+static symbolS*
+get_dw_fde_start_addrS (const struct fde_entry *dw_fde)
+{
+  return dw_fde->start_address;
+}
+
+/* Get the start address symbol from the DWARF FDE.  */
+
+static symbolS*
+get_dw_fde_end_addrS (const struct fde_entry *dw_fde)
+{
+  return dw_fde->end_address;
+}
+
+/* Callback to create the abi/arch identifier for CTF Frame section.  */
+
+unsigned char
+ctf_frame_get_abi_arch_callback (const char *target_arch,
+				 int big_endian_p)
+{
+  unsigned char ctf_frame_abi_arch = 0;
+
+  if (strcmp (target_arch, "aarch64") == 0)
+    {
+      ctf_frame_abi_arch = big_endian_p
+	? CTF_FRAME_ABI_AARCH64_ENDIAN_BIG
+	: CTF_FRAME_ABI_AARCH64_ENDIAN_LITTLE;
+    }
+  else if (strcmp (target_arch, "x86-64") == 0)
+    {
+      gas_assert (!big_endian_p);
+      ctf_frame_abi_arch = CTF_FRAME_ABI_AMD64_ENDIAN_LITTLE;
+    }
+  else
+    {
+      /* Other abi/arch are not supported.  Should be unreachable.  */
+      printf (_("CTF Unsupported abi or arch\n"));
+      abort ();
+    }
+
+  return ctf_frame_abi_arch;
+}
+
+/* CTF Frame Row Entry (FRE) related functions.  */
+
+static void
+ctf_fre_set_begin_addr (struct ctf_frame_row_entry *fre, symbolS *beginS)
+{
+  fre->pc_begin = beginS;
+}
+
+static void
+ctf_fre_set_end_addr (struct ctf_frame_row_entry *fre, symbolS *endS)
+{
+  fre->pc_end = endS;
+}
+
+static void
+ctf_fre_set_cfa_base_reg (struct ctf_frame_row_entry *fre,
+			  unsigned int cfa_base_reg)
+{
+  fre->cfa_base_reg = cfa_base_reg;
+  fre->merge_candidate = false;
+}
+
+static void
+ctf_fre_set_cfa_offset (struct ctf_frame_row_entry *fre, offsetT cfa_offset)
+{
+  fre->cfa_offset = cfa_offset;
+  fre->merge_candidate = false;
+}
+
+#ifdef CTFF_ROW_ENTRY_RA_TRACKING
+static void
+ctf_fre_set_ra_track (struct ctf_frame_row_entry *fre, offsetT ra_offset)
+{
+  fre->ra_loc = CTF_FRE_ELEM_LOC_STACK;
+  fre->ra_offset = ra_offset;
+  fre->merge_candidate = false;
+}
+#endif
+
+static void
+ctf_fre_set_bp_track (struct ctf_frame_row_entry *fre, offsetT bp_offset)
+{
+  fre->bp_loc = CTF_FRE_ELEM_LOC_STACK;
+  fre->bp_offset = bp_offset;
+  fre->merge_candidate = false;
+}
+
+/* All stack offset values within an FRE are uniformly encoded in the same
+   number of bytes.  The size of the stack offset values will, however, vary
+   across FREs.  */
+
+#define VALUE_8BIT  0x7f
+#define VALUE_16BIT 0x7fff
+#define VALUE_32BIT 0x7fffffff
+#define VALUE_64BIT 0x7fffffffffffffff
+
+/* Given a signed offset, return the size in bytes needed to represent it.  */
+
+static unsigned int
+get_offset_size_in_bytes (offsetT value)
+{
+  unsigned int size = 0;
+
+  if (value <= VALUE_8BIT && value >= (long)-VALUE_8BIT)
+    size = 1;
+  else if (value <= VALUE_16BIT && value >= (long)-VALUE_16BIT)
+    size = 2;
+  else if (value <= VALUE_32BIT && value >= (long)-VALUE_32BIT)
+    size = 4;
+  else if (value <= VALUE_64BIT && value >= (long)-VALUE_64BIT)
+    size = 8;
+
+  return size;
+}
+
+#define CTF_FRE_OFFSET_FUNC_MAP_INDEX_1B  0 /* CTF_FRAME_FRE_OFFSET_1B.  */
+#define CTF_FRE_OFFSET_FUNC_MAP_INDEX_2B  1 /* CTF_FRAME_FRE_OFFSET_2B.  */
+#define CTF_FRE_OFFSET_FUNC_MAP_INDEX_4B  2 /* CTF_FRAME_FRE_OFFSET_4B.  */
+#define CTF_FRE_OFFSET_FUNC_MAP_INDEX_8B  3 /* Not supported in CTF.  */
+#define CTF_FRE_OFFSET_FUNC_MAP_INDEX_MAX CTF_FRE_OFFSET_FUNC_MAP_INDEX_8B
+
+/* Helper struct for mapping offset size to output functions.  */
+
+struct ctf_fre_offset_func_map
+{
+  unsigned int offset_size;
+  void (*out_func)(int);
+};
+
+/* Given an OFFSET_SIZE, return the size in bytes needed to represent it.  */
+
+static unsigned int
+ctf_fre_offset_func_map_index (unsigned int offset_size)
+{
+  unsigned int index = CTF_FRE_OFFSET_FUNC_MAP_INDEX_MAX;
+
+  switch (offset_size)
+    {
+      case CTF_FRAME_FRE_OFFSET_1B:
+	index = CTF_FRE_OFFSET_FUNC_MAP_INDEX_1B;
+	break;
+      case CTF_FRAME_FRE_OFFSET_2B:
+	index = CTF_FRE_OFFSET_FUNC_MAP_INDEX_2B;
+	break;
+      case CTF_FRAME_FRE_OFFSET_4B:
+	index = CTF_FRE_OFFSET_FUNC_MAP_INDEX_4B;
+	break;
+      default:
+	/* Not supported in CTF Frame.  */
+	break;
+    }
+
+  return index;
+}
+
+/* Mapping from offset size to the output function to emit the value.  */
+
+static const
+struct ctf_fre_offset_func_map
+fre_offset_func_map[CTF_FRE_OFFSET_FUNC_MAP_INDEX_MAX+1] =
+{
+  { CTF_FRAME_FRE_OFFSET_1B, out_one },
+  { CTF_FRAME_FRE_OFFSET_2B, out_two },
+  { CTF_FRAME_FRE_OFFSET_4B, out_four },
+  { -1, NULL } /* Not Supported in CTF Frame.  */
+};
+
+/* CTF Frame version specific operations access.  */
+
+static struct ctf_frame_version_ops ctf_frame_ver_ops;
+
+/* CTF Frame (CTF_FRAME_VERSION_1) set FRE info.  */
+
+static unsigned char
+ctf_frame_v1_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
+			   unsigned int offset_size)
+{
+  unsigned char fre_info;
+  fre_info = CTF_FRAME_V1_FRE_INFO (base_reg, num_offsets, offset_size);
+  return fre_info;
+}
+
+/* CTF Frame (CTF_FRAME_VERSION_1) set function info.  */
+static unsigned char
+ctf_frame_v1_set_func_info (unsigned int fde_type, unsigned int fre_type)
+{
+  unsigned char func_info;
+  func_info = CTF_FRAME_V1_FUNC_INFO (fde_type, fre_type);
+  return func_info;
+}
+
+/* CTF Frame version specific operations setup.  */
+
+static void
+ctf_frame_set_version (uint32_t ctf_frame_version __attribute__((unused)))
+{
+  ctf_frame_ver_ops.format_version = CTF_FRAME_VERSION_1;
+
+  ctf_frame_ver_ops.set_fre_info = ctf_frame_v1_set_fre_info;
+
+  ctf_frame_ver_ops.set_func_info = ctf_frame_v1_set_func_info;
+}
+
+/* CTF Frame set FRE info.  */
+
+static unsigned char
+ctf_frame_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
+			unsigned int offset_size)
+{
+  return ctf_frame_ver_ops.set_fre_info (base_reg, num_offsets,
+					 offset_size);
+}
+
+/* CTF Frame set func info. */
+
+ATTRIBUTE_UNUSED static unsigned char
+ctf_frame_set_func_info (unsigned int fde_type, unsigned int fre_type)
+{
+  return ctf_frame_ver_ops.set_func_info (fde_type, fre_type);
+}
+
+/* Get the number of CTF FDEs for the current file.  */
+
+static unsigned int
+get_num_ctf_fdes (void);
+
+/* Get the number of CTF frame row entries for the current file.  */
+
+static unsigned int
+get_num_ctf_fres (void);
+
+/* Get CFA base register ID as represented in CTF Frame Row Entry.  */
+
+static unsigned int
+get_fre_base_reg_id (struct ctf_frame_row_entry *ctf_fre)
+{
+  unsigned int cfi_insn_cfa_base_reg = ctf_fre->cfa_base_reg;
+  unsigned fre_base_reg = CTF_FRAME_BASE_REG_SP;
+
+  if (cfi_insn_cfa_base_reg == CTF_FRAME_CFA_FP_REG)
+    fre_base_reg = CTF_FRAME_BASE_REG_FP;
+
+  /* Only one bit is reserved in CTF_FRAME_VERSION_1.  */
+  gas_assert (fre_base_reg == CTF_FRAME_BASE_REG_SP
+	      || fre_base_reg == CTF_FRAME_BASE_REG_FP);
+
+  return fre_base_reg;
+}
+
+/* Get number of offsets necessary for the CTF Frame Row Entry.  */
+
+static unsigned int
+get_fre_num_offsets (struct ctf_frame_row_entry *ctf_fre)
+{
+  /* Atleast 1 must always be present (to recover CFA).  */
+  unsigned int fre_num_offsets = 1;
+
+  if (ctf_fre->bp_loc == CTF_FRE_ELEM_LOC_STACK)
+    fre_num_offsets++;
+#ifdef CTFF_ROW_ENTRY_RA_TRACKING
+  if (ctf_fre->ra_loc == CTF_FRE_ELEM_LOC_STACK)
+    fre_num_offsets++;
+#endif
+  return fre_num_offsets;
+}
+
+/* Get the minimum necessary offset size (in bytes) for this CTF frame
+   row entry.  */
+
+static unsigned int
+ctf_frame_get_fre_offset_size (struct ctf_frame_row_entry *ctf_fre)
+{
+  unsigned int max_offset_size = 0;
+  unsigned int cfa_offset_size = 0;
+  unsigned int bp_offset_size = 0;
+  unsigned int ra_offset_size = 0;
+
+  unsigned int fre_offset_size = 0;
+
+  /* What size of offsets appear in this frame row entry.  */
+  cfa_offset_size = get_offset_size_in_bytes (ctf_fre->cfa_offset);
+  if (ctf_fre->bp_loc == CTF_FRE_ELEM_LOC_STACK)
+    bp_offset_size = get_offset_size_in_bytes (ctf_fre->bp_offset);
+#ifdef CTFF_ROW_ENTRY_RA_TRACKING
+  if (ctf_frame_ra_tracking_p ()
+      && ctf_fre->ra_loc == CTF_FRE_ELEM_LOC_STACK)
+    ra_offset_size = get_offset_size_in_bytes (ctf_fre->ra_offset);
+#endif
+
+  /* Get the maximum size needed to represent the offsets.  */
+  max_offset_size = cfa_offset_size;
+  if (bp_offset_size > max_offset_size)
+    max_offset_size = bp_offset_size;
+  if (ra_offset_size > max_offset_size)
+    max_offset_size = ra_offset_size;
+
+  gas_assert (max_offset_size);
+
+  switch (max_offset_size)
+    {
+    case 1:
+      fre_offset_size = CTF_FRAME_FRE_OFFSET_1B;
+      break;
+    case 2:
+      fre_offset_size = CTF_FRAME_FRE_OFFSET_2B;
+      break;
+    case 4:
+      fre_offset_size = CTF_FRAME_FRE_OFFSET_4B;
+      break;
+    default:
+      /* Offset of size 8 bytes is not supported in CTF Frame format
+	 version 1.  */
+      printf (_("CTF Unsupported offset value\n"));
+      abort ();
+      break;
+    }
+
+  return fre_offset_size;
+}
+
+#if CTF_FRE_TYPE_SELECTION_OPT
+
+/* Create a composite exression CEXP (for CTF FRE start address) such that:
+
+      exp = <val> OP_absent <width>, where,
+
+    - <val> and <width> are themselves expressionS.
+    - <val> stores the expression which when evaluated gives the value of the
+      start address offset of the FRE.
+    - <width> stores the expression when when evaluated gives the number of
+      bytes needed to encode the start address offset of the FRE.
+
+   The use of OP_absent as the X_op_symbol helps identify this expression
+   later when fragments are fixed up.  */
+
+static void
+create_fre_start_addr_exp (expressionS *cexp, symbolS *fre_pc_begin,
+			   symbolS *fde_start_address,
+			   symbolS *fde_end_address)
+{
+  expressionS val;
+  expressionS width;
+
+  /* val expression stores the FDE start address offset from the start PC
+     of function.  */
+  val.X_op = O_subtract;
+  val.X_add_symbol = fre_pc_begin;
+  val.X_op_symbol = fde_start_address;
+  val.X_add_number = 0;
+
+  /* width expressions stores the size of the function.  This is used later
+     to determine the number of bytes to be used to encode the FRE start
+     address of each FRE of the function.  */
+  width.X_op = O_subtract;
+  width.X_add_symbol = fde_end_address;
+  width.X_op_symbol = fde_start_address;
+  width.X_add_number = 0;
+
+  cexp->X_op = O_absent;
+  cexp->X_add_symbol = make_expr_symbol (&val);
+  cexp->X_op_symbol = make_expr_symbol (&width);
+  cexp->X_add_number = 0;
+}
+
+#endif
+
+static void
+output_ctf_frame_row_entry (symbolS *fde_start_addr,
+			    symbolS *fde_end_addr,
+			    struct ctf_frame_row_entry *ctf_fre)
+{
+  unsigned char fre_info;
+  unsigned int fre_num_offsets;
+  unsigned int fre_offset_size;
+  unsigned int fre_base_reg;
+  expressionS exp;
+  unsigned int fre_addr_size;
+
+  unsigned int index = 0;
+  unsigned int fre_write_offsets = 0;
+
+  fre_addr_size = 4; /* 4 bytes by default.   FIXME tie it to fre_type? */
+
+  /* CTF FRE Start Address.  */
+#if CTF_FRE_TYPE_SELECTION_OPT
+  create_fre_start_addr_exp (&exp, ctf_fre->pc_begin, fde_start_addr,
+			     fde_end_addr);
+  frag_grow (fre_addr_size);
+  frag_var (rs_ctf_frame, fre_addr_size, 0, (relax_substateT) 0,
+	    make_expr_symbol (&exp), 0, (char *) frag_now);
+#else
+  gas_assert (fde_end_addr);
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = ctf_fre->pc_begin; /* to.  */
+  exp.X_op_symbol = fde_start_addr; /* from.  */
+  exp.X_add_number = 0;
+  emit_expr (&exp, fre_addr_size);
+#endif
+
+  /* Create the fre_info using the CFA base register, number of offsets and max
+     size of offset in this frame row entry.  */
+  fre_base_reg = get_fre_base_reg_id (ctf_fre);
+  fre_num_offsets = get_fre_num_offsets (ctf_fre);
+  fre_offset_size = ctf_frame_get_fre_offset_size (ctf_fre);
+  fre_info = ctf_frame_set_fre_info (fre_base_reg, fre_num_offsets,
+				     fre_offset_size);
+  out_one (fre_info);
+
+  index = ctf_fre_offset_func_map_index (fre_offset_size);
+  gas_assert (index < CTF_FRE_OFFSET_FUNC_MAP_INDEX_MAX);
+
+  /* Write out the offsets in order - cfa, bp, ra.  */
+  fre_offset_func_map[index].out_func (ctf_fre->cfa_offset);
+  fre_write_offsets++;
+
+  if (ctf_fre->bp_loc == CTF_FRE_ELEM_LOC_STACK)
+    {
+      fre_offset_func_map[index].out_func (ctf_fre->bp_offset);
+      fre_write_offsets++;
+    }
+
+#ifdef CTFF_ROW_ENTRY_RA_TRACKING
+  if (ctf_fre->ra_loc == CTF_FRE_ELEM_LOC_STACK)
+    {
+      fre_offset_func_map[index].out_func (ctf_fre->ra_offset);
+      fre_write_offsets++;
+    }
+#endif
+  /* Check if the expected number offsets have been written out
+     in this FRE.  */
+  gas_assert (fre_write_offsets == fre_num_offsets);
+}
+
+static void
+output_ctf_frame_funcdesc (symbolS *start_of_fre_section,
+			    symbolS *fre_symbol,
+			    struct ctf_func_desc_entry *ctf_fde)
+{
+  expressionS exp;
+  unsigned int addr_size;
+  symbolS *dw_fde_start_addrS, *dw_fde_end_addrS;
+
+  addr_size = CTF_FRAME_RELOC_SIZE;
+  dw_fde_start_addrS = get_dw_fde_start_addrS (ctf_fde->dw_fde);
+  dw_fde_end_addrS = get_dw_fde_end_addrS (ctf_fde->dw_fde);
+
+  /* Start address of the function.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = dw_fde_start_addrS; /* to location.  */
+  exp.X_op_symbol = symbol_temp_new_now (); /* from location.  */
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  /* Size of the function in bytes.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = dw_fde_end_addrS;
+  exp.X_op_symbol = dw_fde_start_addrS;
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  /* Offset to the first frame row entry.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = fre_symbol; /* Minuend.  */
+  exp.X_op_symbol = start_of_fre_section; /* Subtrahend.  */
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  /* Number of FREs.  */
+  out_four (ctf_fde->num_fres);
+
+  /* CTF FDE function info.  */
+#if CTF_FRE_TYPE_SELECTION_OPT
+  expressionS width;
+  width.X_op = O_subtract;
+  width.X_add_symbol = dw_fde_end_addrS;
+  width.X_op_symbol = dw_fde_start_addrS;
+  width.X_add_number = 0;
+  frag_grow (1); /* Size of func info is unsigned char.  */
+  frag_var (rs_ctf_frame, 1, 0, (relax_substateT) 0,
+	    make_expr_symbol (&width), 0, (char *) frag_now);
+#else
+  unsigned char func_info;
+  func_info = ctf_frame_set_func_info (CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCINC,
+				       CTF_FRAME_ROW_ENTRY_TYPE_ADDR4);
+  out_one (func_info);
+#endif
+}
+
+static void
+output_ctf_frame_internal (void)
+{
+  expressionS exp;
+  unsigned int i = 0;
+
+  symbolS *end_of_frame_hdr;
+  symbolS *end_of_frame_section;
+  symbolS *start_of_func_desc_section;
+  symbolS *start_of_fre_section;
+  struct ctf_func_desc_entry *ctf_fde;
+  struct ctf_frame_row_entry *ctf_fre;
+  unsigned char abi_arch = 0;
+  int fixed_bp_offset = CTF_FRAME_CFA_FIXED_FP_INVALID;
+  int fixed_ra_offset = CTF_FRAME_CFA_FIXED_RA_INVALID;
+  unsigned int addr_size;
+
+  addr_size = CTF_FRAME_RELOC_SIZE;
+
+  /* The function desciptor entries as dumped by the assembler are not
+     sorted on PCs.  */
+  unsigned char ctf_frame_flags = 0;
+  ctf_frame_flags |= !CTF_FRAME_F_FDE_SORTED;
+
+  unsigned int num_fdes = get_num_ctf_fdes ();
+  unsigned int num_fres = get_num_ctf_fres ();
+  symbolS **fre_symbols = XNEWVEC (symbolS *, num_fres);
+  for (i = 0; i < num_fres; i++)
+    fre_symbols[i] = symbol_temp_make ();
+
+  end_of_frame_hdr = symbol_temp_make ();
+  start_of_fre_section = symbol_temp_make ();
+  start_of_func_desc_section = symbol_temp_make ();
+  end_of_frame_section = symbol_temp_make ();
+
+  /* Output the preamble of CTF Frame section.  */
+  out_two (CTF_FRAME_MAGIC);
+  out_one (CTF_FRAME_VERSION);
+  out_one (ctf_frame_flags);
+  /* abi/arch.  */
+#ifdef ctf_frame_get_abi_arch
+  abi_arch = ctf_frame_get_abi_arch ();
+#endif
+  gas_assert (abi_arch);
+  out_one (abi_arch);
+
+  /* Offset for the BP register from CFA.  Neither of the AMD64 or AAPCS64
+     ABIs have a fixed offset for the BP register from the CFA.  This may be
+     useful in future (but not without additional support in the toolchain)
+     for specialized handling/encoding for cases where, for example,
+     -fno-omit-frame-pointer is used.  */
+  out_one (fixed_bp_offset);
+
+  /* Offset for the return address from CFA is fixed for some ABIs
+     (e.g., AMD64), output a zero otherwise.  */
+#ifdef CTFF_ROW_ENTRY_RA_TRACKING
+  if (!ctf_frame_ra_tracking_p ())
+    fixed_ra_offset = ctf_frame_cfa_ra_offset ();
+#endif
+  out_one (fixed_ra_offset);
+
+  out_four (num_fdes); /* Number of FDEs.  */
+  out_four (num_fres); /* Number of FREs.  */
+
+  /* FRE sub-section len.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = end_of_frame_section;
+  exp.X_op_symbol = start_of_fre_section;
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  /* Offset of Function Index sub-section.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = end_of_frame_hdr;
+  exp.X_op_symbol = start_of_func_desc_section;
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  /* Offset of FRE sub-section.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = start_of_fre_section;
+  exp.X_op_symbol = end_of_frame_hdr;
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  symbol_set_value_now (end_of_frame_hdr);
+  symbol_set_value_now (start_of_func_desc_section);
+
+  /* Output the CTF Frame function descriptor entries.  */
+  i = 0;
+  for (ctf_fde = all_ctf_fde_data; ctf_fde; ctf_fde = ctf_fde->next)
+    {
+      output_ctf_frame_funcdesc (start_of_fre_section,
+				 fre_symbols[i], ctf_fde);
+      i += ctf_fde->num_fres;
+    }
+
+  symbol_set_value_now (start_of_fre_section);
+
+  /* Output the CTF Frame FREs.  */
+  i = 0;
+  ctf_fde = all_ctf_fde_data;
+
+  for (ctf_fde = all_ctf_fde_data; ctf_fde; ctf_fde = ctf_fde->next)
+    {
+      for (ctf_fre = ctf_fde->ctf_fres; ctf_fre; ctf_fre = ctf_fre->next)
+	{
+	  symbol_set_value_now (fre_symbols[i]);
+	  output_ctf_frame_row_entry (get_dw_fde_start_addrS (ctf_fde->dw_fde),
+				      get_dw_fde_end_addrS (ctf_fde->dw_fde),
+				      ctf_fre);
+	  i++;
+	}
+    }
+
+  symbol_set_value_now (end_of_frame_section);
+
+  gas_assert (i == num_fres);
+
+  free (fre_symbols);
+  fre_symbols = NULL;
+}
+
+/* List of CTF FDE entries.  */
+
+struct ctf_func_desc_entry *all_ctf_fde_data;
+
+/* Tail of the list to add to.  */
+
+static struct ctf_func_desc_entry **last_ctf_fde_data = &all_ctf_fde_data;
+
+static unsigned int
+get_num_ctf_fdes (void)
+{
+  struct ctf_func_desc_entry *ctf_fde;
+  unsigned int total_fdes = 0;
+
+  for (ctf_fde = all_ctf_fde_data; ctf_fde ; ctf_fde = ctf_fde->next)
+    total_fdes++;
+
+  return total_fdes;
+}
+
+/* Get the total number of CTF Frame row entries across the FDEs.  */
+
+static unsigned int
+get_num_ctf_fres (void)
+{
+  struct ctf_func_desc_entry *ctf_fde;
+  unsigned int total_fres = 0;
+
+  for (ctf_fde = all_ctf_fde_data; ctf_fde ; ctf_fde = ctf_fde->next)
+    total_fres += ctf_fde->num_fres;
+
+  return total_fres;
+}
+
+/* Allocate a CTF FDE.  */
+
+static struct ctf_func_desc_entry*
+ctf_fde_alloc (void)
+{
+  struct ctf_func_desc_entry *ctf_fde = XCNEW (struct ctf_func_desc_entry);
+  return ctf_fde;
+}
+
+/* Link the CTF FDE in.  */
+
+static int
+ctf_fde_link (struct ctf_func_desc_entry *ctf_fde)
+{
+  *last_ctf_fde_data = ctf_fde;
+  last_ctf_fde_data = &ctf_fde->next;
+
+  return 0;
+}
+
+/* Free up the CTF FDE.  */
+
+static void
+ctf_fde_free (struct ctf_func_desc_entry *ctf_fde)
+{
+  XDELETE (ctf_fde);
+  ctf_fde = NULL;
+}
+
+/* CTF Frame translation context functions.  */
+
+/* Allocate a new CTF Frame translation context.  */
+
+static struct ctf_frame_xlate_ctx*
+ctf_frame_xlate_ctx_alloc (void)
+{
+  struct ctf_frame_xlate_ctx* xlate_ctx = XCNEW (struct ctf_frame_xlate_ctx);
+  return xlate_ctx;
+}
+
+/* Initialize the given CTF Frame translation context.  */
+
+static void
+ctf_frame_xlate_ctx_init (struct ctf_frame_xlate_ctx *xlate_ctx)
+{
+  xlate_ctx->dw_fde = NULL;
+  xlate_ctx->first_fre = NULL;
+  xlate_ctx->last_fre = NULL;
+  xlate_ctx->cur_fre = NULL;
+  xlate_ctx->remember_fre = NULL;
+  xlate_ctx->num_xlate_fres = 0;
+}
+
+/* Cleanup the given CTF Frame translation context.  */
+
+static void
+ctf_frame_xlate_ctx_cleanup (struct ctf_frame_xlate_ctx *xlate_ctx)
+{
+  struct ctf_frame_row_entry *fre, *fre_next;
+
+  if (xlate_ctx->num_xlate_fres)
+  {
+    fre = xlate_ctx->first_fre;
+    while (fre)
+    {
+      fre_next = fre->next;
+      XDELETE (fre);
+      fre = fre_next;
+    }
+  }
+
+  ctf_frame_xlate_ctx_init (xlate_ctx);
+}
+
+/* Transfer the state from the CTF Frame translation context to the CTF FDE.  */
+
+static void
+ctf_frame_xlate_ctx_finalize (struct ctf_frame_xlate_ctx *xlate_ctx,
+			      struct ctf_func_desc_entry *ctf_fde)
+{
+  ctf_fde->dw_fde = xlate_ctx->dw_fde;
+  ctf_fde->ctf_fres = xlate_ctx->first_fre;
+  ctf_fde->num_fres = xlate_ctx->num_xlate_fres;
+}
+
+static struct ctf_frame_row_entry*
+ctf_frame_row_entry_new (void)
+{
+  struct ctf_frame_row_entry *fre = XCNEW (struct ctf_frame_row_entry);
+  /* Reset cfa_base_reg to -1.  A value of 0 will imply some valid register
+     for the supported arches.  */
+  fre->cfa_base_reg = -1;
+  fre->merge_candidate = true;
+
+  return fre;
+}
+
+/* Add the given FRE in the list of frame row entries in the given FDE
+   translation context.  */
+
+static void
+ctf_frame_xlate_ctx_add_fre (struct ctf_frame_xlate_ctx *xlate_ctx,
+			 struct ctf_frame_row_entry *fre)
+{
+  gas_assert (xlate_ctx && fre);
+
+  /* Add the frame row entry.  */
+  if (!xlate_ctx->first_fre)
+    xlate_ctx->first_fre = fre;
+  else if (xlate_ctx->last_fre)
+    xlate_ctx->last_fre->next = fre;
+
+  xlate_ctx->last_fre = fre;
+
+  /* Keep track of the total number of CTF frame row entries.  */
+  xlate_ctx->num_xlate_fres++;
+}
+
+/* A CTF Frame Row Entry is self-sufficient in terms of unwind information for
+   a given PC.  It contains information assimilated from multiple CFI
+   instructions, and hence, a new CTF FRE is initialized with the data from
+   the previous known FRE, if any.
+
+   Understandably, not all information (especially the instruction begin
+   and end boundaries) needs to be relayed.  Hence, the caller of this API
+   must set the pc_begin and pc_end as applicable.  */
+
+static void
+ctf_frame_row_entry_initialize (struct ctf_frame_row_entry *cur_fre,
+				struct ctf_frame_row_entry *prev_fre)
+{
+  gas_assert (prev_fre);
+  cur_fre->cfa_base_reg = prev_fre->cfa_base_reg;
+  cur_fre->cfa_offset = prev_fre->cfa_offset;
+  cur_fre->bp_loc = prev_fre->bp_loc;
+  cur_fre->bp_offset = prev_fre->bp_offset;
+  cur_fre->ra_loc = prev_fre->ra_loc;
+  cur_fre->ra_offset = prev_fre->ra_offset;
+}
+
+static int
+ctf_xlate_do_advance_loc (struct ctf_frame_xlate_ctx *xlate_ctx,
+			 struct cfi_insn_data *cfi_insn)
+{
+  struct ctf_frame_row_entry *last_fre = xlate_ctx->last_fre;
+  /* Get the scratchpad FRE currently being updated as the cfi_insn's
+     get interpreted.  This FRE eventually gets linked in into the
+     list of FREs for the specific function.  */
+  struct ctf_frame_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  if (cur_fre)
+    {
+      if (!cur_fre->merge_candidate)
+	{
+	  ctf_fre_set_end_addr (cur_fre, cfi_insn->u.ll.lab2);
+
+	  ctf_frame_xlate_ctx_add_fre (xlate_ctx, cur_fre);
+	  last_fre = xlate_ctx->last_fre;
+
+	  xlate_ctx->cur_fre = ctf_frame_row_entry_new ();
+	  cur_fre = xlate_ctx->cur_fre;
+
+	  if (last_fre)
+	    ctf_frame_row_entry_initialize (cur_fre, last_fre);
+	}
+      else
+	{
+	  ctf_fre_set_end_addr (last_fre, cfi_insn->u.ll.lab2);
+	  gas_assert (last_fre->merge_candidate == false);
+	}
+    }
+  else
+    {
+      xlate_ctx->cur_fre = ctf_frame_row_entry_new ();
+      cur_fre = xlate_ctx->cur_fre;
+    }
+
+  gas_assert (cur_fre);
+  ctf_fre_set_begin_addr (cur_fre, cfi_insn->u.ll.lab2);
+
+  return 0;
+}
+
+static int
+ctf_xlate_do_def_cfa (struct ctf_frame_xlate_ctx *xlate_ctx,
+		      struct cfi_insn_data *cfi_insn)
+
+{
+  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
+  struct ctf_frame_row_entry *cur_fre = xlate_ctx->cur_fre;
+  if (!cur_fre)
+  {
+    xlate_ctx->cur_fre = ctf_frame_row_entry_new ();
+    cur_fre = xlate_ctx->cur_fre;
+    ctf_fre_set_begin_addr (cur_fre,
+			    get_dw_fde_start_addrS (xlate_ctx->dw_fde));
+  }
+  /* Define the current CFA rule to use the provided register and
+     offset.  */
+  ctf_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
+  ctf_fre_set_cfa_offset (cur_fre, cfi_insn->u.ri.offset);
+  cur_fre->merge_candidate = false;
+
+  return 0;
+}
+
+static int
+ctf_xlate_do_def_cfa_register (struct ctf_frame_xlate_ctx *xlate_ctx,
+			       struct cfi_insn_data *cfi_insn)
+{
+  struct ctf_frame_row_entry *last_fre = xlate_ctx->last_fre;
+  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
+  struct ctf_frame_row_entry *cur_fre = xlate_ctx->cur_fre;
+  gas_assert (cur_fre);
+  /* Define the current CFA rule to use the provided register (but to
+     keep the old offset).  */
+  ctf_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
+  ctf_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
+  cur_fre->merge_candidate = false;
+
+  return 0;
+}
+
+static int
+ctf_xlate_do_def_cfa_offset (struct ctf_frame_xlate_ctx *xlate_ctx,
+			     struct cfi_insn_data *cfi_insn)
+{
+  /* The scratchpad FRE currently being updated with each cfi_insn
+     being interpreted.  This FRE eventually gets linked in into the
+     list of FREs for the specific function.  */
+  struct ctf_frame_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  gas_assert (cur_fre);
+  /*  Define the current CFA rule to use the provided offset (but to keep
+      the old register).  However, if the old register is not FP/SP,
+      skip creating CTF Frame unwind info for the function. */
+  if ((cur_fre->cfa_base_reg == CTF_FRAME_CFA_FP_REG)
+      || (cur_fre->cfa_base_reg == CTF_FRAME_CFA_SP_REG))
+    {
+      ctf_fre_set_cfa_offset (cur_fre, cfi_insn->u.i);
+      cur_fre->merge_candidate = false;
+    }
+  else
+    return -1;
+
+  return 0;
+}
+
+static int
+ctf_xlate_do_offset (struct ctf_frame_xlate_ctx *xlate_ctx,
+		     struct cfi_insn_data *cfi_insn)
+{
+  /* The scratchpad FRE currently being updated with each cfi_insn
+     being interpreted.  This FRE eventually gets linked in into the
+     list of FREs for the specific function.  */
+  struct ctf_frame_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  gas_assert (cur_fre);
+  /* Change the rule for the register indicated by the register number to
+     be the specified offset.  */
+  if (cfi_insn->u.r == CTF_FRAME_CFA_FP_REG)
+    {
+      gas_assert (!cur_fre->base_reg);
+      ctf_fre_set_bp_track (cur_fre, cfi_insn->u.ri.offset);
+      cur_fre->merge_candidate = false;
+    }
+#ifdef CTFF_ROW_ENTRY_RA_TRACKING
+  else if (ctf_frame_ra_tracking_p ()
+	   && cfi_insn->u.r == CTF_FRAME_CFA_RA_REG)
+    {
+      ctf_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
+      cur_fre->merge_candidate = false;
+    }
+#endif
+  /* This is used to track changes to non-rsp registers, skip all others
+     except FP / RA for now.  */
+  return 0;
+}
+
+static int
+ctf_xlate_do_val_offset (struct ctf_frame_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
+			 struct cfi_insn_data *cfi_insn)
+{
+  /* Previous value of register is CFA + offset.  However, if the specified
+     register is not interesting (FP or RA reg), the current DW_CFA_val_offset
+     instruction can be safely skipped without sacrificing the asynchonicity of
+     unwind information.  */
+  if (cfi_insn->u.r == CTF_FRAME_CFA_FP_REG)
+    return 1; /* Not represented.  */
+#ifdef CTFF_ROW_ENTRY_RA_TRACKING
+  else if (ctf_frame_ra_tracking_p ()
+	   && cfi_insn->u.r == CTF_FRAME_CFA_RA_REG)
+    return 1; /* Not represented.  */
+#endif
+
+  /* Safe to skip.  */
+  return 0;
+}
+
+
+static int
+ctf_xlate_do_remember_state (struct ctf_frame_xlate_ctx *xlate_ctx)
+{
+  struct ctf_frame_row_entry *last_fre = xlate_ctx->last_fre;
+
+  /* If there is no FRE state to remember, nothing to do here.  Return
+     early with non-zero error code, this will cause no CTF Frame unwind info
+     for the function involved.  */
+  if (!last_fre)
+    return -1;
+
+  if (!xlate_ctx->remember_fre)
+    xlate_ctx->remember_fre = ctf_frame_row_entry_new ();
+  ctf_frame_row_entry_initialize (xlate_ctx->remember_fre, last_fre);
+
+  return 0;
+}
+
+static int
+ctf_xlate_do_restore_state (struct ctf_frame_xlate_ctx *xlate_ctx)
+{
+  /* The scratchpad FRE currently being updated with each cfi_insn
+     being interpreted.  This FRE eventually gets linked in into the
+     list of FREs for the specific function.  */
+  struct ctf_frame_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  gas_assert (xlate_ctx->remember_fre);
+  gas_assert (cur_fre && cur_fre->merge_candidate);
+
+  /* Get the CFA state from the DW_CFA_remember_state insn.  */
+  ctf_frame_row_entry_initialize (cur_fre, xlate_ctx->remember_fre);
+  /* The PC boundaries of the current CTF FRE are updated
+     via other machinery.  */
+  cur_fre->merge_candidate = false;
+  return 0;
+}
+
+static int
+ctf_xlate_do_restore (struct ctf_frame_xlate_ctx *xlate_ctx,
+		      struct cfi_insn_data *cfi_insn)
+{
+  struct ctf_frame_row_entry *cie_fre = xlate_ctx->first_fre;
+  /* The scratchpad FRE currently being updated with each cfi_insn
+     being interpreted.  This FRE eventually gets linked in into the
+     list of FREs for the specific function.  */
+  struct ctf_frame_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  /* Change the rule for the indicated register to the rule assigned to
+     it by the initial_instructions in the CIE.  */
+  gas_assert (cie_fre);
+  /* CTF FREs track only CFA and FP / RA for backtracing purposes;
+     skip the other .cfi_restore directives.  */
+  if (cfi_insn->u.r == CTF_FRAME_CFA_FP_REG)
+    {
+      gas_assert (cur_fre);
+      cur_fre->bp_loc = cie_fre->bp_loc;
+      cur_fre->bp_offset = cie_fre->bp_offset;
+      cur_fre->merge_candidate = false;
+    }
+#ifdef CTFF_ROW_ENTRY_RA_TRACKING
+  else if (ctf_frame_ra_tracking_p ()
+	   && cfi_insn->u.r == CTF_FRAME_CFA_RA_REG)
+    {
+      gas_assert (cur_fre);
+      cur_fre->ra_loc = cie_fre->ra_loc;
+      cur_fre->ra_offset = cie_fre->ra_offset;
+      cur_fre->merge_candidate = false;
+    }
+#endif
+  return 0;
+}
+
+/* Process CFI_INSN and update the translation context with the FRE
+   information.
+
+   Returns an error code if CFI_INSN is not successfully processed.  */
+
+static int
+ctf_frame_do_cfi_insn (struct ctf_frame_xlate_ctx *xlate_ctx,
+		       struct cfi_insn_data *cfi_insn)
+{
+  int err = 0;
+
+  /* Atleast one cfi_insn per FDE is expected.  */
+  gas_assert (cfi_insn);
+  int op = cfi_insn->insn;
+
+  switch (op)
+    {
+    case DW_CFA_advance_loc:
+      err = ctf_xlate_do_advance_loc (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_def_cfa:
+      err = ctf_xlate_do_def_cfa (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_def_cfa_register:
+      err = ctf_xlate_do_def_cfa_register (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_def_cfa_offset:
+      err = ctf_xlate_do_def_cfa_offset (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_offset:
+      err = ctf_xlate_do_offset (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_val_offset:
+      err = ctf_xlate_do_val_offset (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_remember_state:
+      err = ctf_xlate_do_remember_state (xlate_ctx);
+      break;
+    case DW_CFA_restore_state:
+      err = ctf_xlate_do_restore_state (xlate_ctx);
+      break;
+    case DW_CFA_restore:
+      err = ctf_xlate_do_restore (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_undefined:
+    case DW_CFA_same_value:
+      break;
+    default:
+      {
+	/* Other CFI opcodes are not processed at this time.
+	   These do not impact the coverage of the basic stack unwinding
+	   information as conveyed in the CTF Frame format.
+	    - DW_CFA_register,
+	    - ...
+
+	   Following skipped operations do, however, impact the asynchronicity:
+	     - CFI_escape,
+	     - DW_CFA_GNU_window_save,
+	     - DW_CFA_AARCH64_negate_ra_state (multiplexed with
+	       DW_CFA_GNU_window_save)  */
+
+	err = 1;
+	// printf (_("CTF Unsupported or unknown Dwarf CFI number: %#x\n"), op);
+      }
+    }
+
+  return err;
+}
+
+static int ctf_frame_do_fde (struct ctf_frame_xlate_ctx *xlate_ctx,
+			     const struct fde_entry *dw_fde)
+{
+  struct cfi_insn_data *cfi_insn;
+
+  xlate_ctx->dw_fde = dw_fde;
+
+  /* If the return column is not RIP, CTF Frame format cannot represent it.  */
+  if (xlate_ctx->dw_fde->return_column != DWARF2_DEFAULT_RETURN_COLUMN)
+    return 1;
+
+  /* Iterate over the CFIs and create CTF FREs.  */
+  for (cfi_insn = dw_fde->data; cfi_insn; cfi_insn = cfi_insn->next)
+    {
+      /* Translate each CFI, and buffer the state in translation context.  */
+      if (ctf_frame_do_cfi_insn (xlate_ctx, cfi_insn))
+	{
+	  /* Skip generating CTF Frame unwind info for the function if any offending
+	     CFI is encountered by ctf_frame_do_cfi_insn ().  */
+	  /* FIXME - get a detailed look at the individual cases.  */
+	  // printf ("WATCH THIS ONE! ctf_frame_do_cfi_insn skipped. \n");
+	  return 1;  /* Error.  */
+	}
+    }
+
+  /* No errors encountered.  */
+
+  /* Link in the scratchpad FRE that the last few CFI insns helped create.  */
+  if (xlate_ctx->cur_fre)
+    {
+      ctf_frame_xlate_ctx_add_fre (xlate_ctx, xlate_ctx->cur_fre);
+      xlate_ctx->cur_fre = NULL;
+    }
+  /* Designate the end of the last CTF FRE.  */
+  if (xlate_ctx->last_fre)
+    {
+      xlate_ctx->last_fre->pc_end
+	= get_dw_fde_end_addrS (xlate_ctx->dw_fde);
+    }
+
+  return 0;
+}
+
+/* Create CTF Frame unwind info for all functions.
+
+   This function consumes the already generated FDEs (by dw2gencfi) and
+   generates unwind data in CTF format.  */
+
+static void create_ctf_frame_all (void)
+{
+  struct fde_entry *dw_fde = NULL;
+  struct ctf_func_desc_entry *ctf_fde = NULL;
+
+  struct ctf_frame_xlate_ctx *xlate_ctx = ctf_frame_xlate_ctx_alloc ();
+
+  for (dw_fde = all_fde_data; dw_fde ; dw_fde = dw_fde->next)
+    {
+      /* FIXME - enable this assert once the compiler is generating
+	 .cfi_sections with .ctf_frame enabled.  */
+      // gas_assert ((fde->sections & CFI_EMIT_ctf_frame));
+      ctf_fde = ctf_fde_alloc ();
+      /* Initialize the translation context with information anew.  */
+      ctf_frame_xlate_ctx_init (xlate_ctx);
+
+      /* Process and link CTF Frame FDEs if no error.  Also skip adding a CTF
+	 FDE if it does not contain any CTF FREs.  There is little use of a CTF
+	 FDE if there is no unwind information about the function.  */
+      int err = ctf_frame_do_fde (xlate_ctx, dw_fde);
+      if (err || xlate_ctx->num_xlate_fres == 0)
+	{
+	  ctf_frame_xlate_ctx_cleanup (xlate_ctx);
+	  ctf_fde_free (ctf_fde);
+	}
+      else
+	{
+	  /* All done.  Transfer the state from the CTF Frame translation
+	     context to the CTF FDE.  */
+	  ctf_frame_xlate_ctx_finalize (xlate_ctx, ctf_fde);
+	  ctf_fde_link (ctf_fde);
+	}
+    }
+}
+
+void output_ctf_frame (segT ctf_frame_seg)
+{
+  (void) ctf_frame_seg;
+
+  /* Setup the version specific access functions.  */
+  ctf_frame_set_version (CTF_FRAME_VERSION_1);
+
+  /* Process all fdes and create CTF Frame unwind information.  */
+  create_ctf_frame_all ();
+
+  output_ctf_frame_internal ();
+}
+
+#else  /*  support_ctf_frame_p  */
+
+/* Callback to create the abi/arch identifier for CTF Frame section.  */
+
+unsigned char
+ctf_frame_get_abi_arch_callback (const char *tarch __attribute__((unused)),
+				 int big_endian_p __attribute__((unused)))
+{
+  unsigned char ctf_frame_abi_arch = 0;
+
+  return ctf_frame_abi_arch;
+}
+
+void output_ctf_frame (segT ctf_frame_seg __attribute__((unused)))
+{
+}
+
+#endif /*  support_ctf_frame_p  */
diff --git a/gas/gen-ctf-frame.h b/gas/gen-ctf-frame.h
new file mode 100644
index 00000000000..6b27a7f2256
--- /dev/null
+++ b/gas/gen-ctf-frame.h
@@ -0,0 +1,142 @@
+/* gen-ctf-frame.h - Support for generating CTF Frame.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS 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, or (at your option)
+   any later version.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#ifndef GENCTFFRAME_H
+#define GENCTFFRAME_H
+
+#define CTF_FRE_ELEM_LOC_REG		0
+#define CTF_FRE_ELEM_LOC_STACK		1
+
+/* CTF Frame Row Entry (FRE).
+
+   A frame row entry is a slice of the frame and can be valid for a set of
+   program instructions.  It keeps all information needed to retrieve the CFA
+   and the Return Address (RA) if tracked.
+
+   A frame row entry effectively stores accumulated information gathered by
+   interpreting multiple CFI instructions.  More precisely, it is a
+   self-sufficient record in its own right.  Only the subset of information
+   necessary for unwinding is stored: Given a PC, how to retrieve the CFA and
+   the RA.
+*/
+
+struct ctf_frame_row_entry
+{
+  /* A linked list.  */
+  struct ctf_frame_row_entry *next;
+
+  /* Start and end of the frame row entry.  */
+  symbolS *pc_begin;
+  symbolS *pc_end;
+
+  /* A frame row entry is a merge candidate if new information can be updated
+     on it.  */
+  bool merge_candidate;
+
+  /* Track CFA base (architectural) register ID.  */
+  unsigned int cfa_base_reg;
+  /* Offset from the CFA base register for recovering CFA.  */
+  offsetT cfa_offset;
+
+  /* Track the other register used as base register for CFA.  Specify whether
+     it is in register or memory.  */
+  unsigned int base_reg;
+  unsigned int bp_loc;
+  /* If the other register is stashed on stack, note the offset.  */
+  offsetT bp_offset;
+
+  /* Track RA location.  Specify whether it is in register or memory.  */
+  unsigned int ra_loc;
+  /* If RA is stashed on stack, note the offset.  */
+  offsetT ra_offset;
+};
+
+/* CTF Function Description Entry.  */
+
+struct ctf_func_desc_entry
+{
+  /* A linked list.  */
+  struct ctf_func_desc_entry *next;
+
+  /* Reference to the FDE created from CFI in dw2gencfi.  Some information
+     like the start_address and the segment is made available via this
+     member.  */
+  const struct fde_entry *dw_fde;
+
+  /* Reference to the first FRE for this function.  */
+  struct ctf_frame_row_entry *ctf_fres;
+
+  unsigned int num_fres;
+};
+
+/* CTF Frame Function Description Entry Translation Context.  */
+
+struct ctf_frame_xlate_ctx
+{
+  /* Reference to the FDE created from CFI in dw2gencfi.  Information
+     like the FDE start_address, end_address and the cfi insns are
+     made available via this member.  */
+  const struct fde_entry *dw_fde;
+
+  /* List of FREs in the current FDE translation context, bounded by first_fre
+     and last_fre.  */
+
+  /* Keep track of the first FRE for the purpose of restoring state if
+     necessary (for DW_CFA_restore).  */
+  struct ctf_frame_row_entry *first_fre;
+  /* The last FRE in the list.  */
+  struct ctf_frame_row_entry *last_fre;
+
+  /* The current FRE under construction.  */
+  struct ctf_frame_row_entry *cur_fre;
+  /* Remember FRE for an eventual restore.  */
+  struct ctf_frame_row_entry *remember_fre;
+
+  unsigned num_xlate_fres;
+};
+
+/* Callback to create the abi/arch identifier for CTF Frame section.  */
+
+unsigned char
+ctf_frame_get_abi_arch_callback (const char *target_arch,
+				 int big_endian_p);
+
+/* The list of all FDEs with data in CTF internal representation.  */
+
+extern struct ctf_func_desc_entry *all_ctf_fde_data;
+
+/* CTF Frame version specific operations structure.  */
+
+struct ctf_frame_version_ops
+{
+  unsigned char format_version;    /* CTF Frame format version.  */
+  /* set CTF Frame FRE info.  */
+  unsigned char (*set_fre_info) (unsigned int, unsigned int, unsigned int);
+  /* set CTF Frame Func info.  */
+  unsigned char (*set_func_info) (unsigned int, unsigned int);
+};
+
+/* Generate CTF Frame unwind info and prepare contents for the output.
+   outout_ctf_frame ()  is called at the end of file.  */
+
+extern void output_ctf_frame (segT ctf_frame_seg);
+
+#endif /* GENCTFFRAME_H */
+
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.d b/gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.d
new file mode 100644
index 00000000000..60ee0f794ea
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.d
@@ -0,0 +1,20 @@
+#as:
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame generation on aarch64
+#...
+Contents of the CTF Frame section .ctf_frame:
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 3
+
+  Function Index :
+
+    func idx \[0\]: pc = 0x0, size = 80 bytes
+    STARTPC +CFA +FP +RA +
+    0+0000 +sp\+0 +u +u +
+    0+0004 +sp\+144 +u +u +
+    0+004c +sp\+0 +u +u +
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.s b/gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.s
new file mode 100644
index 00000000000..44c6124bf70
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-aarch64-1.s
@@ -0,0 +1,61 @@
+        .cfi_sections .ctf_frame
+	.cfi_startproc
+	stp	x19, x20, [sp, -144]!
+	.cfi_def_cfa_offset 144
+	.cfi_offset 19, -144
+	.cfi_offset 20, -136
+	stp	x21, x22, [sp, 16]
+	stp	x23, x24, [sp, 32]
+	stp	x25, x26, [sp, 48]
+	stp	x27, x28, [sp, 64]
+	stp	d8, d9, [sp, 80]
+	stp	d10, d11, [sp, 96]
+	stp	d12, d13, [sp, 112]
+	stp	d14, d15, [sp, 128]
+	.cfi_offset 21, -128
+	.cfi_offset 22, -120
+	.cfi_offset 23, -112
+	.cfi_offset 24, -104
+	.cfi_offset 25, -96
+	.cfi_offset 26, -88
+	.cfi_offset 27, -80
+	.cfi_offset 28, -72
+	.cfi_offset 72, -64
+	.cfi_offset 73, -56
+	.cfi_offset 74, -48
+	.cfi_offset 75, -40
+	.cfi_offset 76, -32
+	.cfi_offset 77, -24
+	.cfi_offset 78, -16
+	.cfi_offset 79, -8
+	nop
+	ldp	x21, x22, [sp, 16]
+	ldp	x23, x24, [sp, 32]
+	ldp	x25, x26, [sp, 48]
+	ldp	x27, x28, [sp, 64]
+	ldp	d8, d9, [sp, 80]
+	ldp	d10, d11, [sp, 96]
+	ldp	d12, d13, [sp, 112]
+	ldp	d14, d15, [sp, 128]
+	ldp	x19, x20, [sp], 144
+	.cfi_restore 20
+	.cfi_restore 19
+	.cfi_restore 78
+	.cfi_restore 79
+	.cfi_restore 76
+	.cfi_restore 77
+	.cfi_restore 74
+	.cfi_restore 75
+	.cfi_restore 72
+	.cfi_restore 73
+	.cfi_restore 27
+	.cfi_restore 28
+	.cfi_restore 25
+	.cfi_restore 26
+	.cfi_restore 23
+	.cfi_restore 24
+	.cfi_restore 21
+	.cfi_restore 22
+	.cfi_def_cfa_offset 0
+	ret
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.d b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.d
new file mode 100644
index 00000000000..d35ab5f62b7
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.d
@@ -0,0 +1,17 @@
+#as: --gctf-frame
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame generation using CFI directive .cfi_sections
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 1
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 0 bytes
+    STARTPC + CFA + FP + RA +
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.s b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.s
new file mode 100644
index 00000000000..112b1212a01
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-1.s
@@ -0,0 +1,3 @@
+	.cfi_sections .ctf_frame
+	.cfi_startproc
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.d b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.d
new file mode 100644
index 00000000000..52eae6d0fa0
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.d
@@ -0,0 +1,17 @@
+#as: --gctf-frame
+#objdump: --ctf-frame=.ctf_frame
+#name: Command line option for generating CTF Frame
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 1
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 0 bytes
+    STARTPC + CFA + FP + RA +
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.s b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.s
new file mode 100644
index 00000000000..659b3b9d99b
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-2.s
@@ -0,0 +1,2 @@
+	.cfi_startproc
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.d b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.d
new file mode 100644
index 00000000000..a30387174cd
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.d
@@ -0,0 +1,17 @@
+#as:
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame can co-exist with EH Frame
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 1
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 0 bytes
+    STARTPC + CFA + FP + RA +
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.s b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.s
new file mode 100644
index 00000000000..c61ad201bdf
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-3.s
@@ -0,0 +1,4 @@
+	.cfi_sections .eh_frame
+	.cfi_sections .ctf_frame
+	.cfi_startproc
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.d b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.d
new file mode 100644
index 00000000000..477abb8a82f
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.d
@@ -0,0 +1,21 @@
+#as: --gctf-frame
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame - cfi_def_cfa_offset test
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 3
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 12 bytes
+    STARTPC + CFA + FP + RA +
+#...
+    0+0004 +sp\+16 +u +u +
+    0+0008 +sp\+32 +u +u +
+
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.s b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.s
new file mode 100644
index 00000000000..0d026bba71a
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-4.s
@@ -0,0 +1,8 @@
+## Testcase for cfi_def_cfa_offset
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 16
+	.long 0
+	.cfi_def_cfa_offset 32
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.d b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.d
new file mode 100644
index 00000000000..e5c115f1f9b
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.d
@@ -0,0 +1,21 @@
+#as: --gctf-frame
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame cfi_adjust_cfa_offset test
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 3
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 12 bytes
+    STARTPC + CFA + FP + RA +
+#...
+    0+0004 +sp\+16 +u +u +
+    0+0008 +sp\+24 +u +u +
+
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.s b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.s
new file mode 100644
index 00000000000..c985c39af9d
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-5.s
@@ -0,0 +1,7 @@
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 16
+	.long 0
+	.cfi_adjust_cfa_offset 8
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.d b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.d
new file mode 100644
index 00000000000..28752bb11b4
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.d
@@ -0,0 +1,21 @@
+#as: --gctf-frame
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame cfi_offset test
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 3
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 12 bytes
+    STARTPC + CFA + FP + RA +
+#...
+    0+0004 +sp\+8 +u +u +
+    0+0008 +sp\+8 +u +u +
+
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.s b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.s
new file mode 100644
index 00000000000..389f324dc5f
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-6.s
@@ -0,0 +1,7 @@
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 8
+	.long 0
+	.cfi_offset 0, 8
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.d b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.d
new file mode 100644
index 00000000000..d9912043338
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.d
@@ -0,0 +1,21 @@
+#as: --gctf-frame
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame cfi_rel_offset test
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 3
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 12 bytes
+    STARTPC + CFA + FP + RA +
+#...
+    0+0004 +sp\+8 +u +u +
+    0+0008 +sp\+8 +u +u +
+
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.s b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.s
new file mode 100644
index 00000000000..21fa031fb30
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-7.s
@@ -0,0 +1,7 @@
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 8
+	.long 0
+	.cfi_rel_offset 1, 8
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.d b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.d
new file mode 100644
index 00000000000..bd0c6cd390d
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.d
@@ -0,0 +1,20 @@
+#as: --gctf-frame
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame cfi_val_offset test
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 2
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 8 bytes
+    STARTPC + CFA + FP + RA +
+#...
+    0+0004 +sp\+16 +u +u +
+
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.s b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.s
new file mode 100644
index 00000000000..4d223e34120
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-common-8.s
@@ -0,0 +1,12 @@
+## cfi_val_offset when used with "not interesting" registers (from the
+## perspective of CTF Frame section, non FP/RA registers are not
+## interesting) does not affect the asynchronicity of the CTF Frame
+## unwind information.  Such CFI directives can be skipped for CTF Frame
+## unwind info generation.
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 16
+	.cfi_val_offset 1, 8
+	.cfi_val_offset 2, -32
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.d b/gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.d
new file mode 100644
index 00000000000..383821c1580
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.d
@@ -0,0 +1,22 @@
+#as: -O0
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame generation on x86_64
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 4
+
+  Function Index :
+
+    func idx \[0\]: pc = 0x0, size = 25 bytes
+    STARTPC +CFA +FP +RA +
+    0+0000 +sp\+8 +u +u +
+    0+0001 +sp\+16 +c\-16 +u +
+    0+0004 +fp\+16 +c\-16 +u +
+    0+0018 +sp\+8 +c\-16 +u +
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.s b/gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.s
new file mode 100644
index 00000000000..49a093ffffa
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf-x86_64-1.s
@@ -0,0 +1,30 @@
+        .cfi_sections .ctf_frame
+	.cfi_startproc
+        pushq   %rbp
+        .cfi_def_cfa_offset 16
+        .cfi_offset 6, -16
+        movq    %rsp, %rbp
+        .cfi_def_cfa_register 6
+        pushq   %r15
+        pushq   %r14
+        pushq   %r13
+        pushq   %r12
+        pushq   %rbx
+  ## These CFI opcodes are not interesting
+  ## for CTF Frame generation and will be
+  ## skipped.
+        .cfi_offset 15, -24
+        .cfi_offset 14, -32
+        .cfi_offset 13, -40
+        .cfi_offset 12, -48
+        .cfi_offset 3, -56
+        nop
+        popq    %rbx
+        popq    %r12
+        popq    %r13
+        popq    %r14
+        popq    %r15
+        popq    %rbp
+        .cfi_def_cfa 7, 8
+        ret
+        .cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/cfi-ctf.exp b/gas/testsuite/gas/cfi-ctf/cfi-ctf.exp
new file mode 100644
index 00000000000..8f49c9a9cc3
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/cfi-ctf.exp
@@ -0,0 +1,58 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+if { ![is_elf_format] } then {
+    return
+}
+
+proc gas_x86_64_check { } {
+    global NM
+    global NMFLAGS
+
+    set status [gas_host_run "$NM $NMFLAGS --help" ""]
+    return [regexp "targets:.*x86-64" [lindex $status 1]];
+}
+
+if  { [istarget "x86_64-*-*"] || [istarget "aarch64-*-*"] } then {
+
+    global ASFLAGS
+    set old_ASFLAGS "$ASFLAGS"
+
+    run_dump_test "cfi-ctf-common-1"
+    run_dump_test "cfi-ctf-common-2"
+    run_dump_test "cfi-ctf-common-3"
+    run_dump_test "cfi-ctf-common-4"
+    run_dump_test "cfi-ctf-common-5"
+    run_dump_test "cfi-ctf-common-6"
+    run_dump_test "cfi-ctf-common-7"
+    run_dump_test "cfi-ctf-common-8"
+
+    run_dump_test "common-empty-1"
+    run_dump_test "common-empty-2"
+    run_dump_test "common-empty-3"
+    run_dump_test "common-empty-4"
+
+    if { [gas_x86_64_check] } then {
+	set ASFLAGS "$ASFLAGS --64"
+	run_dump_test "cfi-ctf-x86_64-1"
+	set ASFLAGS "$old_ASFLAGS"
+    }
+}
+
+# aarch64 specific tests
+if { [istarget "aarch64-*-*"] } then {
+    run_dump_test "cfi-ctf-aarch64-1"
+}
diff --git a/gas/testsuite/gas/cfi-ctf/common-empty-1.d b/gas/testsuite/gas/cfi-ctf/common-empty-1.d
new file mode 100644
index 00000000000..c49aac436c2
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/common-empty-1.d
@@ -0,0 +1,14 @@
+#as: --gctf-frame
+#objdump: --ctf-frame=.ctf_frame
+#name: Uninteresting cfi directives generate an empty CTF Frame section
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/common-empty-1.s b/gas/testsuite/gas/cfi-ctf/common-empty-1.s
new file mode 100644
index 00000000000..91303df269b
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/common-empty-1.s
@@ -0,0 +1,5 @@
+      .cfi_sections .ctf_frame
+      .cfi_startproc
+      .cfi_remember_state
+      .cfi_restore_state
+      .cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/common-empty-2.d b/gas/testsuite/gas/cfi-ctf/common-empty-2.d
new file mode 100644
index 00000000000..e6611568411
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/common-empty-2.d
@@ -0,0 +1,14 @@
+#as: --gctf-frame
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame supports only FP/SP based CFA
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/common-empty-2.s b/gas/testsuite/gas/cfi-ctf/common-empty-2.s
new file mode 100644
index 00000000000..82e0b077b7a
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/common-empty-2.s
@@ -0,0 +1,8 @@
+## CFA register is not defined to be SP/FP.
+## No CTF Frame unwind info for this function will be generated.
+	.cfi_startproc simple
+	.long 0
+	.long 0
+	.cfi_adjust_cfa_offset 16
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/common-empty-3.d b/gas/testsuite/gas/cfi-ctf/common-empty-3.d
new file mode 100644
index 00000000000..9dc3d7bee8a
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/common-empty-3.d
@@ -0,0 +1,14 @@
+#as: --gctf-frame
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame supports only default return column
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/common-empty-3.s b/gas/testsuite/gas/cfi-ctf/common-empty-3.s
new file mode 100644
index 00000000000..5cf164a7e3e
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/common-empty-3.s
@@ -0,0 +1,9 @@
+## The return column is not the default value.
+## No CTF Frame unwind info for this function will be generated.
+	.cfi_startproc
+	.cfi_return_column 0
+	.long 0
+	.long 0
+	.cfi_adjust_cfa_offset 16
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-ctf/common-empty-4.d b/gas/testsuite/gas/cfi-ctf/common-empty-4.d
new file mode 100644
index 00000000000..9dc3d7bee8a
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/common-empty-4.d
@@ -0,0 +1,14 @@
+#as: --gctf-frame
+#objdump: --ctf-frame=.ctf_frame
+#name: CTF Frame supports only default return column
+#...
+Contents of the CTF Frame section .ctf_frame:
+
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-ctf/common-empty-4.s b/gas/testsuite/gas/cfi-ctf/common-empty-4.s
new file mode 100644
index 00000000000..8d80d67da4d
--- /dev/null
+++ b/gas/testsuite/gas/cfi-ctf/common-empty-4.s
@@ -0,0 +1,18 @@
+## ARMv8.3 addded support a new security feature named Pointer Authentication. The
+## main idea behind this is to use the unused bits in the pointer values.
+## Each pointer is patched with a PAC before writing to memory, and is verified
+## before using it.
+## When the pointers are mangled, the unwinder needs to know so it can mask off
+## the PAC from the pointer value to recover the return address, and
+## conversely, skip doing so if the pointers are not mangled.
+## 
+## .cfi_negate_ra_state CFI directive is used to convey this information.
+##
+## CTF Frame does not have any means to represent this information at this time.
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 16
+	.cfi_negate_ra_state
+	.long 0
+	.cfi_endproc
+
diff --git a/gas/write.c b/gas/write.c
index 20f5ce24d5f..90656ab620c 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -487,6 +487,10 @@ cvt_frag_to_fill (segT sec ATTRIBUTE_UNUSED, fragS *fragP)
       dwarf2dbg_convert_frag (fragP);
       break;
 
+    case rs_ctf_frame:
+      ctf_frame_convert_frag (fragP);
+      break;
+
     case rs_machine_dependent:
       md_convert_frag (stdoutput, sec, fragP);
 
@@ -2788,6 +2792,11 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
 	  address += dwarf2dbg_estimate_size_before_relax (fragP);
 	  break;
 
+	case rs_ctf_frame:
+	  /* Initial estimate can be set to atleast 1 byte.  */
+	  address += ctf_frame_estimate_size_before_relax (fragP);
+	  break;
+
 	default:
 	  BAD_CASE (fragP->fr_type);
 	  break;
@@ -3131,6 +3140,10 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
 		growth = dwarf2dbg_relax_frag (fragP);
 		break;
 
+	      case rs_ctf_frame:
+		growth = ctf_frame_relax_frag (fragP);
+		break;
+
 	      default:
 		BAD_CASE (fragP->fr_type);
 		break;
-- 
2.37.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V6 04/10] libctfframe: add the CTF Frame library
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
                   ` (2 preceding siblings ...)
  2022-08-02  8:04 ` [PATCH,V6 03/10] gas: generate .ctf_frame Indu Bhagat
@ 2022-08-02  8:04 ` Indu Bhagat
  2022-08-15 12:46   ` Nick Clifton
  2022-08-02  8:04 ` [PATCH,V6 05/10] libctfframe: add GNU poke pickles for CTF Frame Indu Bhagat
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-08-02  8:04 UTC (permalink / raw)
  To: binutils

From: Weimin Pan <weimin.pan@oracle.com>

[Changes from V5]
 - testuite fixes for various warnings on x86_64-linux.
 - libctfframe testsuite now uses recursive makefiles for building the
   test programs.  This keeps the test machinery simple.  These tests
   use the host compiler to build the tests.
 - The test programs in libctfframe testsuite now use dejagnu pass () /
   fail () methods.
[End of changes from V5]

[No changes in V4]

[Changes from V3]
 - Bugfixes around endian flipping code.
 - ctf_frame_find_fre () API now performs the checks according to the
   type of FDE:
   For CTF_FRAME_DESCRIPTOR_ENTRY_TYPE_ADDRINC: return the entry where
   (PC >= fre_start_addr)
   For CTF_FRAME_DESCRIPTOR_ENTRY_TYPE_ADDRMASK: return the entry where
   (PC & MASK >= MASK)
 - Additional testcases for CTF Frame encoder and endian flipping.
[End of changes from V3]

[Changes from V2]
 - consistent use of terminology around CTF Frame and its components.
 - Added testsuite for CTF frame decoder.
[End of changes from V2]

[Changes from V1]
 - bugfixes
[End of changes from V1]

libctfframe is a library that allows you to:
- decode a .ctf_frame section
- probe and inspect a .ctf_frame section
- encode (and eventually write) a .ctf_frame section.

This library is currently being used by the linker, readelf, objdump and
the unwinder.

The file include/ctf-frame-api.h defines the user-facing APIs for decoding,
encoding and probing .ctf_frame sections. A set of error codes together
with their error message strings are also defined.

Endian flipping is performed automatically at read and write time, if
cross-endianness is detected.

PS: libctfframe/configure has NOT been included in the patch.  Please
regenerate.

ChangeLog:

	* Makefile.def: Add libctfframe as new module with its
	dependencies.
	* Makefile.in: Regenerated.
	* binutils/Makefile.am: Add libctfframe.
	* binutils/Makefile.in: Regenerated.
	* configure: Regenerated
	* configure.ac: Add libctfframe to host_libs.
	* libctfframe/Makefile.am: New file.
	* libctfframe/Makefile.in: New file.
	* libctfframe/aclocal.m4: New file.
	* libctfframe/config.h.in: New file.
	* libctfframe/configure: New file.  <-- [REMOVED FROM THE PATCH.
	  PLEASE REGENERATE.]
	* libctfframe/configure.ac: New file.
	* libctfframe/ctf-frame-error.c: New file.
	* libctfframe/ctf-frame-impl.h: New file.
	* libctfframe/ctf-frame.c: New file.

include/ChangeLog:

	* ctf-frame-api.h: New file.

testsuite/ChangeLog:

	* libctfframe/testsuite/Makefile.am: New file.
	* libctfframe/testsuite/Makefile.in: Regenerated.
	* libctfframe/testsuite/libctfframe.decode/Makefile.am: New
	  file.
	* libctfframe/testsuite/libctfframe.decode/Makefile.in:
	  Regenerated.
	* libctfframe/testsuite/libctfframe.decode/decode.exp: New file.
	* libctfframe/testsuite/libctfframe.encode/Makefile.am:
	  Likewise.
	* libctfframe/testsuite/libctfframe.encode/Makefile.in:
	  Regenerated.
	* libctfframe/testsuite/libctfframe.encode/encode.exp: New file.
	* libctfframe/testsuite/libctfframe.decode/bigendian_data.c:
	  Likewise.
	* libctfframe/testsuite/libctfframe.decode/frecnt_1.c: Likewise.
	* libctfframe/testsuite/libctfframe.decode/frecnt_2.c: Likewise.
---
 Makefile.def                                  |    2 +
 Makefile.in                                   | 1288 +++++++++++++-
 binutils/Makefile.am                          |    2 +
 binutils/Makefile.in                          |    1 +
 configure                                     |    2 +-
 configure.ac                                  |    2 +-
 include/ctf-frame-api.h                       |  210 +++
 libctfframe/Makefile.am                       |   43 +
 libctfframe/Makefile.in                       | 1048 +++++++++++
 libctfframe/aclocal.m4                        | 1241 +++++++++++++
 libctfframe/config.h.in                       |  144 ++
 libctfframe/configure.ac                      |   78 +
 libctfframe/ctf-frame-error.c                 |   49 +
 libctfframe/ctf-frame-impl.h                  |   55 +
 libctfframe/ctf-frame.c                       | 1569 +++++++++++++++++
 libctfframe/testsuite/Makefile.am             |   23 +
 libctfframe/testsuite/Makefile.in             |  682 +++++++
 libctfframe/testsuite/config/default.exp      |   54 +
 .../testsuite/libctfframe.decode/DATA1        |  Bin 0 -> 59 bytes
 .../testsuite/libctfframe.decode/DATA2        |  Bin 0 -> 91 bytes
 .../testsuite/libctfframe.decode/DATA_BIGE    |  Bin 0 -> 59 bytes
 .../testsuite/libctfframe.decode/Makefile.am  |   14 +
 .../testsuite/libctfframe.decode/Makefile.in  |  661 +++++++
 .../libctfframe.decode/bigendian_data.c       |  107 ++
 .../testsuite/libctfframe.decode/decode.exp   |   41 +
 .../testsuite/libctfframe.decode/frecnt_1.c   |   99 ++
 .../testsuite/libctfframe.decode/frecnt_2.c   |  103 ++
 .../testsuite/libctfframe.encode/Makefile.am  |    6 +
 .../testsuite/libctfframe.encode/Makefile.in  |  608 +++++++
 .../testsuite/libctfframe.encode/encode.exp   |   25 +
 .../testsuite/libctfframe.encode/encode_1.c   |  182 ++
 31 files changed, 8332 insertions(+), 7 deletions(-)
 create mode 100644 include/ctf-frame-api.h
 create mode 100644 libctfframe/Makefile.am
 create mode 100644 libctfframe/Makefile.in
 create mode 100644 libctfframe/aclocal.m4
 create mode 100644 libctfframe/config.h.in
 create mode 100644 libctfframe/configure.ac
 create mode 100644 libctfframe/ctf-frame-error.c
 create mode 100644 libctfframe/ctf-frame-impl.h
 create mode 100644 libctfframe/ctf-frame.c
 create mode 100644 libctfframe/testsuite/Makefile.am
 create mode 100644 libctfframe/testsuite/Makefile.in
 create mode 100644 libctfframe/testsuite/config/default.exp
 create mode 100644 libctfframe/testsuite/libctfframe.decode/DATA1
 create mode 100644 libctfframe/testsuite/libctfframe.decode/DATA2
 create mode 100644 libctfframe/testsuite/libctfframe.decode/DATA_BIGE
 create mode 100644 libctfframe/testsuite/libctfframe.decode/Makefile.am
 create mode 100644 libctfframe/testsuite/libctfframe.decode/Makefile.in
 create mode 100644 libctfframe/testsuite/libctfframe.decode/bigendian_data.c
 create mode 100644 libctfframe/testsuite/libctfframe.decode/decode.exp
 create mode 100644 libctfframe/testsuite/libctfframe.decode/frecnt_1.c
 create mode 100644 libctfframe/testsuite/libctfframe.decode/frecnt_2.c
 create mode 100644 libctfframe/testsuite/libctfframe.encode/Makefile.am
 create mode 100644 libctfframe/testsuite/libctfframe.encode/Makefile.in
 create mode 100644 libctfframe/testsuite/libctfframe.encode/encode.exp
 create mode 100644 libctfframe/testsuite/libctfframe.encode/encode_1.c

diff --git a/Makefile.def b/Makefile.def
index acdcd625ed6..a63c3966513 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -149,6 +149,7 @@ host_modules= { module= lto-plugin; bootstrap=true;
 host_modules= { module= libcc1; extra_configure_flags=--enable-shared; };
 host_modules= { module= gotools; };
 host_modules= { module= libctf; bootstrap=true; };
+host_modules= { module=libctfframe; bootstrap=true; };
 
 target_modules = { module= libstdc++-v3;
 		   bootstrap=true;
@@ -478,6 +479,7 @@ dependencies = { module=all-binutils; on=all-intl; };
 dependencies = { module=all-binutils; on=all-gas; };
 dependencies = { module=all-binutils; on=all-libctf; };
 dependencies = { module=all-ld; on=all-libctf; };
+dependencies = { module=all-binutils; on=all-libctfframe; };
 
 // We put install-opcodes before install-binutils because the installed
 // binutils might be on PATH, and they might need the shared opcodes
diff --git a/Makefile.in b/Makefile.in
index cb39e4790d6..7b93fd14ffb 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1109,7 +1109,8 @@ configure-host:  \
     maybe-configure-lto-plugin \
     maybe-configure-libcc1 \
     maybe-configure-gotools \
-    maybe-configure-libctf
+    maybe-configure-libctf \
+    maybe-configure-libctfframe
 .PHONY: configure-target
 configure-target:  \
     maybe-configure-target-libstdc++-v3 \
@@ -1290,6 +1291,9 @@ all-host: maybe-all-gotools
 @if libctf-no-bootstrap
 all-host: maybe-all-libctf
 @endif libctf-no-bootstrap
+@if libctfframe-no-bootstrap
+all-host: maybe-all-libctfframe
+@endif libctfframe-no-bootstrap
 
 .PHONY: all-target
 
@@ -1396,6 +1400,7 @@ info-host: maybe-info-lto-plugin
 info-host: maybe-info-libcc1
 info-host: maybe-info-gotools
 info-host: maybe-info-libctf
+info-host: maybe-info-libctfframe
 
 .PHONY: info-target
 
@@ -1487,6 +1492,7 @@ dvi-host: maybe-dvi-lto-plugin
 dvi-host: maybe-dvi-libcc1
 dvi-host: maybe-dvi-gotools
 dvi-host: maybe-dvi-libctf
+dvi-host: maybe-dvi-libctfframe
 
 .PHONY: dvi-target
 
@@ -1578,6 +1584,7 @@ pdf-host: maybe-pdf-lto-plugin
 pdf-host: maybe-pdf-libcc1
 pdf-host: maybe-pdf-gotools
 pdf-host: maybe-pdf-libctf
+pdf-host: maybe-pdf-libctfframe
 
 .PHONY: pdf-target
 
@@ -1669,6 +1676,7 @@ html-host: maybe-html-lto-plugin
 html-host: maybe-html-libcc1
 html-host: maybe-html-gotools
 html-host: maybe-html-libctf
+html-host: maybe-html-libctfframe
 
 .PHONY: html-target
 
@@ -1760,6 +1768,7 @@ TAGS-host: maybe-TAGS-lto-plugin
 TAGS-host: maybe-TAGS-libcc1
 TAGS-host: maybe-TAGS-gotools
 TAGS-host: maybe-TAGS-libctf
+TAGS-host: maybe-TAGS-libctfframe
 
 .PHONY: TAGS-target
 
@@ -1851,6 +1860,7 @@ install-info-host: maybe-install-info-lto-plugin
 install-info-host: maybe-install-info-libcc1
 install-info-host: maybe-install-info-gotools
 install-info-host: maybe-install-info-libctf
+install-info-host: maybe-install-info-libctfframe
 
 .PHONY: install-info-target
 
@@ -1942,6 +1952,7 @@ install-dvi-host: maybe-install-dvi-lto-plugin
 install-dvi-host: maybe-install-dvi-libcc1
 install-dvi-host: maybe-install-dvi-gotools
 install-dvi-host: maybe-install-dvi-libctf
+install-dvi-host: maybe-install-dvi-libctfframe
 
 .PHONY: install-dvi-target
 
@@ -2033,6 +2044,7 @@ install-pdf-host: maybe-install-pdf-lto-plugin
 install-pdf-host: maybe-install-pdf-libcc1
 install-pdf-host: maybe-install-pdf-gotools
 install-pdf-host: maybe-install-pdf-libctf
+install-pdf-host: maybe-install-pdf-libctfframe
 
 .PHONY: install-pdf-target
 
@@ -2124,6 +2136,7 @@ install-html-host: maybe-install-html-lto-plugin
 install-html-host: maybe-install-html-libcc1
 install-html-host: maybe-install-html-gotools
 install-html-host: maybe-install-html-libctf
+install-html-host: maybe-install-html-libctfframe
 
 .PHONY: install-html-target
 
@@ -2215,6 +2228,7 @@ installcheck-host: maybe-installcheck-lto-plugin
 installcheck-host: maybe-installcheck-libcc1
 installcheck-host: maybe-installcheck-gotools
 installcheck-host: maybe-installcheck-libctf
+installcheck-host: maybe-installcheck-libctfframe
 
 .PHONY: installcheck-target
 
@@ -2306,6 +2320,7 @@ mostlyclean-host: maybe-mostlyclean-lto-plugin
 mostlyclean-host: maybe-mostlyclean-libcc1
 mostlyclean-host: maybe-mostlyclean-gotools
 mostlyclean-host: maybe-mostlyclean-libctf
+mostlyclean-host: maybe-mostlyclean-libctfframe
 
 .PHONY: mostlyclean-target
 
@@ -2397,6 +2412,7 @@ clean-host: maybe-clean-lto-plugin
 clean-host: maybe-clean-libcc1
 clean-host: maybe-clean-gotools
 clean-host: maybe-clean-libctf
+clean-host: maybe-clean-libctfframe
 
 .PHONY: clean-target
 
@@ -2488,6 +2504,7 @@ distclean-host: maybe-distclean-lto-plugin
 distclean-host: maybe-distclean-libcc1
 distclean-host: maybe-distclean-gotools
 distclean-host: maybe-distclean-libctf
+distclean-host: maybe-distclean-libctfframe
 
 .PHONY: distclean-target
 
@@ -2579,6 +2596,7 @@ maintainer-clean-host: maybe-maintainer-clean-lto-plugin
 maintainer-clean-host: maybe-maintainer-clean-libcc1
 maintainer-clean-host: maybe-maintainer-clean-gotools
 maintainer-clean-host: maybe-maintainer-clean-libctf
+maintainer-clean-host: maybe-maintainer-clean-libctfframe
 
 .PHONY: maintainer-clean-target
 
@@ -2727,7 +2745,8 @@ check-host:  \
     maybe-check-lto-plugin \
     maybe-check-libcc1 \
     maybe-check-gotools \
-    maybe-check-libctf
+    maybe-check-libctf \
+    maybe-check-libctfframe
 
 .PHONY: check-target
 check-target:  \
@@ -2865,7 +2884,8 @@ install-host-nogcc:  \
     maybe-install-lto-plugin \
     maybe-install-libcc1 \
     maybe-install-gotools \
-    maybe-install-libctf
+    maybe-install-libctf \
+    maybe-install-libctfframe
 
 .PHONY: install-host
 install-host:  \
@@ -2921,7 +2941,8 @@ install-host:  \
     maybe-install-lto-plugin \
     maybe-install-libcc1 \
     maybe-install-gotools \
-    maybe-install-libctf
+    maybe-install-libctf \
+    maybe-install-libctfframe
 
 .PHONY: install-target
 install-target:  \
@@ -3032,7 +3053,8 @@ install-strip-host:  \
     maybe-install-strip-lto-plugin \
     maybe-install-strip-libcc1 \
     maybe-install-strip-gotools \
-    maybe-install-strip-libctf
+    maybe-install-strip-libctf \
+    maybe-install-strip-libctfframe
 
 .PHONY: install-strip-target
 install-strip-target:  \
@@ -44044,6 +44066,1146 @@ maintainer-clean-libctf:
 
 
 
+.PHONY: configure-libctfframe maybe-configure-libctfframe
+maybe-configure-libctfframe:
+@if gcc-bootstrap
+configure-libctfframe: stage_current
+@endif gcc-bootstrap
+@if libctfframe
+maybe-configure-libctfframe: configure-libctfframe
+configure-libctfframe: 
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	test ! -f $(HOST_SUBDIR)/libctfframe/Makefile || exit 0; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe; \
+	$(HOST_EXPORTS)  \
+	echo Configuring in $(HOST_SUBDIR)/libctfframe; \
+	cd "$(HOST_SUBDIR)/libctfframe" || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctfframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctfframe; \
+	$(SHELL) \
+	  $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias}  \
+	  || exit 1
+@endif libctfframe
+
+
+
+.PHONY: configure-stage1-libctfframe maybe-configure-stage1-libctfframe
+maybe-configure-stage1-libctfframe:
+@if libctfframe-bootstrap
+maybe-configure-stage1-libctfframe: configure-stage1-libctfframe
+configure-stage1-libctfframe:
+	@[ $(current_stage) = stage1 ] || $(MAKE) stage1-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE1_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctfframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	CFLAGS="$(STAGE1_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE1_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(LIBCFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 1 in $(HOST_SUBDIR)/libctfframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe; \
+	cd $(HOST_SUBDIR)/libctfframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctfframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctfframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	   \
+	  $(STAGE1_CONFIGURE_FLAGS)
+@endif libctfframe-bootstrap
+
+.PHONY: configure-stage2-libctfframe maybe-configure-stage2-libctfframe
+maybe-configure-stage2-libctfframe:
+@if libctfframe-bootstrap
+maybe-configure-stage2-libctfframe: configure-stage2-libctfframe
+configure-stage2-libctfframe:
+	@[ $(current_stage) = stage2 ] || $(MAKE) stage2-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE2_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctfframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGE2_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE2_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGE2_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 2 in $(HOST_SUBDIR)/libctfframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe; \
+	cd $(HOST_SUBDIR)/libctfframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctfframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctfframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGE2_CONFIGURE_FLAGS)
+@endif libctfframe-bootstrap
+
+.PHONY: configure-stage3-libctfframe maybe-configure-stage3-libctfframe
+maybe-configure-stage3-libctfframe:
+@if libctfframe-bootstrap
+maybe-configure-stage3-libctfframe: configure-stage3-libctfframe
+configure-stage3-libctfframe:
+	@[ $(current_stage) = stage3 ] || $(MAKE) stage3-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE3_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctfframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGE3_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE3_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGE3_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 3 in $(HOST_SUBDIR)/libctfframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe; \
+	cd $(HOST_SUBDIR)/libctfframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctfframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctfframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGE3_CONFIGURE_FLAGS)
+@endif libctfframe-bootstrap
+
+.PHONY: configure-stage4-libctfframe maybe-configure-stage4-libctfframe
+maybe-configure-stage4-libctfframe:
+@if libctfframe-bootstrap
+maybe-configure-stage4-libctfframe: configure-stage4-libctfframe
+configure-stage4-libctfframe:
+	@[ $(current_stage) = stage4 ] || $(MAKE) stage4-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE4_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctfframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGE4_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE4_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGE4_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 4 in $(HOST_SUBDIR)/libctfframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe; \
+	cd $(HOST_SUBDIR)/libctfframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctfframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctfframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGE4_CONFIGURE_FLAGS)
+@endif libctfframe-bootstrap
+
+.PHONY: configure-stageprofile-libctfframe maybe-configure-stageprofile-libctfframe
+maybe-configure-stageprofile-libctfframe:
+@if libctfframe-bootstrap
+maybe-configure-stageprofile-libctfframe: configure-stageprofile-libctfframe
+configure-stageprofile-libctfframe:
+	@[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEprofile_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctfframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEprofile_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEprofile_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEprofile_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage profile in $(HOST_SUBDIR)/libctfframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe; \
+	cd $(HOST_SUBDIR)/libctfframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctfframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctfframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEprofile_CONFIGURE_FLAGS)
+@endif libctfframe-bootstrap
+
+.PHONY: configure-stagetrain-libctfframe maybe-configure-stagetrain-libctfframe
+maybe-configure-stagetrain-libctfframe:
+@if libctfframe-bootstrap
+maybe-configure-stagetrain-libctfframe: configure-stagetrain-libctfframe
+configure-stagetrain-libctfframe:
+	@[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEtrain_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctfframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEtrain_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEtrain_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEtrain_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage train in $(HOST_SUBDIR)/libctfframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe; \
+	cd $(HOST_SUBDIR)/libctfframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctfframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctfframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEtrain_CONFIGURE_FLAGS)
+@endif libctfframe-bootstrap
+
+.PHONY: configure-stagefeedback-libctfframe maybe-configure-stagefeedback-libctfframe
+maybe-configure-stagefeedback-libctfframe:
+@if libctfframe-bootstrap
+maybe-configure-stagefeedback-libctfframe: configure-stagefeedback-libctfframe
+configure-stagefeedback-libctfframe:
+	@[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEfeedback_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctfframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEfeedback_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEfeedback_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEfeedback_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage feedback in $(HOST_SUBDIR)/libctfframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe; \
+	cd $(HOST_SUBDIR)/libctfframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctfframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctfframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEfeedback_CONFIGURE_FLAGS)
+@endif libctfframe-bootstrap
+
+.PHONY: configure-stageautoprofile-libctfframe maybe-configure-stageautoprofile-libctfframe
+maybe-configure-stageautoprofile-libctfframe:
+@if libctfframe-bootstrap
+maybe-configure-stageautoprofile-libctfframe: configure-stageautoprofile-libctfframe
+configure-stageautoprofile-libctfframe:
+	@[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEautoprofile_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctfframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEautoprofile_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEautoprofile_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEautoprofile_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage autoprofile in $(HOST_SUBDIR)/libctfframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe; \
+	cd $(HOST_SUBDIR)/libctfframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctfframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctfframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEautoprofile_CONFIGURE_FLAGS)
+@endif libctfframe-bootstrap
+
+.PHONY: configure-stageautofeedback-libctfframe maybe-configure-stageautofeedback-libctfframe
+maybe-configure-stageautofeedback-libctfframe:
+@if libctfframe-bootstrap
+maybe-configure-stageautofeedback-libctfframe: configure-stageautofeedback-libctfframe
+configure-stageautofeedback-libctfframe:
+	@[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEautofeedback_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libctfframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEautofeedback_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEautofeedback_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEautofeedback_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage autofeedback in $(HOST_SUBDIR)/libctfframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libctfframe; \
+	cd $(HOST_SUBDIR)/libctfframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libctfframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libctfframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEautofeedback_CONFIGURE_FLAGS)
+@endif libctfframe-bootstrap
+
+
+
+
+
+.PHONY: all-libctfframe maybe-all-libctfframe
+maybe-all-libctfframe:
+@if gcc-bootstrap
+all-libctfframe: stage_current
+@endif gcc-bootstrap
+@if libctfframe
+TARGET-libctfframe=all
+maybe-all-libctfframe: all-libctfframe
+all-libctfframe: configure-libctfframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS)  \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_HOST_FLAGS) $(STAGE1_FLAGS_TO_PASS)  \
+		$(TARGET-libctfframe))
+@endif libctfframe
+
+
+
+.PHONY: all-stage1-libctfframe maybe-all-stage1-libctfframe
+.PHONY: clean-stage1-libctfframe maybe-clean-stage1-libctfframe
+maybe-all-stage1-libctfframe:
+maybe-clean-stage1-libctfframe:
+@if libctfframe-bootstrap
+maybe-all-stage1-libctfframe: all-stage1-libctfframe
+all-stage1: all-stage1-libctfframe
+TARGET-stage1-libctfframe = $(TARGET-libctfframe)
+all-stage1-libctfframe: configure-stage1-libctfframe
+	@[ $(current_stage) = stage1 ] || $(MAKE) stage1-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE1_TFLAGS)"; \
+	$(HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE1_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGE1_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGE1_CXXFLAGS)" \
+		LIBCFLAGS="$(LIBCFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS)  \
+		$(STAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE1_TFLAGS)"  \
+		$(TARGET-stage1-libctfframe)
+
+maybe-clean-stage1-libctfframe: clean-stage1-libctfframe
+clean-stage1: clean-stage1-libctfframe
+clean-stage1-libctfframe:
+	@if [ $(current_stage) = stage1 ]; then \
+	  [ -f $(HOST_SUBDIR)/libctfframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage1-libctfframe/Makefile ] || exit 0; \
+	  $(MAKE) stage1-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS)  \
+	$(STAGE1_FLAGS_TO_PASS)  clean
+@endif libctfframe-bootstrap
+
+
+.PHONY: all-stage2-libctfframe maybe-all-stage2-libctfframe
+.PHONY: clean-stage2-libctfframe maybe-clean-stage2-libctfframe
+maybe-all-stage2-libctfframe:
+maybe-clean-stage2-libctfframe:
+@if libctfframe-bootstrap
+maybe-all-stage2-libctfframe: all-stage2-libctfframe
+all-stage2: all-stage2-libctfframe
+TARGET-stage2-libctfframe = $(TARGET-libctfframe)
+all-stage2-libctfframe: configure-stage2-libctfframe
+	@[ $(current_stage) = stage2 ] || $(MAKE) stage2-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE2_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE2_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGE2_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGE2_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGE2_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE2_TFLAGS)"  \
+		$(TARGET-stage2-libctfframe)
+
+maybe-clean-stage2-libctfframe: clean-stage2-libctfframe
+clean-stage2: clean-stage2-libctfframe
+clean-stage2-libctfframe:
+	@if [ $(current_stage) = stage2 ]; then \
+	  [ -f $(HOST_SUBDIR)/libctfframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage2-libctfframe/Makefile ] || exit 0; \
+	  $(MAKE) stage2-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctfframe-bootstrap
+
+
+.PHONY: all-stage3-libctfframe maybe-all-stage3-libctfframe
+.PHONY: clean-stage3-libctfframe maybe-clean-stage3-libctfframe
+maybe-all-stage3-libctfframe:
+maybe-clean-stage3-libctfframe:
+@if libctfframe-bootstrap
+maybe-all-stage3-libctfframe: all-stage3-libctfframe
+all-stage3: all-stage3-libctfframe
+TARGET-stage3-libctfframe = $(TARGET-libctfframe)
+all-stage3-libctfframe: configure-stage3-libctfframe
+	@[ $(current_stage) = stage3 ] || $(MAKE) stage3-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE3_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE3_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGE3_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGE3_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGE3_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE3_TFLAGS)"  \
+		$(TARGET-stage3-libctfframe)
+
+maybe-clean-stage3-libctfframe: clean-stage3-libctfframe
+clean-stage3: clean-stage3-libctfframe
+clean-stage3-libctfframe:
+	@if [ $(current_stage) = stage3 ]; then \
+	  [ -f $(HOST_SUBDIR)/libctfframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage3-libctfframe/Makefile ] || exit 0; \
+	  $(MAKE) stage3-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctfframe-bootstrap
+
+
+.PHONY: all-stage4-libctfframe maybe-all-stage4-libctfframe
+.PHONY: clean-stage4-libctfframe maybe-clean-stage4-libctfframe
+maybe-all-stage4-libctfframe:
+maybe-clean-stage4-libctfframe:
+@if libctfframe-bootstrap
+maybe-all-stage4-libctfframe: all-stage4-libctfframe
+all-stage4: all-stage4-libctfframe
+TARGET-stage4-libctfframe = $(TARGET-libctfframe)
+all-stage4-libctfframe: configure-stage4-libctfframe
+	@[ $(current_stage) = stage4 ] || $(MAKE) stage4-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE4_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE4_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGE4_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGE4_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGE4_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE4_TFLAGS)"  \
+		$(TARGET-stage4-libctfframe)
+
+maybe-clean-stage4-libctfframe: clean-stage4-libctfframe
+clean-stage4: clean-stage4-libctfframe
+clean-stage4-libctfframe:
+	@if [ $(current_stage) = stage4 ]; then \
+	  [ -f $(HOST_SUBDIR)/libctfframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage4-libctfframe/Makefile ] || exit 0; \
+	  $(MAKE) stage4-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctfframe-bootstrap
+
+
+.PHONY: all-stageprofile-libctfframe maybe-all-stageprofile-libctfframe
+.PHONY: clean-stageprofile-libctfframe maybe-clean-stageprofile-libctfframe
+maybe-all-stageprofile-libctfframe:
+maybe-clean-stageprofile-libctfframe:
+@if libctfframe-bootstrap
+maybe-all-stageprofile-libctfframe: all-stageprofile-libctfframe
+all-stageprofile: all-stageprofile-libctfframe
+TARGET-stageprofile-libctfframe = $(TARGET-libctfframe)
+all-stageprofile-libctfframe: configure-stageprofile-libctfframe
+	@[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEprofile_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEprofile_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGEprofile_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGEprofile_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEprofile_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEprofile_TFLAGS)"  \
+		$(TARGET-stageprofile-libctfframe)
+
+maybe-clean-stageprofile-libctfframe: clean-stageprofile-libctfframe
+clean-stageprofile: clean-stageprofile-libctfframe
+clean-stageprofile-libctfframe:
+	@if [ $(current_stage) = stageprofile ]; then \
+	  [ -f $(HOST_SUBDIR)/libctfframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stageprofile-libctfframe/Makefile ] || exit 0; \
+	  $(MAKE) stageprofile-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctfframe-bootstrap
+
+
+.PHONY: all-stagetrain-libctfframe maybe-all-stagetrain-libctfframe
+.PHONY: clean-stagetrain-libctfframe maybe-clean-stagetrain-libctfframe
+maybe-all-stagetrain-libctfframe:
+maybe-clean-stagetrain-libctfframe:
+@if libctfframe-bootstrap
+maybe-all-stagetrain-libctfframe: all-stagetrain-libctfframe
+all-stagetrain: all-stagetrain-libctfframe
+TARGET-stagetrain-libctfframe = $(TARGET-libctfframe)
+all-stagetrain-libctfframe: configure-stagetrain-libctfframe
+	@[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEtrain_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEtrain_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGEtrain_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGEtrain_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEtrain_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEtrain_TFLAGS)"  \
+		$(TARGET-stagetrain-libctfframe)
+
+maybe-clean-stagetrain-libctfframe: clean-stagetrain-libctfframe
+clean-stagetrain: clean-stagetrain-libctfframe
+clean-stagetrain-libctfframe:
+	@if [ $(current_stage) = stagetrain ]; then \
+	  [ -f $(HOST_SUBDIR)/libctfframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stagetrain-libctfframe/Makefile ] || exit 0; \
+	  $(MAKE) stagetrain-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctfframe-bootstrap
+
+
+.PHONY: all-stagefeedback-libctfframe maybe-all-stagefeedback-libctfframe
+.PHONY: clean-stagefeedback-libctfframe maybe-clean-stagefeedback-libctfframe
+maybe-all-stagefeedback-libctfframe:
+maybe-clean-stagefeedback-libctfframe:
+@if libctfframe-bootstrap
+maybe-all-stagefeedback-libctfframe: all-stagefeedback-libctfframe
+all-stagefeedback: all-stagefeedback-libctfframe
+TARGET-stagefeedback-libctfframe = $(TARGET-libctfframe)
+all-stagefeedback-libctfframe: configure-stagefeedback-libctfframe
+	@[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEfeedback_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEfeedback_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGEfeedback_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGEfeedback_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEfeedback_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEfeedback_TFLAGS)"  \
+		$(TARGET-stagefeedback-libctfframe)
+
+maybe-clean-stagefeedback-libctfframe: clean-stagefeedback-libctfframe
+clean-stagefeedback: clean-stagefeedback-libctfframe
+clean-stagefeedback-libctfframe:
+	@if [ $(current_stage) = stagefeedback ]; then \
+	  [ -f $(HOST_SUBDIR)/libctfframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stagefeedback-libctfframe/Makefile ] || exit 0; \
+	  $(MAKE) stagefeedback-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctfframe-bootstrap
+
+
+.PHONY: all-stageautoprofile-libctfframe maybe-all-stageautoprofile-libctfframe
+.PHONY: clean-stageautoprofile-libctfframe maybe-clean-stageautoprofile-libctfframe
+maybe-all-stageautoprofile-libctfframe:
+maybe-clean-stageautoprofile-libctfframe:
+@if libctfframe-bootstrap
+maybe-all-stageautoprofile-libctfframe: all-stageautoprofile-libctfframe
+all-stageautoprofile: all-stageautoprofile-libctfframe
+TARGET-stageautoprofile-libctfframe = $(TARGET-libctfframe)
+all-stageautoprofile-libctfframe: configure-stageautoprofile-libctfframe
+	@[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEautoprofile_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	$$s/gcc/config/i386/$(AUTO_PROFILE) \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEautoprofile_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGEautoprofile_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGEautoprofile_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEautoprofile_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEautoprofile_TFLAGS)"  \
+		$(TARGET-stageautoprofile-libctfframe)
+
+maybe-clean-stageautoprofile-libctfframe: clean-stageautoprofile-libctfframe
+clean-stageautoprofile: clean-stageautoprofile-libctfframe
+clean-stageautoprofile-libctfframe:
+	@if [ $(current_stage) = stageautoprofile ]; then \
+	  [ -f $(HOST_SUBDIR)/libctfframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stageautoprofile-libctfframe/Makefile ] || exit 0; \
+	  $(MAKE) stageautoprofile-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctfframe-bootstrap
+
+
+.PHONY: all-stageautofeedback-libctfframe maybe-all-stageautofeedback-libctfframe
+.PHONY: clean-stageautofeedback-libctfframe maybe-clean-stageautofeedback-libctfframe
+maybe-all-stageautofeedback-libctfframe:
+maybe-clean-stageautofeedback-libctfframe:
+@if libctfframe-bootstrap
+maybe-all-stageautofeedback-libctfframe: all-stageautofeedback-libctfframe
+all-stageautofeedback: all-stageautofeedback-libctfframe
+TARGET-stageautofeedback-libctfframe = $(TARGET-libctfframe)
+all-stageautofeedback-libctfframe: configure-stageautofeedback-libctfframe
+	@[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEautofeedback_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEautofeedback_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGEautofeedback_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGEautofeedback_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEautofeedback_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEautofeedback_TFLAGS)" PERF_DATA=perf.data \
+		$(TARGET-stageautofeedback-libctfframe)
+
+maybe-clean-stageautofeedback-libctfframe: clean-stageautofeedback-libctfframe
+clean-stageautofeedback: clean-stageautofeedback-libctfframe
+clean-stageautofeedback-libctfframe:
+	@if [ $(current_stage) = stageautofeedback ]; then \
+	  [ -f $(HOST_SUBDIR)/libctfframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stageautofeedback-libctfframe/Makefile ] || exit 0; \
+	  $(MAKE) stageautofeedback-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libctfframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libctfframe-bootstrap
+
+
+
+
+
+.PHONY: check-libctfframe maybe-check-libctfframe
+maybe-check-libctfframe:
+@if libctfframe
+maybe-check-libctfframe: check-libctfframe
+
+check-libctfframe:
+	@: $(MAKE); $(unstage)
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) $(EXTRA_HOST_EXPORTS) \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(FLAGS_TO_PASS)  $(EXTRA_BOOTSTRAP_FLAGS) check)
+
+@endif libctfframe
+
+.PHONY: install-libctfframe maybe-install-libctfframe
+maybe-install-libctfframe:
+@if libctfframe
+maybe-install-libctfframe: install-libctfframe
+
+install-libctfframe: installdirs
+	@: $(MAKE); $(unstage)
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(FLAGS_TO_PASS)  install)
+
+@endif libctfframe
+
+.PHONY: install-strip-libctfframe maybe-install-strip-libctfframe
+maybe-install-strip-libctfframe:
+@if libctfframe
+maybe-install-strip-libctfframe: install-strip-libctfframe
+
+install-strip-libctfframe: installdirs
+	@: $(MAKE); $(unstage)
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(FLAGS_TO_PASS)  install-strip)
+
+@endif libctfframe
+
+# Other targets (info, dvi, pdf, etc.)
+
+.PHONY: maybe-info-libctfframe info-libctfframe
+maybe-info-libctfframe:
+@if libctfframe
+maybe-info-libctfframe: info-libctfframe
+
+info-libctfframe: \
+    configure-libctfframe 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing info in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          info) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-dvi-libctfframe dvi-libctfframe
+maybe-dvi-libctfframe:
+@if libctfframe
+maybe-dvi-libctfframe: dvi-libctfframe
+
+dvi-libctfframe: \
+    configure-libctfframe 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing dvi in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          dvi) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-pdf-libctfframe pdf-libctfframe
+maybe-pdf-libctfframe:
+@if libctfframe
+maybe-pdf-libctfframe: pdf-libctfframe
+
+pdf-libctfframe: \
+    configure-libctfframe 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing pdf in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          pdf) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-html-libctfframe html-libctfframe
+maybe-html-libctfframe:
+@if libctfframe
+maybe-html-libctfframe: html-libctfframe
+
+html-libctfframe: \
+    configure-libctfframe 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing html in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          html) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-TAGS-libctfframe TAGS-libctfframe
+maybe-TAGS-libctfframe:
+@if libctfframe
+maybe-TAGS-libctfframe: TAGS-libctfframe
+
+TAGS-libctfframe: \
+    configure-libctfframe 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing TAGS in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          TAGS) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-install-info-libctfframe install-info-libctfframe
+maybe-install-info-libctfframe:
+@if libctfframe
+maybe-install-info-libctfframe: install-info-libctfframe
+
+install-info-libctfframe: \
+    configure-libctfframe \
+    info-libctfframe 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing install-info in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          install-info) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-install-dvi-libctfframe install-dvi-libctfframe
+maybe-install-dvi-libctfframe:
+@if libctfframe
+maybe-install-dvi-libctfframe: install-dvi-libctfframe
+
+install-dvi-libctfframe: \
+    configure-libctfframe \
+    dvi-libctfframe 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing install-dvi in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          install-dvi) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-install-pdf-libctfframe install-pdf-libctfframe
+maybe-install-pdf-libctfframe:
+@if libctfframe
+maybe-install-pdf-libctfframe: install-pdf-libctfframe
+
+install-pdf-libctfframe: \
+    configure-libctfframe \
+    pdf-libctfframe 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing install-pdf in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          install-pdf) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-install-html-libctfframe install-html-libctfframe
+maybe-install-html-libctfframe:
+@if libctfframe
+maybe-install-html-libctfframe: install-html-libctfframe
+
+install-html-libctfframe: \
+    configure-libctfframe \
+    html-libctfframe 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing install-html in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          install-html) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-installcheck-libctfframe installcheck-libctfframe
+maybe-installcheck-libctfframe:
+@if libctfframe
+maybe-installcheck-libctfframe: installcheck-libctfframe
+
+installcheck-libctfframe: \
+    configure-libctfframe 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing installcheck in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          installcheck) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-mostlyclean-libctfframe mostlyclean-libctfframe
+maybe-mostlyclean-libctfframe:
+@if libctfframe
+maybe-mostlyclean-libctfframe: mostlyclean-libctfframe
+
+mostlyclean-libctfframe: 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing mostlyclean in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          mostlyclean) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-clean-libctfframe clean-libctfframe
+maybe-clean-libctfframe:
+@if libctfframe
+maybe-clean-libctfframe: clean-libctfframe
+
+clean-libctfframe: 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing clean in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          clean) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-distclean-libctfframe distclean-libctfframe
+maybe-distclean-libctfframe:
+@if libctfframe
+maybe-distclean-libctfframe: distclean-libctfframe
+
+distclean-libctfframe: 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing distclean in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          distclean) \
+	  || exit 1
+
+@endif libctfframe
+
+.PHONY: maybe-maintainer-clean-libctfframe maintainer-clean-libctfframe
+maybe-maintainer-clean-libctfframe:
+@if libctfframe
+maybe-maintainer-clean-libctfframe: maintainer-clean-libctfframe
+
+maintainer-clean-libctfframe: 
+	@[ -f ./libctfframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing maintainer-clean in libctfframe"; \
+	(cd $(HOST_SUBDIR)/libctfframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          maintainer-clean) \
+	  || exit 1
+
+@endif libctfframe
+
+
+
 # ---------------------------------------
 # Modules which run on the target machine
 # ---------------------------------------
@@ -59280,6 +60442,11 @@ stage1-start::
 	  mkdir stage1-libctf; \
 	mv stage1-libctf libctf
 @endif libctf
+@if libctfframe
+	@cd $(HOST_SUBDIR); [ -d stage1-libctfframe ] || \
+	  mkdir stage1-libctfframe; \
+	mv stage1-libctfframe libctfframe
+@endif libctfframe
 	@[ -d stage1-$(TARGET_SUBDIR) ] || \
 	  mkdir stage1-$(TARGET_SUBDIR); \
 	mv stage1-$(TARGET_SUBDIR) $(TARGET_SUBDIR)
@@ -59405,6 +60572,11 @@ stage1-end::
 	  cd $(HOST_SUBDIR); mv libctf stage1-libctf; \
 	fi
 @endif libctf
+@if libctfframe
+	@if test -d $(HOST_SUBDIR)/libctfframe; then \
+	  cd $(HOST_SUBDIR); mv libctfframe stage1-libctfframe; \
+	fi
+@endif libctfframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage1-$(TARGET_SUBDIR); \
 	fi
@@ -59597,6 +60769,12 @@ stage2-start::
 	mv stage2-libctf libctf; \
 	mv stage1-libctf prev-libctf || test -f stage1-lean 
 @endif libctf
+@if libctfframe
+	@cd $(HOST_SUBDIR); [ -d stage2-libctfframe ] || \
+	  mkdir stage2-libctfframe; \
+	mv stage2-libctfframe libctfframe; \
+	mv stage1-libctfframe prev-libctfframe || test -f stage1-lean 
+@endif libctfframe
 	@[ -d stage2-$(TARGET_SUBDIR) ] || \
 	  mkdir stage2-$(TARGET_SUBDIR); \
 	mv stage2-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -59747,6 +60925,12 @@ stage2-end::
 	  mv prev-libctf stage1-libctf; : ; \
 	fi
 @endif libctf
+@if libctfframe
+	@if test -d $(HOST_SUBDIR)/libctfframe; then \
+	  cd $(HOST_SUBDIR); mv libctfframe stage2-libctfframe; \
+	  mv prev-libctfframe stage1-libctfframe; : ; \
+	fi
+@endif libctfframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage2-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage1-$(TARGET_SUBDIR); : ; \
@@ -59963,6 +61147,12 @@ stage3-start::
 	mv stage3-libctf libctf; \
 	mv stage2-libctf prev-libctf || test -f stage2-lean 
 @endif libctf
+@if libctfframe
+	@cd $(HOST_SUBDIR); [ -d stage3-libctfframe ] || \
+	  mkdir stage3-libctfframe; \
+	mv stage3-libctfframe libctfframe; \
+	mv stage2-libctfframe prev-libctfframe || test -f stage2-lean 
+@endif libctfframe
 	@[ -d stage3-$(TARGET_SUBDIR) ] || \
 	  mkdir stage3-$(TARGET_SUBDIR); \
 	mv stage3-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -60113,6 +61303,12 @@ stage3-end::
 	  mv prev-libctf stage2-libctf; : ; \
 	fi
 @endif libctf
+@if libctfframe
+	@if test -d $(HOST_SUBDIR)/libctfframe; then \
+	  cd $(HOST_SUBDIR); mv libctfframe stage3-libctfframe; \
+	  mv prev-libctfframe stage2-libctfframe; : ; \
+	fi
+@endif libctfframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage3-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage2-$(TARGET_SUBDIR); : ; \
@@ -60385,6 +61581,12 @@ stage4-start::
 	mv stage4-libctf libctf; \
 	mv stage3-libctf prev-libctf || test -f stage3-lean 
 @endif libctf
+@if libctfframe
+	@cd $(HOST_SUBDIR); [ -d stage4-libctfframe ] || \
+	  mkdir stage4-libctfframe; \
+	mv stage4-libctfframe libctfframe; \
+	mv stage3-libctfframe prev-libctfframe || test -f stage3-lean 
+@endif libctfframe
 	@[ -d stage4-$(TARGET_SUBDIR) ] || \
 	  mkdir stage4-$(TARGET_SUBDIR); \
 	mv stage4-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -60535,6 +61737,12 @@ stage4-end::
 	  mv prev-libctf stage3-libctf; : ; \
 	fi
 @endif libctf
+@if libctfframe
+	@if test -d $(HOST_SUBDIR)/libctfframe; then \
+	  cd $(HOST_SUBDIR); mv libctfframe stage4-libctfframe; \
+	  mv prev-libctfframe stage3-libctfframe; : ; \
+	fi
+@endif libctfframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage4-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage3-$(TARGET_SUBDIR); : ; \
@@ -60795,6 +62003,12 @@ stageprofile-start::
 	mv stageprofile-libctf libctf; \
 	mv stage1-libctf prev-libctf || test -f stage1-lean 
 @endif libctf
+@if libctfframe
+	@cd $(HOST_SUBDIR); [ -d stageprofile-libctfframe ] || \
+	  mkdir stageprofile-libctfframe; \
+	mv stageprofile-libctfframe libctfframe; \
+	mv stage1-libctfframe prev-libctfframe || test -f stage1-lean 
+@endif libctfframe
 	@[ -d stageprofile-$(TARGET_SUBDIR) ] || \
 	  mkdir stageprofile-$(TARGET_SUBDIR); \
 	mv stageprofile-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -60945,6 +62159,12 @@ stageprofile-end::
 	  mv prev-libctf stage1-libctf; : ; \
 	fi
 @endif libctf
+@if libctfframe
+	@if test -d $(HOST_SUBDIR)/libctfframe; then \
+	  cd $(HOST_SUBDIR); mv libctfframe stageprofile-libctfframe; \
+	  mv prev-libctfframe stage1-libctfframe; : ; \
+	fi
+@endif libctfframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stageprofile-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage1-$(TARGET_SUBDIR); : ; \
@@ -61138,6 +62358,12 @@ stagetrain-start::
 	mv stagetrain-libctf libctf; \
 	mv stageprofile-libctf prev-libctf || test -f stageprofile-lean 
 @endif libctf
+@if libctfframe
+	@cd $(HOST_SUBDIR); [ -d stagetrain-libctfframe ] || \
+	  mkdir stagetrain-libctfframe; \
+	mv stagetrain-libctfframe libctfframe; \
+	mv stageprofile-libctfframe prev-libctfframe || test -f stageprofile-lean 
+@endif libctfframe
 	@[ -d stagetrain-$(TARGET_SUBDIR) ] || \
 	  mkdir stagetrain-$(TARGET_SUBDIR); \
 	mv stagetrain-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -61288,6 +62514,12 @@ stagetrain-end::
 	  mv prev-libctf stageprofile-libctf; : ; \
 	fi
 @endif libctf
+@if libctfframe
+	@if test -d $(HOST_SUBDIR)/libctfframe; then \
+	  cd $(HOST_SUBDIR); mv libctfframe stagetrain-libctfframe; \
+	  mv prev-libctfframe stageprofile-libctfframe; : ; \
+	fi
+@endif libctfframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stagetrain-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stageprofile-$(TARGET_SUBDIR); : ; \
@@ -61481,6 +62713,12 @@ stagefeedback-start::
 	mv stagefeedback-libctf libctf; \
 	mv stagetrain-libctf prev-libctf || test -f stagetrain-lean 
 @endif libctf
+@if libctfframe
+	@cd $(HOST_SUBDIR); [ -d stagefeedback-libctfframe ] || \
+	  mkdir stagefeedback-libctfframe; \
+	mv stagefeedback-libctfframe libctfframe; \
+	mv stagetrain-libctfframe prev-libctfframe || test -f stagetrain-lean 
+@endif libctfframe
 	@[ -d stagefeedback-$(TARGET_SUBDIR) ] || \
 	  mkdir stagefeedback-$(TARGET_SUBDIR); \
 	mv stagefeedback-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -61631,6 +62869,12 @@ stagefeedback-end::
 	  mv prev-libctf stagetrain-libctf; : ; \
 	fi
 @endif libctf
+@if libctfframe
+	@if test -d $(HOST_SUBDIR)/libctfframe; then \
+	  cd $(HOST_SUBDIR); mv libctfframe stagefeedback-libctfframe; \
+	  mv prev-libctfframe stagetrain-libctfframe; : ; \
+	fi
+@endif libctfframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stagefeedback-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stagetrain-$(TARGET_SUBDIR); : ; \
@@ -61847,6 +63091,12 @@ stageautoprofile-start::
 	mv stageautoprofile-libctf libctf; \
 	mv stage1-libctf prev-libctf || test -f stage1-lean 
 @endif libctf
+@if libctfframe
+	@cd $(HOST_SUBDIR); [ -d stageautoprofile-libctfframe ] || \
+	  mkdir stageautoprofile-libctfframe; \
+	mv stageautoprofile-libctfframe libctfframe; \
+	mv stage1-libctfframe prev-libctfframe || test -f stage1-lean 
+@endif libctfframe
 	@[ -d stageautoprofile-$(TARGET_SUBDIR) ] || \
 	  mkdir stageautoprofile-$(TARGET_SUBDIR); \
 	mv stageautoprofile-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -61997,6 +63247,12 @@ stageautoprofile-end::
 	  mv prev-libctf stage1-libctf; : ; \
 	fi
 @endif libctf
+@if libctfframe
+	@if test -d $(HOST_SUBDIR)/libctfframe; then \
+	  cd $(HOST_SUBDIR); mv libctfframe stageautoprofile-libctfframe; \
+	  mv prev-libctfframe stage1-libctfframe; : ; \
+	fi
+@endif libctfframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stageautoprofile-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage1-$(TARGET_SUBDIR); : ; \
@@ -62190,6 +63446,12 @@ stageautofeedback-start::
 	mv stageautofeedback-libctf libctf; \
 	mv stageautoprofile-libctf prev-libctf || test -f stageautoprofile-lean 
 @endif libctf
+@if libctfframe
+	@cd $(HOST_SUBDIR); [ -d stageautofeedback-libctfframe ] || \
+	  mkdir stageautofeedback-libctfframe; \
+	mv stageautofeedback-libctfframe libctfframe; \
+	mv stageautoprofile-libctfframe prev-libctfframe || test -f stageautoprofile-lean 
+@endif libctfframe
 	@[ -d stageautofeedback-$(TARGET_SUBDIR) ] || \
 	  mkdir stageautofeedback-$(TARGET_SUBDIR); \
 	mv stageautofeedback-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -62340,6 +63602,12 @@ stageautofeedback-end::
 	  mv prev-libctf stageautoprofile-libctf; : ; \
 	fi
 @endif libctf
+@if libctfframe
+	@if test -d $(HOST_SUBDIR)/libctfframe; then \
+	  cd $(HOST_SUBDIR); mv libctfframe stageautofeedback-libctfframe; \
+	  mv prev-libctfframe stageautoprofile-libctfframe; : ; \
+	fi
+@endif libctfframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stageautofeedback-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stageautoprofile-$(TARGET_SUBDIR); : ; \
@@ -63259,6 +64527,16 @@ all-stagetrain-ld: maybe-all-stagetrain-libctf
 all-stagefeedback-ld: maybe-all-stagefeedback-libctf
 all-stageautoprofile-ld: maybe-all-stageautoprofile-libctf
 all-stageautofeedback-ld: maybe-all-stageautofeedback-libctf
+all-binutils: maybe-all-libctfframe
+all-stage1-binutils: maybe-all-stage1-libctfframe
+all-stage2-binutils: maybe-all-stage2-libctfframe
+all-stage3-binutils: maybe-all-stage3-libctfframe
+all-stage4-binutils: maybe-all-stage4-libctfframe
+all-stageprofile-binutils: maybe-all-stageprofile-libctfframe
+all-stagetrain-binutils: maybe-all-stagetrain-libctfframe
+all-stagefeedback-binutils: maybe-all-stagefeedback-libctfframe
+all-stageautoprofile-binutils: maybe-all-stageautoprofile-libctfframe
+all-stageautofeedback-binutils: maybe-all-stageautofeedback-libctfframe
 install-binutils: maybe-install-opcodes
 install-strip-binutils: maybe-install-strip-opcodes
 install-libctf: maybe-install-bfd
diff --git a/binutils/Makefile.am b/binutils/Makefile.am
index 751fbacce12..17dcc27fc86 100644
--- a/binutils/Makefile.am
+++ b/binutils/Makefile.am
@@ -176,6 +176,8 @@ LIBCTF =
 LIBCTF_NOBFD =
 endif
 
+LIBCTFFRAME = ../libctfframe/libctfframe.la
+
 LIBIBERTY = ../libiberty/libiberty.a
 
 POTFILES = $(CFILES) $(DEBUG_SRCS) $(HFILES)
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index 78d32b350e3..2ed7f05bf37 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -738,6 +738,7 @@ OPCODES = ../opcodes/libopcodes.la
 @ENABLE_LIBCTF_TRUE@LIBCTF = ../libctf/libctf.la
 @ENABLE_LIBCTF_FALSE@LIBCTF_NOBFD = 
 @ENABLE_LIBCTF_TRUE@LIBCTF_NOBFD = ../libctf/libctf-nobfd.la
+LIBCTFFRAME = ../libctfframe/libctfframe.la
 LIBIBERTY = ../libiberty/libiberty.a
 POTFILES = $(CFILES) $(DEBUG_SRCS) $(HFILES)
 EXPECT = expect
diff --git a/configure b/configure
index be433ef6d5d..53a06675d4d 100755
--- a/configure
+++ b/configure
@@ -2784,7 +2784,7 @@ build_tools="build-texinfo build-flex build-bison build-m4 build-fixincludes"
 
 # these libraries are used by various programs built for the host environment
 #f
-host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv libctf"
+host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv libctf libctfframe"
 
 # these tools are built for the host environment
 # Note, the powerpc-eabi build depends on sim occurring before gdb in order to
diff --git a/configure.ac b/configure.ac
index 1651cbf3b02..8959335e02e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -132,7 +132,7 @@ build_tools="build-texinfo build-flex build-bison build-m4 build-fixincludes"
 
 # these libraries are used by various programs built for the host environment
 #f
-host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv libctf"
+host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv libctf libctfframe"
 
 # these tools are built for the host environment
 # Note, the powerpc-eabi build depends on sim occurring before gdb in order to
diff --git a/include/ctf-frame-api.h b/include/ctf-frame-api.h
new file mode 100644
index 00000000000..59c2abadf0e
--- /dev/null
+++ b/include/ctf-frame-api.h
@@ -0,0 +1,210 @@
+/* Public API to CTF Frame.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This 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/>.  */
+
+#ifndef	_CTF_FRAME_API_H
+#define	_CTF_FRAME_API_H
+
+#include <ctf-frame.h>
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+typedef struct ctf_frame_decoder_ctx ctf_frame_decoder_ctx;
+typedef struct ctf_frame_encoder_ctx ctf_frame_encoder_ctx;
+
+#define MAX_OFFSET_BYTES (CTF_FRAME_FRE_OFFSET_4B * 2 * 3)
+
+/* User interfacing CTF Frame Row Entry.
+   An abstraction provided by libctfframe so the consumer is decoupled from
+   the binary format representation of the same.  */
+
+typedef struct ctf_frame_row_entry
+{
+  uint32_t fre_start_addr;
+  unsigned char fre_info;
+  unsigned char fre_offsets[MAX_OFFSET_BYTES];
+} ctf_frame_row_entry;
+
+#define CTF_FRAME_ERR ((int) -1)
+
+/* This macro holds information about all the available ctf frame
+   errors.  It is used to form both an enum holding all the error
+   constants, and also the error strings themselves.  To use, define
+   _CTF_FRAME_FIRST and _CTF_FRAME_ITEM to expand as you like, then
+   mention the macro name.  See the enum after this for an example.  */
+#define _CTF_FRAME_ERRORS \
+  _CTF_FRAME_FIRST (ECTF_FRAME_VERSION_INVAL, "CTF Frame version not supported.") \
+  _CTF_FRAME_ITEM (ECTF_FRAME_NOMEM, "Out of Memory.")			\
+  _CTF_FRAME_ITEM (ECTF_FRAME_INVAL, "Corrupt CTF Frame.")		\
+  _CTF_FRAME_ITEM (ECTF_FRAME_BUF_INVAL, "Corrupt CTF Frame buffer.")	\
+  _CTF_FRAME_ITEM (ECTF_FRAME_DCTX_INVAL, "Corrupt CTF Frame decoder.") \
+  _CTF_FRAME_ITEM (ECTF_FRAME_ECTX_INVAL, "Corrupt CTF Frame encoder.")	\
+  _CTF_FRAME_ITEM (ECTF_FRAME_FDE_INVAL, "Corrput FDE.")		\
+  _CTF_FRAME_ITEM (ECTF_FRAME_FRE_INVAL, "Corrupt FRE.")		\
+  _CTF_FRAME_ITEM (ECTF_FRAME_FDE_NOTFOUND,"FDE not found.")		\
+  _CTF_FRAME_ITEM (ECTF_FRAME_FRE_NOTFOUND,"FRE not found.")		\
+  _CTF_FRAME_ITEM (ECTF_FRAME_FREOFFSET_NOPRESENT,"FRE offset not present.")
+
+#define	ECTF_FRAME_BASE	2000	/* Base value for libctfframe errnos.  */
+
+enum
+  {
+#define _CTF_FRAME_FIRST(NAME, STR) NAME = ECTF_FRAME_BASE
+#define _CTF_FRAME_ITEM(NAME, STR) , NAME
+_CTF_FRAME_ERRORS
+#undef _CTF_FRAME_ITEM
+#undef _CTF_FRAME_FIRST
+  };
+
+/* Count of CTF errors.  */
+#define ECTF_FRAME_NERR (ECTF_FRAME_NOMEM - ECTF_FRAME_BASE + 1)
+
+/* Get the error message string.  */
+
+extern const char *
+ctf_frame_errmsg (int error);
+
+/* Get FDE function info given a FRE_TYPE.  */
+
+extern unsigned char
+ctf_frame_fde_func_info (unsigned int fre_type, unsigned int fde_type);
+
+/* Gather the FRE type given the function size.  */
+
+extern unsigned int
+ctf_frame_calc_fre_type (unsigned int func_size);
+
+/* The CTF Frame Decoder.  */
+
+/* Decode the specified CTF Frame buffer CF_BUF of size CF_SIZE and return the
+   new CTF Frame decoder context.  Sets ERRP for the caller if any error.  */
+extern ctf_frame_decoder_ctx *
+ctf_frame_decode (const char *cf_buf, size_t cf_size, int *errp);
+
+/* Free the decoder context.  */
+extern void
+ctf_frame_decoder_free (ctf_frame_decoder_ctx **dctx);
+
+/* Get the CTF Frame's abi/arch info.  */
+extern unsigned char
+ctf_frame_decoder_get_abi_arch (ctf_frame_decoder_ctx *dctx);
+
+/* Return the number of function descriptor entries in the CTF Frame decoder
+   DCTX.  */
+unsigned int
+ctf_frame_decoder_get_num_fidx (ctf_frame_decoder_ctx *dctx);
+
+/* Find the function descriptor entry which contains the specified address.  */
+extern ctf_frame_func_desc_entry *
+ctf_frame_get_funcdesc_with_addr (ctf_frame_decoder_ctx *dctx,
+				  int32_t addr, int *errp);
+
+/* Find the CTF Frame Row Entry which contains the PC.  Returns
+   CTF_FRAME_ERR if failure.  */
+
+extern int
+ctf_frame_find_fre (ctf_frame_decoder_ctx *ctx, int32_t pc,
+		    ctf_frame_row_entry *frep);
+
+/* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
+   index entry in the CTF Frame decoder CTX.  Returns error code as
+   applicable.  */
+extern int
+ctf_frame_decoder_get_fre (ctf_frame_decoder_ctx *ctx,
+			   unsigned int func_idx,
+			   unsigned int fre_idx,
+			   ctf_frame_row_entry *fre);
+
+/* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
+   descriptor entry at index I'th in the decoder CTX.  If failed,
+   return error code.  */
+extern int
+ctf_frame_decoder_get_funcdesc (ctf_frame_decoder_ctx *ctx,
+				unsigned int i,
+				uint32_t *num_fres,
+				uint32_t *func_size,
+				int32_t *func_start_address,
+				unsigned char *func_info);
+
+
+/* Get the base reg id from the FRE info.  Sets errp if fails.  */
+extern unsigned int
+ctf_frame_fre_get_base_reg_id (ctf_frame_row_entry *fre, int *errp);
+
+/* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
+extern int32_t
+ctf_frame_fre_get_cfa_offset (ctf_frame_row_entry *fre, int *errp);
+
+/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
+extern int32_t
+ctf_frame_fre_get_fp_offset (ctf_frame_row_entry *fre, int *errp);
+
+/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
+extern int32_t
+ctf_frame_fre_get_ra_offset (ctf_frame_row_entry *fre, int *errp);
+
+/* The CTF Frame Encoder.  */
+
+/* Create an encoder context with the given CTF format version VER, FLAGS and
+   ABI information.  Sets errp if failure.  */
+extern ctf_frame_encoder_ctx *
+ctf_frame_encode (unsigned char ver, unsigned char flags, int abi, int *errp);
+
+/* Free the encoder context.  */
+extern void
+ctf_free_encoder (ctf_frame_encoder_ctx *encoder);
+
+/* Get the abi/arch info from the CTF Frame encoder context CTX.  */
+extern unsigned char
+ctf_frame_encoder_get_abi_arch (ctf_frame_encoder_ctx *encoder);
+
+/* Return the number of function descriptor entries in the CTF Frame encoder
+   ENCODER.  */
+extern unsigned int
+ctf_frame_encoder_get_num_fidx (ctf_frame_encoder_ctx *encoder);
+
+/* Add an FRE to function at FUNC_IDX'th function descriptor index entry in
+   the encoder context.  */
+extern int
+ctf_frame_encoder_add_fre (ctf_frame_encoder_ctx *encoder,
+			   unsigned int func_idx,
+			   ctf_frame_row_entry *frep);
+
+/* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
+   to the encoder.  */
+extern int
+ctf_frame_encoder_add_funcdesc (ctf_frame_encoder_ctx *encoder,
+				int32_t start_addr,
+				uint32_t func_size,
+				unsigned char func_info,
+				uint32_t num_fres);
+
+/* Serialize the contents of the encoder and return the buffer.  ENCODED_SIZE
+   is updated to the size of the buffer.  Sets ERRP if failure.  */
+extern char  *
+ctf_frame_write_encoder (ctf_frame_encoder_ctx *encoder,
+			 size_t *encoded_size, int *errp);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _CTF_FRAME_API_H */
diff --git a/libctfframe/Makefile.am b/libctfframe/Makefile.am
new file mode 100644
index 00000000000..07d76c75748
--- /dev/null
+++ b/libctfframe/Makefile.am
@@ -0,0 +1,43 @@
+## Process this file with automake to produce Makefile.in.
+#
+#   Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file 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 2 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; see the file COPYING.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+
+SUBDIRS = testsuite
+
+ACLOCAL_AMFLAGS = -I .. -I ../config
+
+AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+
+BASEDIR = $(srcdir)/..
+INCDIR = $(srcdir)/../include
+# include libctf for swap.h
+AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../libctf
+AM_CFLAGS = -std=gnu99 @ac_libctfframe_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@
+
+if INSTALL_LIBBFD
+lib_LTLIBRARIES = libctfframe.la
+include_HEADERS = $(INCDIR)/ctf-frame.h $(INCDIR)/ctf-frame-api.h
+else
+include_HEADERS =
+noinst_LTLIBRARIES = libctfframe.la
+endif
+
+libctfframe_la_SOURCES = ctf-frame.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
new file mode 100644
index 00000000000..e6d3ee7ff3c
--- /dev/null
+++ b/libctfframe/Makefile.in
@@ -0,0 +1,1048 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+#   Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file 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 2 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; see the file COPYING.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
+	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/depstand.m4 \
+	$(top_srcdir)/../config/jobserver.m4 \
+	$(top_srcdir)/../config/lead-dot.m4 \
+	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/warnings.m4 \
+	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
+	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
+	$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+	$(am__configure_deps) $(am__include_HEADERS_DIST) \
+	$(am__DIST_COMMON)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+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-error.lo
+libctfframe_la_OBJECTS = $(am_libctfframe_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+@INSTALL_LIBBFD_FALSE@am_libctfframe_la_rpath =
+@INSTALL_LIBBFD_TRUE@am_libctfframe_la_rpath = -rpath $(libdir)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libctfframe_la_SOURCES)
+DIST_SOURCES = $(libctfframe_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__include_HEADERS_DIST = $(INCDIR)/ctf-frame.h \
+	$(INCDIR)/ctf-frame-api.h
+HEADERS = $(include_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	cscope distdir dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+	$(LISP)config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+	$(top_srcdir)/../ar-lib $(top_srcdir)/../compile \
+	$(top_srcdir)/../config.guess $(top_srcdir)/../config.sub \
+	$(top_srcdir)/../depcomp $(top_srcdir)/../install-sh \
+	$(top_srcdir)/../ltmain.sh $(top_srcdir)/../missing \
+	$(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  if test -d "$(distdir)"; then \
+    find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+      && rm -rf "$(distdir)" \
+      || { sleep 5 && rm -rf "$(distdir)"; }; \
+  else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+  | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_PEDANTIC = @WARN_PEDANTIC@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_libctfframe_warn_cflags = @ac_libctfframe_warn_cflags@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_warn = @c_warn@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_noncanonical = @host_noncanonical@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+target_noncanonical = @target_noncanonical@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+warn = @warn@
+SUBDIRS = testsuite
+ACLOCAL_AMFLAGS = -I .. -I ../config
+AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+BASEDIR = $(srcdir)/..
+INCDIR = $(srcdir)/../include
+# include libctf for swap.h
+AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../libctf
+AM_CFLAGS = -std=gnu99 @ac_libctfframe_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@
+@INSTALL_LIBBFD_TRUE@lib_LTLIBRARIES = libctfframe.la
+@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_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include \
+                          -I$(srcdir)/../libctf
+
+all: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+am--refresh: Makefile
+	@:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+	@test -f $@ || rm -f stamp-h1
+	@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f config.h stamp-h1
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libctfframe.la: $(libctfframe_la_OBJECTS) $(libctfframe_la_DEPENDENCIES) $(EXTRA_libctfframe_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK) $(am_libctfframe_la_rpath) $(libctfframe_la_OBJECTS) $(libctfframe_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@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@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libctfframe_la-ctf-frame.lo: ctf-frame.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.lo -MD -MP -MF $(DEPDIR)/libctfframe_la-ctf-frame.Tpo -c -o libctfframe_la-ctf-frame.lo `test -f 'ctf-frame.c' || echo '$(srcdir)/'`ctf-frame.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libctfframe_la-ctf-frame.Tpo $(DEPDIR)/libctfframe_la-ctf-frame.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ctf-frame.c' object='libctfframe_la-ctf-frame.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.lo `test -f 'ctf-frame.c' || echo '$(srcdir)/'`ctf-frame.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
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ctf-frame-error.c' object='libctfframe_la-ctf-frame-error.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-error.lo `test -f 'ctf-frame-error.c' || echo '$(srcdir)/'`ctf-frame-error.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool config.lt
+install-includeHEADERS: $(include_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+	done
+
+uninstall-includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+	test ! -s cscope.files \
+	  || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+	-rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	test -d "$(distdir)" || mkdir "$(distdir)"
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	-test -n "$(am__skip_mode_fix)" \
+	|| find "$(distdir)" -type d ! -perm -755 \
+		-exec chmod u+rwx,go+rx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
+	$(am__post_remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+	$(am__post_remove_distdir)
+
+dist-lzip: distdir
+	tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+	$(am__post_remove_distdir)
+
+dist-xz: distdir
+	tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+	$(am__post_remove_distdir)
+
+dist-tarZ: distdir
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__post_remove_distdir)
+
+dist-shar: distdir
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
+	$(am__post_remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__post_remove_distdir)
+
+dist dist-all:
+	$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+	$(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lz*) \
+	  lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+	*.tar.xz*) \
+	  xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir)
+	chmod u+w $(distdir)
+	mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+	chmod a-w $(distdir)
+	test -d $(distdir)/_build || exit 0; \
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && am__cwd=`pwd` \
+	  && $(am__cd) $(distdir)/_build/sub \
+	  && ../../configure \
+	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	    --srcdir=../.. --prefix="$$dc_install_base" \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+	  && cd "$$am__cwd" \
+	  || exit 1
+	$(am__post_remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@test -n '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: trying to run $@ with an empty' \
+	       '$$(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	$(am__cd) '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-includeHEADERS
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
+
+.MAKE: $(am__recursive_targets) all install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+	am--refresh check check-am clean clean-cscope clean-generic \
+	clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \
+	cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
+	dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \
+	distcheck distclean distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags distcleancheck \
+	distdir distuninstallcheck dvi dvi-am html html-am info \
+	info-am install install-am install-data install-data-am \
+	install-dvi install-dvi-am install-exec install-exec-am \
+	install-html install-html-am install-includeHEADERS \
+	install-info install-info-am install-libLTLIBRARIES \
+	install-man install-pdf install-pdf-am install-ps \
+	install-ps-am install-strip installcheck installcheck-am \
+	installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am uninstall-includeHEADERS \
+	uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libctfframe/aclocal.m4 b/libctfframe/aclocal.m4
new file mode 100644
index 00000000000..3a0b3426ebc
--- /dev/null
+++ b/libctfframe/aclocal.m4
@@ -0,0 +1,1241 @@
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.15'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.15.1], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_AR([ACT-IF-FAIL])
+# -------------------------
+# Try to determine the archiver interface, and trigger the ar-lib wrapper
+# if it is needed.  If the detection of archiver interface fails, run
+# ACT-IF-FAIL (default is to abort configure with a proper error message).
+AC_DEFUN([AM_PROG_AR],
+[AC_BEFORE([$0], [LT_INIT])dnl
+AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([ar-lib])dnl
+AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false])
+: ${AR=ar}
+
+AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface],
+  [AC_LANG_PUSH([C])
+   am_cv_ar_interface=ar
+   AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])],
+     [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([am_ar_try])
+      if test "$ac_status" -eq 0; then
+        am_cv_ar_interface=ar
+      else
+        am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+        AC_TRY_EVAL([am_ar_try])
+        if test "$ac_status" -eq 0; then
+          am_cv_ar_interface=lib
+        else
+          am_cv_ar_interface=unknown
+        fi
+      fi
+      rm -f conftest.lib libconftest.a
+     ])
+   AC_LANG_POP([C])])
+
+case $am_cv_ar_interface in
+ar)
+  ;;
+lib)
+  # Microsoft lib, so override with the ar-lib wrapper script.
+  # FIXME: It is wrong to rewrite AR.
+  # But if we don't then we get into trouble of one sort or another.
+  # A longer-term fix would be to have automake use am__AR in this case,
+  # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+  # similar.
+  AR="$am_aux_dir/ar-lib $AR"
+  ;;
+unknown)
+  m4_default([$1],
+             [AC_MSG_ERROR([could not determine $AR interface])])
+  ;;
+esac
+AC_SUBST([AR])dnl
+])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC],   [depcc="$CC"   am_compiler_list=],
+      [$1], [CXX],  [depcc="$CXX"  am_compiler_list=],
+      [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+      [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+      [$1], [UPC],  [depcc="$UPC"  am_compiler_list=],
+      [$1], [GCJ],  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                    [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  am__universal=false
+  m4_case([$1], [CC],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac],
+    [CXX],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac])
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+  [--enable-dependency-tracking],
+  [do not reject slow dependency extractors])
+AS_HELP_STRING(
+  [--disable-dependency-tracking],
+  [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`AS_DIRNAME("$mf")`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`AS_DIRNAME(["$file"])`
+      AS_MKDIR_P([$dirpart/$fdir])
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+             [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+  [ok:ok],,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+	      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+			     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+		  [_AM_DEPENDENCIES([CC])],
+		  [m4_define([AC_PROG_CC],
+			     m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+		  [_AM_DEPENDENCIES([CXX])],
+		  [m4_define([AC_PROG_CXX],
+			     m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+		  [_AM_DEPENDENCIES([OBJC])],
+		  [m4_define([AC_PROG_OBJC],
+			     m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+		  [_AM_DEPENDENCIES([OBJCXX])],
+		  [m4_define([AC_PROG_OBJCXX],
+			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+  fi
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST([install_sh])])
+
+# Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless 'enable' is passed literally.
+# For symmetry, 'disable' may be passed as well.  Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+       [enable], [m4_define([am_maintainer_other], [disable])],
+       [disable], [m4_define([am_maintainer_other], [enable])],
+       [m4_define([am_maintainer_other], [enable])
+        m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+  dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+  AC_ARG_ENABLE([maintainer-mode],
+    [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
+      am_maintainer_other[ make rules and dependencies not useful
+      (and sometimes confusing) to the casual installer])],
+    [USE_MAINTAINER_MODE=$enableval],
+    [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+  AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+  AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+  MAINT=$MAINTAINER_MODE_TRUE
+  AC_SUBST([MAINT])dnl
+]
+)
+
+# Check to see how 'make' treats includes.	            -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake.  We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+  [whether $CC understands -c and -o together],
+  [am_cv_prog_cc_c_o],
+  [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \	]]*)
+    AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$[*]" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$[*]" != "X $srcdir/configure conftest.file" \
+	&& test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment])
+     fi
+     if test "$[2]" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+  [AC_MSG_CHECKING([that generated files are newer than configure])
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+  [--enable-silent-rules],
+  [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+  [--disable-silent-rules],
+  [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+   [am_cv_make_support_nested_variables],
+   [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+  dnl Using '$V' instead of '$(V)' breaks IRIX make.
+  AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+  [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+  [m4_case([$1],
+    [ustar],
+     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+      # There is notably a 21 bits limit for the UID and the GID.  In fact,
+      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+      # and bug#13588).
+      am_max_uid=2097151 # 2^21 - 1
+      am_max_gid=$am_max_uid
+      # The $UID and $GID variables are not portable, so we need to resort
+      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls
+      # below are definitely unexpected, so allow the users to see them
+      # (that is, avoid stderr redirection).
+      am_uid=`id -u || echo unknown`
+      am_gid=`id -g || echo unknown`
+      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+      if test $am_uid -le $am_max_uid; then
+         AC_MSG_RESULT([yes])
+      else
+         AC_MSG_RESULT([no])
+         _am_tools=none
+      fi
+      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+      if test $am_gid -le $am_max_gid; then
+         AC_MSG_RESULT([yes])
+      else
+        AC_MSG_RESULT([no])
+        _am_tools=none
+      fi],
+
+  [pax],
+    [],
+
+  [m4_fatal([Unknown tar format])])
+
+  AC_MSG_CHECKING([how to create a $1 tar archive])
+
+  # Go ahead even if we have the value already cached.  We do so because we
+  # need to set the values for the 'am__tar' and 'am__untar' variables.
+  _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+  for _am_tool in $_am_tools; do
+    case $_am_tool in
+    gnutar)
+      for _am_tar in tar gnutar gtar; do
+        AM_RUN_LOG([$_am_tar --version]) && break
+      done
+      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      am__untar="$_am_tar -xf -"
+      ;;
+    plaintar)
+      # Must skip GNU tar: if it does not support --format= it doesn't create
+      # ustar tarball either.
+      (tar --version) >/dev/null 2>&1 && continue
+      am__tar='tar chf - "$$tardir"'
+      am__tar_='tar chf - "$tardir"'
+      am__untar='tar xf -'
+      ;;
+    pax)
+      am__tar='pax -L -x $1 -w "$$tardir"'
+      am__tar_='pax -L -x $1 -w "$tardir"'
+      am__untar='pax -r'
+      ;;
+    cpio)
+      am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+      am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+      am__untar='cpio -i -H $1 -d'
+      ;;
+    none)
+      am__tar=false
+      am__tar_=false
+      am__untar=false
+      ;;
+    esac
+
+    # If the value was cached, stop now.  We just wanted to have am__tar
+    # and am__untar set.
+    test -n "${am_cv_prog_tar_$1}" && break
+
+    # tar/untar a dummy directory, and stop if the command works.
+    rm -rf conftest.dir
+    mkdir conftest.dir
+    echo GrepMe > conftest.dir/file
+    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+    rm -rf conftest.dir
+    if test -s conftest.tar; then
+      AM_RUN_LOG([$am__untar <conftest.tar])
+      AM_RUN_LOG([cat conftest.dir/file])
+      grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+    fi
+  done
+  rm -rf conftest.dir
+
+  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+  AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([../bfd/acinclude.m4])
+m4_include([../config/acx.m4])
+m4_include([../config/depstand.m4])
+m4_include([../config/jobserver.m4])
+m4_include([../config/lead-dot.m4])
+m4_include([../config/override.m4])
+m4_include([../config/warnings.m4])
+m4_include([../libtool.m4])
+m4_include([../ltoptions.m4])
+m4_include([../ltsugar.m4])
+m4_include([../ltversion.m4])
+m4_include([../lt~obsolete.m4])
diff --git a/libctfframe/config.h.in b/libctfframe/config.h.in
new file mode 100644
index 00000000000..6712ff1cc81
--- /dev/null
+++ b/libctfframe/config.h.in
@@ -0,0 +1,144 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <byteswap.h> header file. */
+#undef HAVE_BYTESWAP_H
+
+/* Define to 1 if you have the declaration of `asprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_ASPRINTF
+
+/* Define to 1 if you have the declaration of `bswap_16', and to 0 if you
+   don't. */
+#undef HAVE_DECL_BSWAP_16
+
+/* Define to 1 if you have the declaration of `bswap_32', and to 0 if you
+   don't. */
+#undef HAVE_DECL_BSWAP_32
+
+/* Define to 1 if you have the declaration of `bswap_64', and to 0 if you
+   don't. */
+#undef HAVE_DECL_BSWAP_64
+
+/* Define to 1 if you have the declaration of `stpcpy', and to 0 if you don't.
+   */
+#undef HAVE_DECL_STPCPY
+
+/* Define to 1 if you have the declaration of `vasprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_VASPRINTF
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <endian.h> header file. */
+#undef HAVE_ENDIAN_H
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#undef VERSION
+
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
diff --git a/libctfframe/configure.ac b/libctfframe/configure.ac
new file mode 100644
index 00000000000..eafe7bea96a
--- /dev/null
+++ b/libctfframe/configure.ac
@@ -0,0 +1,78 @@
+dnl                                            -*- Autoconf -*-
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl   Copyright (C) 2022 Free Software Foundation, Inc.
+dnl
+dnl This file is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; see the file COPYING.  If not see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_INIT([libctfframe], BFD_VERSION)
+AC_CONFIG_SRCDIR(ctf-frame.c)
+AC_CONFIG_MACRO_DIR(..)
+AC_CONFIG_MACRO_DIR(../config)
+AC_CONFIG_MACRO_DIR(../bfd)
+AC_USE_SYSTEM_EXTENSIONS
+AM_INIT_AUTOMAKE
+
+# Checks for programs.
+AC_PROG_MAKE_SET
+AC_PROG_CC
+AC_PROG_RANLIB
+AM_PROG_AR
+
+dnl Default to a non shared library.  This may be overridden by the
+dnl configure option --enable-shared.
+AC_DISABLE_SHARED
+
+LT_INIT
+AC_SYS_LARGEFILE
+
+MISSING=`cd $ac_aux_dir && ${PWDCMD-pwd}`/missing
+AC_CHECK_PROGS([ACLOCAL], [aclocal], [$MISSING aclocal])
+AC_CHECK_PROGS([AUTOCONF], [autoconf], [$MISSING autoconf])
+AC_CHECK_PROGS([AUTOHEADER], [autoheader], [$MISSING autoheader])
+
+# Figure out what compiler warnings we can enable.
+# See config/warnings.m4 for details.
+
+ACX_PROG_CC_WARNING_OPTS([-W -Wall -Wno-narrowing -Wwrite-strings \
+			  -Wmissing-format-attribute], [warn])
+ACX_PROG_CC_WARNING_OPTS([-Wstrict-prototypes -Wmissing-prototypes \
+			  -Wold-style-definition], [c_warn])
+ACX_PROG_CC_WARNING_ALMOST_PEDANTIC([-Wno-long-long])
+
+# Only enable with --enable-werror-always until existing warnings are
+# corrected.
+ACX_PROG_CC_WARNINGS_ARE_ERRORS([manual])
+
+AM_MAINTAINER_MODE
+AM_INSTALL_LIBBFD
+ACX_PROG_CC_WARNING_OPTS([-Wall], [ac_libctfframe_warn_cflags])
+
+AC_FUNC_MMAP
+AC_CHECK_HEADERS(byteswap.h endian.h)
+
+dnl Check for bswap_{16,32,64}
+AC_CHECK_DECLS([bswap_16, bswap_32, bswap_64], [], [], [[#include <byteswap.h>]])
+AC_CHECK_DECLS([asprintf, vasprintf, stpcpy])
+
+AC_CONFIG_FILES(Makefile
+		testsuite/Makefile
+		testsuite/libctfframe.decode/Makefile
+		testsuite/libctfframe.encode/Makefile)
+AC_CONFIG_HEADERS(config.h)
+AC_OUTPUT
+
+GNU_MAKE_JOBSERVER
diff --git a/libctfframe/ctf-frame-error.c b/libctfframe/ctf-frame-error.c
new file mode 100644
index 00000000000..c0c65aa426a
--- /dev/null
+++ b/libctfframe/ctf-frame-error.c
@@ -0,0 +1,49 @@
+/* ctf-frame-error.c - Error messages.
+
+   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 "ctf-frame-api.h"
+#include <stddef.h>
+#include <string.h>
+
+/* In this file, we want to treat the first item of the ctf error
+   macro like subsequent items.  */
+#define _CTF_FRAME_FIRST(NAME, VALUE) _CTF_FRAME_ITEM(NAME, VALUE)
+
+/* The error message strings, each in a unique structure member precisely big
+   enough for that error, plus a str member to access them all as a string
+   table.  */
+
+static const char *const _ctf_frame_errlist[] = {
+#define _CTF_FRAME_ITEM(n, s) s,
+_CTF_FRAME_ERRORS
+#undef _CTF_FRAME_ITEM
+};
+
+const char *
+ctf_frame_errmsg (int error)
+{
+  const char *str;
+
+  if (error >= ECTF_FRAME_BASE && (error - ECTF_FRAME_BASE) < ECTF_FRAME_NERR)
+    str = _ctf_frame_errlist[error - ECTF_FRAME_BASE];
+  else
+    str = (const char *) strerror (error);
+
+  return (str ? str : "Unknown error");
+}
diff --git a/libctfframe/ctf-frame-impl.h b/libctfframe/ctf-frame-impl.h
new file mode 100644
index 00000000000..c4d7a48a679
--- /dev/null
+++ b/libctfframe/ctf-frame-impl.h
@@ -0,0 +1,55 @@
+/* Implementation header.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This 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/>.  */
+
+#ifndef _CTF_FRAME_IMPL_H
+#define _CTF_FRAME_IMPL_H
+
+#include "ctf-frame-api.h"
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+#include <assert.h>
+#define ctf_frame_assert(expr) (assert (expr))
+
+struct ctf_frame_decoder_ctx
+{
+  ctf_frame_header cfd_header;	      /* CTF Frame header.  */
+  uint32_t *cfd_funcdesc;	      /* CTF function desc entries table.  */
+  void *cfd_fres;		      /* CTF FRE table.  */
+  int cfd_fre_nbytes;		      /* CTF fres number of bytes.  */
+};
+
+struct ctf_frame_encoder_ctx
+{
+  ctf_frame_header cfe_header;		/* CTF Frame header.  */
+  uint32_t *cfe_funcdesc;		/* CTF function desc entries table.  */
+  ctf_frame_row_entry *cfe_fres;	/* CTF FRE table.  */
+  uint32_t cfe_fre_nbytes;		/* CTF fres size in bytes.  */
+  char *cfe_data;			/* CTF data buffer.  */
+  size_t cfe_data_size;			/* CTF data buffer.  */
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _CTF_FRAME_IMPL_H */
diff --git a/libctfframe/ctf-frame.c b/libctfframe/ctf-frame.c
new file mode 100644
index 00000000000..fa90547269a
--- /dev/null
+++ b/libctfframe/ctf-frame.c
@@ -0,0 +1,1569 @@
+/* ctf-frame.c - CTF Frame decoder/encoder.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This 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 "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include "ctf-frame-impl.h"
+#include "swap.h"
+
+typedef struct cf_funidx_tbl
+{
+  unsigned int count;
+  unsigned int alloced;
+  ctf_frame_func_desc_entry entry[1];
+} cf_funidx_tbl;
+
+typedef struct cf_fre_tbl
+{
+  unsigned int count;
+  unsigned int alloced;
+  ctf_frame_row_entry entry[1];
+} cf_fre_tbl;
+
+#define _cf_printflike_(string_index,first_to_check) \
+    __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
+
+static void debug_printf (const char *, ...);
+
+static int _ctf_frame_debug;	/* Control for printing out debug info.  */
+static int number_of_entries = 64;
+
+static void
+ctf_frame_init_debug (void)
+{
+  static int inited;
+
+  if (!inited)
+    {
+      _ctf_frame_debug = getenv ("CTF_FRAME_DEBUG") != NULL;
+      inited = 1;
+    }
+}
+
+_cf_printflike_ (1, 2)
+static void debug_printf (const char *format, ...)
+{
+  if (_ctf_frame_debug)
+    {
+      va_list args;
+
+      va_start (args, format);
+      vfprintf (stderr, format, args);
+      va_end (args);
+    }
+}
+
+/* Generate bitmask of given size in bytes.  This is used for
+   some checks on the FRE start address.
+   CTF_FRAME_ROW_ENTRY_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ]
+   CTF_FRAME_ROW_ENTRY_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ]
+   CTF_FRAME_ROW_ENTRY_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ].  */
+#define CTF_BITMASK_OF_SIZE(size_in_bytes) \
+  (((uint64_t)1 << (size_in_bytes*8)) - 1)
+
+/* Store the specified error code into errp if it is non-NULL.
+   Return CTF_FRAME_ERR.  */
+
+static int
+ctf_frame_set_errno (int *errp, int error)
+{
+  if (errp != NULL)
+    *errp = error;
+  return CTF_FRAME_ERR;
+}
+
+/* Store the specified error code into errp if it is non-NULL.
+   Return NULL.  */
+
+static void *
+ctf_frame_ret_set_errno (int *errp, int error)
+{
+  if (errp != NULL)
+    *errp = error;
+  return NULL;
+}
+
+/* Access functions for frame row entry data.  */
+
+static unsigned int
+ctf_frame_fre_get_offset_count (unsigned char fre_info)
+{
+  return CTF_FRAME_V1_FRE_OFFSET_COUNT (fre_info);
+}
+
+static unsigned int
+ctf_frame_fre_get_offset_size (unsigned char fre_info)
+{
+  return CTF_FRAME_V1_FRE_OFFSET_SIZE (fre_info);
+}
+
+/* Access functions for info from function descriptor entry.  */
+
+static unsigned int
+ctf_frame_get_fre_type (ctf_frame_func_desc_entry *fdep)
+{
+  unsigned int fre_type = 0;
+  if (fdep)
+    fre_type = CTF_FRAME_V1_FUNC_FRE_TYPE (fdep->ctf_func_info);
+  return fre_type;
+}
+
+static unsigned int
+ctf_frame_get_fde_type (ctf_frame_func_desc_entry *fdep)
+{
+  unsigned int fde_type = 0;
+  if (fdep)
+    fde_type = CTF_FRAME_V1_FUNC_FDE_TYPE (fdep->ctf_func_info);
+  return fde_type;
+}
+
+/* Check if flipping is needed, based on ENDIAN.  */
+
+static int
+need_swapping (int endian)
+{
+  unsigned int ui = 1;
+  char *c = (char *)&ui;
+  int is_little = (int)*c;
+
+  switch (endian)
+    {
+      case CTF_FRAME_ABI_AARCH64_ENDIAN_LITTLE:
+      case CTF_FRAME_ABI_AMD64_ENDIAN_LITTLE:
+	return !is_little;
+      case CTF_FRAME_ABI_AARCH64_ENDIAN_BIG:
+	return is_little;
+      default:
+	break;
+    }
+
+  return 0;
+}
+
+/* Flip the endianness of the CTF header.  */
+
+static void
+flip_header (ctf_frame_header *cfh)
+{
+  swap_thing (cfh->cth_frame_preamble.ctfp_magic);
+  swap_thing (cfh->cth_frame_preamble.ctfp_version);
+  swap_thing (cfh->cth_frame_preamble.ctfp_flags);
+  swap_thing (cfh->cth_cfa_fixed_fp_offset);
+  swap_thing (cfh->cth_cfa_fixed_ra_offset);
+  swap_thing (cfh->cth_num_fdes);
+  swap_thing (cfh->cth_num_fres);
+  swap_thing (cfh->cth_fre_len);
+  swap_thing (cfh->cth_fdeoff);
+  swap_thing (cfh->cth_freoff);
+}
+
+static void
+flip_fde (ctf_frame_func_desc_entry *fdep)
+{
+  swap_thing (fdep->ctf_func_start_address);
+  swap_thing (fdep->ctf_func_size);
+  swap_thing (fdep->ctf_func_start_fre_off);
+  swap_thing (fdep->ctf_func_num_fres);
+}
+
+/* Check if CTF Frame header has valid data.  */
+
+static int
+ctf_frame_header_sanity_check_p (ctf_frame_header *hp)
+{
+  unsigned char all_flags = CTF_FRAME_F_FDE_SORTED | CTF_FRAME_F_FRAME_POINTER;
+  /* Check preamble is valid.  */
+  if ((hp->cth_frame_preamble.ctfp_magic != CTF_FRAME_MAGIC)
+      || (hp->cth_frame_preamble.ctfp_version != CTF_FRAME_VERSION)
+      || ((hp->cth_frame_preamble.ctfp_flags | all_flags)
+	  != all_flags))
+    return 0;
+
+  /* Check offsets are valid.  */
+  if (hp->cth_fdeoff > hp->cth_freoff)
+    return 0;
+
+  return 1;
+}
+
+/* Flip the start address pointed to by FP.  */
+
+static void
+flip_fre_start_address (char *fp, unsigned int fre_type)
+{
+  void *start = (void*)fp;
+  if (fre_type == CTF_FRAME_ROW_ENTRY_TYPE_ADDR2)
+    {
+      unsigned short *start_addr = (unsigned short *)(start);
+      swap_thing (*start_addr);
+    }
+  else if (fre_type == CTF_FRAME_ROW_ENTRY_TYPE_ADDR4)
+    {
+      uint32_t *start_addr = (uint32_t *)(start);
+      swap_thing (*start_addr);
+    }
+}
+
+static void
+flip_fre_stack_offsets (char *fp, unsigned char offset_size,
+			unsigned char offset_cnt)
+{
+  int j;
+  void *offsets = (void *)fp;
+
+  if (offset_size == CTF_FRAME_FRE_OFFSET_2B)
+    {
+      unsigned short *ust = (unsigned short *)offsets;
+      for (j = offset_cnt; j > 0; ust++, j--)
+	swap_thing (*ust);
+    }
+  else if (offset_size == CTF_FRAME_FRE_OFFSET_4B)
+    {
+      uint32_t *uit = (uint32_t *)offsets;
+      for (j = offset_cnt; j > 0; uit++, j--)
+	swap_thing (*uit);
+    }
+}
+
+/* Get the FRE start address size, given the FRE_TYPE.  */
+
+static size_t
+ctf_fre_start_addr_size (unsigned int fre_type)
+{
+  size_t addr_size = 0;
+  switch (fre_type)
+    {
+    case CTF_FRAME_ROW_ENTRY_TYPE_ADDR1:
+      addr_size = 1;
+      break;
+    case CTF_FRAME_ROW_ENTRY_TYPE_ADDR2:
+      addr_size = 2;
+      break;
+    case CTF_FRAME_ROW_ENTRY_TYPE_ADDR4:
+      addr_size = 4;
+      break;
+    default:
+      /* No other value is expected.  */
+      ctf_frame_assert (0);
+      break;
+    }
+  return addr_size;
+}
+
+/* Check if the FREP has valid data.  */
+
+static int
+ctf_fre_sanity_check_p (ctf_frame_row_entry *frep)
+{
+  unsigned int offset_size, offset_cnt;
+  unsigned int fre_info;
+
+  if (frep == NULL)
+    return 0;
+
+  fre_info = frep->fre_info;
+  offset_size = ctf_frame_fre_get_offset_size (fre_info);
+
+  if (offset_size != CTF_FRAME_FRE_OFFSET_1B
+      && offset_size != CTF_FRAME_FRE_OFFSET_2B
+      && offset_size != CTF_FRAME_FRE_OFFSET_4B)
+    return 0;
+
+  offset_cnt = ctf_frame_fre_get_offset_count (fre_info);
+  if (offset_cnt > 3)
+    return 0;
+
+  return 1;
+}
+
+/* Get FRE_INFO's offset size in bytes.  */
+
+static size_t
+ctf_fre_offset_bytes_size (unsigned char fre_info)
+{
+  unsigned int offset_size, offset_cnt;
+
+  offset_size = ctf_frame_fre_get_offset_size (fre_info);
+
+  debug_printf ("offset_size =  %u\n", offset_size);
+
+  offset_cnt = ctf_frame_fre_get_offset_count (fre_info);
+
+  if (offset_size == CTF_FRAME_FRE_OFFSET_2B
+      || offset_size == CTF_FRAME_FRE_OFFSET_4B)	/* 2 or 4 bytes.  */
+    return (offset_cnt * (offset_size * 2));
+
+  return (offset_cnt);
+}
+
+/* Get total size in bytes to represent FREP in the binary format.  This
+   includes the starting address, FRE info, and all the offsets.  */
+
+static size_t
+ctf_fre_entry_size (ctf_frame_row_entry *frep, unsigned int fre_type)
+{
+  if (frep == NULL)
+    return 0;
+
+  unsigned char fre_info = frep->fre_info;
+  size_t addr_size = ctf_fre_start_addr_size (fre_type);
+
+  return (addr_size + sizeof (frep->fre_info)
+	  + ctf_fre_offset_bytes_size (fre_info));
+}
+
+static int
+flip_fre (char *fp, unsigned int fre_type, size_t *fre_size)
+{
+  unsigned char fre_info;
+  unsigned int offset_size, offset_cnt;
+  size_t addr_size, fre_info_size = 0;
+  int err = 0;
+
+  if (fre_size == NULL)
+    return ctf_frame_set_errno (&err, EINVAL);
+
+  flip_fre_start_address (fp, fre_type);
+
+  /* Advance the buffer pointer to where the FRE info is.  */
+  addr_size = ctf_fre_start_addr_size (fre_type);
+  fp += addr_size;
+
+  /* FRE info is unsigned char.  No need to flip.  */
+  fre_info = *(unsigned char*)fp;
+  offset_size = ctf_frame_fre_get_offset_size (fre_info);
+  offset_cnt = ctf_frame_fre_get_offset_count (fre_info);
+
+  /* Advance the buffer pointer to where the stack offsets are.  */
+  fre_info_size = sizeof (unsigned char);
+  fp += fre_info_size;
+  flip_fre_stack_offsets (fp, offset_size, offset_cnt);
+
+  *fre_size
+    = addr_size + fre_info_size + ctf_fre_offset_bytes_size (fre_info);
+
+  return 0;
+}
+
+/* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
+   The CTF Frame header in the FRAME_BUF must be endian flipped prior to
+   calling flip_ctf_frame.  If an error code is returned, the buffer should
+   not be used.  */
+
+static int
+flip_ctf_frame (char *frame_buf, size_t buf_size)
+{
+  unsigned int i, j, prev_frep_index;
+  ctf_frame_header *ihp;
+  char *fdes;
+  char *fp = NULL;
+  ctf_frame_func_desc_entry *fdep;
+  unsigned int num_fdes, num_fres;
+  unsigned int fre_type;
+  size_t esz;
+  int err = 0;
+
+  /* Header must have been flipped by now.  */
+  ihp = (ctf_frame_header *)frame_buf;
+
+  if (!ctf_frame_header_sanity_check_p (ihp))
+    return ctf_frame_set_errno (&err, ECTF_FRAME_BUF_INVAL);
+
+  /* The contents of the CTF Frame header are safe to read.  Get the number of
+     FDEs and the first FDE in the buffer.  */
+  num_fdes = ihp->cth_num_fdes;
+  fdes = frame_buf + sizeof (ctf_frame_header) + ihp->cth_fdeoff;
+  fdep = (ctf_frame_func_desc_entry *)fdes;
+
+  j = 0;
+  prev_frep_index = 0;
+  for (i = 0; i < num_fdes; fdep++, i++)
+    {
+      flip_fde (fdep);
+
+      num_fres = fdep->ctf_func_num_fres;
+      fre_type = ctf_frame_get_fre_type (fdep);
+
+      fp = frame_buf + sizeof (ctf_frame_header) + ihp->cth_freoff;
+      fp += fdep->ctf_func_start_fre_off;
+      for (; j < prev_frep_index + num_fres; j++)
+	{
+	  if (flip_fre (fp, fre_type, &esz))
+	    goto bad;
+
+	  if (esz == 0)
+	    goto bad;
+	  fp += esz;
+	}
+      prev_frep_index = j;
+    }
+  /* All FREs must have been endian flipped by now.  */
+  if (j != ihp->cth_num_fres)
+    goto bad;
+  /* All contents must have been processed by now.  */
+  if ((frame_buf + buf_size) != (void*)fp)
+    goto bad;
+
+  /* Success.  */
+  return 0;
+bad:
+  return CTF_FRAME_ERR;
+}
+
+/* The CTF Frame Decoder.  */
+
+/* Compare function for qsort'ing the FDE table.  */
+
+static int
+fde_func (const void *p1, const void *p2)
+{
+  const ctf_frame_func_desc_entry *aa = p1;
+  const ctf_frame_func_desc_entry *bb = p2;
+
+  if (aa->ctf_func_start_address < bb->ctf_func_start_address)
+    return -1;
+  else if (aa->ctf_func_start_address > bb->ctf_func_start_address)
+    return 1;
+  return 0;
+}
+
+/* Get IDX'th offset from FRE.  Set errp as applicable.  */
+
+static int32_t
+ctf_frame_get_fre_offset (ctf_frame_row_entry *fre, int idx, int *errp)
+{
+  int offset_cnt, offset_size;
+
+  if (fre == NULL || !ctf_fre_sanity_check_p (fre))
+    return ctf_frame_set_errno (errp, ECTF_FRAME_FRE_INVAL);
+
+  offset_cnt = ctf_frame_fre_get_offset_count (fre->fre_info);
+  offset_size = ctf_frame_fre_get_offset_size (fre->fre_info);
+
+  if (offset_cnt < idx + 1)
+    return ctf_frame_set_errno (errp, ECTF_FRAME_FREOFFSET_NOPRESENT);
+
+  if (errp)
+    *errp = 0; /* Offset Valid.  */
+
+  if (offset_size == CTF_FRAME_FRE_OFFSET_1B)
+    {
+      int8_t *sp = (int8_t *)fre->fre_offsets;
+      return sp[idx];
+    }
+  else if (offset_size == CTF_FRAME_FRE_OFFSET_2B)
+    {
+      int16_t *sp = (int16_t *)fre->fre_offsets;
+      return sp[idx];
+    }
+  else
+    {
+      int32_t *ip = (int32_t *)fre->fre_offsets;
+      return ip[idx];
+    }
+}
+
+/* Free the decoder context.  */
+
+void
+ctf_frame_decoder_free (ctf_frame_decoder_ctx **decoder)
+{
+  if (decoder != NULL)
+    {
+      ctf_frame_decoder_ctx *dctx = *decoder;
+      if (dctx == NULL)
+	return;
+
+      if (dctx->cfd_funcdesc != NULL)
+	{
+	  free (dctx->cfd_funcdesc);
+	  dctx->cfd_funcdesc = NULL;
+	}
+      if (dctx->cfd_fres != NULL)
+	{
+	  free (dctx->cfd_fres);
+	  dctx->cfd_fres = NULL;
+	}
+
+      free (*decoder);
+      *decoder = NULL;
+    }
+}
+
+/* Get FDE function info given a FRE_TYPE.  */
+/* FIXME API for linker.  Revisit if its better placed somewhere else?  */
+
+unsigned char
+ctf_frame_fde_func_info (unsigned int fre_type,
+			 unsigned int fde_type)
+{
+  unsigned char func_info;
+  ctf_frame_assert (fre_type == CTF_FRAME_ROW_ENTRY_TYPE_ADDR1
+		   || fre_type == CTF_FRAME_ROW_ENTRY_TYPE_ADDR2
+		   || fre_type == CTF_FRAME_ROW_ENTRY_TYPE_ADDR4);
+  ctf_frame_assert (fde_type == CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCINC
+		    || fde_type == CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCMASK);
+  func_info = CTF_FRAME_V1_FUNC_INFO (fde_type, fre_type);
+  return func_info;
+}
+
+/* Gather the FRE type given the function size.  */
+/* FIXME API for linker.  Revisit if its better placed somewhere else?  */
+
+unsigned int
+ctf_frame_calc_fre_type (unsigned int func_size)
+{
+  unsigned int fre_type = 0;
+  if (func_size <= 0xff)
+    fre_type = CTF_FRAME_ROW_ENTRY_TYPE_ADDR1;
+  else if (func_size <= 0xffff)
+    fre_type = CTF_FRAME_ROW_ENTRY_TYPE_ADDR2;
+  else if (func_size <= 0xffffffff)
+    fre_type = CTF_FRAME_ROW_ENTRY_TYPE_ADDR4;
+  return fre_type;
+}
+
+/* Get the base reg id from the FRE info.  Set errp if failure.  */
+
+unsigned int
+ctf_frame_fre_get_base_reg_id (ctf_frame_row_entry *fre, int *errp)
+{
+  if (fre == NULL)
+    return ctf_frame_set_errno (errp, ECTF_FRAME_FRE_INVAL);
+
+  unsigned int fre_info = fre->fre_info;
+  return CTF_FRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
+}
+
+/* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+ctf_frame_fre_get_cfa_offset (ctf_frame_row_entry *fre, int *errp)
+{
+  return ctf_frame_get_fre_offset (fre, CTF_FRAME_FRE_CFA_OFFSET_IDX, errp);
+}
+
+/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+ctf_frame_fre_get_fp_offset (ctf_frame_row_entry *fre, int *errp)
+{
+  return ctf_frame_get_fre_offset (fre, CTF_FRAME_FRE_FP_OFFSET_IDX, errp);
+}
+
+/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+ctf_frame_fre_get_ra_offset (ctf_frame_row_entry *fre, int *errp)
+{
+  return ctf_frame_get_fre_offset (fre, CTF_FRAME_FRE_RA_OFFSET_IDX, errp);
+}
+
+static int
+ctf_frame_row_entry_copy (ctf_frame_row_entry *dst, ctf_frame_row_entry *src)
+{
+  int err = 0;
+
+  if (dst == NULL || src == NULL)
+    return ctf_frame_set_errno (&err, EINVAL);
+
+  memcpy (dst, src, sizeof (ctf_frame_row_entry));
+  return 0;
+}
+
+static int
+ctf_frame_decode_fre_start_address (const char *fre_buf,
+				    uint32_t *fre_start_addr,
+				    unsigned int fre_type)
+{
+  uint32_t saddr = 0;
+  int err = 0;
+
+  if (fre_type == CTF_FRAME_ROW_ENTRY_TYPE_ADDR1)
+    {
+      uint8_t *uc = (uint8_t *)fre_buf;
+      saddr = (uint32_t)*uc;
+    }
+  else if (fre_type == CTF_FRAME_ROW_ENTRY_TYPE_ADDR2)
+    {
+      uint16_t *ust = (uint16_t *)fre_buf;
+      saddr = (uint32_t)*ust;
+    }
+  else if (fre_type == CTF_FRAME_ROW_ENTRY_TYPE_ADDR4)
+    {
+      uint32_t *uit = (uint32_t *)fre_buf;
+      saddr = (uint32_t)*uit;
+    }
+  else
+    return ctf_frame_set_errno (&err, EINVAL);
+
+  *fre_start_addr = saddr;
+  return 0;
+}
+
+/* Decode a frame row entry FRE which starts at location FRE_BUF.  The function
+   updates ESZ to the size of the FRE as stored in the binary format.
+
+   This function works closely with the CTF Frame binary format.
+
+   Returns CTF_FRAME_ERR if failure.  */
+
+static int
+ctf_frame_decode_fre (const char *fre_buf, ctf_frame_row_entry *fre,
+		      unsigned int fre_type,
+		      size_t *esz)
+{
+  int err = 0;
+  void *stack_offsets = NULL;
+  size_t stack_offsets_sz;
+  size_t addr_size;
+  size_t fre_size;
+
+  if (fre_buf == NULL || fre == NULL || esz == NULL)
+    return ctf_frame_set_errno (&err, EINVAL);
+
+  /* Copy over the FRE start address.  */
+  ctf_frame_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
+
+  addr_size = ctf_fre_start_addr_size (fre_type);
+  fre->fre_info = *(unsigned char *)(fre_buf + addr_size);
+  /* Sanity check as the API works closely with the binary format.  */
+  ctf_frame_assert (sizeof (fre->fre_info) == sizeof (unsigned char));
+
+  /* Cleanup the space for fre_offsets first, then copy over the valid
+     bytes.  */
+  memset (fre->fre_offsets, 0, MAX_OFFSET_BYTES);
+  /* Get offsets size.  */
+  stack_offsets_sz = ctf_fre_offset_bytes_size (fre->fre_info);
+  stack_offsets = (unsigned char *)fre_buf + addr_size + sizeof (fre->fre_info);
+  memcpy (fre->fre_offsets, stack_offsets, stack_offsets_sz);
+
+  /* The FRE has been decoded.  Use it to perform one last sanity check.  */
+  fre_size = ctf_fre_entry_size (fre, fre_type);
+  ctf_frame_assert (fre_size == (addr_size + sizeof (fre->fre_info)
+				 + stack_offsets_sz));
+  *esz = fre_size;
+
+  return 0;
+}
+
+/* Decode the specified CTF Frame buffer CF_BUF of size CF_SIZE and return the
+   new CTF Frame decoder context.
+
+   Sets ERRP for the caller if any error.  Frees up the allocated memory in
+   case of error.  */
+
+ctf_frame_decoder_ctx *
+ctf_frame_decode (const char *cf_buf, size_t cf_size, int *errp)
+{
+  const ctf_frame_preamble *cfpp;
+  size_t hdrsz = sizeof (ctf_frame_header);
+  ctf_frame_header *cfhp;
+  ctf_frame_decoder_ctx *dctx;
+  char *frame_buf;
+  char *tempbuf = NULL;
+
+  int fidx_size;
+  uint32_t fre_bytes;
+  int foreign_endian = 0;
+
+  ctf_frame_init_debug ();
+
+  if ((cf_buf == NULL) || (!cf_size))
+    return ctf_frame_ret_set_errno (errp, ECTF_FRAME_INVAL);
+  else if (cf_size < hdrsz)
+    return ctf_frame_ret_set_errno (errp, ECTF_FRAME_BUF_INVAL);
+
+  cfpp = (const ctf_frame_preamble *) cf_buf;
+
+  debug_printf ("ctf_frame_decode: magic=0x%x version=%u flags=%u\n",
+		cfpp->ctfp_magic, cfpp->ctfp_version, cfpp->ctfp_flags);
+
+  /* Check for foreign endianness.  */
+  if (cfpp->ctfp_magic != CTF_FRAME_MAGIC)
+    {
+      if (cfpp->ctfp_magic == bswap_16 (CTF_FRAME_MAGIC))
+	foreign_endian = 1;
+      else
+	return ctf_frame_ret_set_errno (errp, ECTF_FRAME_BUF_INVAL);
+    }
+
+  /* Initialize a new decoder context.  */
+  if ((dctx = malloc (sizeof (ctf_frame_decoder_ctx))) == NULL)
+    return ctf_frame_ret_set_errno (errp, ECTF_FRAME_NOMEM);
+  memset (dctx, 0, sizeof (ctf_frame_decoder_ctx));
+
+  if (foreign_endian)
+    {
+      /* Allocate a new buffer and initialize it.  */
+      tempbuf = (char *) malloc (cf_size * sizeof (char));
+      if (tempbuf == NULL)
+	return ctf_frame_ret_set_errno (errp, ECTF_FRAME_NOMEM);
+      memcpy (tempbuf, cf_buf, cf_size);
+
+      /* Flip the header.  */
+      ctf_frame_header *ihp = (ctf_frame_header *) tempbuf;
+      flip_header (ihp);
+      /* Flip the rest of the CTF Frame section data buffer.  */
+      if (flip_ctf_frame (tempbuf, cf_size))
+	{
+	  free (tempbuf);
+	  return ctf_frame_ret_set_errno (errp, ECTF_FRAME_BUF_INVAL);
+	}
+      frame_buf = tempbuf;
+    }
+  else
+    frame_buf = (char *)cf_buf;
+
+  /* Handle the CTF header.  */
+  dctx->cfd_header = *(ctf_frame_header *) frame_buf;
+  /* Validate the contents of CTF header.  */
+  cfhp = &dctx->cfd_header;
+  if (!ctf_frame_header_sanity_check_p (cfhp))
+    {
+      ctf_frame_ret_set_errno (errp, ECTF_FRAME_NOMEM);
+      goto decode_fail_free;
+    }
+  frame_buf += hdrsz;
+
+  /* Handle the CTF Function Descriptor Entry section.  */
+  fidx_size
+    = cfhp->cth_num_fdes * sizeof (ctf_frame_func_desc_entry);
+  dctx->cfd_funcdesc = malloc (fidx_size);
+  if (dctx->cfd_funcdesc == NULL)
+    {
+      ctf_frame_ret_set_errno (errp, ECTF_FRAME_NOMEM);
+      goto decode_fail_free;
+    }
+  memcpy (dctx->cfd_funcdesc, frame_buf, fidx_size);
+
+  debug_printf ("%u total fidx size\n", fidx_size);
+
+  frame_buf += (fidx_size);
+
+  /* Handle the CTF Frame Row Entry section.  */
+  dctx->cfd_fres = malloc (cfhp->cth_fre_len);
+  if (dctx->cfd_fres == NULL)
+    {
+      ctf_frame_ret_set_errno (errp, ECTF_FRAME_NOMEM);
+      goto decode_fail_free;
+    }
+  memcpy (dctx->cfd_fres, frame_buf, cfhp->cth_fre_len);
+
+  fre_bytes = cfhp->cth_fre_len;
+  dctx->cfd_fre_nbytes = fre_bytes;
+
+  debug_printf ("%u total fre bytes\n", fre_bytes);
+
+  return dctx;
+
+decode_fail_free:
+  if (foreign_endian && tempbuf != NULL)
+    free (tempbuf);
+  ctf_frame_decoder_free (&dctx);
+  dctx = NULL;
+  return dctx;
+}
+
+/* Get DECODER's CTF Frame header.  */
+
+static ctf_frame_header *
+ctf_frame_decoder_get_header (ctf_frame_decoder_ctx *decoder)
+{
+  ctf_frame_header *hp = NULL;
+  if (decoder != NULL)
+    hp = &decoder->cfd_header;
+  return hp;
+}
+
+/* Get the CTF Frame's abi/arch info.  */
+
+unsigned char
+ctf_frame_decoder_get_abi_arch (ctf_frame_decoder_ctx *ctx)
+{
+  ctf_frame_header *ctff_header;
+  ctff_header = ctf_frame_decoder_get_header (ctx);
+  return ctff_header->cth_frame_abi_arch;
+}
+
+/* Find the function descriptor entry starting which contains the specified
+   address ADDR.  */
+
+ctf_frame_func_desc_entry *
+ctf_frame_get_funcdesc_with_addr (ctf_frame_decoder_ctx *ctx,
+				  int32_t addr, int *errp)
+{
+  ctf_frame_header *dhp;
+  ctf_frame_func_desc_entry *fdp;
+  int low, high, cnt;
+
+  if (ctx == NULL)
+    return ctf_frame_ret_set_errno (errp, EINVAL);
+
+  dhp = ctf_frame_decoder_get_header (ctx);
+
+  if (dhp == NULL || dhp->cth_num_fdes == 0 || ctx->cfd_funcdesc == NULL)
+    return ctf_frame_ret_set_errno (errp, ECTF_FRAME_DCTX_INVAL);
+  /* If the FDE sub-section is not sorted on PCs,  it is OK to do it now.
+     This allows the usage of binary search later below.  */
+  if ((dhp->cth_frame_preamble.ctfp_flags & CTF_FRAME_F_FDE_SORTED) == 0)
+    {
+      /* Sort the FDE table.  */
+      qsort (ctx->cfd_funcdesc, dhp->cth_num_fdes,
+	     sizeof (ctf_frame_func_desc_entry), fde_func);
+      dhp->cth_frame_preamble.ctfp_flags |= CTF_FRAME_F_FDE_SORTED;
+    }
+
+  /* Do the binary search.  */
+  fdp = (ctf_frame_func_desc_entry *) ctx->cfd_funcdesc;
+  low = 0;
+  high = dhp->cth_num_fdes;
+  cnt = high;
+  while (low <= high)
+    {
+      int mid = low + (high - low) / 2;
+
+      if (fdp[mid].ctf_func_start_address == addr)
+	return fdp + mid;
+
+      if (fdp[mid].ctf_func_start_address < addr)
+	{
+	  if (mid == (cnt - 1)) 	/* Check if it's the last one.  */
+	    return fdp + (cnt - 1) ;
+	  else if (fdp[mid+1].ctf_func_start_address > addr)
+	    return fdp + mid;
+	  low = mid + 1;
+	}
+      else
+	high = mid - 1;
+    }
+
+  return ctf_frame_ret_set_errno (errp, ECTF_FRAME_FDE_NOTFOUND);
+}
+
+/* Find the CTF Frame Row Entry which contains the PC.  Returns
+   CTF_FRAME_ERR if failure.  */
+
+int
+ctf_frame_find_fre (ctf_frame_decoder_ctx *ctx, int32_t pc,
+		    ctf_frame_row_entry *frep)
+{
+  ctf_frame_func_desc_entry *fdep;
+  uint32_t start_address, i;
+  ctf_frame_row_entry cur_fre, next_fre;
+  unsigned char *sp;
+  unsigned int fre_type, fde_type;
+  size_t esz;
+  int err = 0;
+  size_t size = 0;
+  /* For regular FDEs (i.e. fde_type CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCMASK),
+     where the start address in the FRE is an offset from start pc,
+     use a bitmask with all bits set so that none of the address bits are
+     ignored.  In this case, we need to return the FRE where
+     (PC >= FRE_START_ADDR) */
+  uint64_t bitmask = 0xffffffff;
+
+  if ((ctx == NULL) || (frep == NULL))
+    return ctf_frame_set_errno (&err, EINVAL);
+
+  /* Find the FDE which contains the PC, then scan its fre entries.  */
+  fdep = ctf_frame_get_funcdesc_with_addr (ctx, pc, &err);
+  if (fdep == NULL || ctx->cfd_fres == NULL)
+    return ctf_frame_set_errno (&err, ECTF_FRAME_DCTX_INVAL);
+
+  fre_type = ctf_frame_get_fre_type (fdep);
+  fde_type = ctf_frame_get_fde_type (fdep);
+
+  /* For FDEs for repetitive pattern of insns, we need to return the FRE
+     such that (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK).
+     so, update the bitmask to the start address.  */
+  if (fde_type == CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCMASK)
+    bitmask = start_address;
+
+  sp = (unsigned char *) ctx->cfd_fres + fdep->ctf_func_start_fre_off;
+  for (i = 0; i < fdep->ctf_func_num_fres; i++)
+   {
+     err = ctf_frame_decode_fre ((const char *)sp, &next_fre,
+				 fre_type, &esz);
+     start_address = next_fre.fre_start_addr;
+
+     if (((fdep->ctf_func_start_address
+	   + (int32_t) start_address) & bitmask) <= (pc & bitmask))
+       {
+	 ctf_frame_row_entry_copy (&cur_fre, &next_fre);
+
+	 /* Get the next FRE in sequence.  */
+	 if (i < fdep->ctf_func_num_fres - 1)
+	   {
+	     sp += esz;
+	     err = ctf_frame_decode_fre ((const char*)sp, &next_fre,
+					 fre_type, &esz);
+
+	     /* Sanity check the next FRE.  */
+	     if (!ctf_fre_sanity_check_p (&next_fre))
+	       return ctf_frame_set_errno (&err, ECTF_FRAME_FRE_INVAL);
+
+	     size = next_fre.fre_start_addr;
+	   }
+	 else size = fdep->ctf_func_size;
+
+	 /* If the cur FRE is the one that contains the PC, return it.  */
+	 if (((fdep->ctf_func_start_address
+	       + (int32_t)size) & bitmask) > (pc & bitmask))
+	   {
+	     ctf_frame_row_entry_copy (frep, &cur_fre);
+	     return 0;
+	   }
+       }
+     else
+       return ctf_frame_set_errno (&err, ECTF_FRAME_FRE_INVAL);
+   }
+  return ctf_frame_set_errno (&err, ECTF_FRAME_FDE_INVAL);
+}
+
+/* Return the number of function descriptor entries in the CTF Frame decoder
+   DCTX.  */
+
+unsigned int
+ctf_frame_decoder_get_num_fidx (ctf_frame_decoder_ctx *ctx)
+{
+  unsigned int num_fdes = 0;
+  ctf_frame_header *dhp = NULL;
+  dhp = ctf_frame_decoder_get_header (ctx);
+  if (dhp)
+    num_fdes = dhp->cth_num_fdes;
+  return num_fdes;
+}
+
+/* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
+   descriptor entry at index I'th in the decoder CTX.  If failed,
+   return error code.  */
+/* FIXME - consolidate the args and return a
+   ctf_frame_func_desc_index_elem rather?  */
+
+int
+ctf_frame_decoder_get_funcdesc (ctf_frame_decoder_ctx *ctx,
+				unsigned int i,
+				uint32_t *num_fres,
+				uint32_t *func_size,
+				int32_t *func_start_address,
+				unsigned char *func_info)
+{
+  ctf_frame_func_desc_entry *fdp;
+  unsigned int num_fdes;
+  int err = 0;
+
+  if (ctx == NULL || func_start_address == NULL || num_fres == NULL
+      || func_size == NULL)
+    return ctf_frame_set_errno (&err, EINVAL);
+
+  num_fdes = ctf_frame_decoder_get_num_fidx (ctx);
+  if (num_fdes == 0
+      || i >= num_fdes
+      || ctx->cfd_funcdesc == NULL)
+    return ctf_frame_set_errno (&err, ECTF_FRAME_DCTX_INVAL);
+
+  fdp = (ctf_frame_func_desc_entry *) ctx->cfd_funcdesc + i;
+  *num_fres = fdp->ctf_func_num_fres;
+  *func_start_address = fdp->ctf_func_start_address;
+  *func_size = fdp->ctf_func_size;
+  *func_info = fdp->ctf_func_info;
+
+  return 0;
+}
+
+/* Get the function descriptor entry at index FUNC_IDX in the decoder
+   context CTX.  */
+
+static ctf_frame_func_desc_entry *
+ctf_frame_decoder_get_funcdesc_at_index (ctf_frame_decoder_ctx *ctx,
+					 uint32_t func_idx)
+{
+  /* Invalid argument.  No FDE will be found.  */
+  if (func_idx >= ctf_frame_decoder_get_num_fidx (ctx))
+    return NULL;
+
+  ctf_frame_func_desc_entry *fdep;
+  fdep = (ctf_frame_func_desc_entry *) ctx->cfd_funcdesc;
+  return fdep + func_idx;
+}
+
+/* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
+   descriptor entry in the CTF Frame decoder CTX.  Returns error code as
+   applicable.  */
+
+int
+ctf_frame_decoder_get_fre (ctf_frame_decoder_ctx *ctx,
+			   unsigned int func_idx,
+			   unsigned int fre_idx,
+			   ctf_frame_row_entry *fre)
+{
+  ctf_frame_func_desc_entry *fdep;
+  ctf_frame_row_entry ifre;
+  unsigned char *sp;
+  uint32_t i;
+  unsigned int fre_type;
+  size_t esz = 0;
+  int err = 0;
+
+  if (ctx == NULL || fre == NULL)
+    return ctf_frame_set_errno (&err, EINVAL);
+
+  /* Get function descriptor entry at index func_idx.  */
+  fdep = ctf_frame_decoder_get_funcdesc_at_index (ctx, func_idx);
+
+  if (fdep == NULL)
+    return ctf_frame_set_errno (&err, ECTF_FRAME_FDE_NOTFOUND);
+
+  fre_type = ctf_frame_get_fre_type (fdep);
+  /* Now scan the FRE entries.  */
+  sp = (unsigned char *) ctx->cfd_fres + fdep->ctf_func_start_fre_off;
+  for (i = 0; i < fdep->ctf_func_num_fres; i++)
+   {
+     /* Decode the FRE at the current position.  Return it if valid.  */
+     err = ctf_frame_decode_fre ((const char *)sp, &ifre, fre_type, &esz);
+     if (i == fre_idx)
+       {
+	 if (!ctf_fre_sanity_check_p (&ifre))
+	   return ctf_frame_set_errno (&err, ECTF_FRAME_FRE_INVAL);
+
+	 ctf_frame_row_entry_copy (fre, &ifre);
+
+	 if (fdep->ctf_func_size)
+	   ctf_frame_assert (fre->fre_start_addr < fdep->ctf_func_size);
+	 else
+	   /* A CTF FDE with func size equal to zero is possible.  */
+	   ctf_frame_assert (fre->fre_start_addr == fdep->ctf_func_size);
+
+	 return 0;
+       }
+     /* Next FRE.  */
+     sp += esz;
+   }
+
+  return ctf_frame_set_errno (&err, ECTF_FRAME_FDE_NOTFOUND);
+}
+
+
+/* CTF Frame Encoder.  */
+
+/* Get a reference to the ENCODER's CTF Frame header.  */
+
+static ctf_frame_header *
+ctf_frame_encoder_get_header (ctf_frame_encoder_ctx *encoder)
+{
+  ctf_frame_header *hp = NULL;
+  if (encoder)
+    hp = &encoder->cfe_header;
+  return hp;
+}
+
+static ctf_frame_func_desc_entry *
+ctf_frame_encoder_get_funcdesc_at_index (ctf_frame_encoder_ctx *encoder,
+					 uint32_t func_idx)
+{
+  ctf_frame_func_desc_entry *fde = NULL;
+  if (func_idx < ctf_frame_encoder_get_num_fidx (encoder))
+    {
+      cf_funidx_tbl *func_tbl = (cf_funidx_tbl *) encoder->cfe_funcdesc;
+      fde = func_tbl->entry + func_idx;
+    }
+  return fde;
+}
+
+/* Create an encoder context with the given CTF format version VER, FLAGS and
+   ABI information.  Sets errp if failure.  */
+
+ctf_frame_encoder_ctx *
+ctf_frame_encode (unsigned char ver, unsigned char flags, int abi_arch,
+		  int *errp)
+{
+  ctf_frame_header *hp;
+  ctf_frame_encoder_ctx *fp;
+
+  if (ver != CTF_FRAME_VERSION)
+    return ctf_frame_ret_set_errno (errp, ECTF_FRAME_VERSION_INVAL);
+
+  if ((fp = malloc (sizeof (ctf_frame_encoder_ctx))) == NULL)
+    return ctf_frame_ret_set_errno (errp, ECTF_FRAME_NOMEM);
+
+  memset (fp, 0, sizeof (ctf_frame_encoder_ctx));
+
+  /* Get the CTF header and update it.  */
+  hp = ctf_frame_encoder_get_header (fp);
+  hp->cth_frame_preamble.ctfp_version = ver;
+  hp->cth_frame_preamble.ctfp_magic = CTF_FRAME_MAGIC;
+  hp->cth_frame_preamble.ctfp_flags = flags;
+  hp->cth_frame_abi_arch = abi_arch;
+
+  return fp;
+}
+
+/* Free the encoder context.  */
+
+void
+ctf_free_encoder (ctf_frame_encoder_ctx *encoder)
+{
+  if (encoder != NULL)
+    {
+      free (encoder->cfe_funcdesc);
+      free (encoder->cfe_fres);
+      free (encoder->cfe_data);
+      free (encoder);
+    }
+}
+
+/* Get the abi/arch info from the CTF Frame encoder context ENCODER.  */
+
+unsigned char
+ctf_frame_encoder_get_abi_arch (ctf_frame_encoder_ctx *encoder)
+{
+  unsigned char abi_arch = 0;
+  ctf_frame_header *ehp;
+  ehp = ctf_frame_encoder_get_header (encoder);
+  if (ehp)
+    abi_arch = ehp->cth_frame_abi_arch;
+  return abi_arch;
+}
+
+/* Return the number of function descriptor entries in the CTF Frame encoder
+   ENCODER.  */
+
+unsigned int
+ctf_frame_encoder_get_num_fidx (ctf_frame_encoder_ctx *encoder)
+{
+  unsigned int num_fdes = 0;
+  ctf_frame_header *ehp = NULL;
+  ehp = ctf_frame_encoder_get_header (encoder);
+  if (ehp)
+    num_fdes = ehp->cth_num_fdes;
+  return num_fdes;
+}
+
+/* Add an FRE to function at FUNC_IDX'th function descriptor entry in
+   the encoder context.  */
+
+int
+ctf_frame_encoder_add_fre (ctf_frame_encoder_ctx *encoder,
+			   unsigned int func_idx,
+			   ctf_frame_row_entry *frep)
+{
+  ctf_frame_header *ehp;
+  ctf_frame_func_desc_entry *fdep;
+  ctf_frame_row_entry *ectx_frep;
+  size_t offsets_sz, esz;
+  unsigned int fre_type;
+  size_t fre_tbl_sz;
+  int err = 0;
+
+  if (encoder == NULL || frep == NULL)
+    return ctf_frame_set_errno (&err, EINVAL);
+  if (!ctf_fre_sanity_check_p (frep))
+    return ctf_frame_set_errno (&err, ECTF_FRAME_FRE_INVAL);
+
+  /* Use func_idx to gather the function descriptor entry.  */
+  fdep = ctf_frame_encoder_get_funcdesc_at_index (encoder, func_idx);
+
+  if (fdep == NULL)
+    return ctf_frame_set_errno (&err, ECTF_FRAME_FDE_NOTFOUND);
+
+  fre_type = ctf_frame_get_fre_type (fdep);
+  cf_fre_tbl *fre_tbl = (cf_fre_tbl *) encoder->cfe_fres;
+
+  if (fre_tbl == NULL)
+    {
+      fre_tbl_sz = (sizeof (cf_fre_tbl)
+		    + (number_of_entries * sizeof (ctf_frame_row_entry)));
+      fre_tbl = malloc (fre_tbl_sz);
+
+      if (fre_tbl == NULL)
+	{
+	  ctf_frame_set_errno (&err, ECTF_FRAME_NOMEM);
+	  goto bad;		/* OOM.  */
+	}
+      memset (fre_tbl, 0, fre_tbl_sz);
+      fre_tbl->alloced = number_of_entries;
+    }
+  else if (fre_tbl->count == fre_tbl->alloced)
+    {
+      fre_tbl_sz = (sizeof (cf_fre_tbl)
+		    + ((fre_tbl->alloced + number_of_entries)
+		       * sizeof (ctf_frame_row_entry)));
+      fre_tbl = realloc (fre_tbl, fre_tbl_sz);
+      if (fre_tbl == NULL)
+	{
+	  ctf_frame_set_errno (&err, ECTF_FRAME_NOMEM);
+	  goto bad;		/* OOM.  */
+	}
+
+      memset (&fre_tbl->entry[fre_tbl->alloced], 0,
+	      number_of_entries * sizeof (ctf_frame_row_entry));
+      fre_tbl->alloced += number_of_entries;
+    }
+
+  ectx_frep = &fre_tbl->entry[fre_tbl->count];
+  ectx_frep->fre_start_addr
+    = frep->fre_start_addr;
+  ectx_frep->fre_info = frep->fre_info;
+
+  if (fdep->ctf_func_size)
+    ctf_frame_assert (frep->fre_start_addr < fdep->ctf_func_size);
+  else
+    /* A CTF FDE with func size equal to zero is possible.  */
+    ctf_frame_assert (frep->fre_start_addr == fdep->ctf_func_size);
+
+  /* frep has already been sanity check'd.  Get offsets size.  */
+  offsets_sz = ctf_fre_offset_bytes_size (frep->fre_info);
+  memcpy (&ectx_frep->fre_offsets, &frep->fre_offsets, offsets_sz);
+
+  esz = ctf_fre_entry_size (frep, fre_type);
+  fre_tbl->count++;
+
+  encoder->cfe_fres = (void *) fre_tbl;
+  encoder->cfe_fre_nbytes += esz;
+
+  ehp = ctf_frame_encoder_get_header (encoder);
+  ehp->cth_num_fres = fre_tbl->count;
+
+  /* Update the value of the number of FREs for the function.  */
+  fdep->ctf_func_num_fres++;
+
+  return 0;
+
+bad:
+  if (fre_tbl != NULL)
+    free (fre_tbl);
+  encoder->cfe_fres = NULL;
+  encoder->cfe_fre_nbytes = 0;
+  return -1;
+}
+
+/* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
+   to the encoder.  */
+
+int
+ctf_frame_encoder_add_funcdesc (ctf_frame_encoder_ctx *encoder,
+			      int32_t start_addr,
+			      uint32_t func_size,
+			      unsigned char func_info,
+			      uint32_t num_fres __attribute__ ((unused)))
+{
+  ctf_frame_header *ehp;
+  cf_funidx_tbl *fd_info;
+  size_t fd_tbl_sz;
+  int err = 0;
+
+  /* FIXME book-keep num_fres for error checking.  */
+  if (encoder == NULL)
+    return ctf_frame_set_errno (&err, EINVAL);
+
+  fd_info = (cf_funidx_tbl *) encoder->cfe_funcdesc;
+  ehp = ctf_frame_encoder_get_header (encoder);
+
+  if (fd_info == NULL)
+    {
+      fd_tbl_sz = (sizeof (cf_funidx_tbl)
+		   + (number_of_entries * sizeof (ctf_frame_func_desc_entry)));
+      fd_info = malloc (fd_tbl_sz);
+      if (fd_info == NULL)
+	{
+	  ctf_frame_set_errno (&err, ECTF_FRAME_NOMEM);
+	  goto bad;		/* OOM.  */
+	}
+      memset (fd_info, 0, fd_tbl_sz);
+      fd_info->alloced = number_of_entries;
+    }
+  else if (fd_info->count == fd_info->alloced)
+    {
+      fd_tbl_sz = (sizeof (cf_funidx_tbl)
+		   + ((fd_info->alloced + number_of_entries)
+		      * sizeof (ctf_frame_func_desc_entry)));
+      fd_info = realloc (fd_info, fd_tbl_sz);
+      if (fd_info == NULL)
+	{
+	  ctf_frame_set_errno (&err, ECTF_FRAME_NOMEM);
+	  goto bad;		/* OOM.  */
+	}
+
+      memset (&fd_info->entry[fd_info->alloced], 0,
+	      number_of_entries * sizeof (ctf_frame_func_desc_entry));
+      fd_info->alloced += number_of_entries;
+    }
+
+  fd_info->entry[fd_info->count].ctf_func_start_address = start_addr;
+  /* Num FREs is updated as FREs are added for the function later via
+     ctf_frame_encoder_add_fre.  */
+  fd_info->entry[fd_info->count].ctf_func_size = func_size;
+  fd_info->entry[fd_info->count].ctf_func_start_fre_off
+    = encoder->cfe_fre_nbytes;
+#if 0
+  // Linker optimization test code cleanup later ibhagat TODO FIXME
+  unsigned int fre_type = ctf_frame_calc_fre_type (func_size);
+
+  fd_info->entry[fd_info->count].ctf_func_info
+    = ctf_frame_fde_func_info (fre_type);
+#endif
+  fd_info->entry[fd_info->count].ctf_func_info = func_info;
+  fd_info->count++;
+  encoder->cfe_funcdesc = (void *) fd_info;
+  ehp->cth_num_fdes++;
+  return 0;
+
+bad:
+  if (fd_info != NULL)
+    free (fd_info);
+  encoder->cfe_funcdesc = NULL;
+  ehp->cth_num_fdes = 0;
+  return -1;
+}
+
+static int
+ctf_frame_sort_funcdesc (ctf_frame_encoder_ctx *encoder)
+{
+  ctf_frame_header *ehp;
+
+  ehp = ctf_frame_encoder_get_header (encoder);
+  /* Sort and write out the FDE table.  */
+  cf_funidx_tbl *fd_info = (cf_funidx_tbl *) encoder->cfe_funcdesc;
+  if (fd_info)
+    {
+      qsort (fd_info->entry, fd_info->count,
+	     sizeof (ctf_frame_func_desc_entry), fde_func);
+      /* Update preamble's flags.  */
+      ehp->cth_frame_preamble.ctfp_flags |= CTF_FRAME_F_FDE_SORTED;
+    }
+  return 0;
+}
+
+/* Write a frame row entry pointed to by FREP into the buffer CONTENTS.  The
+   size in bytes written out are updated in ESZ.
+
+   This function works closely with the CTF Frame binary format.
+
+   Returns CTF_FRAME_ERR if failure.  */
+
+static int
+ctf_frame_encoder_write_fre (char *contents, ctf_frame_row_entry *frep,
+			     unsigned int fre_type, size_t *esz)
+{
+  size_t fre_size;
+  size_t fre_start_addr_sz;
+  size_t fre_stack_offsets_sz;
+  int err = 0;
+
+  if (!ctf_fre_sanity_check_p (frep))
+    return ctf_frame_set_errno (&err, ECTF_FRAME_FRE_INVAL);
+
+  fre_start_addr_sz = ctf_fre_start_addr_size (fre_type);
+  fre_stack_offsets_sz = ctf_fre_offset_bytes_size (frep->fre_info);
+
+  /* The FRE start address must be encodable in the available number of
+     bytes.  */
+  uint64_t bitmask = CTF_BITMASK_OF_SIZE (fre_start_addr_sz);
+  ctf_frame_assert ((uint64_t)frep->fre_start_addr <= bitmask);
+
+  memcpy (contents,
+	  &frep->fre_start_addr,
+	  fre_start_addr_sz);
+  contents += fre_start_addr_sz;
+
+  memcpy (contents,
+	  &frep->fre_info,
+	  sizeof (frep->fre_info));
+  contents += sizeof (frep->fre_info);
+
+  memcpy (contents,
+	  frep->fre_offsets,
+	  fre_stack_offsets_sz);
+  contents+= fre_stack_offsets_sz;
+
+  fre_size = ctf_fre_entry_size (frep, fre_type);
+  /* Sanity checking.  */
+  ctf_frame_assert ((fre_start_addr_sz
+		     + sizeof (frep->fre_info)
+		     + fre_stack_offsets_sz) == fre_size);
+
+  *esz = fre_size;
+
+  return 0;
+}
+
+/* Serialize the core contents of the CTF Frame section and write out to the
+   output buffer held in the ENCODER.  Return CTF_FRAME_ERR if failure.  */
+
+static int
+ctf_frame_encoder_write_ctf_frame (ctf_frame_encoder_ctx *encoder)
+{
+  char *contents;
+  size_t buf_size;
+  size_t hdr_size;
+  size_t all_fdes_size;
+  size_t fre_size;
+  size_t esz = 0;
+  ctf_frame_header *ehp;
+  unsigned char flags;
+  cf_funidx_tbl *fd_info;
+  cf_fre_tbl *fr_info;
+  uint32_t i, num_fdes;
+  uint32_t j, num_fres;
+  ctf_frame_func_desc_entry *fdep;
+  ctf_frame_row_entry *frep;
+
+  unsigned int fre_type;
+  int err = 0;
+
+  contents = encoder->cfe_data;
+  buf_size = encoder->cfe_data_size;
+  hdr_size = sizeof (ctf_frame_header);
+  num_fdes = ctf_frame_encoder_get_num_fidx (encoder);
+  all_fdes_size = num_fdes * sizeof (ctf_frame_func_desc_entry);
+  ehp = ctf_frame_encoder_get_header (encoder);
+
+  fd_info = (cf_funidx_tbl *) encoder->cfe_funcdesc;
+  fr_info = (cf_fre_tbl *) encoder->cfe_fres;
+
+  /* Sanity checks:
+     - buffers must be malloc'd by the caller.  */
+  if ((contents == NULL) || (buf_size < hdr_size))
+    return ctf_frame_set_errno (&err, ECTF_FRAME_BUF_INVAL);
+  if (fr_info == NULL)
+    return ctf_frame_set_errno (&err, ECTF_FRAME_FRE_INVAL);
+
+  /* Write out the FRE table first.
+
+     Recall that read/write of FREs needs information from the corresponding
+     FDE; the latter stores the information about the FRE type record used for
+     the function.  Also note that sorting of FDEs does NOT impact the order
+     in which FREs are stored in the CTF Frame's FRE sub-section.  This means
+     that writing out FREs after sorting of FDEs will need some additional
+     book-keeping.  At this time, we can afford to avoid it by writing out
+     the FREs first to the output buffer.  */
+  fre_size = 0;
+  uint32_t global = 0;
+  uint32_t fre_index = 0;
+
+  contents += hdr_size + all_fdes_size;
+  for (i = 0; i < num_fdes; i++)
+    {
+      fdep = &fd_info->entry[i];
+      fre_type = ctf_frame_get_fre_type (fdep);
+      num_fres = fdep->ctf_func_num_fres;
+
+      for (j = 0; j < num_fres; j++)
+	{
+	  fre_index = global + j;
+	  frep = &fr_info->entry[fre_index];
+
+	  ctf_frame_encoder_write_fre (contents, frep, fre_type, &esz);
+	  contents += esz;
+	  fre_size += esz; /* For debugging only.  */
+	}
+      global += j;
+    }
+
+  ctf_frame_assert (fre_size == ehp->cth_fre_len);
+  ctf_frame_assert (global == ehp->cth_num_fres);
+  ctf_frame_assert ((size_t)(contents - encoder->cfe_data) == buf_size);
+
+  /* Sort the FDE table */
+  ctf_frame_sort_funcdesc (encoder);
+
+  /* Sanity checks:
+     - the FDE section must have been sorted by now on the start address
+     of each function.  */
+  flags = ehp->cth_frame_preamble.ctfp_flags;
+  if (!(flags & CTF_FRAME_F_FDE_SORTED)
+      || (fd_info == NULL))
+    return ctf_frame_set_errno (&err, ECTF_FRAME_FDE_INVAL);
+
+  contents = encoder->cfe_data;
+  /* Write out the CTF Frame header.  The CTF Frame header in the encoder
+     object has already been updated with correct offsets by the caller.  */
+  memcpy (contents, ehp, hdr_size);
+  contents += hdr_size;
+
+  /* Write out the FDE table sorted on funtion start address.  */
+  memcpy (contents, fd_info->entry, all_fdes_size);
+  contents += all_fdes_size;
+
+  return 0;
+}
+
+/* Serialize the contents of the encoder and return the buffer.  ENCODED_SIZE
+   is updated to the size of the buffer.  */
+
+char *
+ctf_frame_write_encoder (ctf_frame_encoder_ctx *encoder,
+			 size_t *encoded_size, int *errp)
+{
+  ctf_frame_header *ehp;
+  size_t hdrsize, fsz, fresz, bufsize;
+  int foreign_endian;
+
+  /* Initialize the encoded_size to zero.  This makes it simpler to just
+     return from the function in case of failure.  Free'ing up of
+     encoder->cfe_data is the responsibility of the caller.  */
+  *encoded_size = 0;
+
+  if (encoder == NULL || encoded_size == NULL || errp == NULL)
+    return ctf_frame_ret_set_errno (errp, EINVAL);
+
+  hdrsize = sizeof (ctf_frame_header);
+  fsz = ctf_frame_encoder_get_num_fidx (encoder)
+    * sizeof (ctf_frame_func_desc_entry);
+  fresz = encoder->cfe_fre_nbytes;
+
+  /* The total size of buffer is the sum of header, CTF Function Descriptor
+     Entries section and the FRE section.  */
+  bufsize = hdrsize + fsz + fresz;
+  encoder->cfe_data = (char *) malloc (bufsize);
+  if (encoder->cfe_data == NULL)
+    return ctf_frame_ret_set_errno (errp, ECTF_FRAME_NOMEM);
+  encoder->cfe_data_size = bufsize;
+
+  /* Update the header information.  */
+  ehp = ctf_frame_encoder_get_header (encoder);
+  /* CTF FDE section follows immediately after the header.  */
+  ehp->cth_fdeoff = 0;
+  /* CTF FRE section follows immediately after the CTF FDE section.  */
+  ehp->cth_freoff = fsz;
+  ehp->cth_fre_len = fresz;
+  /* FIXME - cth_cfa_fixed_fp_offset cth_cfa_fixed_ra_offset?? */
+
+  foreign_endian = need_swapping (ehp->cth_frame_abi_arch);
+
+  /* Write out the FDE Index and the FRE table. */
+  if (ctf_frame_encoder_write_ctf_frame (encoder))
+    return ctf_frame_ret_set_errno (errp, ECTF_FRAME_BUF_INVAL);
+
+  /* Endian flip the contents if necessary.  */
+  if (foreign_endian)
+    {
+      flip_header ((ctf_frame_header*)encoder->cfe_data);
+      if (flip_ctf_frame (encoder->cfe_data, bufsize))
+	return ctf_frame_ret_set_errno (errp, ECTF_FRAME_BUF_INVAL);
+    }
+
+  *encoded_size = bufsize;
+  return encoder->cfe_data;
+}
diff --git a/libctfframe/testsuite/Makefile.am b/libctfframe/testsuite/Makefile.am
new file mode 100644
index 00000000000..03266696945
--- /dev/null
+++ b/libctfframe/testsuite/Makefile.am
@@ -0,0 +1,23 @@
+AUTOMAKE_OPTIONS = dejagnu foreign
+
+SUBDIRS = libctfframe.decode libctfframe.encode
+
+# Setup the testing framework
+EXPECT = expect
+RUNTEST = runtest
+RUNTESTFLAGS =
+
+check-DEJAGNU: site.exp
+	srcroot=`cd $(srcdir) && pwd`; export srcroot; \
+	r=`pwd`; export r; \
+	LC_ALL=C; export LC_ALL; \
+	EXPECT=$(EXPECT); export EXPECT; \
+	runtest=$(RUNTEST); \
+	if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
+	  $$runtest --tool $(DEJATOOL) \
+		CC="$(CC)" \
+		CROSS_COMPILE="$(CROSS_COMPILE)" \
+		CFLAGS="$(CFLAGS) -I$(top_srcdir)/../include -I$(top_srcdir) -I$(top_builddir)" \
+		$(RUNTESTFLAGS); \
+	else echo "WARNING: could not find \`runtest'" 1>&2; :;\
+	fi
diff --git a/libctfframe/testsuite/Makefile.in b/libctfframe/testsuite/Makefile.in
new file mode 100644
index 00000000000..3a6accc9e53
--- /dev/null
+++ b/libctfframe/testsuite/Makefile.in
@@ -0,0 +1,682 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = testsuite
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
+	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/depstand.m4 \
+	$(top_srcdir)/../config/jobserver.m4 \
+	$(top_srcdir)/../config/lead-dot.m4 \
+	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/warnings.m4 \
+	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
+	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
+	$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DEJATOOL = $(PACKAGE)
+RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_PEDANTIC = @WARN_PEDANTIC@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_libctfframe_warn_cflags = @ac_libctfframe_warn_cflags@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_warn = @c_warn@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_noncanonical = @host_noncanonical@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+target_noncanonical = @target_noncanonical@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+warn = @warn@
+AUTOMAKE_OPTIONS = dejagnu foreign
+SUBDIRS = libctfframe.decode libctfframe.encode
+
+# Setup the testing framework
+EXPECT = expect
+RUNTEST = runtest
+RUNTESTFLAGS = 
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign testsuite/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+site.exp: Makefile $(EXTRA_DEJAGNU_SITE_CONFIG)
+	@echo 'Making a new site.exp file ...'
+	@echo '## these variables are automatically generated by make ##' >site.tmp
+	@echo '# Do not edit here.  If you wish to override these values' >>site.tmp
+	@echo '# edit the last section' >>site.tmp
+	@echo 'set srcdir "$(srcdir)"' >>site.tmp
+	@echo "set objdir `pwd`" >>site.tmp
+	@echo 'set build_alias "$(build_alias)"' >>site.tmp
+	@echo 'set build_triplet $(build_triplet)' >>site.tmp
+	@echo 'set host_alias "$(host_alias)"' >>site.tmp
+	@echo 'set host_triplet $(host_triplet)' >>site.tmp
+	@list='$(EXTRA_DEJAGNU_SITE_CONFIG)'; for f in $$list; do \
+	  echo "## Begin content included from file $$f.  Do not modify. ##" \
+	   && cat `test -f "$$f" || echo '$(srcdir)/'`$$f \
+	   && echo "## End content included from file $$f. ##" \
+	   || exit 1; \
+	 done >> site.tmp
+	@echo "## End of auto-generated content; you can edit from here. ##" >> site.tmp
+	@if test -f site.exp; then \
+	   sed -e '1,/^## End of auto-generated content.*##/d' site.exp >> site.tmp; \
+	 fi
+	@-rm -f site.bak
+	@test ! -f site.exp || mv site.exp site.bak
+	@mv site.tmp site.exp
+
+distclean-DEJAGNU:
+	-rm -f site.exp site.bak
+	-l='$(DEJATOOL)'; for tool in $$l; do \
+	  rm -f $$tool.sum $$tool.log; \
+	done
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f Makefile
+distclean-am: clean-am distclean-DEJAGNU distclean-generic \
+	distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+	check-DEJAGNU check-am clean clean-generic clean-libtool \
+	cscopelist-am ctags ctags-am distclean distclean-DEJAGNU \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-dvi install-dvi-am \
+	install-exec install-exec-am install-html install-html-am \
+	install-info install-info-am install-man install-pdf \
+	install-pdf-am install-ps install-ps-am install-strip \
+	installcheck installcheck-am installdirs installdirs-am \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+check-DEJAGNU: site.exp
+	srcroot=`cd $(srcdir) && pwd`; export srcroot; \
+	r=`pwd`; export r; \
+	LC_ALL=C; export LC_ALL; \
+	EXPECT=$(EXPECT); export EXPECT; \
+	runtest=$(RUNTEST); \
+	if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
+	  $$runtest --tool $(DEJATOOL) \
+		CC="$(CC)" \
+		CROSS_COMPILE="$(CROSS_COMPILE)" \
+		CFLAGS="$(CFLAGS) -I$(top_srcdir)/../include -I$(top_srcdir) -I$(top_builddir)" \
+		$(RUNTESTFLAGS); \
+	else echo "WARNING: could not find \`runtest'" 1>&2; :;\
+	fi
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libctfframe/testsuite/config/default.exp b/libctfframe/testsuite/config/default.exp
new file mode 100644
index 00000000000..c91c01b2265
--- /dev/null
+++ b/libctfframe/testsuite/config/default.exp
@@ -0,0 +1,54 @@
+# Basic expect script for libctfframe decoder tests.
+#   Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This file 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Written by Jeffrey Wheat (cassidy@cygnus.com)
+#
+
+if ![info exists ld] then {
+    set ld [findfile $base_dir/../ld/ld-new $base_dir/../ld/ld-new [transform ld]]
+}
+
+if ![info exists as] then {
+    set as [findfile $base_dir/../gas/as-new $base_dir/../gas/as-new [transform as]]
+}
+
+remote_exec host "mkdir -p tmpdir"
+
+# Make symlinks from tmpdir/libctfframe to the linker and assembler in the
+# build tree, so that we can use a -B option to gcc to force it to use
+# the newly built linker and assembler.
+if {![file isdirectory tmpdir/libctfframe]} then {
+    catch "exec mkdir tmpdir/libctfframe" status
+    catch "exec ln -s ../../../ld/ld-new tmpdir/libctfframe/ld" status
+    catch "exec ln -s ld tmpdir/libctfframe/collect-ld" status
+    catch "exec ln -s ../../../gas/as-new tmpdir/libctfframe/as" status
+}
+set gcc_B_opt "-B[pwd]/tmpdir/libctfframe/"
+set ld_L_opt ""
+
+if {![info exists CC]} {
+    set CC gcc
+}
+if {![info exists CFLAGS]} {
+    set CFLAGS "-g -O2"
+}
+if {![info exists CFLAGS_FOR_TARGET]} {
+    set CFLAGS_FOR_TARGET $CFLAGS
+}
diff --git a/libctfframe/testsuite/libctfframe.decode/DATA1 b/libctfframe/testsuite/libctfframe.decode/DATA1
new file mode 100644
index 0000000000000000000000000000000000000000..8a6d4a3b68f6be1d67c42b78c3d88807249c3a56
GIT binary patch
literal 59
zcmaEKkCBm?fq{{Mfq?~x`GFV&1cCV9`~Ux?!90i@BLg!BBdfp%78ZdIQmh;w0QnIK
ACIA2c

literal 0
HcmV?d00001

diff --git a/libctfframe/testsuite/libctfframe.decode/DATA2 b/libctfframe/testsuite/libctfframe.decode/DATA2
new file mode 100644
index 0000000000000000000000000000000000000000..71c3be0a8497df2b2055484d45c89d3b0e53e815
GIT binary patch
literal 91
zcmaEKkCBm?fq{vEfq?^v<$xFjlz{l!`~Ux?!8`^A79h>|5hx%4WbgwqSb%|<gOOF>
S0}G452PsyL4@g{oAQu3xLl8;;

literal 0
HcmV?d00001

diff --git a/libctfframe/testsuite/libctfframe.decode/DATA_BIGE b/libctfframe/testsuite/libctfframe.decode/DATA_BIGE
new file mode 100644
index 0000000000000000000000000000000000000000..37c3f39a4bad0afccc09d693bf16a8ee6a2d4c50
GIT binary patch
literal 59
zcmccjh>?+z0R%uK3lQ^zI6xry|Nr}cKw28i1IjTnFmo`n3VdK;5%?g*%JBgJ_vQ&C

literal 0
HcmV?d00001

diff --git a/libctfframe/testsuite/libctfframe.decode/Makefile.am b/libctfframe/testsuite/libctfframe.decode/Makefile.am
new file mode 100644
index 00000000000..39b5dbe1460
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.decode/Makefile.am
@@ -0,0 +1,14 @@
+check_PROGRAMS = bigendian_data frecnt_1 frecnt_2
+
+bigendian_data_SOURCES = bigendian_data.c
+bigendian_data_LDADD = ${top_builddir}/libctfframe.la 
+bigendian_data_CPPFLAGS = -I${top_srcdir}/../include -Wall
+
+frecnt_1_SOURCES = frecnt_1.c
+frecnt_1_LDADD = ${top_builddir}/libctfframe.la 
+frecnt_1_CPPFLAGS = -I${top_srcdir}/../include -Wall
+
+frecnt_2_SOURCES = frecnt_2.c
+frecnt_2_LDADD = ${top_builddir}/libctfframe.la 
+frecnt_2_CPPFLAGS = -I${top_srcdir}/../include -Wall
+
diff --git a/libctfframe/testsuite/libctfframe.decode/Makefile.in b/libctfframe/testsuite/libctfframe.decode/Makefile.in
new file mode 100644
index 00000000000..a34cb02191c
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.decode/Makefile.in
@@ -0,0 +1,661 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = bigendian_data$(EXEEXT) frecnt_1$(EXEEXT) \
+	frecnt_2$(EXEEXT)
+subdir = testsuite/libctfframe.decode
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
+	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/depstand.m4 \
+	$(top_srcdir)/../config/jobserver.m4 \
+	$(top_srcdir)/../config/lead-dot.m4 \
+	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/warnings.m4 \
+	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
+	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
+	$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_bigendian_data_OBJECTS = bigendian_data-bigendian_data.$(OBJEXT)
+bigendian_data_OBJECTS = $(am_bigendian_data_OBJECTS)
+bigendian_data_DEPENDENCIES = ${top_builddir}/libctfframe.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+am_frecnt_1_OBJECTS = frecnt_1-frecnt_1.$(OBJEXT)
+frecnt_1_OBJECTS = $(am_frecnt_1_OBJECTS)
+frecnt_1_DEPENDENCIES = ${top_builddir}/libctfframe.la
+am_frecnt_2_OBJECTS = frecnt_2-frecnt_2.$(OBJEXT)
+frecnt_2_OBJECTS = $(am_frecnt_2_OBJECTS)
+frecnt_2_DEPENDENCIES = ${top_builddir}/libctfframe.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(bigendian_data_SOURCES) $(frecnt_1_SOURCES) \
+	$(frecnt_2_SOURCES)
+DIST_SOURCES = $(bigendian_data_SOURCES) $(frecnt_1_SOURCES) \
+	$(frecnt_2_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../depcomp \
+	$(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_PEDANTIC = @WARN_PEDANTIC@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_libctfframe_warn_cflags = @ac_libctfframe_warn_cflags@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_warn = @c_warn@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_noncanonical = @host_noncanonical@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+target_noncanonical = @target_noncanonical@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+warn = @warn@
+bigendian_data_SOURCES = bigendian_data.c
+bigendian_data_LDADD = ${top_builddir}/libctfframe.la 
+bigendian_data_CPPFLAGS = -I${top_srcdir}/../include -Wall
+frecnt_1_SOURCES = frecnt_1.c
+frecnt_1_LDADD = ${top_builddir}/libctfframe.la 
+frecnt_1_CPPFLAGS = -I${top_srcdir}/../include -Wall
+frecnt_2_SOURCES = frecnt_2.c
+frecnt_2_LDADD = ${top_builddir}/libctfframe.la 
+frecnt_2_CPPFLAGS = -I${top_srcdir}/../include -Wall
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/libctfframe.decode/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign testsuite/libctfframe.decode/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+bigendian_data$(EXEEXT): $(bigendian_data_OBJECTS) $(bigendian_data_DEPENDENCIES) $(EXTRA_bigendian_data_DEPENDENCIES) 
+	@rm -f bigendian_data$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(bigendian_data_OBJECTS) $(bigendian_data_LDADD) $(LIBS)
+
+frecnt_1$(EXEEXT): $(frecnt_1_OBJECTS) $(frecnt_1_DEPENDENCIES) $(EXTRA_frecnt_1_DEPENDENCIES) 
+	@rm -f frecnt_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(frecnt_1_OBJECTS) $(frecnt_1_LDADD) $(LIBS)
+
+frecnt_2$(EXEEXT): $(frecnt_2_OBJECTS) $(frecnt_2_DEPENDENCIES) $(EXTRA_frecnt_2_DEPENDENCIES) 
+	@rm -f frecnt_2$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(frecnt_2_OBJECTS) $(frecnt_2_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bigendian_data-bigendian_data.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/frecnt_1-frecnt_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/frecnt_2-frecnt_2.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+bigendian_data-bigendian_data.o: bigendian_data.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bigendian_data_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bigendian_data-bigendian_data.o -MD -MP -MF $(DEPDIR)/bigendian_data-bigendian_data.Tpo -c -o bigendian_data-bigendian_data.o `test -f 'bigendian_data.c' || echo '$(srcdir)/'`bigendian_data.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/bigendian_data-bigendian_data.Tpo $(DEPDIR)/bigendian_data-bigendian_data.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bigendian_data.c' object='bigendian_data-bigendian_data.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bigendian_data_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bigendian_data-bigendian_data.o `test -f 'bigendian_data.c' || echo '$(srcdir)/'`bigendian_data.c
+
+bigendian_data-bigendian_data.obj: bigendian_data.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bigendian_data_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bigendian_data-bigendian_data.obj -MD -MP -MF $(DEPDIR)/bigendian_data-bigendian_data.Tpo -c -o bigendian_data-bigendian_data.obj `if test -f 'bigendian_data.c'; then $(CYGPATH_W) 'bigendian_data.c'; else $(CYGPATH_W) '$(srcdir)/bigendian_data.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/bigendian_data-bigendian_data.Tpo $(DEPDIR)/bigendian_data-bigendian_data.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bigendian_data.c' object='bigendian_data-bigendian_data.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bigendian_data_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bigendian_data-bigendian_data.obj `if test -f 'bigendian_data.c'; then $(CYGPATH_W) 'bigendian_data.c'; else $(CYGPATH_W) '$(srcdir)/bigendian_data.c'; fi`
+
+frecnt_1-frecnt_1.o: frecnt_1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT frecnt_1-frecnt_1.o -MD -MP -MF $(DEPDIR)/frecnt_1-frecnt_1.Tpo -c -o frecnt_1-frecnt_1.o `test -f 'frecnt_1.c' || echo '$(srcdir)/'`frecnt_1.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/frecnt_1-frecnt_1.Tpo $(DEPDIR)/frecnt_1-frecnt_1.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='frecnt_1.c' object='frecnt_1-frecnt_1.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o frecnt_1-frecnt_1.o `test -f 'frecnt_1.c' || echo '$(srcdir)/'`frecnt_1.c
+
+frecnt_1-frecnt_1.obj: frecnt_1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT frecnt_1-frecnt_1.obj -MD -MP -MF $(DEPDIR)/frecnt_1-frecnt_1.Tpo -c -o frecnt_1-frecnt_1.obj `if test -f 'frecnt_1.c'; then $(CYGPATH_W) 'frecnt_1.c'; else $(CYGPATH_W) '$(srcdir)/frecnt_1.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/frecnt_1-frecnt_1.Tpo $(DEPDIR)/frecnt_1-frecnt_1.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='frecnt_1.c' object='frecnt_1-frecnt_1.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o frecnt_1-frecnt_1.obj `if test -f 'frecnt_1.c'; then $(CYGPATH_W) 'frecnt_1.c'; else $(CYGPATH_W) '$(srcdir)/frecnt_1.c'; fi`
+
+frecnt_2-frecnt_2.o: frecnt_2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT frecnt_2-frecnt_2.o -MD -MP -MF $(DEPDIR)/frecnt_2-frecnt_2.Tpo -c -o frecnt_2-frecnt_2.o `test -f 'frecnt_2.c' || echo '$(srcdir)/'`frecnt_2.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/frecnt_2-frecnt_2.Tpo $(DEPDIR)/frecnt_2-frecnt_2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='frecnt_2.c' object='frecnt_2-frecnt_2.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o frecnt_2-frecnt_2.o `test -f 'frecnt_2.c' || echo '$(srcdir)/'`frecnt_2.c
+
+frecnt_2-frecnt_2.obj: frecnt_2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT frecnt_2-frecnt_2.obj -MD -MP -MF $(DEPDIR)/frecnt_2-frecnt_2.Tpo -c -o frecnt_2-frecnt_2.obj `if test -f 'frecnt_2.c'; then $(CYGPATH_W) 'frecnt_2.c'; else $(CYGPATH_W) '$(srcdir)/frecnt_2.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/frecnt_2-frecnt_2.Tpo $(DEPDIR)/frecnt_2-frecnt_2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='frecnt_2.c' object='frecnt_2-frecnt_2.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o frecnt_2-frecnt_2.obj `if test -f 'frecnt_2.c'; then $(CYGPATH_W) 'frecnt_2.c'; else $(CYGPATH_W) '$(srcdir)/frecnt_2.c'; fi`
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libctfframe/testsuite/libctfframe.decode/bigendian_data.c b/libctfframe/testsuite/libctfframe.decode/bigendian_data.c
new file mode 100644
index 00000000000..3ef9867e4bf
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.decode/bigendian_data.c
@@ -0,0 +1,107 @@
+/* bigendian_data.c -- Test for handling different endianness in libctfframe.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "ctf-frame-api.h"
+
+/* DejaGnu should not use gnulib's vsnprintf replacement here.  */
+#undef vsnprintf
+#include <dejagnu.h>
+
+/*
+ * CTF Frame info from the following source (1 fde 4 fres):
+ * static int cnt;
+ * int main() { cnt++; return (cnt); }
+ *
+ * Then its contents are flipped from little-endian to big-endian.
+ */
+#define DATA	"DATA_BIGE"
+
+int
+main ()
+{
+  ctf_frame_decoder_ctx *dctx = NULL;
+  uint32_t nfres, fsize;
+  int32_t fstart;
+  unsigned char finfo;
+  int err = 0;
+  FILE *fp;
+  struct stat st;
+  char *cf_buf;
+  size_t cf_size;
+
+#define TEST(name, cond)                                                      \
+  do                                                                          \
+    {                                                                         \
+      if (cond)                                                               \
+	pass (name);                                                          \
+      else                                                                    \
+	fail (name);                                                          \
+    }                                                                         \
+    while (0)
+
+  /* Test setup.  */
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    goto setup_fail;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      goto setup_fail;
+    }
+  cf_buf = malloc (st.st_size);
+  if (cf_buf == NULL)
+    {
+      perror ("malloc");
+      goto setup_fail;
+    }
+  cf_size = fread (cf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  if (cf_size == 0)
+    {
+      fprintf (stderr, "Decode: Read buffer failed\n");
+      goto setup_fail;
+    }
+
+  /* Execute tests.  */
+
+  /* Call to ctf_frame_decode will endian flip the input buffer and
+     keep the new copy of buffer internally.  */
+  dctx = ctf_frame_decode (cf_buf, cf_size, &err);
+  TEST ("bigendian_data: Decoder setup", dctx != NULL);
+
+  unsigned int fde_cnt = ctf_frame_decoder_get_num_fidx (dctx);
+  TEST ("bigendian_data: Decoder FDE count", fde_cnt == 1);
+
+  err = ctf_frame_decoder_get_funcdesc (dctx, 0, &nfres, &fsize, &fstart, &finfo);
+  TEST ("bigendian_data: Decoder get FDE", err == 0);
+  TEST ("bigendian_data: Decoder FRE count", nfres == 4);
+      
+  ctf_frame_decoder_free (&dctx);
+  return 0;
+
+setup_fail:
+  ctf_frame_decoder_free (&dctx);
+  fail ("bigendian_data: Test setup");
+  return 1;
+}
diff --git a/libctfframe/testsuite/libctfframe.decode/decode.exp b/libctfframe/testsuite/libctfframe.decode/decode.exp
new file mode 100644
index 00000000000..ef0cd95f6f9
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.decode/decode.exp
@@ -0,0 +1,41 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+load_lib dejagnu.exp
+
+catch "exec ln -s $srcdir/../testsuite/libctfframe.decode/DATA1 ." status
+catch "exec ln -s $srcdir/../testsuite/libctfframe.decode/DATA2 ." status
+catch "exec ln -s $srcdir/../testsuite/libctfframe.decode/DATA_BIGE ." status
+
+if { [host_execute "libctfframe.decode/bigendian_data"] ne "" } {
+    fail "bigendian_data"
+}
+
+if { [host_execute "libctfframe.decode/frecnt_1"] ne "" } {
+    fail "frecnt_1"
+}
+
+if { [host_execute "libctfframe.decode/frecnt_2"] ne "" } {
+    fail "frecnt_2"
+}
+
+catch "exec rm libctfframe.decode/DATA1" status
+catch "exec rm libctfframe.decode/DATA2" status
+catch "exec rm libctfframe.decode/DATA_BIGE" status
diff --git a/libctfframe/testsuite/libctfframe.decode/frecnt_1.c b/libctfframe/testsuite/libctfframe.decode/frecnt_1.c
new file mode 100644
index 00000000000..0e1a1154c85
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.decode/frecnt_1.c
@@ -0,0 +1,99 @@
+/* frecnt_1.c -- Test for decoder in libctfframe.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "ctf-frame-api.h"
+
+/* DejaGnu should not use gnulib's vsnprintf replacement here.  */
+#undef vsnprintf
+#include <dejagnu.h>
+
+/*
+ * CTF Frame info from the following source (1 fde 4 fres):
+ * static int cnt;
+ * int main() { cnt++; return (cnt); }
+ */
+#define DATA	"DATA1"
+
+int
+main ()
+{
+  ctf_frame_decoder_ctx *dctx = NULL;
+  uint32_t nfres, fsize;
+  int32_t fstart;
+  unsigned char finfo;
+  int err = 0;
+  FILE *fp;
+  struct stat st;
+  char *cf_buf;
+  size_t cf_size;
+
+#define TEST(name, cond)                                                      \
+  do                                                                          \
+    {                                                                         \
+      if (cond)                                                               \
+	pass (name);                                                          \
+      else                                                                    \
+	fail (name);                                                          \
+    }                                                                         \
+    while (0)
+
+  /* Test Setup.  */
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    goto setup_fail;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      goto setup_fail;
+    }
+  cf_buf = malloc (st.st_size);
+  if (cf_buf == NULL)
+    {
+      perror ("malloc");
+      goto setup_fail;
+    }
+
+  /* Execute tests.  */
+  cf_size = fread (cf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  TEST ("frecnt_1: Read section", cf_size != 0);
+
+  dctx = ctf_frame_decode (cf_buf, cf_size, &err);
+  TEST ("frecnt_1: Decoder setup", dctx != NULL);
+
+  unsigned int fde_cnt = ctf_frame_decoder_get_num_fidx (dctx);
+  TEST ("frecnt_1: Decoder FDE count", fde_cnt == 1);
+
+  err = ctf_frame_decoder_get_funcdesc (dctx, 0, &nfres, &fsize, &fstart, &finfo);
+  TEST ("frecnt_1: Decoder get FDE", err == 0);
+  TEST ("frecnt_1: Decoder FRE count", nfres == 4);
+
+  ctf_frame_decoder_free (&dctx);
+  return 0;
+
+setup_fail:
+  ctf_frame_decoder_free (&dctx);
+  fail ("frecnt_1: Test setup");
+  return 1;
+}
diff --git a/libctfframe/testsuite/libctfframe.decode/frecnt_2.c b/libctfframe/testsuite/libctfframe.decode/frecnt_2.c
new file mode 100644
index 00000000000..eaef2da260f
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.decode/frecnt_2.c
@@ -0,0 +1,103 @@
+/* frecnt_2.c -- Test for decoder in libctfframe.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "ctf-frame-api.h"
+
+/* DejaGnu should not use gnulib's vsnprintf replacement here.  */
+#undef vsnprintf
+#include <dejagnu.h>
+
+/*
+ * CTF Frame info from the following source (2 fde 8 fres):
+ * static int cnt;
+ * int foo() { return ++cnt; }
+ * int main() { return foo(); }
+ */
+#define DATA	"DATA2"
+
+int
+main ()
+{
+  ctf_frame_decoder_ctx *dctx = NULL;
+  uint32_t nfres, fsize;
+  int32_t fstart;
+  unsigned char finfo;
+  int i, err = 0;
+  FILE *fp;
+  struct stat st;
+  char *cf_buf;
+  size_t cf_size;
+
+#define TEST(name, cond)                                                      \
+  do                                                                          \
+    {                                                                         \
+      if (cond)                                                               \
+	pass (name);                                                          \
+      else                                                                    \
+	fail (name);                                                          \
+    }                                                                         \
+    while (0)
+
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    goto setup_fail;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      goto setup_fail;
+    }
+  cf_buf = malloc (st.st_size);
+  if (cf_buf == NULL)
+    {
+      perror ("malloc");
+      goto setup_fail;
+    }
+
+  /* Execute tests.  */
+  cf_size = fread (cf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  TEST ("frecnt_2: Read section", cf_size != 0);
+
+  dctx = ctf_frame_decode (cf_buf, cf_size, &err);
+  TEST ("frecnt_2: Decode setup", dctx != NULL);
+
+  unsigned int fde_cnt = ctf_frame_decoder_get_num_fidx (dctx);
+  TEST ("frecnt_2: Decode FDE count", fde_cnt == 2);
+
+  for (i = 0; i < fde_cnt; ++i)
+    {
+      err = ctf_frame_decoder_get_funcdesc (dctx, i, &nfres, &fsize, &fstart,
+		 			    &finfo);
+      TEST ("frecnt_2: Decode get FDE", err == 0);
+      TEST ("frecnt_2: Decode get FRE", nfres == 4); 
+    }
+
+  ctf_frame_decoder_free (&dctx);
+  return 0;
+
+setup_fail:
+  ctf_frame_decoder_free (&dctx);
+  fail ("frecnt_2: Test setup");
+  return 1;
+}
diff --git a/libctfframe/testsuite/libctfframe.encode/Makefile.am b/libctfframe/testsuite/libctfframe.encode/Makefile.am
new file mode 100644
index 00000000000..6ee264664a6
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.encode/Makefile.am
@@ -0,0 +1,6 @@
+check_PROGRAMS = encode_1
+
+encode_1_SOURCES = encode_1.c
+encode_1_LDADD = ${top_builddir}/libctfframe.la
+encode_1_CPPFLAGS = -I${top_srcdir}/../include -Wall
+
diff --git a/libctfframe/testsuite/libctfframe.encode/Makefile.in b/libctfframe/testsuite/libctfframe.encode/Makefile.in
new file mode 100644
index 00000000000..da8702d30c2
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.encode/Makefile.in
@@ -0,0 +1,608 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = encode_1$(EXEEXT)
+subdir = testsuite/libctfframe.encode
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
+	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/depstand.m4 \
+	$(top_srcdir)/../config/jobserver.m4 \
+	$(top_srcdir)/../config/lead-dot.m4 \
+	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/warnings.m4 \
+	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
+	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
+	$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_encode_1_OBJECTS = encode_1-encode_1.$(OBJEXT)
+encode_1_OBJECTS = $(am_encode_1_OBJECTS)
+encode_1_DEPENDENCIES = ${top_builddir}/libctfframe.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(encode_1_SOURCES)
+DIST_SOURCES = $(encode_1_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../depcomp \
+	$(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_PEDANTIC = @WARN_PEDANTIC@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_libctfframe_warn_cflags = @ac_libctfframe_warn_cflags@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_warn = @c_warn@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_noncanonical = @host_noncanonical@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+target_noncanonical = @target_noncanonical@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+warn = @warn@
+encode_1_SOURCES = encode_1.c
+encode_1_LDADD = ${top_builddir}/libctfframe.la
+encode_1_CPPFLAGS = -I${top_srcdir}/../include -Wall
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/libctfframe.encode/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign testsuite/libctfframe.encode/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+encode_1$(EXEEXT): $(encode_1_OBJECTS) $(encode_1_DEPENDENCIES) $(EXTRA_encode_1_DEPENDENCIES) 
+	@rm -f encode_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(encode_1_OBJECTS) $(encode_1_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encode_1-encode_1.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+encode_1-encode_1.o: encode_1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(encode_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT encode_1-encode_1.o -MD -MP -MF $(DEPDIR)/encode_1-encode_1.Tpo -c -o encode_1-encode_1.o `test -f 'encode_1.c' || echo '$(srcdir)/'`encode_1.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/encode_1-encode_1.Tpo $(DEPDIR)/encode_1-encode_1.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='encode_1.c' object='encode_1-encode_1.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(encode_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o encode_1-encode_1.o `test -f 'encode_1.c' || echo '$(srcdir)/'`encode_1.c
+
+encode_1-encode_1.obj: encode_1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(encode_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT encode_1-encode_1.obj -MD -MP -MF $(DEPDIR)/encode_1-encode_1.Tpo -c -o encode_1-encode_1.obj `if test -f 'encode_1.c'; then $(CYGPATH_W) 'encode_1.c'; else $(CYGPATH_W) '$(srcdir)/encode_1.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/encode_1-encode_1.Tpo $(DEPDIR)/encode_1-encode_1.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='encode_1.c' object='encode_1-encode_1.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(encode_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o encode_1-encode_1.obj `if test -f 'encode_1.c'; then $(CYGPATH_W) 'encode_1.c'; else $(CYGPATH_W) '$(srcdir)/encode_1.c'; fi`
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libctfframe/testsuite/libctfframe.encode/encode.exp b/libctfframe/testsuite/libctfframe.encode/encode.exp
new file mode 100644
index 00000000000..58a436bd1d1
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.encode/encode.exp
@@ -0,0 +1,25 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+load_lib dejagnu.exp
+
+if { [host_execute "libctfframe.encode/encode_1"] ne "" } {
+    fail "encode_1"
+}
diff --git a/libctfframe/testsuite/libctfframe.encode/encode_1.c b/libctfframe/testsuite/libctfframe.encode/encode_1.c
new file mode 100644
index 00000000000..2a093b5e08e
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.encode/encode_1.c
@@ -0,0 +1,182 @@
+/* encode_1.c -- Test for encoder in libctfframe.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "ctf-frame-api.h"
+
+/* DejaGnu should not use gnulib's vsnprintf replacement here.  */
+#undef vsnprintf
+#include <dejagnu.h>
+
+static int
+add_fde1 (ctf_frame_encoder_ctx *encode, int idx)
+{
+  int i, err;
+  /* A contiguous block containing 4 FREs.  */
+  ctf_frame_row_entry fres[]
+    = { {0x0, 0x3, {0x8, 0, 0}},
+	{0x1, 0x5, {0x10, 0xf0, 0}},
+	{0x4, 0x4, {0x10, 0xf0, 0}},
+	{0x1a, 0x5, {0x8, 0xf0, 0}}
+      };
+
+  unsigned char finfo = ctf_frame_fde_func_info (CTF_FRAME_ROW_ENTRY_TYPE_ADDR1,
+		  		CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCINC);
+  err = ctf_frame_encoder_add_funcdesc (encode, 0xffffefd6, 0x1b, finfo, 4);
+  if (err == -1)
+    return err;
+
+  for (i = 0; i < 4; i++)
+    if (ctf_frame_encoder_add_fre (encode, idx,fres+i) == CTF_FRAME_ERR)
+      return -1;
+
+  return 0;
+}
+
+static int
+add_fde2 (ctf_frame_encoder_ctx *encode, int idx)
+{
+  int i, err;
+  /* A contiguous block containing 4 FREs.  */
+  ctf_frame_row_entry fres[]
+    = { {0x0, 0x3, {0x8, 0, 0}},
+	{0x1, 0x5, {0x10, 0xf0, 0}},
+	{0x4, 0x4, {0x10, 0xf0, 0}},
+	{0xf, 0x5, {0x8, 0xf0, 0}}
+      };
+
+  unsigned char finfo = ctf_frame_fde_func_info (CTF_FRAME_ROW_ENTRY_TYPE_ADDR1,
+		  		CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCINC);
+  err = ctf_frame_encoder_add_funcdesc (encode, 0xffffeff1, 0x10, finfo, 4);
+  if (err == -1)
+    return err;
+
+  for (i = 0; i < 4; i++)
+    if (ctf_frame_encoder_add_fre (encode, idx, fres+i) == CTF_FRAME_ERR)
+      return -1;
+
+  return 0;
+}
+
+/*
+ * CTF Frame info from the following source (2 fdes, 4 fres in each fde):
+ * static int cnt;
+ * int foo() { return ++cnt; }
+ * int main() { return foo(); }
+ */
+#define DATA    "DATA2"
+
+static int
+data_match (char *ctfp, size_t sz)
+{
+  FILE *fp;
+  struct stat st;
+  char *cf_buf;
+  size_t cf_size;
+  int diffs;
+
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    return 0;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      return 0;
+    }
+  cf_buf = malloc (st.st_size);
+  if (cf_buf == NULL)
+    {
+      perror ("malloc");
+      return 0;
+    }
+  cf_size = fread (cf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  if (cf_size == 0 || cf_buf == NULL)
+    {
+      fprintf (stderr, "Encode: Read section failed\n");
+      return 0;
+    }
+  if (cf_size != sz)
+    return 0;
+
+  diffs = memcmp (cf_buf, ctfp, sz);
+
+  free (cf_buf);
+  return diffs == 0;
+}
+
+int main ()
+{
+  ctf_frame_encoder_ctx *encode;
+  ctf_frame_row_entry frep;
+  char *ctfp;
+  size_t ctf_sz;
+  int err = 0;
+
+  encode = ctf_frame_encode (CTF_FRAME_VERSION, 0,
+		  CTF_FRAME_ABI_AMD64_ENDIAN_LITTLE, &err);
+
+  if (ctf_frame_encoder_get_num_fidx (encode) != 0)
+    {
+      fprintf (stderr, "Encode: incorrect FDEs count\n");
+      goto fail;
+    }
+
+  /* Error test.  */
+  if (ctf_frame_encoder_add_fre (encode, 1, &frep) != CTF_FRAME_ERR)
+    {
+      fprintf (stderr, "Encode: Adding FRE befoer FDE does\n");
+      goto fail;
+    }
+
+  if (add_fde1 (encode, 0) == -1)
+    {
+      fprintf (stderr, "Encode: Adding FDE1\n");
+      goto fail;
+    }
+  if (add_fde2 (encode, 1) == -1)
+    {
+      fprintf (stderr, "Encode: Adding FDE2\n");
+      goto fail;
+    }
+
+  if (ctf_frame_encoder_get_num_fidx (encode) != 2)
+    {
+      fprintf (stderr, "Encode: Wrong FDE count\n");
+      goto fail;
+    }
+
+  ctfp = ctf_frame_write_encoder (encode, &ctf_sz, &err);
+  if (err)
+    return 1;
+  if (data_match (ctfp, ctf_sz))
+    {
+      ctf_frame_encoder_free (&encode);
+      pass ("encode test");
+    }
+
+fail:
+  ctf_frame_encoder_free (&encode);
+  return 1;
+}
-- 
2.37.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V6 05/10] libctfframe: add GNU poke pickles for CTF Frame
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
                   ` (3 preceding siblings ...)
  2022-08-02  8:04 ` [PATCH,V6 04/10] libctfframe: add the CTF Frame library Indu Bhagat
@ 2022-08-02  8:04 ` Indu Bhagat
  2022-08-15 12:50   ` Nick Clifton
  2022-08-02  8:04 ` [PATCH,V6 06/10] bfd: linker: merge .ctf_frame sections Indu Bhagat
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-08-02  8:04 UTC (permalink / raw)
  To: binutils; +Cc: amodra, weimin.pan, Indu Bhagat

[No changes from V5]

[Added in V4]

If you want to use these pickles in GNU poke, following is one way to
use the pickles.

$ objcopy --dump-section .ctf_frame=output_ctf_frame binary
$ poke output_ctf_frame

In the GNU poke program:
(poke) .load libctfframe/ctf-frame-dump.pk
(poke) .set omode tree
(poke) var ctf_frame = CTF_Frame_section @ 0#B

ChangeLog:

	* libctfframe/ctf-frame-dump.pk: New file.
	* libctfframe/ctf-frame.pk: Likewise.
---
 libctfframe/ctf-frame-dump.pk |  68 ++++++++++++
 libctfframe/ctf-frame.pk      | 200 ++++++++++++++++++++++++++++++++++
 2 files changed, 268 insertions(+)
 create mode 100644 libctfframe/ctf-frame-dump.pk
 create mode 100644 libctfframe/ctf-frame.pk

diff --git a/libctfframe/ctf-frame-dump.pk b/libctfframe/ctf-frame-dump.pk
new file mode 100644
index 00000000000..ad90d423e61
--- /dev/null
+++ b/libctfframe/ctf-frame-dump.pk
@@ -0,0 +1,68 @@
+/* ctf-frame-dump.pk - Utilities for dumping CTF Frame information.  */
+
+/* Copyright (C) 2022 Free Software Foundation.  */
+
+/* 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/>.
+ */
+
+/* This file contains routines for dumping out CTF Frame information.  */
+
+load "ctf-frame.pk";
+
+/* Dump each FDE in the CTF Frame section.  */
+
+fun ctf_frame_dump_fdes = (CTF_Frame_section ctf_frame_arg) void:
+{
+  var i = 0;
+  for (index in ctf_frame_arg.funcidx)
+    printf ("%u32d:   %v \n", i++, index);
+}
+
+/* Dump CTF Frame FREs.  */
+
+fun ctf_frame_dump_fres = (CTF_Frame_section ctf_frame_arg) void:
+{
+  var i = 0;
+
+  for (func in ctf_frame_arg.funcidx)
+    {
+      /* Get the FRE type.  */
+      var fre_type = func.func_info.fre_type;
+      var num_fres = func.func_num_fres;
+      var fre_off = ctf_frame_arg.header'size + ctf_frame_arg.header.cth_freoff;
+
+      if (fre_type == CTF_FRAME_ROW_ENTRY_TYPE_ADDR1)
+	{
+	  var fres = func.get_fres_addr1s (fre_off);
+	  /* print fres.  */
+	  for (fre in fres)
+	    printf ("%u32d:   %v \n", i++, fre);
+	}
+      else if (fre_type == CTF_FRAME_ROW_ENTRY_TYPE_ADDR2)
+	{
+	  var fres = func.get_fres_addr2s (fre_off);
+	  /* print fres.  */
+	  for (fre in fres)
+	    printf ("%u32d:   %v \n", i++, fre);
+	}
+      else if (fre_type == CTF_FRAME_ROW_ENTRY_TYPE_ADDR4)
+	{
+	  var fres = func.get_fres_addr4s (fre_off);
+	  /* print fres.  */
+	  for (fre in fres)
+	    printf ("%u32d:   %v \n", i++, fre);
+	}
+
+    }
+}
diff --git a/libctfframe/ctf-frame.pk b/libctfframe/ctf-frame.pk
new file mode 100644
index 00000000000..059c20c72cf
--- /dev/null
+++ b/libctfframe/ctf-frame.pk
@@ -0,0 +1,200 @@
+/* ctf-frame.pk - CTF Frame implementation for GNU poke.  */
+
+/* Copyright (C) 2022 Free Software Foundation.  */
+
+/* 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/>.
+ */
+
+load elf;
+
+/* Constants for CTF Preamble.  */
+var CTF_FRAME_VERSION_1 = 1;
+var CTF_FRAME_MAGIC = 0xdee2;
+/* Various flags for CTF Frame section.  */
+var CTF_FRAME_F_FDE_SORTED = 0x1;
+var CTF_FRAME_F_FRAME_POINTER = 0x2;
+
+type CTF_Frame_Preamble =
+  struct
+  {
+    uint<16> ctfp_magic : ((ctfp_magic == CTF_FRAME_MAGIC)
+			   || (ctfp_magic == 0xe2de && set_endian (!get_endian)))
+		          = CTF_FRAME_MAGIC;
+
+    byte ctfp_version = CTF_FRAME_VERSION_1;
+    byte ctfp_flags;
+  };
+
+var CTF_FRAME_ROW_ENTRY_TYPE_ADDR1 = 1;
+var CTF_FRAME_ROW_ENTRY_TYPE_ADDR2 = 2;
+var CTF_FRAME_ROW_ENTRY_TYPE_ADDR4 = 3;
+
+/* CTF Frame FDE types.
+   The CTF Frame format has two possible representations for functions.  The
+   choice of which type to use is made according to the instruction patterns
+   in the relevant program stub.  */
+
+/* Unwinders perform a (PC >= FRE_START_ADDR) to look up a matching FRE.  */
+var CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCINC = 0;
+/* Unwinders perform a (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK)
+   to look up a matching FRE.  */
+var CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCMASK = 1;
+
+/* CTF Frame FDE Function Info.  */
+type CTF_Frame_Func_Info =
+  struct
+{
+  uint<3> unused;
+  uint<1> fde_type : fde_type in [CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCINC,
+				  CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCMASK];
+  uint<4> fre_type : fre_type in [CTF_FRAME_ROW_ENTRY_TYPE_ADDR1,
+				  CTF_FRAME_ROW_ENTRY_TYPE_ADDR2,
+				  CTF_FRAME_ROW_ENTRY_TYPE_ADDR4];
+};
+
+/* Supported ABIs/Arch.  */
+var CTF_FRAME_ABI_AARCH64_ENDIAN_BIG = 1; /* AARCH64 little endian.  */
+var CTF_FRAME_ABI_AARCH64_ENDIAN_LITTLE = 2; /* AARCH64 big endian.  */
+var CTF_FRAME_ABI_AMD64_ENDIAN_LITTLE = 3; /* AMD64 little endian.  */
+
+var CTF_FRAME_FRE_TYPE_BASIC = 0x0;
+
+type CTF_Frame_Header =
+  struct
+  {
+    CTF_Frame_Preamble cth_frame_preamble;
+    byte cth_frame_abi_arch : cth_frame_abi_arch in [CTF_FRAME_ABI_AARCH64_ENDIAN_BIG,
+						    CTF_FRAME_ABI_AARCH64_ENDIAN_LITTLE,
+					            CTF_FRAME_ABI_AMD64_ENDIAN_LITTLE];
+    int<8> cth_cfa_fixed_bp_offset;
+    int<8> cth_cfa_fixed_ra_offset;
+    uint<32> cth_num_fdes;
+    uint<32> cth_num_fres;
+    offset<uint32,B> cth_frelen;
+
+    offset<uint32,B> cth_fdeoff;
+    offset<uint32,B> cth_freoff;
+  };
+
+var CTF_FRAME_FRE_OFFSET_1B = 0;
+var CTF_FRAME_FRE_OFFSET_2B = 1;
+var CTF_FRAME_FRE_OFFSET_4B = 2;
+/* At this time, a max of 3 distinct offsets are supported.  */
+var CTF_FRAME_FRE_OFFSET_NUM = 3;
+
+/* A CTF FRE can be SP or BP based.  */
+var CTF_FRAME_BASE_REG_BP = 0;
+var CTF_FRAME_BASE_REG_SP = 1;
+
+type CTF_Frame_FRE_Info =
+  struct byte
+  {
+    uint<1> unused;
+    uint<2> offset_size : offset_size in [CTF_FRAME_FRE_OFFSET_1B,
+					  CTF_FRAME_FRE_OFFSET_2B,
+					  CTF_FRAME_FRE_OFFSET_4B];
+    uint<4> offset_num : offset_num <= CTF_FRAME_FRE_OFFSET_NUM;
+    uint<1> base_reg_id : base_reg_id in [CTF_FRAME_BASE_REG_BP,
+					  CTF_FRAME_BASE_REG_SP];
+  };
+
+/* CTF FRE.  */
+type CTF_FRE_addr1 =
+  struct
+  {
+    uint<8> fre_start_address;
+    CTF_Frame_FRE_Info fre_info;
+    union
+    {
+      int<8>[fre_info.offset_num] offsets_1B
+         : fre_info.offset_size == CTF_FRAME_FRE_OFFSET_1B;
+      int<16>[fre_info.offset_num] offsets_2B
+         : fre_info.offset_size == CTF_FRAME_FRE_OFFSET_2B;
+      int<32>[fre_info.offset_num] offsets_4B
+         : fre_info.offset_size == CTF_FRAME_FRE_OFFSET_4B;
+    } offsets;
+  };
+
+type CTF_FRE_addr2 =
+  struct
+  {
+    uint<16> fre_start_address;
+    CTF_Frame_FRE_Info fre_info;
+    union
+    {
+      int<8>[fre_info.offset_num] offsets_1B
+         : fre_info.offset_size == CTF_FRAME_FRE_OFFSET_1B;
+      int<16>[fre_info.offset_num] offsets_2B
+         : fre_info.offset_size == CTF_FRAME_FRE_OFFSET_2B;
+      int<32>[fre_info.offset_num] offsets_4B
+         : fre_info.offset_size == CTF_FRAME_FRE_OFFSET_4B;
+    } offsets;
+  };
+
+type CTF_FRE_addr4=
+  struct
+  {
+    uint<32> fre_start_address;
+    CTF_Frame_FRE_Info fre_info;
+    union
+    {
+      int<8>[fre_info.offset_num] offsets_1B
+         : fre_info.offset_size == CTF_FRAME_FRE_OFFSET_1B;
+      int<16>[fre_info.offset_num] offsets_2B
+         : fre_info.offset_size == CTF_FRAME_FRE_OFFSET_2B;
+      int<32>[fre_info.offset_num] offsets_4B
+         : fre_info.offset_size == CTF_FRAME_FRE_OFFSET_4B;
+    } offsets;
+  };
+
+
+type CTF_Frame_Func_Desc_Entry =
+  struct
+  {
+    uint<32> func_start_address;
+    uint<32> func_size;
+    offset<uint32,B> func_freoff;
+    uint<32> func_num_fres;
+    CTF_Frame_Func_Info func_info;
+
+    method get_fres_addr1s = (offset<uint32,B> hdr_freoff) CTF_FRE_addr1[]:
+      {
+	var off = hdr_freoff + func_freoff;
+	return CTF_FRE_addr1[func_num_fres] @ off;
+      }
+    method get_fres_addr2s = (offset<uint32,B> hdr_freoff) CTF_FRE_addr2[]:
+      {
+	var off = hdr_freoff + func_freoff;
+	return CTF_FRE_addr2[func_num_fres] @ off;
+      }
+    method get_fres_addr4s = (offset<uint32,B> hdr_freoff) CTF_FRE_addr4[]:
+      {
+	var off = hdr_freoff + func_freoff;
+	return CTF_FRE_addr4[func_num_fres] @ off;
+      }
+  };
+
+type CTF_Frame_section =
+  struct
+  {
+    CTF_Frame_Header header;
+
+    var func_index_off = OFFSET + header.cth_fdeoff;
+    var func_index_size = header.cth_freoff - header.cth_fdeoff;
+    var fre_off = OFFSET + header.cth_freoff;
+    var fre_size = header.cth_frelen;
+
+    CTF_Frame_Func_Desc_Entry[func_index_size] funcidx @ func_index_off;
+    byte[fre_size] fres_data_bytes @ fre_off;
+  };
-- 
2.37.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V6 06/10] bfd: linker: merge .ctf_frame sections
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
                   ` (4 preceding siblings ...)
  2022-08-02  8:04 ` [PATCH,V6 05/10] libctfframe: add GNU poke pickles for CTF Frame Indu Bhagat
@ 2022-08-02  8:04 ` Indu Bhagat
  2022-08-15 13:02   ` Nick Clifton
  2022-08-02  8:04 ` [PATCH,V6 07/10] readelf/objdump: support for CTF Frame section Indu Bhagat
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-08-02  8:04 UTC (permalink / raw)
  To: binutils; +Cc: amodra, weimin.pan, Indu Bhagat

[No Changes from V4, V5]

[Changes from V3]
 - Fix generation of CTF Frame unwind info for pltn entries.  Use FDE
   type CTF_FRAME_DESCRIPTOR_ENTRY_TYPE_ADDRMASK for pltn entries.
 - Testsuite: Split out the checks for CTF Frame unwind info for the plt
   entries into a separate test.  This test now serves to check the pltn
   unwind info generation on x86_64.
[End of changes from V3]

[Changes from V2]
 - consistent use of terminology around CTF Frame and its components.
 - few bugfixes:
   - CTF Frame unwind info generation for plt0 was incorrect.
   - do not update section size in _bfd_elf_write_section_ctf_frame for
   relocatable link.
 - added a testsuite in ld for CTF Frame.
[End of changes from V2]

[Changes from V1]
 - Refactor the code associated with the writing of .ctf_frame section
   for the dynamic .plt sections.
 - bugfix: Do not add a new segment PT_GNU_CTF_FRAME if .ctf_frame is
   an empty section.
 - ld: testsuite: fix ld bootstrap testcase by including libctfframe.
 - bugfix: linker-script: remove KEEP keyword for .ctf_frame secitons.
[End of changes from V1]

The linker merges all the input .ctf_frame sections.  When merging, the
linker verifies that all the input .ctf_frame sections have the same
abi/arch.

The linker uses libctfframe library to perform key actions on the
.ctf_frame sections - decode, read, and create output data.  This
implies buildsystem changes to make and install libctfframe before
libbfd.

The linker places the output .ctf_frame section in a new segment of its
own: PT_GNU_CTF_FRAME.

When a section is discarded from the final link, the corresponding
entries in the .ctf_frame section for those functions are also deleted.

This patch also adds support for generation of CTF Frame unwind
information for the .plt* sections on x86_64.  CTF Frame unwind info is
generated for IBT enabled PLT, lazy/non-lazy PLT. These bits are arguably
unsatisfactory in terms of code quality and will be improved upon.  Also
recall that the CTF Frame format for PLT entries needs adjustments, so
these chunks around .plt* sections are bound to evolve for the better.

The existing linker option --no-ld-generated-unwind-info has been
adapted to include the control of whether .ctf_frame unwind information
will be generated for the linker generated sections like PLT.

Changes to the linker script have been made as necessary.

ChangeLog:

	* Makefile.def: Add install dependency on libctfframe for libbfd.
	* Makefile.in: Regenerated.
	* bfd/Makefile.am: Add elf-ctf-frame.c
	* bfd/Makefile.in: Regenerated.
	* bfd/bfd-in2.h (SEC_INFO_TYPE_CTF_FRAME): Regenerated.
	* bfd/configure: Regenerate.
	* bfd/configure.ac: Add elf-ctf-frame.lo.
	* bfd/elf-bfd.h (struct ctf_frame_func_bfdinfo): New struct.
	(struct ctf_frame_dec_info): Likewise.
	(struct ctf_frame_enc_info): Likewise.
	(struct elf_link_hash_table): New member for encoded .ctf_frame
	object.
	(struct output_elf_obj_tdata): New member.
	(elf_ctf_frame): New access macro.
	(_bfd_elf_set_section_ctf_frame): New declaration.
	* bfd/elf.c (get_segment_type): Handle new segment
	PT_GNU_CTF_FRAME.
	(bfd_section_from_phdr): Likewise.
	(get_program_header_size): Likewise.
	(_bfd_elf_map_sections_to_segments): Likewise.
	* bfd/elf64-x86-64.c (elf_x86_64_link_setup_gnu_properties): Add
	contents to the .ctf_frame sections or .plt* entries.
	* bfd/elflink.c (elf_section_ignore_discarded_relocs): Handle
	SEC_INFO_TYPE_CTF_FRAME.
	(_bfd_elf_default_action_discarded): Handle .ctf_frame section.
	(elf_link_input_bfd): Merge .ctf_frame section.
	(bfd_elf_final_link): Write the output .ctf_frame section.
	(bfd_elf_discard_info): Handle discarding .ctf_frame section.
	* bfd/elfxx-x86.c (_bfd_x86_elf_size_dynamic_sections): Create
	.ctf_frame section for .plt and .plt.sec.
	(_bfd_x86_elf_finish_dynamic_sections): Handle .ctf_frame from
	.plt* sections.
	* bfd/elfxx-x86.h (PLT_CTF_FRAME_FDE_START_OFFSET): New
	definition.
	(CTF_FRAME_PLT0_MAX_NUM_FRES): Likewise.
	(CTF_FRAME_PLTN_MAX_NUM_FRES): Likewise.
	(struct elf_x86_ctf_frame_plt): New structure.
	(struct elf_x86_link_hash_table): New member.
	(struct elf_x86_init_table): New members for .ctf_frame
	creation.
	* bfd/section.c: Add new definition SEC_INFO_TYPE_CTF_FRAME.
	* binutils/readelf.c (get_segment_type): Handle new segment
	PT_GNU_CTF_FRAME.
	* ld/ld.texi: Update documentation for
	--no-ld-generated-unwind-info.
	* ld/scripttempl/elf.sc: Support .ctf_frame sections.
	* Makefile.am (TESTCTFFRAMELIB): Use it.
	(check-DEJAGNU): Likewise.
	* configure.ac (TESTCTFFRAMELIB): Set to the .so or .a like TESTBFDLIB.
	* testsuite/ld-bootstrap/bootstrap.exp: Add CTFFRAMELIB.
	* bfd/elf-ctf-frame.c: New file.

include/ChangeLog:

	* elf/common.h (PT_GNU_CTF_FRAME): New definition.
	* elf/internal.h (struct elf_segment_map): Handle new segment
	type PT_GNU_CTF_FRAME.

ld/testsuite/ChangeLog:

	* ld/testsuite/ld-aarch64/aarch64-elf.exp: Add new test
	  ctf-frame-simple-1.
	* ld/testsuite/ld-aarch64/ctf-frame-bar.s: New file.
	* ld/testsuite/ld-aarch64/ctf-frame-foo.s: Likewise.
	* ld/testsuite/ld-aarch64/ctf-frame-simple-1.d: Likewise.
	* ld/testsuite/ld-ctf-frame/ctf-frame-empty.d: New test.
	* ld/testsuite/ld-ctf-frame/ctf-frame-empty.s: New file.
	* ld/testsuite/ld-ctf-frame/ctfframe.exp: New testsuite.
	* ld/testsuite/ld-x86-64/ctf-frame-bar.s: New file.
	* ld/testsuite/ld-x86-64/ctf-frame-foo.s: Likewise.
	* ld/testsuite/ld-x86-64/ctf-frame-simple-1.d: Likewise.
	* ld/testsuite/ld-x86-64/ctf-frame-plt-1.d: Likewise.
	* ld/testsuite/ld-x86-64/ctf-frame-simple-1.d: Likewise.
	* ld/testsuite/ld-x86-64/x86-64.exp: Add new tests -
	  ctf-frame-simple-1, ctf-frame-plt-1.
	* ld/testsuite/lib/ld-lib.exp: Add new proc to check if
	  assembler supports CTF Frame section.
	* ld/testsuite/ld-ctf-frame/discard.d: New file.
	* ld/testsuite/ld-ctf-frame/discard.ld: Likewise.
	* ld/testsuite/ld-ctf-frame/discard.s: Likewise.
---
 Makefile.def                                 |   5 +-
 Makefile.in                                  |  21 +-
 bfd/Makefile.am                              |   6 +-
 bfd/Makefile.in                              |   7 +-
 bfd/bfd-in2.h                                |   1 +
 bfd/configure                                |   2 +-
 bfd/configure.ac                             |   2 +-
 bfd/elf-bfd.h                                |  55 ++
 bfd/elf-ctf-frame.c                          | 529 +++++++++++++++++++
 bfd/elf.c                                    |  32 ++
 bfd/elf64-x86-64.c                           |  97 +++-
 bfd/elflink.c                                |  52 ++
 bfd/elfxx-x86.c                              | 379 ++++++++++++-
 bfd/elfxx-x86.h                              |  46 ++
 bfd/section.c                                |   1 +
 binutils/readelf.c                           |   1 +
 include/ctf-frame-api.h                      |   2 +-
 include/elf/common.h                         |   1 +
 include/elf/internal.h                       |   1 +
 ld/Makefile.am                               |   2 +
 ld/Makefile.in                               |   2 +
 ld/configure                                 |   8 +-
 ld/configure.ac                              |   3 +
 ld/ld.texi                                   |   4 +-
 ld/scripttempl/elf.sc                        |   2 +
 ld/testsuite/ld-aarch64/aarch64-elf.exp      |   2 +
 ld/testsuite/ld-aarch64/ctf-frame-bar.s      |   7 +
 ld/testsuite/ld-aarch64/ctf-frame-foo.s      |  10 +
 ld/testsuite/ld-aarch64/ctf-frame-simple-1.d |  26 +
 ld/testsuite/ld-bootstrap/bootstrap.exp      |   8 +-
 ld/testsuite/ld-ctf-frame/ctf-frame-empty.d  |  10 +
 ld/testsuite/ld-ctf-frame/ctf-frame-empty.s  |   2 +
 ld/testsuite/ld-ctf-frame/ctf-frame.exp      |  47 ++
 ld/testsuite/ld-ctf-frame/discard.d          |  10 +
 ld/testsuite/ld-ctf-frame/discard.ld         |   9 +
 ld/testsuite/ld-ctf-frame/discard.s          |  13 +
 ld/testsuite/ld-x86-64/ctf-frame-bar.s       |  31 ++
 ld/testsuite/ld-x86-64/ctf-frame-foo.s       |  37 ++
 ld/testsuite/ld-x86-64/ctf-frame-plt-1.d     |  29 +
 ld/testsuite/ld-x86-64/ctf-frame-simple-1.d  |  35 ++
 ld/testsuite/ld-x86-64/x86-64.exp            |   2 +
 ld/testsuite/lib/ld-lib.exp                  |  45 ++
 libctfframe/ctf-frame.c                      |  28 +-
 43 files changed, 1577 insertions(+), 35 deletions(-)
 create mode 100644 bfd/elf-ctf-frame.c
 create mode 100644 ld/testsuite/ld-aarch64/ctf-frame-bar.s
 create mode 100644 ld/testsuite/ld-aarch64/ctf-frame-foo.s
 create mode 100644 ld/testsuite/ld-aarch64/ctf-frame-simple-1.d
 create mode 100644 ld/testsuite/ld-ctf-frame/ctf-frame-empty.d
 create mode 100644 ld/testsuite/ld-ctf-frame/ctf-frame-empty.s
 create mode 100644 ld/testsuite/ld-ctf-frame/ctf-frame.exp
 create mode 100644 ld/testsuite/ld-ctf-frame/discard.d
 create mode 100644 ld/testsuite/ld-ctf-frame/discard.ld
 create mode 100644 ld/testsuite/ld-ctf-frame/discard.s
 create mode 100644 ld/testsuite/ld-x86-64/ctf-frame-bar.s
 create mode 100644 ld/testsuite/ld-x86-64/ctf-frame-foo.s
 create mode 100644 ld/testsuite/ld-x86-64/ctf-frame-plt-1.d
 create mode 100644 ld/testsuite/ld-x86-64/ctf-frame-simple-1.d

diff --git a/Makefile.def b/Makefile.def
index a63c3966513..2aacfec6c81 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -458,11 +458,14 @@ dependencies = { module=all-gdbsupport; on=all-gnulib; };
 dependencies = { module=all-gdbsupport; on=all-intl; };
 
 // Host modules specific to binutils.
+// build libctfframe before bfd for encoder/decoder support for linking
+// CTF frame sections
 dependencies = { module=configure-bfd; on=configure-libiberty; hard=true; };
 dependencies = { module=configure-bfd; on=configure-intl; };
 dependencies = { module=all-bfd; on=all-libiberty; };
 dependencies = { module=all-bfd; on=all-intl; };
 dependencies = { module=all-bfd; on=all-zlib; };
+dependencies = { module=all-bfd; on=all-libctfframe; };
 dependencies = { module=configure-opcodes; on=configure-libiberty; hard=true; };
 dependencies = { module=all-opcodes; on=all-libiberty; };
 
@@ -479,7 +482,6 @@ dependencies = { module=all-binutils; on=all-intl; };
 dependencies = { module=all-binutils; on=all-gas; };
 dependencies = { module=all-binutils; on=all-libctf; };
 dependencies = { module=all-ld; on=all-libctf; };
-dependencies = { module=all-binutils; on=all-libctfframe; };
 
 // We put install-opcodes before install-binutils because the installed
 // binutils might be on PATH, and they might need the shared opcodes
@@ -488,6 +490,7 @@ dependencies = { module=install-binutils; on=install-opcodes; };
 dependencies = { module=install-strip-binutils; on=install-strip-opcodes; };
 
 // Likewise for ld, libctf, and bfd.
+dependencies = { module=install-bfd; on=install-libctfframe; };
 dependencies = { module=install-libctf; on=install-bfd; };
 dependencies = { module=install-ld; on=install-bfd; };
 dependencies = { module=install-ld; on=install-libctf; };
diff --git a/Makefile.in b/Makefile.in
index 7b93fd14ffb..08e32e13f24 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -64407,6 +64407,16 @@ all-stagetrain-bfd: maybe-all-stagetrain-zlib
 all-stagefeedback-bfd: maybe-all-stagefeedback-zlib
 all-stageautoprofile-bfd: maybe-all-stageautoprofile-zlib
 all-stageautofeedback-bfd: maybe-all-stageautofeedback-zlib
+all-bfd: maybe-all-libctfframe
+all-stage1-bfd: maybe-all-stage1-libctfframe
+all-stage2-bfd: maybe-all-stage2-libctfframe
+all-stage3-bfd: maybe-all-stage3-libctfframe
+all-stage4-bfd: maybe-all-stage4-libctfframe
+all-stageprofile-bfd: maybe-all-stageprofile-libctfframe
+all-stagetrain-bfd: maybe-all-stagetrain-libctfframe
+all-stagefeedback-bfd: maybe-all-stagefeedback-libctfframe
+all-stageautoprofile-bfd: maybe-all-stageautoprofile-libctfframe
+all-stageautofeedback-bfd: maybe-all-stageautofeedback-libctfframe
 configure-opcodes: configure-libiberty
 configure-stage1-opcodes: configure-stage1-libiberty
 configure-stage2-opcodes: configure-stage2-libiberty
@@ -64527,18 +64537,9 @@ all-stagetrain-ld: maybe-all-stagetrain-libctf
 all-stagefeedback-ld: maybe-all-stagefeedback-libctf
 all-stageautoprofile-ld: maybe-all-stageautoprofile-libctf
 all-stageautofeedback-ld: maybe-all-stageautofeedback-libctf
-all-binutils: maybe-all-libctfframe
-all-stage1-binutils: maybe-all-stage1-libctfframe
-all-stage2-binutils: maybe-all-stage2-libctfframe
-all-stage3-binutils: maybe-all-stage3-libctfframe
-all-stage4-binutils: maybe-all-stage4-libctfframe
-all-stageprofile-binutils: maybe-all-stageprofile-libctfframe
-all-stagetrain-binutils: maybe-all-stagetrain-libctfframe
-all-stagefeedback-binutils: maybe-all-stagefeedback-libctfframe
-all-stageautoprofile-binutils: maybe-all-stageautoprofile-libctfframe
-all-stageautofeedback-binutils: maybe-all-stageautofeedback-libctfframe
 install-binutils: maybe-install-opcodes
 install-strip-binutils: maybe-install-strip-opcodes
+install-bfd: maybe-install-libctfframe
 install-libctf: maybe-install-bfd
 install-ld: maybe-install-bfd
 install-ld: maybe-install-libctf
diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 670e0598f55..505d7290cf6 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -286,6 +286,7 @@ BFD32_BACKENDS = \
 	ecofflink.lo \
 	elf-attrs.lo \
 	elf-eh-frame.lo \
+	elf-ctf-frame.lo \
 	elf-ifunc.lo \
 	elf-m10200.lo \
 	elf-m10300.lo \
@@ -418,6 +419,7 @@ BFD32_BACKENDS_CFILES = \
 	ecofflink.c \
 	elf-attrs.c \
 	elf-eh-frame.c \
+	elf-ctf-frame.c \
 	elf-ifunc.c \
 	elf-m10200.c \
 	elf-m10300.c \
@@ -770,8 +772,8 @@ ofiles: stamp-ofiles ; @true
 # dependency tracking fragments are picked up in the Makefile.
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
-libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB)
+libbfd_la_DEPENDENCIES = $(OFILES) ofiles ../libctfframe/libctfframe.la
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) ../libctfframe/libctfframe.la
 libbfd_la_LDFLAGS += -release `cat libtool-soversion` @SHARED_LDFLAGS@
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index d3ef4c2524b..f22a1cdff96 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -749,6 +749,7 @@ BFD32_BACKENDS = \
 	ecofflink.lo \
 	elf-attrs.lo \
 	elf-eh-frame.lo \
+	elf-ctf-frame.lo \
 	elf-ifunc.lo \
 	elf-m10200.lo \
 	elf-m10300.lo \
@@ -881,6 +882,7 @@ BFD32_BACKENDS_CFILES = \
 	ecofflink.c \
 	elf-attrs.c \
 	elf-eh-frame.c \
+	elf-ctf-frame.c \
 	elf-ifunc.c \
 	elf-m10200.c \
 	elf-m10300.c \
@@ -1194,8 +1196,8 @@ OFILES = $(BFD_BACKENDS) $(BFD_MACHINES) @COREFILE@ @bfd64_libs@
 # dependency tracking fragments are picked up in the Makefile.
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
-libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB)
+libbfd_la_DEPENDENCIES = $(OFILES) ofiles ../libctfframe/libctfframe.la
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) ../libctfframe/libctfframe.la
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
 # directory so that we don't have to convert all the programs that use
@@ -1555,6 +1557,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecoff.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecofflink.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-attrs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-ctf-frame.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-eh-frame.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-ifunc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-m10200.Plo@am__quote@
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 2d6e1bbc0b0..40ba24b9adb 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -999,6 +999,7 @@ typedef struct bfd_section
 #define SEC_INFO_TYPE_JUST_SYMS 4
 #define SEC_INFO_TYPE_TARGET    5
 #define SEC_INFO_TYPE_EH_FRAME_ENTRY 6
+#define SEC_INFO_TYPE_CTF_FRAME  7
 
   /* Nonzero if this section uses RELA relocations, rather than REL.  */
   unsigned int use_rela_p:1;
diff --git a/bfd/configure b/bfd/configure
index 590986efb61..7d67eeab891 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -13311,7 +13311,7 @@ selarchs="$f"
 tb=
 
 elf="elf.lo elflink.lo elf-attrs.lo elf-strtab.lo elf-eh-frame.lo
-     dwarf1.lo dwarf2.lo"
+     elf-ctf-frame.lo dwarf1.lo dwarf2.lo"
 coffgen="coffgen.lo dwarf2.lo"
 coff="cofflink.lo $coffgen"
 ecoff="ecofflink.lo $coffgen"
diff --git a/bfd/configure.ac b/bfd/configure.ac
index aad4f3c83a5..30e58a2079a 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -389,7 +389,7 @@ selarchs="$f"
 tb=
 
 elf="elf.lo elflink.lo elf-attrs.lo elf-strtab.lo elf-eh-frame.lo
-     dwarf1.lo dwarf2.lo"
+     elf-ctf-frame.lo dwarf1.lo dwarf2.lo"
 coffgen="coffgen.lo dwarf2.lo"
 coff="cofflink.lo $coffgen"
 ecoff="ecofflink.lo $coffgen"
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 65bd1128263..9233c294e27 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -490,6 +490,40 @@ struct eh_frame_hdr_info
   u;
 };
 
+/* Additional information for each function (used at link time).  */
+struct ctf_frame_func_bfdinfo
+{
+  /* Whether the function has been discarded from the final output.  */
+  bool func_deleted_p;
+  /* Relocation offset.  */
+  unsigned int func_r_offset;
+  /* Relocation index.  */
+  unsigned int func_reloc_index;
+};
+
+/* CTF Frame decoder info.
+   Contains all information for a decoded .ctf_frame section.  */
+struct ctf_frame_dec_info
+{
+  /* Decoder context.  */
+  struct ctf_frame_decoder_ctx *cfd_ctx;
+  /* Number of function descriptor entries in this .ctf_frame.  */
+  unsigned int cfd_fde_count;
+  /* Additional information for linking.  */
+  struct ctf_frame_func_bfdinfo *cfd_func_bfdinfo;
+};
+
+/* CTF Frame encoder info.
+   Contains all information for an encoded .ctf_frame section to be
+   written out.  */
+struct ctf_frame_enc_info
+{
+  /* Encoder context.  */
+  struct ctf_frame_encoder_ctx *cfe_ctx;
+  /* Output section.  */
+  asection *ctf_frame_section;
+};
+
 /* Enum used to identify target specific extensions to the elf_obj_tdata
    and elf_link_hash_table structures.  Note the enums deliberately start
    from 1 so that we can detect an uninitialized field.  The generic value
@@ -668,6 +702,9 @@ struct elf_link_hash_table
   /* Used by eh_frame code when editing .eh_frame.  */
   struct eh_frame_hdr_info eh_info;
 
+  /* Used to link unwind data in .ctf_frame sections.  */
+  struct ctf_frame_enc_info cfe_info;
+
   /* A linked list of local symbols to be added to .dynsym.  */
   struct elf_link_local_dynamic_entry *dynlocal;
 
@@ -1941,6 +1978,10 @@ struct output_elf_obj_tdata
   /* Segment flags for the PT_GNU_STACK segment.  */
   unsigned int stack_flags;
 
+  /* Used to determine if PT_GNU_CTF_FRAME segment header should be
+     created.  */
+  asection *ctf_frame;
+
   /* Used to determine if the e_flags field has been initialized */
   bool flags_init;
 };
@@ -2122,6 +2163,7 @@ struct elf_obj_tdata
 #define elf_link_info(bfd)	(elf_tdata(bfd) -> o->link_info)
 #define elf_next_file_pos(bfd)	(elf_tdata(bfd) -> o->next_file_pos)
 #define elf_stack_flags(bfd)	(elf_tdata(bfd) -> o->stack_flags)
+#define elf_ctf_frame(bfd)	(elf_tdata(bfd) -> o->ctf_frame)
 #define elf_shstrtab(bfd)	(elf_tdata(bfd) -> o->strtab_ptr)
 #define elf_onesymtab(bfd)	(elf_tdata(bfd) -> symtab_section)
 #define elf_symtab_shndx_list(bfd)	(elf_tdata(bfd) -> symtab_shndx_list)
@@ -2433,6 +2475,19 @@ extern bool _bfd_elf_eh_frame_entry_present
 extern bool _bfd_elf_maybe_strip_eh_frame_hdr
   (struct bfd_link_info *);
 
+extern bool _bfd_elf_ctf_frame_present
+  (struct bfd_link_info *);
+extern void _bfd_elf_parse_ctf_frame
+  (bfd *, struct bfd_link_info *, asection *, struct elf_reloc_cookie *);
+extern bool _bfd_elf_discard_section_ctf_frame
+  (bfd *, struct bfd_link_info *, asection *,
+   bool (*) (bfd_vma, void *), struct elf_reloc_cookie *);
+extern bool _bfd_elf_merge_section_ctf_frame
+  (bfd *, struct bfd_link_info *, asection *, bfd_byte *);
+extern bool _bfd_elf_write_section_ctf_frame
+  (bfd *, struct bfd_link_info *);
+extern bool _bfd_elf_set_section_ctf_frame (bfd *, struct bfd_link_info *);
+
 extern bool _bfd_elf_hash_symbol (struct elf_link_hash_entry *);
 
 extern long _bfd_elf_link_lookup_local_dynindx
diff --git a/bfd/elf-ctf-frame.c b/bfd/elf-ctf-frame.c
new file mode 100644
index 00000000000..243429fca45
--- /dev/null
+++ b/bfd/elf-ctf-frame.c
@@ -0,0 +1,529 @@
+/* .ctf_frame section processing.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "ctf-frame-api.h"
+
+/* Return TRUE if the function has been marked for deletion during the linking
+   process.  */
+
+static bool
+ctf_frame_decoder_func_deleted_p (struct ctf_frame_dec_info *cfd_info,
+				  unsigned int func_idx)
+{
+  return cfd_info->cfd_func_bfdinfo[func_idx].func_deleted_p;
+}
+
+/* Mark the function in the decoder info for deletion.  */
+
+static void
+ctf_frame_decoder_mark_func_deleted (struct ctf_frame_dec_info *cfd_info,
+				     unsigned int func_idx)
+{
+  BFD_ASSERT (func_idx < cfd_info->cfd_fde_count);
+  cfd_info->cfd_func_bfdinfo[func_idx].func_deleted_p = true;
+}
+
+/* Get the relocation offset from the decoder info for the given function.  */
+
+static unsigned int
+ctf_frame_decoder_get_func_r_offset (struct ctf_frame_dec_info *cfd_info,
+				     unsigned int func_idx)
+{
+  BFD_ASSERT (func_idx < cfd_info->cfd_fde_count);
+  unsigned int func_r_offset
+    = cfd_info->cfd_func_bfdinfo[func_idx].func_r_offset;
+  /* There must have been a reloc.  */
+  BFD_ASSERT (func_r_offset);
+  return func_r_offset;
+}
+
+/* Bookkeep the function relocation offset in the decoder info.  */
+
+static void
+ctf_frame_decoder_set_func_r_offset (struct ctf_frame_dec_info *cfd_info,
+				     unsigned int func_idx,
+				     unsigned int r_offset)
+{
+  BFD_ASSERT (func_idx < cfd_info->cfd_fde_count);
+  cfd_info->cfd_func_bfdinfo[func_idx].func_r_offset = r_offset;
+}
+
+/* Get the relocation index in the elf_reloc_cookie for the function.  */
+
+static unsigned int
+ctf_frame_decoder_get_func_reloc_index (struct ctf_frame_dec_info *cfd_info,
+					unsigned int func_idx)
+{
+  BFD_ASSERT (func_idx < cfd_info->cfd_fde_count);
+  return cfd_info->cfd_func_bfdinfo[func_idx].func_reloc_index;
+}
+
+/* Bookkeep the relocation index in the elf_reloc_cookie for the function.  */
+
+static void
+ctf_frame_decoder_set_func_reloc_index (struct ctf_frame_dec_info *cfd_info,
+					unsigned int func_idx,
+					unsigned int reloc_index)
+{
+  BFD_ASSERT (func_idx < cfd_info->cfd_fde_count);
+  cfd_info->cfd_func_bfdinfo[func_idx].func_reloc_index = reloc_index;
+}
+
+/* Initialize the set of additional information in CFD_INFO,
+   needed for linking SEC.  Returns TRUE if setup is done successfully.  */
+
+static bool
+ctf_frame_decoder_init_func_bfdinfo (asection *sec,
+				     struct ctf_frame_dec_info *cfd_info,
+				     struct elf_reloc_cookie *cookie)
+{
+  unsigned int fde_count;
+  unsigned int func_bfdinfo_size, i;
+
+  fde_count = ctf_frame_decoder_get_num_fidx (cfd_info->cfd_ctx);
+  cfd_info->cfd_fde_count = fde_count;
+
+  /* Allocate and clear the memory.  */
+  func_bfdinfo_size = (sizeof (struct ctf_frame_func_bfdinfo)) * fde_count;
+  cfd_info->cfd_func_bfdinfo
+    = (struct ctf_frame_func_bfdinfo*) bfd_malloc (func_bfdinfo_size);
+  if (cfd_info->cfd_func_bfdinfo == NULL)
+    return false;
+  memset (cfd_info->cfd_func_bfdinfo, 0, func_bfdinfo_size);
+
+  /* For linker generated .ctf_frame sections, we have no relocs.  Skip.  */
+  if ((sec->flags & SEC_LINKER_CREATED) && cookie->rels == NULL)
+    return true;
+
+  for (i = 0; i < fde_count; i++)
+    {
+      cookie->rel = cookie->rels + i;
+      BFD_ASSERT (cookie->rel < cookie->relend);
+      /* Bookkeep the relocation offset and relocation index of each function
+	 for later use.  */
+      ctf_frame_decoder_set_func_r_offset (cfd_info, i, cookie->rel->r_offset);
+      ctf_frame_decoder_set_func_reloc_index (cfd_info, i,
+					      (cookie->rel - cookie->rels));
+
+      cookie->rel++;
+    }
+  BFD_ASSERT (cookie->rel == cookie->relend);
+
+  return true;
+}
+
+/* Read the value from CONTENTS at the specified OFFSET for the given ABFD.  */
+
+static bfd_vma
+ctf_frame_read_value (bfd *abfd, bfd_byte *contents, unsigned int offset,
+		      unsigned int width)
+{
+  BFD_ASSERT (contents && offset);
+  /* Supporting the usecase of reading only the 4-byte relocated
+     value (signed offset for func start addr) for now.  */
+  BFD_ASSERT (width == 4);
+  /* FIXME endianness ?? */
+  unsigned char *buf = contents + offset;
+  bfd_vma value = bfd_get_signed_32 (abfd, buf);
+  return value;
+}
+
+/* Return true if there is at least one non-empty .ctf_frame section in
+   input files.  Can only be called after ld has mapped input to
+   output sections, and before sections are stripped.  */
+
+bool
+_bfd_elf_ctf_frame_present (struct bfd_link_info *info)
+{
+  asection *ctff = bfd_get_section_by_name (info->output_bfd, ".ctf_frame");
+
+  if (ctff == NULL)
+    return false;
+
+  /* Count only sections which have at least a single FDE.  */
+  for (ctff = ctff->map_head.s; ctff != NULL; ctff = ctff->map_head.s)
+    if (ctff->size > sizeof (ctf_frame_header))
+      return true;
+  return false;
+}
+
+/* Try to parse .ctf_frame section SEC, which belongs to ABFD.  Store the
+   information in the section's sec_info field on success.  COOKIE
+   describes the relocations in SEC.  */
+
+void
+_bfd_elf_parse_ctf_frame (bfd *abfd, struct bfd_link_info *info,
+			  asection *sec, struct elf_reloc_cookie *cookie)
+{
+  bfd_byte *ctfbuf = NULL;
+  struct ctf_frame_dec_info *cfd_info;
+  ctf_frame_decoder_ctx *cfd_ctx;
+  bfd_size_type cf_size;
+  int decerr = 0;
+
+  if (sec->size == 0
+      || sec->sec_info_type != SEC_INFO_TYPE_NONE)
+    {
+      /* This file does not contain .ctf_frame information.  */
+      return;
+    }
+
+  if (bfd_is_abs_section (sec->output_section))
+    {
+      /* At least one of the sections is being discarded from the
+	 link, so we should just ignore them.  */
+      return;
+    }
+
+  /* Read the ctf frame unwind information from abfd.  */
+  if (!bfd_malloc_and_get_section (abfd, sec, &ctfbuf))
+    goto fail_no_free;
+
+  /* Decode the buffer and keep decoded contents for later use.
+     Relocations are performed later, but are such that the section's
+     size is unaffected.  */
+  cfd_info = bfd_malloc (sizeof (struct ctf_frame_dec_info));
+  cf_size = sec->size;
+  BFD_ASSERT (cf_size);
+
+  cfd_info->cfd_ctx = ctf_frame_decode ((const char*)ctfbuf, cf_size, &decerr);
+  cfd_ctx = cfd_info->cfd_ctx;
+  if (!cfd_ctx)
+    /* Free'ing up any memory held by decoder context is done by
+       ctf_frame_decode in case of error.  */
+    goto fail_no_free;
+
+  if (!ctf_frame_decoder_init_func_bfdinfo (sec, cfd_info, cookie))
+    {
+      ctf_frame_decoder_free (&cfd_ctx);
+      goto fail_no_free;
+    }
+
+  elf_section_data (sec)->sec_info = cfd_info;
+  sec->sec_info_type = SEC_INFO_TYPE_CTF_FRAME;
+
+  BFD_ASSERT (abfd && info && cookie);
+  goto success;
+
+fail_no_free:
+  _bfd_error_handler
+   (_("error in %pB(%pA); no .ctf_frame will be created"),
+    abfd, sec);
+success:
+  free (ctfbuf);
+}
+
+/* This function is called for each input file before the .ctf_frame section
+   is relocated.  It marks the CTF FDE for the discarded functions for
+   deletion.
+
+   The function returns TRUE iff any entries have been deleted.  */
+
+bool
+_bfd_elf_discard_section_ctf_frame
+   (bfd *abfd, struct bfd_link_info *info, asection *sec,
+    bool (*reloc_symbol_deleted_p) (bfd_vma, void *),
+    struct elf_reloc_cookie *cookie)
+{
+  struct ctf_frame_dec_info *cfd_info;
+  BFD_ASSERT (abfd && info);
+  BFD_ASSERT (reloc_symbol_deleted_p);
+  cfd_info = (struct ctf_frame_dec_info *) elf_section_data (sec)->sec_info;
+
+  bool changed = false;
+  /* FIXME - if relocatable link and changed = true, how does the final
+     .rela.ctf_frame get updated ?.  */
+  bool keep = false;
+  unsigned int i = 0;
+  unsigned int func_desc_offset = 0;
+  unsigned int num_fidx = 0;
+
+  /* Skip checking for the linker created .ctf_frame sections
+     (for PLT sections).  */
+  if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL)
+    {
+      num_fidx = ctf_frame_decoder_get_num_fidx (cfd_info->cfd_ctx);
+      for (i = 0; i < num_fidx; i++)
+	{
+	  func_desc_offset = ctf_frame_decoder_get_func_r_offset (cfd_info, i);
+
+	  cookie->rel = cookie->rels
+	    + ctf_frame_decoder_get_func_reloc_index (cfd_info, i);
+	  keep = !(*reloc_symbol_deleted_p) (func_desc_offset, cookie);
+
+	  if (!keep)
+	    {
+	      ctf_frame_decoder_mark_func_deleted (cfd_info, i);
+	      changed = true;
+	    }
+	}
+    }
+  return changed;
+}
+
+/* Update the reference to the output .ctf_frame section in the output ELF
+   BFD ABFD.  Returns true if no error.  */
+
+bool
+_bfd_elf_set_section_ctf_frame (bfd *abfd,
+				struct bfd_link_info *info)
+{
+  asection *cfsec;
+
+  cfsec = bfd_get_section_by_name (info->output_bfd, ".ctf_frame");
+  if (!cfsec)
+    return false;
+
+  elf_ctf_frame (abfd) = cfsec;
+
+  return true;
+}
+
+/* Merge .ctf_frame section SEC.  This is called with the relocated
+   CONTENTS.  */
+
+bool
+_bfd_elf_merge_section_ctf_frame (bfd *abfd,
+				  struct bfd_link_info *info,
+				  asection *sec,
+				  bfd_byte *contents)
+{
+  struct ctf_frame_dec_info *cfd_info;
+  struct ctf_frame_enc_info *cfe_info;
+  ctf_frame_decoder_ctx *cfd_ctx;
+  ctf_frame_encoder_ctx *cfe_ctx;
+  unsigned char cfd_ctx_abi_arch = 0;
+  int encerr = 0;
+
+  struct elf_link_hash_table *htab;
+  asection *cfsec;
+
+  BFD_ASSERT (abfd && info && sec && contents);
+
+  BFD_ASSERT (sec->sec_info_type == SEC_INFO_TYPE_CTF_FRAME);
+
+  cfd_info = (struct ctf_frame_dec_info *) elf_section_data (sec)->sec_info;
+  cfd_ctx = cfd_info->cfd_ctx;
+
+  htab = elf_hash_table (info);
+  cfe_info = &(htab->cfe_info);
+  cfe_ctx = cfe_info->cfe_ctx;
+
+  /* All input bfds are expected to have a valid CTF Frame section.  Even if
+     the CTF Frame section is empty with only a header, the section will have
+     been parsed and decoded by now.  */
+  BFD_ASSERT (cfd_info && cfd_ctx);
+
+  BFD_ASSERT (htab);
+  BFD_ASSERT (cfe_info);
+  BFD_ASSERT (sec->output_section);
+
+  if (htab->cfe_info.cfe_ctx == NULL)
+    {
+      cfd_ctx_abi_arch = ctf_frame_decoder_get_abi_arch (cfd_ctx);
+      BFD_ASSERT (cfd_ctx_abi_arch); /* Valid values are non-zero.  */
+      htab->cfe_info.cfe_ctx = ctf_frame_encode (CTF_FRAME_VERSION_1,
+						 0, /* CTF Frame flags.  */
+						 cfd_ctx_abi_arch,
+						 &encerr);
+      /* Handle errors from ctf_frame_encode.  */
+      if (htab->cfe_info.cfe_ctx == NULL)
+	return false;
+    }
+  cfe_ctx = cfe_info->cfe_ctx;
+
+  if (cfe_info->ctf_frame_section == NULL)
+    {
+      /* Make sure things are set for an eventual write.
+	 Size of the output section is not known until
+	 _bfd_elf_write_section_ctf_frame is ready with the buffer
+	 to write out.  */
+      cfsec = bfd_get_section_by_name (info->output_bfd, ".ctf_frame");
+      if (cfsec)
+	{
+	  cfe_info->ctf_frame_section = cfsec;
+	  // elf_ctf_frame (abfd) = cfsec;
+	}
+      else
+	return false;
+    }
+
+  /* Check that all .ctf_frame sections being linked have the same
+     ABI/arch.  */
+  if (ctf_frame_decoder_get_abi_arch (cfd_ctx)
+      != ctf_frame_encoder_get_abi_arch (cfe_ctx))
+    {
+      _bfd_error_handler
+	(_("input CTF Frame sections with different abi prevent .ctf_frame"
+	  " generation"));
+      return false;
+    }
+
+  /* Iterate over the function descriptor entries and the FREs of the
+     function from the decoder context.  Add each of them to the encoder
+     context, if suitable.  */
+  unsigned int i = 0, j = 0, cur_fidx = 0;
+
+  unsigned int num_fidx = ctf_frame_decoder_get_num_fidx (cfd_ctx);
+  unsigned int num_enc_fidx = ctf_frame_encoder_get_num_fidx (cfe_ctx);
+
+  for (i = 0; i < num_fidx; i++)
+    {
+      unsigned int num_fres = 0;
+      int32_t func_start_address;
+      bfd_vma address;
+      uint32_t func_size = 0;
+      unsigned char func_info = 0;
+      unsigned int r_offset = 0;
+      bool pltn_reloc_by_hand = false;
+      unsigned int pltn_r_offset = 0;
+
+      if (!ctf_frame_decoder_get_funcdesc (cfd_ctx, i, &num_fres, &func_size,
+					   &func_start_address, &func_info))
+	{
+	  /* If function belongs to a deleted section, skip editing the
+	     function descriptor entry.  */
+	  if (ctf_frame_decoder_func_deleted_p(cfd_info, i))
+	    continue;
+
+	  /* Don't edit function descriptor entries for relocatable link.  */
+	  if (!bfd_link_relocatable (info))
+	    {
+	      if (!(sec->flags & SEC_LINKER_CREATED))
+		{
+		  /* Get relocated contents by reading the value of the
+		     relocated function start address at the beginning of the
+		     function descriptor entry.  */
+		  r_offset = ctf_frame_decoder_get_func_r_offset (cfd_info, i);
+		}
+	      else
+		{
+		  /* Expected to land here for CTF Frame unwind info as created
+		     for the .plt* sections.  These sections can have upto two
+		     FDE entries.  Although the code should work for > 2,
+		     leaving this assert here for safety.  */
+		  BFD_ASSERT (num_fidx <= 2);
+		  /* For the first entry, we know the offset of the CTF FDE's
+		     ctf_func_start_address.  Side note: see how the value
+		     of PLT_CTF_FRAME_FDE_START_OFFSET is also set to the
+		     same.  */
+		  r_offset = sizeof (ctf_frame_header);
+		  /* For any further CTF FDEs, the generator has already put in
+		     an offset in place of ctf_func_start_address of the
+		     corresponding FDE.  We will use it by hand to relocate.  */
+		  if (i > 0)
+		    {
+		      pltn_r_offset
+			= r_offset + (i * sizeof (ctf_frame_func_desc_entry));
+		      pltn_reloc_by_hand = true;
+		    }
+		}
+
+	      /* Get the CTF FDE function start address after relocation.  */
+	      address = ctf_frame_read_value (abfd, contents, r_offset, 4);
+	      if (pltn_reloc_by_hand)
+		address += ctf_frame_read_value (abfd, contents,
+						 pltn_r_offset, 4);
+	      address += (sec->output_offset + r_offset);
+
+	      /* FIXME For testing only. Cleanup later.  */
+	      // address += (sec->output_section->vma);
+
+	      func_start_address = address;
+	    }
+
+	  /* Update the encoder context with updated content.  */
+	  int err = ctf_frame_encoder_add_funcdesc (cfe_ctx, func_start_address,
+						    func_size, func_info,
+						    num_fres);
+	  cur_fidx++;
+	  BFD_ASSERT (!err);
+	}
+
+      for (j = 0; j < num_fres; j++)
+	{
+	  ctf_frame_row_entry fre;
+	  if (!ctf_frame_decoder_get_fre (cfd_ctx, i, j, &fre))
+	    {
+	      int err = ctf_frame_encoder_add_fre (cfe_ctx,
+						   cur_fidx-1+num_enc_fidx,
+						   &fre);
+	      BFD_ASSERT (!err);
+	    }
+	}
+    }
+  /* Free the CTF Frame decoder context.  */
+  ctf_frame_decoder_free (&cfd_ctx);
+
+  return true;
+}
+
+/* Write out the .ctf_frame section.  This must be called after
+   _bfd_elf_merge_section_ctf_frame has been called on all input
+   .ctf_frame sections.  */
+
+bool
+_bfd_elf_write_section_ctf_frame (bfd *abfd, struct bfd_link_info *info)
+{
+  bool retval = true;
+  BFD_ASSERT (abfd && info);
+
+  struct elf_link_hash_table *htab;
+  struct ctf_frame_enc_info *cfe_info;
+  ctf_frame_encoder_ctx *cfe_ctx;
+  asection *sec;
+  void *contents;
+  bfd_size_type sec_size;
+  int err = 0;
+
+  htab = elf_hash_table (info);
+  cfe_info = &htab->cfe_info;
+  sec = cfe_info->ctf_frame_section;
+  cfe_ctx = cfe_info->cfe_ctx;
+
+  // FIXME use assert
+  // BFD_ASSERT (sec);
+  if (sec == NULL)
+    return true;
+
+
+  contents = ctf_frame_write_encoder (cfe_ctx, &sec_size, &err);
+  sec->size = sec_size;
+
+  if (!bfd_set_section_contents (abfd, sec->output_section, contents,
+				 (file_ptr) sec->output_offset,
+				 sec_size))
+    retval = false;
+  else if (!bfd_link_relocatable (info))
+    {
+      Elf_Internal_Shdr *hdr = &elf_section_data (sec)->this_hdr;
+      hdr->sh_size = sec_size;
+    }
+  /* For relocatable links, do not update the section size as the section
+     contents have not been relocated.  */
+
+  ctf_frame_encoder_free (&cfe_ctx);
+
+  return retval;
+}
diff --git a/bfd/elf.c b/bfd/elf.c
index 89484ceb233..43b65117053 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1646,6 +1646,7 @@ get_segment_type (unsigned int p_type)
     case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
     case PT_GNU_STACK: pt = "STACK"; break;
     case PT_GNU_RELRO: pt = "RELRO"; break;
+    case PT_GNU_CTF_FRAME: pt = "CTF_FRAME"; break;
     default: pt = NULL; break;
     }
   return pt;
@@ -3060,6 +3061,10 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index)
     case PT_GNU_RELRO:
       return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "relro");
 
+    case PT_GNU_CTF_FRAME:
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index,
+					      "ctf_frame");
+
     default:
       /* Check for any processor-specific program segment types.  */
       bed = get_elf_backend_data (abfd);
@@ -4408,6 +4413,12 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
       ++segs;
     }
 
+  if (elf_ctf_frame (abfd))
+    {
+      /* We need a PT_GNU_CTF_FRAME segment.  */
+      ++segs;
+    }
+
   s = bfd_get_section_by_name (abfd,
 			       NOTE_GNU_PROPERTY_SECTION_NAME);
   if (s != NULL && s->size != 0)
@@ -4673,6 +4684,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd,
       asection *first_tls = NULL;
       asection *first_mbind = NULL;
       asection *dynsec, *eh_frame_hdr;
+      asection *ctf_frame;
       size_t amt;
       bfd_vma addr_mask, wrap_to = 0;  /* Bytes.  */
       bfd_size_type phdr_size;  /* Octets/bytes.  */
@@ -5190,6 +5202,26 @@ _bfd_elf_map_sections_to_segments (bfd *abfd,
 	  pm = &m->next;
 	}
 
+      /* If there is a .ctf_frame section, throw in a PT_GNU_CTF_FRAME
+	 segment.  */
+      ctf_frame = elf_ctf_frame (abfd);
+      if (ctf_frame != NULL
+	  && (ctf_frame->output_section->flags & SEC_LOAD) != 0
+	  && ctf_frame->size != 0)
+	{
+	  amt = sizeof (struct elf_segment_map);
+	  m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+	  if (m == NULL)
+	    goto error_return;
+	  m->next = NULL;
+	  m->p_type = PT_GNU_CTF_FRAME;
+	  m->count = 1;
+	  m->sections[0] = ctf_frame->output_section;
+
+	  *pm = m;
+	  pm = &m->next;
+	}
+
       if (info != NULL && info->relro)
 	{
 	  for (m = mfirst; m != NULL; m = m->next)
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 62a9a22317a..a73673b2b4b 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -22,6 +22,7 @@
 #include "elfxx-x86.h"
 #include "dwarf2.h"
 #include "libiberty.h"
+#include "ctf-frame.h"
 
 #include "opcode/i386.h"
 
@@ -818,6 +819,87 @@ static const bfd_byte elf_x86_64_eh_frame_non_lazy_plt[] =
   DW_CFA_nop, DW_CFA_nop, DW_CFA_nop
 };
 
+static const ctf_frame_row_entry elf_x86_64_ctf_frame_null_fre =
+{
+  0,
+  CTF_FRAME_V1_FRE_INFO (CTF_FRAME_BASE_REG_SP, 1, CTF_FRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .ctf_frame FRE covering the .plt section entry.  */
+static const ctf_frame_row_entry elf_x86_64_ctf_frame_plt0_fre1 =
+{
+  0, /* CTF FRE start address.  */
+  CTF_FRAME_V1_FRE_INFO (CTF_FRAME_BASE_REG_SP, 1, CTF_FRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .ctf_frame FRE covering the .plt section entry.  */
+static const ctf_frame_row_entry elf_x86_64_ctf_frame_plt0_fre2 =
+{
+  6, /* CTF FRE start address.  */
+  CTF_FRAME_V1_FRE_INFO (CTF_FRAME_BASE_REG_SP, 1, CTF_FRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .ctf_frame FRE covering the .plt section entry.  */
+static const ctf_frame_row_entry elf_x86_64_ctf_frame_pltn_fre1 =
+{
+  0, /* CTF FRE start address.  */
+  CTF_FRAME_V1_FRE_INFO (CTF_FRAME_BASE_REG_SP, 1, CTF_FRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .ctf_frame FRE covering the .plt section entry.  */
+static const ctf_frame_row_entry elf_x86_64_ctf_frame_pltn_fre2 =
+{
+  11, /* CTF FRE start address.  */
+  CTF_FRAME_V1_FRE_INFO (CTF_FRAME_BASE_REG_SP, 1, CTF_FRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .ctf_frame FRE covering the second .plt section entry.  */
+static const ctf_frame_row_entry elf_x86_64_ctf_frame_sec_pltn_fre1 =
+{
+  0, /* CTF FRE start address.  */
+  CTF_FRAME_V1_FRE_INFO (CTF_FRAME_BASE_REG_SP, 1, CTF_FRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* CTF Frame helper object for non-lazy PLT.  Also used for IBT enabled PLT.  */
+static const struct elf_x86_ctf_frame_plt elf_x86_64_ctf_frame_non_lazy_plt =
+{
+  LAZY_PLT_ENTRY_SIZE,
+  2, /* Number of FREs for PLT0.  */
+  /* Array of CTF Frame FREs for plt0.  */
+  { &elf_x86_64_ctf_frame_plt0_fre1, &elf_x86_64_ctf_frame_plt0_fre2 },
+  LAZY_PLT_ENTRY_SIZE,
+  1, /* Number of FREs for PLTn.  */
+  /* Array of CTF Frame FREs for plt.  */
+  { &elf_x86_64_ctf_frame_sec_pltn_fre1, &elf_x86_64_ctf_frame_null_fre },
+  0,
+  0, /* There is no second PLT necessary.  */
+  { &elf_x86_64_ctf_frame_null_fre }
+};
+
+/* CTF Frame helper object for lazy PLT.  Also used for IBT enabled PLT.  */
+static const struct elf_x86_ctf_frame_plt elf_x86_64_ctf_frame_plt =
+{
+  LAZY_PLT_ENTRY_SIZE,
+  2, /* Number of FREs for PLT0.  */
+  /* Array of CTF Frame FREs for plt0.  */
+  { &elf_x86_64_ctf_frame_plt0_fre1, &elf_x86_64_ctf_frame_plt0_fre2 },
+  LAZY_PLT_ENTRY_SIZE,
+  2, /* Number of FREs for PLTn.  */
+  /* Array of CTF Frame FREs for plt.  */
+  { &elf_x86_64_ctf_frame_pltn_fre1, &elf_x86_64_ctf_frame_pltn_fre2 },
+  NON_LAZY_PLT_ENTRY_SIZE,
+  1, /* Number of FREs for PLTn for second PLT.  */
+  /* FREs for second plt ( unwind info for .plt.got is
+     identical).  Used when IBT or non-lazy PLT is in effect.  */
+  { &elf_x86_64_ctf_frame_sec_pltn_fre1 }
+};
+
 /* These are the standard parameters.  */
 static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_plt =
   {
@@ -971,7 +1053,6 @@ static const struct elf_x86_non_lazy_plt_layout elf_x32_non_lazy_ibt_plt =
     sizeof (elf_x86_64_eh_frame_non_lazy_plt) /* eh_frame_plt_size */
   };
 
-
 static bool
 elf64_x86_64_elf_object_p (bfd *abfd)
 {
@@ -5227,6 +5308,20 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info)
       init_table.non_lazy_ibt_plt = &elf_x32_non_lazy_ibt_plt;
     }
 
+  if (ABI_64_P (info->output_bfd))
+    {
+      init_table.ctf_frame_lazy_plt = &elf_x86_64_ctf_frame_plt;
+      init_table.ctf_frame_non_lazy_plt = &elf_x86_64_ctf_frame_non_lazy_plt;
+      init_table.ctf_frame_lazy_ibt_plt = &elf_x86_64_ctf_frame_plt;
+      init_table.ctf_frame_non_lazy_ibt_plt = &elf_x86_64_ctf_frame_non_lazy_plt;
+    }
+  else
+    {
+      /* CTF Frame is not supported for non AMD64.  */
+      init_table.ctf_frame_lazy_plt = NULL;
+      init_table.ctf_frame_non_lazy_plt = NULL;
+    }
+
   if (ABI_64_P (info->output_bfd))
     {
       init_table.r_info = elf64_r_info;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 2b1450fa4e1..67bc6a32c9b 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -10899,6 +10899,7 @@ elf_section_ignore_discarded_relocs (asection *sec)
     case SEC_INFO_TYPE_STABS:
     case SEC_INFO_TYPE_EH_FRAME:
     case SEC_INFO_TYPE_EH_FRAME_ENTRY:
+    case SEC_INFO_TYPE_CTF_FRAME:
       return true;
     default:
       break;
@@ -10930,6 +10931,9 @@ _bfd_elf_default_action_discarded (asection *sec)
   if (strcmp (".eh_frame", sec->name) == 0)
     return 0;
 
+  if (strcmp (".ctf_frame", sec->name) == 0)
+    return 0;
+
   if (strcmp (".gcc_except_table", sec->name) == 0)
     return 0;
 
@@ -11863,6 +11867,16 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 	      return false;
 	  }
 	  break;
+	case SEC_INFO_TYPE_CTF_FRAME:
+	    {
+	      /* Merge .ctf_frame sections into the ctf frame encoder
+		 context of the output_bfd's section.  The final .ctf_frame
+		 output section will be written out later.  */
+	      if (!_bfd_elf_merge_section_ctf_frame (output_bfd, flinfo->info,
+						     o, contents))
+		return false;
+	    }
+	    break;
 	default:
 	  {
 	    if (! (o->flags & SEC_EXCLUDE))
@@ -13446,6 +13460,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info))
     goto error_return;
 
+  if (! _bfd_elf_write_section_ctf_frame (abfd, info))
+    goto error_return;
+
   if (info->callbacks->emit_ctf)
       info->callbacks->emit_ctf ();
 
@@ -14901,6 +14918,41 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
 				_bfd_elf_adjust_eh_frame_global_symbol, NULL);
     }
 
+  o = bfd_get_section_by_name (output_bfd, ".ctf_frame");
+  if (o != NULL)
+    {
+      asection *i;
+
+      for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+	{
+	  if (i->size == 0)
+	    continue;
+
+	  abfd = i->owner;
+	  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+	    continue;
+
+	  if (!init_reloc_cookie_for_section (&cookie, info, i))
+	    return -1;
+
+	  _bfd_elf_parse_ctf_frame (abfd, info, i, &cookie);
+
+	  if (_bfd_elf_discard_section_ctf_frame (abfd, info, i,
+						  bfd_elf_reloc_symbol_deleted_p,
+						  &cookie))
+	    {
+	      if (i->size != i->rawsize)
+		changed = 1;
+	    }
+
+	  fini_reloc_cookie_for_section (&cookie, i);
+	}
+      /* Update the reference to the output .ctf_frame section.  Used to
+	 determine later if PT_GNU_CTF_FRAME segment is to be generated.  */
+      if (!_bfd_elf_set_section_ctf_frame (output_bfd, info))
+	return -1;
+    }
+
   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
     {
       const struct elf_backend_data *bed;
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 7fb972752b3..1ee2da5c413 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -1777,6 +1777,191 @@ elf_x86_relative_reloc_compare (const void *pa, const void *pb)
   return 0;
 }
 
+enum dynobj_ctf_frame_plt_type
+{
+  CTF_FRAME_PLT = 1,
+  CTF_FRAME_PLT_SEC = 2
+};
+
+/* Create CTF Frame unwind info for the plt entries in the .plt section
+   of type PLT_SEC_TYPE.  */
+
+static bool
+_bfd_x86_elf_create_ctf_frame_plt (bfd *output_bfd,
+				  struct bfd_link_info *info,
+				  unsigned int plt_sec_type)
+{
+  struct elf_x86_link_hash_table *htab;
+  const struct elf_backend_data *bed;
+
+  bool plt0_generated_p;
+  unsigned int plt0_entry_size;
+  unsigned char func_info;
+  unsigned int fre_type;
+  /* The dynamic plt section for which .ctf_frame unwind information is being
+     created.  */
+  asection *dpltsec;
+
+  int err = 0;
+
+  ctf_frame_encoder_ctx **ectx = NULL;
+  unsigned plt_entry_size = 0;
+  unsigned int num_pltn_fres = 0;
+  unsigned int num_pltn_entries = 0;
+
+  bed = get_elf_backend_data (output_bfd);
+  htab = elf_x86_hash_table (info, bed->target_id);
+  /* Whether CTF Frame unwind info for plt0 is to be generated.  */
+  plt0_generated_p = htab->plt.has_plt0;
+  plt0_entry_size
+    = (plt0_generated_p) ? htab->ctf_frame_plt->plt0_entry_size : 0;
+
+  switch (plt_sec_type)
+    {
+    case CTF_FRAME_PLT:
+	{
+	  ectx = &htab->plt_cfe_ctx;
+	  dpltsec = htab->elf.splt;
+
+	  plt_entry_size = htab->plt.plt_entry_size;
+	  num_pltn_fres = htab->ctf_frame_plt->pltn_num_fres;
+	  num_pltn_entries
+	    = (htab->elf.splt->size - plt0_entry_size) / plt_entry_size;
+
+	  break;
+	}
+    case CTF_FRAME_PLT_SEC:
+	{
+	  ectx = &htab->plt_second_cfe_ctx;
+	  /* FIXME - this or htab->plt_second_ctf_frame ?  */
+	  dpltsec = htab->plt_second_eh_frame;
+
+	  plt_entry_size = htab->ctf_frame_plt->sec_pltn_entry_size;
+	  num_pltn_fres = htab->ctf_frame_plt->sec_pltn_num_fres;
+	  num_pltn_entries
+		= htab->plt_second_eh_frame->size / plt_entry_size;
+	  break;
+	}
+    default:
+      /* No other value is possible.  */
+      return false;
+      break;
+    }
+
+  *ectx = ctf_frame_encode (CTF_FRAME_VERSION_1,
+			    0,
+			    CTF_FRAME_ABI_AMD64_ENDIAN_LITTLE,
+			    &err);
+
+  /* FRE type is dependent on the size of the function.  */
+  fre_type = ctf_frame_calc_fre_type (dpltsec->size);
+  func_info = ctf_frame_fde_func_info (fre_type,
+				       CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCINC);
+
+  /* Add CTF FDE and the associated FREs for plt0 if plt0 has been
+     generated.  */
+  if (plt0_generated_p)
+    {
+      /* Add CTF FDE for plt0, the function start address is updated later
+	 at _bfd_elf_merge_section_ctf_frame time.  */
+      ctf_frame_encoder_add_funcdesc (*ectx,
+				      0, /* func start addr.  */
+				      plt0_entry_size,
+				      func_info,
+				      0 /* Num FREs.  */);
+      ctf_frame_row_entry plt0_fre;
+      unsigned int num_plt0_fres = htab->ctf_frame_plt->plt0_num_fres;
+      for (unsigned int j = 0; j < num_plt0_fres; j++)
+	{
+	  plt0_fre = *(htab->ctf_frame_plt->plt0_fres[j]);
+	  ctf_frame_encoder_add_fre (*ectx, 0, &plt0_fre);
+	}
+    }
+
+
+  if (num_pltn_entries)
+    {
+      /* pltn entries use a CTF FDE of type
+	 CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCMASK to exploit the repetitive
+	 pattern of the instructions in these entries.  Using this CTF FDE
+	 type helps in keeping the unwind information for pltn entries
+	 compact.  */
+      func_info
+	= ctf_frame_fde_func_info (fre_type,
+				   CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCMASK);
+      /* Add the CTF FDE for all PCs starting at the first pltn entry (hence,
+	 function start address = plt0_entry_size.  As usual, this will be
+	 updated later at _bfd_elf_merge_section_ctf_frame, by when the
+	 sections are relocated.  */
+      ctf_frame_encoder_add_funcdesc (*ectx,
+				      plt0_entry_size, /* func start addr.  */
+				      dpltsec->size - plt0_entry_size,
+				      func_info,
+				      0 /* Num FREs.  */);
+
+      ctf_frame_row_entry pltn_fre;
+      /* Now add the FREs for pltn.  Simply adding the two FREs suffices due
+	 to the usage of CTF_FRAME_FUNC_DESC_ENTRY_TYPE_PCMASK above.  */
+      for (unsigned int j = 0; j < num_pltn_fres; j++)
+	{
+	  pltn_fre = *(htab->ctf_frame_plt->pltn_fres[j]);
+	  ctf_frame_encoder_add_fre (*ectx, 1, &pltn_fre);
+	}
+    }
+
+  return true;
+}
+
+/* Put contents of the .ctf_frame section corresponding to the specified
+   PLT_SEC_TYPE.  */
+
+static bool
+_bfd_x86_elf_write_ctf_frame_plt (bfd *output_bfd,
+				  struct bfd_link_info *info,
+				  unsigned int plt_sec_type)
+{
+  struct elf_x86_link_hash_table *htab;
+  const struct elf_backend_data *bed;
+  ctf_frame_encoder_ctx *ectx;
+  bfd_size_type sec_size;
+  asection *sec;
+  bfd *dynobj;
+
+  int err = 0;
+
+  bed = get_elf_backend_data (output_bfd);
+  htab = elf_x86_hash_table (info, bed->target_id);
+  dynobj = htab->elf.dynobj;
+
+  switch (plt_sec_type)
+    {
+    case CTF_FRAME_PLT:
+      ectx = htab->plt_cfe_ctx;
+      sec = htab->plt_ctf_frame;
+      break;
+    case CTF_FRAME_PLT_SEC:
+      ectx = htab->plt_second_cfe_ctx;
+      sec = htab->plt_second_ctf_frame;
+      break;
+    default:
+      /* No other value is possible.  */
+      return false;
+      break;
+    }
+
+  BFD_ASSERT (ectx);
+
+  void *contents = ctf_frame_write_encoder (ectx, &sec_size, &err);
+
+  sec->size = sec_size;
+  sec->contents = (unsigned char *) bfd_zalloc (dynobj, sec->size);
+  memcpy (sec->contents, contents, sec_size);
+
+  ctf_frame_encoder_free (&ectx);
+
+  return true;
+}
+
 bool
 _bfd_elf_x86_size_relative_relocs (struct bfd_link_info *info,
 				   bool *need_layout)
@@ -2267,6 +2452,42 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
 	  = htab->non_lazy_plt->eh_frame_plt_size;
     }
 
+  /* No need to size the .ctf_frame section explicitly because the write-out
+     mechanism is different.  Simply prep up the FDE/FRE for the
+     .plt section.  */
+  if (_bfd_elf_ctf_frame_present (info))
+    {
+      if (htab->plt_ctf_frame != NULL
+	  && htab->elf.splt != NULL
+	  && htab->elf.splt->size != 0
+	  && !bfd_is_abs_section (htab->elf.splt->output_section))
+	{
+	  _bfd_x86_elf_create_ctf_frame_plt (output_bfd, info, CTF_FRAME_PLT);
+	  /* FIXME - Dirty Hack.  Set the size to something non-zero for now,
+	     so that the section does not get stripped out below.  The precise
+	     size of this section is known only when the contents are
+	     serialized in _bfd_x86_elf_write_ctf_frame_plt.  */
+	  htab->plt_ctf_frame->size = sizeof (ctf_frame_header) + 1;
+	}
+
+      /* FIXME - generate for .got.plt ?  */
+
+      /* Unwind info for the second PLT.  */
+      if (htab->plt_second_ctf_frame != NULL
+	  && htab->plt_second != NULL
+	  && htab->plt_second->size != 0
+	  && !bfd_is_abs_section (htab->plt_second->output_section))
+	{
+	  _bfd_x86_elf_create_ctf_frame_plt (output_bfd, info,
+					     CTF_FRAME_PLT_SEC);
+	  /* FIXME - Dirty Hack.  Set the size to something non-zero for now,
+	     so that the section does not get stripped out below.  The precise
+	     size of this section is known only when the contents are
+	     serialized in _bfd_x86_elf_write_ctf_frame_plt.  */
+	  htab->plt_second_ctf_frame->size = sizeof (ctf_frame_header) + 1;
+	}
+    }
+
   /* We now have determined the sizes of the various dynamic sections.
      Allocate memory for them.  */
   relocs = false;
@@ -2302,6 +2523,8 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
 	       || s == htab->plt_eh_frame
 	       || s == htab->plt_got_eh_frame
 	       || s == htab->plt_second_eh_frame
+	       || s == htab->plt_ctf_frame
+	       || s == htab->plt_second_ctf_frame
 	       || s == htab->elf.sdynbss
 	       || s == htab->elf.sdynrelro)
 	{
@@ -2344,6 +2567,11 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
       if ((s->flags & SEC_HAS_CONTENTS) == 0)
 	continue;
 
+      /* Skip allocating contents for .ctf_frame section as it is written
+	 out differently.  See below.  */
+      if ((s == htab->plt_ctf_frame) || (s == htab->plt_second_ctf_frame))
+	continue;
+
       /* NB: Initially, the iplt section has minimal alignment to
 	 avoid moving dot of the following section backwards when
 	 it is empty.  Update its section alignment now since it
@@ -2393,6 +2621,21 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
 		   + PLT_FDE_LEN_OFFSET));
     }
 
+  if (_bfd_elf_ctf_frame_present (info))
+    {
+      if (htab->plt_ctf_frame != NULL
+	  && htab->elf.splt != NULL
+	  && htab->elf.splt->size != 0
+	  && htab->plt_ctf_frame->contents == NULL)
+	_bfd_x86_elf_write_ctf_frame_plt (output_bfd, info, CTF_FRAME_PLT);
+
+      if (htab->plt_second_ctf_frame != NULL
+	  && htab->elf.splt != NULL
+	  && htab->elf.splt->size != 0
+	  && htab->plt_second_ctf_frame->contents == NULL)
+	_bfd_x86_elf_write_ctf_frame_plt (output_bfd, info, CTF_FRAME_PLT_SEC);
+    }
+
   return _bfd_elf_maybe_vxworks_add_dynamic_tags (output_bfd, info,
 						  relocs);
 }
@@ -2607,6 +2850,78 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd,
 	}
     }
 
+  /* Make any adjustment if necessary and merge .ctf_frame section to
+     create the final .ctf_frame section for output_bfd.  */
+  if (htab->plt_ctf_frame != NULL
+      && htab->plt_ctf_frame->contents != NULL)
+    {
+      if (htab->elf.splt != NULL
+	  && htab->elf.splt->size != 0
+	  && (htab->elf.splt->flags & SEC_EXCLUDE) == 0
+	  && htab->elf.splt->output_section != NULL
+	  && htab->plt_ctf_frame->output_section != NULL)
+	{
+	  bfd_vma plt_start = htab->elf.splt->output_section->vma;
+	  bfd_vma ctf_frame_start = htab->plt_ctf_frame->output_section->vma
+				   + htab->plt_ctf_frame->output_offset
+				   + PLT_CTF_FRAME_FDE_START_OFFSET;
+#if 0 /* FIXME Testing only. Remove before review.  */
+	  bfd_vma test_value = (plt_start - ctf_frame_start)
+	    + htab->plt_ctf_frame->output_section->vma
+	    + htab->plt_ctf_frame->output_offset
+	    + PLT_CTF_FRAME_FDE_START_OFFSET;
+	  bfd_put_signed_32 (dynobj, test_value,
+#endif
+	  bfd_put_signed_32 (dynobj, plt_start - ctf_frame_start,
+			     htab->plt_ctf_frame->contents
+			     + PLT_CTF_FRAME_FDE_START_OFFSET);
+	}
+      if (htab->plt_ctf_frame->sec_info_type == SEC_INFO_TYPE_CTF_FRAME)
+	{
+	  /* FIXME - contents need to be relocated for this call.  Need to
+	     reflect the relocated contents manually ?  */
+	  if (! _bfd_elf_merge_section_ctf_frame (output_bfd, info,
+						 htab->plt_ctf_frame,
+						 htab->plt_ctf_frame->contents))
+	    return NULL;
+	}
+    }
+
+  if (htab->plt_second_ctf_frame != NULL
+      && htab->plt_second_ctf_frame->contents != NULL)
+    {
+      if (htab->plt_second != NULL
+	  && htab->plt_second->size != 0
+	  && (htab->plt_second->flags & SEC_EXCLUDE) == 0
+	  && htab->plt_second->output_section != NULL
+	  && htab->plt_second_ctf_frame->output_section != NULL)
+	{
+	  bfd_vma plt_start = htab->plt_second->output_section->vma;
+	  bfd_vma ctf_frame_start
+	    = (htab->plt_second_ctf_frame->output_section->vma
+	       + htab->plt_second_ctf_frame->output_offset
+	       + PLT_CTF_FRAME_FDE_START_OFFSET);
+#if 0 /* FIXME Testing only. Remove before review.  */
+	  bfd_vma test_value = (plt_start - ctf_frame_start)
+	    + htab->plt_second_ctf_frame->output_section->vma
+	    + htab->plt_second_ctf_frame->output_offset
+	    + PLT_CTF_FRAME_FDE_START_OFFSET;
+	  bfd_put_signed_32 (dynobj, test_value,
+#endif
+	  bfd_put_signed_32 (dynobj, plt_start - ctf_frame_start,
+			     htab->plt_second_ctf_frame->contents
+			     + PLT_CTF_FRAME_FDE_START_OFFSET);
+	}
+      if (htab->plt_second_ctf_frame->sec_info_type == SEC_INFO_TYPE_CTF_FRAME)
+	{
+	  /* FIXME - contents need to be relocated for this call.  Need to
+	     reflect the relocated contents manually ?  */
+	  if (! _bfd_elf_merge_section_ctf_frame (output_bfd, info,
+						 htab->plt_second_ctf_frame,
+						 htab->plt_second_ctf_frame->contents))
+	    return NULL;
+	}
+    }
   if (htab->elf.sgot && htab->elf.sgot->size > 0)
     elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize
       = htab->got_entry_size;
@@ -3949,12 +4264,36 @@ _bfd_x86_elf_link_setup_gnu_properties
 
   pltsec = htab->elf.splt;
 
-  /* If the non-lazy PLT is available, use it for all PLT entries if
-     there are no PLT0 or no .plt section.  */
   if (htab->non_lazy_plt != NULL
       && (!htab->plt.has_plt0 || pltsec == NULL))
+    lazy_plt = false;
+  else
+    lazy_plt = true;
+
+  if (normal_target)
+    {
+      if (use_ibt_plt)
+	{
+	  if (lazy_plt)
+	    htab->ctf_frame_plt = init_table->ctf_frame_lazy_ibt_plt;
+	  else
+	    htab->ctf_frame_plt = init_table->ctf_frame_non_lazy_ibt_plt;
+	}
+      else
+	{
+	  if (lazy_plt)
+	    htab->ctf_frame_plt = init_table->ctf_frame_lazy_plt;
+	  else
+	    htab->ctf_frame_plt = init_table->ctf_frame_non_lazy_plt;
+	}
+    }
+  else
+    htab->ctf_frame_plt = NULL;
+
+  /* If the non-lazy PLT is available, use it for all PLT entries if
+     there are no PLT0 or no .plt section.  */
+  if (!lazy_plt)
     {
-      lazy_plt = false;
       if (bfd_link_pic (info))
 	htab->plt.plt_entry = htab->non_lazy_plt->pic_plt_entry;
       else
@@ -3969,7 +4308,6 @@ _bfd_x86_elf_link_setup_gnu_properties
     }
   else
     {
-      lazy_plt = true;
       if (bfd_link_pic (info))
 	{
 	  htab->plt.plt0_entry = htab->lazy_plt->pic_plt0_entry;
@@ -4145,6 +4483,39 @@ _bfd_x86_elf_link_setup_gnu_properties
 	      htab->plt_second_eh_frame = sec;
 	    }
 	}
+
+      /* .ctf_frame sections are emitted for AMD64 ABI only.  */
+      if (ABI_64_P (info->output_bfd) && !info->no_ld_generated_unwind_info)
+	{
+	  flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+			    | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+			    | SEC_LINKER_CREATED);
+
+	  sec = bfd_make_section_anyway_with_flags (dynobj,
+						    ".ctf_frame",
+						    flags);
+	  if (sec == NULL)
+	    info->callbacks->einfo (_("%F%P: failed to create PLT .ctf_frame section\n"));
+
+	  // FIXME check this
+	  // if (!bfd_set_section_alignment (sec, class_align))
+	  //  goto error_alignment;
+
+	  htab->plt_ctf_frame = sec;
+
+	  /* Second PLT is generated for Intel IBT / MPX Support + lazy plt.  */
+	  if (htab->plt_second != NULL)
+	    {
+	      sec = bfd_make_section_anyway_with_flags (dynobj,
+							".ctf_frame",
+							flags);
+	      if (sec == NULL)
+		info->callbacks->einfo (_("%F%P: failed to create second PLT .ctf_frame section\n"));
+
+	      htab->plt_second_ctf_frame = sec;
+	    }
+	  /* FIXME - add later for plt_got. */
+	}
     }
 
   /* The .iplt section is used for IFUNC symbols in static
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 7d23893938c..4ef118d8575 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -30,6 +30,7 @@
 #include "elf-linker-x86.h"
 #include "elf/i386.h"
 #include "elf/x86-64.h"
+#include "ctf-frame-api.h"
 
 #define X86_64_PCREL_TYPE_P(TYPE) \
   ((TYPE) == R_X86_64_PC8 \
@@ -105,6 +106,8 @@
    || (TYPE) == R_X86_64_PC32_BND \
    || (TYPE) == R_X86_64_PC64)
 
+#define PLT_CTF_FRAME_FDE_START_OFFSET	sizeof (ctf_frame_header)
+
 #define ABI_64_P(abfd) \
   (get_elf_backend_data (abfd)->s->elfclass == ELFCLASS64)
 
@@ -388,6 +391,24 @@ struct elf_x86_link_hash_entry
   bfd_vma tlsdesc_got;
 };
 
+#define CTF_FRAME_PLT0_MAX_NUM_FRES 2
+#define CTF_FRAME_PLTN_MAX_NUM_FRES 2
+
+struct elf_x86_ctf_frame_plt
+{
+  unsigned int plt0_entry_size;
+  unsigned int plt0_num_fres;
+  const ctf_frame_row_entry *plt0_fres[CTF_FRAME_PLT0_MAX_NUM_FRES];
+
+  unsigned int pltn_entry_size;
+  unsigned int pltn_num_fres;
+  const ctf_frame_row_entry *pltn_fres[CTF_FRAME_PLTN_MAX_NUM_FRES];
+
+  unsigned int sec_pltn_entry_size;
+  unsigned int sec_pltn_num_fres;
+  const ctf_frame_row_entry *sec_pltn_fres[CTF_FRAME_PLTN_MAX_NUM_FRES];
+};
+
 struct elf_x86_lazy_plt_layout
 {
   /* The first entry in a lazy procedure linkage table looks like this.  */
@@ -584,6 +605,11 @@ struct elf_x86_link_hash_table
   asection *plt_got;
   asection *plt_got_eh_frame;
 
+  ctf_frame_encoder_ctx *plt_cfe_ctx;
+  asection *plt_ctf_frame;
+  ctf_frame_encoder_ctx *plt_second_cfe_ctx;
+  asection *plt_second_ctf_frame;
+
   /* Parameters describing PLT generation, lazy or non-lazy.  */
   struct elf_x86_plt_layout plt;
 
@@ -593,6 +619,10 @@ struct elf_x86_link_hash_table
   /* Parameters describing non-lazy PLT generation.  */
   const struct elf_x86_non_lazy_plt_layout *non_lazy_plt;
 
+  /* The .ctf_frame helper object for .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_ctf_frame_plt *ctf_frame_plt;
+
   union
   {
     bfd_signed_vma refcount;
@@ -682,6 +712,22 @@ struct elf_x86_init_table
   /* The non-lazy PLT layout for IBT.  */
   const struct elf_x86_non_lazy_plt_layout *non_lazy_ibt_plt;
 
+  /* The .ctf_frame helper object for lazy .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_ctf_frame_plt *ctf_frame_lazy_plt;
+
+  /* The .ctf_frame helper object for non-lazy .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_ctf_frame_plt *ctf_frame_non_lazy_plt;
+
+  /* The .ctf_frame helper object for lazy IBT .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_ctf_frame_plt *ctf_frame_lazy_ibt_plt;
+
+  /* The .ctf_frame helper object for non-lazy IBT .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_ctf_frame_plt *ctf_frame_non_lazy_ibt_plt;
+
   bfd_byte plt0_pad_byte;
 
   bfd_vma (*r_info) (bfd_vma, bfd_vma);
diff --git a/bfd/section.c b/bfd/section.c
index 5a487ce6c6f..fe65a22de57 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -408,6 +408,7 @@ CODE_FRAGMENT
 .#define SEC_INFO_TYPE_JUST_SYMS 4
 .#define SEC_INFO_TYPE_TARGET    5
 .#define SEC_INFO_TYPE_EH_FRAME_ENTRY 6
+.#define SEC_INFO_TYPE_CTF_FRAME  7
 .
 .  {* Nonzero if this section uses RELA relocations, rather than REL.  *}
 .  unsigned int use_rela_p:1;
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 4a3e448e30d..f68147caea7 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -4648,6 +4648,7 @@ get_segment_type (Filedata * filedata, unsigned long p_type)
     case PT_GNU_STACK:	return "GNU_STACK";
     case PT_GNU_RELRO:  return "GNU_RELRO";
     case PT_GNU_PROPERTY: return "GNU_PROPERTY";
+    case PT_GNU_CTF_FRAME: return "GNU_CTF_FRAME";
 
     case PT_OPENBSD_RANDOMIZE: return "OPENBSD_RANDOMIZE";
     case PT_OPENBSD_WXNEEDED: return "OPENBSD_WXNEEDED";
diff --git a/include/ctf-frame-api.h b/include/ctf-frame-api.h
index 59c2abadf0e..c3a39ac0317 100644
--- a/include/ctf-frame-api.h
+++ b/include/ctf-frame-api.h
@@ -170,7 +170,7 @@ ctf_frame_encode (unsigned char ver, unsigned char flags, int abi, int *errp);
 
 /* Free the encoder context.  */
 extern void
-ctf_free_encoder (ctf_frame_encoder_ctx *encoder);
+ctf_frame_encoder_free (ctf_frame_encoder_ctx **encoder);
 
 /* Get the abi/arch info from the CTF Frame encoder context CTX.  */
 extern unsigned char
diff --git a/include/elf/common.h b/include/elf/common.h
index e4bc53e35b4..9dee53d7cd5 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -489,6 +489,7 @@
 #define PT_GNU_STACK	(PT_LOOS + 0x474e551) /* Stack flags */
 #define PT_GNU_RELRO	(PT_LOOS + 0x474e552) /* Read-only after relocation */
 #define PT_GNU_PROPERTY	(PT_LOOS + 0x474e553) /* GNU property */
+#define PT_GNU_CTF_FRAME  (PT_LOOS + 0x474e554) /* CTF Frame unwind information */
 
 /* OpenBSD segment types.  */
 #define PT_OPENBSD_RANDOMIZE (PT_LOOS + 0x5a3dbe6)  /* Fill with random data.  */
diff --git a/include/elf/internal.h b/include/elf/internal.h
index 8affb3d9b2e..0988a66679f 100644
--- a/include/elf/internal.h
+++ b/include/elf/internal.h
@@ -339,6 +339,7 @@ struct elf_segment_map
 	    || (segment)->p_type == PT_GNU_EH_FRAME			\
 	    || (segment)->p_type == PT_GNU_STACK			\
 	    || (segment)->p_type == PT_GNU_RELRO			\
+	    || (segment)->p_type == PT_GNU_CTF_FRAME			\
 	    || ((segment)->p_type >= PT_GNU_MBIND_LO			\
 		&& (segment)->p_type <= PT_GNU_MBIND_HI)))		\
    /* Any section besides one of type SHT_NOBITS must have file		\
diff --git a/ld/Makefile.am b/ld/Makefile.am
index d31021c13e2..502e754080a 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -967,6 +967,7 @@ EXTRA_ld_new_SOURCES += $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES)
 # This is the real libbfd.a and libctf.a created by libtool.
 TESTBFDLIB = @TESTBFDLIB@
 TESTCTFLIB = @TESTCTFLIB@
+TESTCTFFRAMELIB = @TESTCTFFRAMELIB@
 
 check-DEJAGNU: site.exp
 	(cd .libs; test -e ldscripts || test ! -e ld-new || $(LN_S) ../ldscripts .)
@@ -984,6 +985,7 @@ check-DEJAGNU: site.exp
 		CXX_FOR_TARGET="$(CXX_FOR_TARGET)" \
 		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
 		OFILES="$(OFILES)" BFDLIB="$(TESTBFDLIB)" CTFLIB="$(TESTCTFLIB) $(ZLIB)" \
+		CTFFRAMELIB="$(TESTCTFFRAMELIB)" \
 		LIBIBERTY="$(LIBIBERTY) $(LIBINTL)" LIBS="$(LIBS)" \
 		DO_COMPARE="`echo '$(do_compare)' | sed -e 's,\\$$,,g'`" \
 		$(RUNTESTFLAGS); \
diff --git a/ld/Makefile.in b/ld/Makefile.in
index ee0c98f65b0..65f9856aa52 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -468,6 +468,7 @@ TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@
 
 # This is the real libbfd.a and libctf.a created by libtool.
 TESTBFDLIB = @TESTBFDLIB@
+TESTCTFFRAMELIB = @TESTCTFFRAMELIB@
 TESTCTFLIB = @TESTCTFLIB@
 USE_NLS = @USE_NLS@
 VERSION = @VERSION@
@@ -2631,6 +2632,7 @@ check-DEJAGNU: site.exp
 		CXX_FOR_TARGET="$(CXX_FOR_TARGET)" \
 		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
 		OFILES="$(OFILES)" BFDLIB="$(TESTBFDLIB)" CTFLIB="$(TESTCTFLIB) $(ZLIB)" \
+		CTFFRAMELIB="$(TESTCTFFRAMELIB)" \
 		LIBIBERTY="$(LIBIBERTY) $(LIBINTL)" LIBS="$(LIBS)" \
 		DO_COMPARE="`echo '$(do_compare)' | sed -e 's,\\$$,,g'`" \
 		$(RUNTESTFLAGS); \
diff --git a/ld/configure b/ld/configure
index 1c2b64870b1..4048d006852 100755
--- a/ld/configure
+++ b/ld/configure
@@ -634,6 +634,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+TESTCTFFRAMELIB
 TESTCTFLIB
 TESTBFDLIB
 EMULATION_LIBPATH
@@ -11491,7 +11492,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11494 "configure"
+#line 11495 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11597,7 +11598,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11600 "configure"
+#line 11601 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -17331,9 +17332,11 @@ EMULATION_LIBPATH=$all_libpath
 if test x${enable_static} = xno; then
   TESTBFDLIB="-Wl,--rpath,../bfd/.libs ../bfd/.libs/libbfd.so"
   TESTCTFLIB="-Wl,--rpath,../libctf/.libs ../libctf/.libs/libctf.so"
+  TESTCTFFRAMELIB="-Wl,--rpath,../libctfframe/.libs ../libctfframe/.libs/libctfframe.so"
 else
   TESTBFDLIB="../bfd/.libs/libbfd.a"
   TESTCTFLIB="../libctf/.libs/libctf.a"
+  TESTCTFFRAMELIB="../libctfframe/.libs/libctfframe.a"
 fi
 if test "${enable_libctf}" = no; then
     TESTCTFLIB=
@@ -17341,6 +17344,7 @@ fi
 
 
 
+
 target_vendor=${target_vendor=$host_vendor}
 case "$target_vendor" in
   hp) EXTRA_SHLIB_EXTENSION=".sl" ;;
diff --git a/ld/configure.ac b/ld/configure.ac
index eb55904c090..9ac5d75d6ad 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -623,15 +623,18 @@ AC_SUBST(EMULATION_LIBPATH)
 if test x${enable_static} = xno; then
   TESTBFDLIB="-Wl,--rpath,../bfd/.libs ../bfd/.libs/libbfd.so"
   TESTCTFLIB="-Wl,--rpath,../libctf/.libs ../libctf/.libs/libctf.so"
+  TESTCTFFRAMELIB="-Wl,--rpath,../libctfframe/.libs ../libctfframe/.libs/libctfframe.so"
 else
   TESTBFDLIB="../bfd/.libs/libbfd.a"
   TESTCTFLIB="../libctf/.libs/libctf.a"
+  TESTCTFFRAMELIB="../libctfframe/.libs/libctfframe.a"
 fi
 if test "${enable_libctf}" = no; then
     TESTCTFLIB=
 fi
 AC_SUBST(TESTBFDLIB)
 AC_SUBST(TESTCTFLIB)
+AC_SUBST(TESTCTFFRAMELIB)
 
 target_vendor=${target_vendor=$host_vendor}
 case "$target_vendor" in
diff --git a/ld/ld.texi b/ld/ld.texi
index eabbec8faa9..bb349de3416 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -2828,7 +2828,9 @@ section and ELF @code{PT_GNU_EH_FRAME} segment header.
 @item --no-ld-generated-unwind-info
 Request creation of @code{.eh_frame} unwind info for linker
 generated code sections like PLT.  This option is on by default
-if linker generated unwind info is supported.
+if linker generated unwind info is supported.  This option also
+controls the generation of @code{.ctf_frame} unwind info for linker
+generated code sections like PLT.
 
 @kindex --enable-new-dtags
 @kindex --disable-new-dtags
diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
index bf2268bb0ad..d8625d911a7 100644
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -601,6 +601,7 @@ cat <<EOF
   ${OTHER_READONLY_SECTIONS}
   .eh_frame_hdr ${RELOCATING-0} : { *(.eh_frame_hdr)${RELOCATING+ *(.eh_frame_entry .eh_frame_entry.*)} }
   .eh_frame     ${RELOCATING-0} : ONLY_IF_RO { KEEP (*(.eh_frame))${RELOCATING+ *(.eh_frame.*)} }
+  .ctf_frame    ${RELOCATING-0} : ONLY_IF_RO { *(.ctf_frame)${RELOCATING+ *(.ctf_frame.*)} }
   .gcc_except_table ${RELOCATING-0} : ONLY_IF_RO { *(.gcc_except_table${RELOCATING+ .gcc_except_table.*}) }
   .gnu_extab ${RELOCATING-0} : ONLY_IF_RO { *(.gnu_extab*) }
   /* These sections are generated by the Sun/Oracle C++ compiler.  */
@@ -619,6 +620,7 @@ cat <<EOF
 
   /* Exception handling  */
   .eh_frame     ${RELOCATING-0} : ONLY_IF_RW { KEEP (*(.eh_frame))${RELOCATING+ *(.eh_frame.*)} }
+  .ctf_frame    ${RELOCATING-0} : ONLY_IF_RW { *(.ctf_frame)${RELOCATING+ *(.ctf_frame.*)} }
   .gnu_extab    ${RELOCATING-0} : ONLY_IF_RW { *(.gnu_extab) }
   .gcc_except_table ${RELOCATING-0} : ONLY_IF_RW { *(.gcc_except_table${RELOCATING+ .gcc_except_table.*}) }
   .exception_ranges ${RELOCATING-0} : ONLY_IF_RW { *(.exception_ranges${RELOCATING+*}) }
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 3c45f87151f..62a4173c627 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -444,3 +444,5 @@ run_dump_test "bti-pac-plt-2"
 run_dump_test "bti-warn"
 run_dump_test "weak-tls"
 run_dump_test "undef-tls"
+
+run_dump_test "ctf-frame-simple-1"
diff --git a/ld/testsuite/ld-aarch64/ctf-frame-bar.s b/ld/testsuite/ld-aarch64/ctf-frame-bar.s
new file mode 100644
index 00000000000..8dd50bfaa38
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/ctf-frame-bar.s
@@ -0,0 +1,7 @@
+	.cfi_startproc
+	cmp	w0, 1000
+	bgt	.L4
+	ret
+.L4:
+	b	foo
+	.cfi_endproc
diff --git a/ld/testsuite/ld-aarch64/ctf-frame-foo.s b/ld/testsuite/ld-aarch64/ctf-frame-foo.s
new file mode 100644
index 00000000000..a2780a645d6
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/ctf-frame-foo.s
@@ -0,0 +1,10 @@
+	.cfi_startproc
+	mov	w1, 26215
+	movk	w1, 0x6666, lsl 16
+	smull	x1, w0, w1
+	asr	x1, x1, 34
+	sub	w1, w1, w0, asr 31
+	add	w1, w1, w1, lsl 2
+	sub	w0, w0, w1, lsl 1
+	ret
+	.cfi_endproc
diff --git a/ld/testsuite/ld-aarch64/ctf-frame-simple-1.d b/ld/testsuite/ld-aarch64/ctf-frame-simple-1.d
new file mode 100644
index 00000000000..e545122b5a1
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/ctf-frame-simple-1.d
@@ -0,0 +1,26 @@
+#as: --gctf-frame
+#source: ctf-frame-foo.s
+#source: ctf-frame-bar.s
+#objdump: --ctf-frame=.ctf_frame
+#ld: -shared
+#name: Simple link
+
+.*:     file format .*
+
+Contents of the CTF Frame section .ctf_frame:
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: CTF_FRAME_F_FDE_SORTED
+    Num FDEs: 2
+    Num FREs: 2
+
+  Function Index :
+
+#...
+    STARTPC +CFA +FP +RA +
+    0+[0-9a-f]+ +sp\+0 +u +u +
+
+#...
+    STARTPC +CFA +FP +RA +
+    0+[0-9a-f]+ +sp\+0 +u +u +
diff --git a/ld/testsuite/ld-bootstrap/bootstrap.exp b/ld/testsuite/ld-bootstrap/bootstrap.exp
index f6d38af5d40..1b367217195 100644
--- a/ld/testsuite/ld-bootstrap/bootstrap.exp
+++ b/ld/testsuite/ld-bootstrap/bootstrap.exp
@@ -174,7 +174,7 @@ foreach flags $test_flags {
 	setup_xfail "mips*-*-irix5*"
     }
 
-    if ![ld_link $CC tmpdir/ld1 "$CFLAGS $flags tmpdir/ld-partial.o $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+    if ![ld_link $CC tmpdir/ld1 "$CFLAGS $flags tmpdir/ld-partial.o $CTFLIB $BFDLIB $LIBIBERTY $CTFFRAMELIB $extralibs"] {
 	fail $testname
 	continue
     }
@@ -191,13 +191,13 @@ foreach flags $test_flags {
     }
 
     regsub /tmpdir/ld/ $gcc_B_opt_save /tmpdir/gccld1/ gcc_B_opt
-    if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+    if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $CTFFRAMELIB $extralibs"] {
 	fail $testname
 	continue
     }
 
     regsub /tmpdir/ld/ $gcc_B_opt_save /tmpdir/gccld2/ gcc_B_opt
-    if ![ld_link $CC tmpdir/ld3 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+    if ![ld_link $CC tmpdir/ld3 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $CTFFRAMELIB $extralibs"] {
 	fail $testname
 	continue
     }
@@ -210,7 +210,7 @@ foreach flags $test_flags {
 	# generated by different linkers, tmpdir/ld1 and tmpdir/ld2.
 	# So we rebuild tmpdir/ld2 with tmpdir/ld3.
 	regsub /tmpdir/ld/ $gcc_B_opt_save /tmpdir/gccld3/ gcc_B_opt
-	if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+	if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $CTFFRAMELIB $extralibs"] {
 	    fail $testname
 	    continue
 	}
diff --git a/ld/testsuite/ld-ctf-frame/ctf-frame-empty.d b/ld/testsuite/ld-ctf-frame/ctf-frame-empty.d
new file mode 100644
index 00000000000..7aa69757b0f
--- /dev/null
+++ b/ld/testsuite/ld-ctf-frame/ctf-frame-empty.d
@@ -0,0 +1,10 @@
+#as:
+#source: ctf-frame-empty.s
+#objdump: -hw
+#ld: -shared
+#name: Empty CTF Frame section
+
+#failif
+#...
+  [0-9] .ctf_frame .*
+#...
diff --git a/ld/testsuite/ld-ctf-frame/ctf-frame-empty.s b/ld/testsuite/ld-ctf-frame/ctf-frame-empty.s
new file mode 100644
index 00000000000..659b3b9d99b
--- /dev/null
+++ b/ld/testsuite/ld-ctf-frame/ctf-frame-empty.s
@@ -0,0 +1,2 @@
+	.cfi_startproc
+	.cfi_endproc
diff --git a/ld/testsuite/ld-ctf-frame/ctf-frame.exp b/ld/testsuite/ld-ctf-frame/ctf-frame.exp
new file mode 100644
index 00000000000..93954d8d34c
--- /dev/null
+++ b/ld/testsuite/ld-ctf-frame/ctf-frame.exp
@@ -0,0 +1,47 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+if [skip_ctfframe_tests] {
+    unsupported "no CTF Frame format support in the assembler, or CTF Frame disabled"
+    return 0
+}
+
+if ![is_elf_format] {
+    unsupported "CTF Frame not supported"
+    return 0
+}
+
+if {[info exists env(LC_ALL)]} {
+    set old_lc_all $env(LC_ALL)
+}
+set env(LC_ALL) "C"
+
+set ctfframe_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
+
+foreach ctfframe_test $ctfframe_test_list {
+    verbose [file rootname $ctfframe_test]
+    run_dump_test [file rootname $ctfframe_test]
+}
+
+if {[info exists old_lc_all]} {
+    set env(LC_ALL) $old_lc_all
+} else {
+    unset env(LC_ALL)
+}
diff --git a/ld/testsuite/ld-ctf-frame/discard.d b/ld/testsuite/ld-ctf-frame/discard.d
new file mode 100644
index 00000000000..5450a2d1ef6
--- /dev/null
+++ b/ld/testsuite/ld-ctf-frame/discard.d
@@ -0,0 +1,10 @@
+#as:
+#source: discard.s
+#ld: -T discard.ld
+#objdump: -hw
+#name: Check that CTF Frame section can be discarded
+
+#failif
+#...
+  [0-9] .ctf_frame .*
+#...
diff --git a/ld/testsuite/ld-ctf-frame/discard.ld b/ld/testsuite/ld-ctf-frame/discard.ld
new file mode 100644
index 00000000000..d6b1801bf36
--- /dev/null
+++ b/ld/testsuite/ld-ctf-frame/discard.ld
@@ -0,0 +1,9 @@
+ENTRY(_start)
+SECTIONS
+{
+  . = SIZEOF_HEADERS;
+  /* Sections to be discarded */
+  /DISCARD/ : {
+	*(.ctf_frame)
+	}
+}
diff --git a/ld/testsuite/ld-ctf-frame/discard.s b/ld/testsuite/ld-ctf-frame/discard.s
new file mode 100644
index 00000000000..b3115a5a418
--- /dev/null
+++ b/ld/testsuite/ld-ctf-frame/discard.s
@@ -0,0 +1,13 @@
+	.text
+	.cfi_sections .ctf_frame
+	.globl	foo
+	.type	foo, @function
+foo:
+	.cfi_startproc
+	.cfi_def_cfa_offset 16
+	.cfi_def_cfa 7, 8
+	.cfi_endproc
+
+	.globl _start
+_start:
+	.long   foo
diff --git a/ld/testsuite/ld-x86-64/ctf-frame-bar.s b/ld/testsuite/ld-x86-64/ctf-frame-bar.s
new file mode 100644
index 00000000000..14bdbba365b
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/ctf-frame-bar.s
@@ -0,0 +1,31 @@
+	.file	"ctf-frame-bar.c"
+	.text
+	.globl	bar
+	.type	bar, @function
+bar:
+.LFB0:
+	.cfi_startproc
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset 6, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register 6
+	subq	$16, %rsp
+	movl	%edi, -4(%rbp)
+	cmpl	$1000, -4(%rbp)
+	jle	.L2
+	movl	-4(%rbp), %eax
+	movl	%eax, %edi
+	call	foo
+	jmp	.L3
+.L2:
+	movl	-4(%rbp), %eax
+.L3:
+	leave
+	.cfi_def_cfa 7, 8
+	ret
+	.cfi_endproc
+.LFE0:
+	.size	bar, .-bar
+	.ident	"GCC: (GNU) 13.0.0 20220519 (experimental)"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/ctf-frame-foo.s b/ld/testsuite/ld-x86-64/ctf-frame-foo.s
new file mode 100644
index 00000000000..6ec28eafa97
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/ctf-frame-foo.s
@@ -0,0 +1,37 @@
+	.file	"ctf-frame-foo.c"
+	.text
+	.globl	foo
+	.type	foo, @function
+foo:
+.LFB0:
+	.cfi_startproc
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset 6, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register 6
+	movl	%edi, -4(%rbp)
+	movl	-4(%rbp), %ecx
+	movslq	%ecx, %rax
+	imulq	$1717986919, %rax, %rax
+	shrq	$32, %rax
+	movl	%eax, %edx
+	sarl	$2, %edx
+	movl	%ecx, %eax
+	sarl	$31, %eax
+	subl	%eax, %edx
+	movl	%edx, %eax
+	sall	$2, %eax
+	addl	%edx, %eax
+	addl	%eax, %eax
+	subl	%eax, %ecx
+	movl	%ecx, %edx
+	movl	%edx, %eax
+	popq	%rbp
+	.cfi_def_cfa 7, 8
+	ret
+	.cfi_endproc
+.LFE0:
+	.size	foo, .-foo
+	.ident	"GCC: (GNU) 13.0.0 20220519 (experimental)"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/ctf-frame-plt-1.d b/ld/testsuite/ld-x86-64/ctf-frame-plt-1.d
new file mode 100644
index 00000000000..c8699a38b67
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/ctf-frame-plt-1.d
@@ -0,0 +1,29 @@
+#as: --gctf-frame
+#source: ctf-frame-foo.s
+#source: ctf-frame-bar.s
+#objdump: --ctf-frame=.ctf_frame
+#ld: -shared
+#name: CTF Frame for plt0 and pltN
+
+.*: +file format .*
+
+Contents of the CTF Frame section .ctf_frame:
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: CTF_FRAME_F_FDE_SORTED
+#...
+
+  Function Index :
+
+    func idx \[0\]: pc = 0x1000, size = 16 bytes
+    STARTPC +CFA +FP +RA +
+    0+1000 +sp\+16 +u +u +
+    0+1006 +sp\+24 +u +u +
+
+    func idx \[1\]: pc = 0x1010, size = 16 bytes
+    STARTPC\[m\] +CFA +FP +RA +
+    0+0000 +sp\+8 +u +u +
+    0+000b +sp\+16 +u +u +
+
+#...
diff --git a/ld/testsuite/ld-x86-64/ctf-frame-simple-1.d b/ld/testsuite/ld-x86-64/ctf-frame-simple-1.d
new file mode 100644
index 00000000000..7f363d1b6cb
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/ctf-frame-simple-1.d
@@ -0,0 +1,35 @@
+#as: --gctf-frame
+#source: ctf-frame-foo.s
+#source: ctf-frame-bar.s
+#objdump: --ctf-frame=.ctf_frame
+#ld: -shared
+#name: Simple link
+
+.*: +file format .*
+
+Contents of the CTF Frame section .ctf_frame:
+  Header :
+
+    Version: CTF_FRAME_VERSION_1
+    Flags: CTF_FRAME_F_FDE_SORTED
+#...
+
+  Function Index :
+
+#...
+
+#...
+
+    func idx \[2\]: pc = 0x1020, size = 53 bytes
+    STARTPC +CFA +FP +RA +
+    0+1020 +sp\+8 +u +u +
+    0+1021 +sp\+16 +c-16 +u +
+    0+1024 +fp\+16 +c-16 +u +
+    0+1054 +sp\+8 +c-16 +u +
+
+    func idx \[3\]: pc = 0x1055, size = 37 bytes
+    STARTPC +CFA +FP +RA +
+    0+1055 +sp\+8 +u +u +
+    0+1056 +sp\+16 +c-16 +u +
+    0+1059 +fp\+16 +c-16 +u +
+    0+1079 +sp\+8 +c-16 +u +
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index e6a834a2a61..6e9f75b3f89 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -505,6 +505,8 @@ run_dump_test "dt-relr-1a"
 run_dump_test "dt-relr-1a-x32"
 run_dump_test "dt-relr-1b"
 run_dump_test "dt-relr-1b-x32"
+run_dump_test "ctf-frame-simple-1"
+run_dump_test "ctf-frame-plt-1"
 
 if ![istarget "x86_64-*-linux*"] {
     return
diff --git a/ld/testsuite/lib/ld-lib.exp b/ld/testsuite/lib/ld-lib.exp
index ec27388a72e..56a273d2b69 100644
--- a/ld/testsuite/lib/ld-lib.exp
+++ b/ld/testsuite/lib/ld-lib.exp
@@ -1676,3 +1676,48 @@ proc skip_ctf_tests { } {
 
     return 1
 }
+
+# Check if the assembler supports CTF Frame.
+
+proc check_as_ctfframe { } {
+    global check_as_ctfframe_result
+    global as
+    if [info exists check_as_ctfframe_result] {
+	return $check_as_ctfframe_result
+    }
+
+    # CTF Frame generation needs CFI support
+    if { ![check_as_cfi] } {
+	set check_as_ctfframe_result 0;
+	return 0
+    }
+
+    set as_file "tmpdir/check_as_ctfframe.s"
+    set as_fh [open $as_file w 0666]
+    puts $as_fh "# Generated file. DO NOT EDIT"
+    puts $as_fh "\t.cfi_sections \".ctf_frame\""
+    puts $as_fh "\t.cfi_startproc"
+    puts $as_fh "\t.cfi_endproc"
+    close $as_fh
+    remote_download host $as_file
+    verbose -log "Checking CTF Frame:"
+    set success [ld_assemble $as $as_file "/dev/null"]
+    #remote_file host delete $as_file
+    set check_as_ctfframe_result $success
+    return $success
+}
+
+proc skip_ctfframe_tests { } {
+# FIXME TODO
+#    global enable_libctfframe
+#
+#    if {$enable_libctfframe eq "no"} {
+#	return 1
+#    }
+
+    if [check_as_ctfframe] {
+	return 0
+    }
+
+    return 1
+}
diff --git a/libctfframe/ctf-frame.c b/libctfframe/ctf-frame.c
index fa90547269a..273708279fc 100644
--- a/libctfframe/ctf-frame.c
+++ b/libctfframe/ctf-frame.c
@@ -1122,14 +1122,32 @@ ctf_frame_encode (unsigned char ver, unsigned char flags, int abi_arch,
 /* Free the encoder context.  */
 
 void
-ctf_free_encoder (ctf_frame_encoder_ctx *encoder)
+ctf_frame_encoder_free (ctf_frame_encoder_ctx **encoder)
 {
   if (encoder != NULL)
     {
-      free (encoder->cfe_funcdesc);
-      free (encoder->cfe_fres);
-      free (encoder->cfe_data);
-      free (encoder);
+      ctf_frame_encoder_ctx *ectx = *encoder;
+      if (ectx == NULL)
+	return;
+
+      if (ectx->cfe_funcdesc != NULL)
+	{
+	  free (ectx->cfe_funcdesc);
+	  ectx->cfe_funcdesc = NULL;
+	}
+      if (ectx->cfe_fres != NULL)
+	{
+	  free (ectx->cfe_fres);
+	  ectx->cfe_fres = NULL;
+	}
+      if (ectx->cfe_data != NULL)
+	{
+	  free (ectx->cfe_data);
+	  ectx->cfe_data = NULL;
+	}
+
+      free (*encoder);
+      *encoder = NULL;
     }
 }
 
-- 
2.37.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V6 07/10] readelf/objdump: support for CTF Frame section
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
                   ` (5 preceding siblings ...)
  2022-08-02  8:04 ` [PATCH,V6 06/10] bfd: linker: merge .ctf_frame sections Indu Bhagat
@ 2022-08-02  8:04 ` Indu Bhagat
  2022-08-15 13:11   ` Nick Clifton
  2022-08-02  8:04 ` [PATCH,V6 08/10] unwinder: generate backtrace using CTF Frame format Indu Bhagat
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-08-02  8:04 UTC (permalink / raw)
  To: binutils; +Cc: amodra, weimin.pan, Indu Bhagat

[No changes from V5, V4]

[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 4076587151c..026b8d412ef 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'},
@@ -4595,6 +4603,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);
+}
+
 \f
 static void
 dump_bfd_private_header (bfd *abfd)
@@ -5348,6 +5416,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)
@@ -5845,6 +5915,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 f68147caea7..5121fa3af9a 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;
@@ -5115,6 +5118,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,
@@ -5177,6 +5181,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}
@@ -5317,6 +5322,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, _("\
@@ -5590,6 +5597,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;
@@ -15829,6 +15840,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,
@@ -16328,6 +16369,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 07d76c75748..3a4182c19a6 100644
--- a/libctfframe/Makefile.am
+++ b/libctfframe/Makefile.am
@@ -37,7 +37,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 e6d3ee7ff3c..e1f26aecbb4 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@)
@@ -431,7 +432,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
 
@@ -544,6 +545,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@
 
@@ -575,6 +577,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.37.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V6 08/10] unwinder: generate backtrace using CTF Frame format
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
                   ` (6 preceding siblings ...)
  2022-08-02  8:04 ` [PATCH,V6 07/10] readelf/objdump: support for CTF Frame section Indu Bhagat
@ 2022-08-02  8:04 ` Indu Bhagat
  2022-08-15 13:16   ` Nick Clifton
  2022-08-02  8:04 ` [PATCH,V6 09/10] unwinder: Add CTF Frame unwinder tests Indu Bhagat
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-08-02  8:04 UTC (permalink / raw)
  To: binutils

From: Weimin Pan <weimin.pan@oracle.com>

[Changes from V5]
 - fixed a memory leak in ctf_free_cfi.
[End of changes from V5]

[No changes from V4, V3]

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

[Changes from V1]
 - buildsystem: changes have been made to build libctfbacktrace only when
   --gctf-frame support is available in the assembler.  These buildsystem
   changes are necessary because the CTF Frame based unwinder needs the CTF
   Frame unwind info for itself to work.
[End of changes from V1]

A simple unwinder based on CTF Frame format.

PS: libctfframe/configure has NOT been included in the patch.  Please
regenerate.

config/ChangeLog:

	* ctf-frame.m4: New file.

include/ChangeLog:

	* ctf-backtrace-api.h: New file.

ChangeLog:

	* libctfframe/Makefile.am: Build backtrace functionality in its
	own library.  Install libctfbacktrace conditionally.
	* libctfframe/Makefile.in: Regenerate.
	* libctfframe/aclocal.m4: Regenerate.
	* libctfframe/configure: Regenerate.  <-- [REMOVED FROM THE
	  PATCH. PLEASE REGENERATE.]
	* libctfframe/configure.ac: Check if gas supports --gctf-frame
	command line option.
	* libctfframe/ctf-backtrace-err.c: New file.
	* libctfframe/ctf-backtrace.c: New file.
	* libctfframe/ttest.c: New file.
---
 config/ctf-frame.m4                           |  16 +
 include/ctf-backtrace-api.h                   |  57 ++
 libctfframe/Makefile.am                       |  13 +-
 libctfframe/Makefile.in                       |  69 +-
 libctfframe/aclocal.m4                        |   1 +
 libctfframe/configure.ac                      |   7 +
 libctfframe/ctf-backtrace-err.c               |  46 ++
 libctfframe/ctf-backtrace.c                   | 619 ++++++++++++++++++
 libctfframe/testsuite/Makefile.in             |   1 +
 .../testsuite/libctfframe.decode/Makefile.in  |   1 +
 .../testsuite/libctfframe.encode/Makefile.in  |   1 +
 libctfframe/ttest.c                           |  78 +++
 12 files changed, 893 insertions(+), 16 deletions(-)
 create mode 100644 config/ctf-frame.m4
 create mode 100644 include/ctf-backtrace-api.h
 create mode 100644 libctfframe/ctf-backtrace-err.c
 create mode 100644 libctfframe/ctf-backtrace.c
 create mode 100644 libctfframe/ttest.c

diff --git a/config/ctf-frame.m4 b/config/ctf-frame.m4
new file mode 100644
index 00000000000..100840b805f
--- /dev/null
+++ b/config/ctf-frame.m4
@@ -0,0 +1,16 @@
+# CTF_CHECK_AS_CTF_FRAME
+# ----------------------
+# Check whether the assembler supports generation of CTF Frame
+# unwind information.
+#
+# Defines:
+# ac_cv_have_ctfframe
+
+AC_DEFUN([CTF_CHECK_AS_CTF_FRAME],[
+  ac_save_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -Wa,--gctf-frame"
+  AC_MSG_CHECKING([for as that supports --gctf-frame])
+  AC_TRY_COMPILE([], [return 0;], [ac_cv_have_ctfframe=yes], [ac_cv_have_ctfframe=no])
+  AC_MSG_RESULT($ac_cv_have_ctfframe)
+  CFLAGS="$ac_save_CFLAGS"
+])
diff --git a/include/ctf-backtrace-api.h b/include/ctf-backtrace-api.h
new file mode 100644
index 00000000000..7b3463d88a3
--- /dev/null
+++ b/include/ctf-backtrace-api.h
@@ -0,0 +1,57 @@
+/* Public API to CTF backtrace.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of xxxxxx.    (FIXME)
+
+   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/>.  */
+
+#ifndef	_CTF_BACKTRACE_API_H
+#define	_CTF_BACKTRACE_API_H
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+enum ctf_bt_errcode
+{
+  CTF_BT_OK,
+  CTF_BT_ERR_NOCTF,
+  CTF_BT_ERR_PHDR,
+  CTF_BT_ERR_ARG,
+  CTF_BT_ERR_MALLOC,
+  CTF_BT_ERR_REALLOC,
+  CTF_BT_ERR_OPEN,
+  CTF_BT_ERR_READLINK,
+  CTF_BT_ERR_LSEEK,
+  CTF_BT_ERR_READ,
+  CTF_BT_ERR_GETCONTEXT,
+  CTF_BT_ERR_DECODE,
+  CTF_BT_ERR_CFA_OFFSET,
+};
+
+/* Get the backtrace of the calling program by storing return addresses
+   in BUFFER. The SIZE argument specifies the maximum number of addresses
+   that can be stored in the buffer. Return the number of return addresses
+   collected or -1 if there is any error.  */
+extern int ctf_backtrace (void **buffer, int size, int *errp);
+
+extern const char *ctf_bt_errmsg (enum ctf_bt_errcode ecode);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _CTF_BACKTRACE_API_H */
diff --git a/libctfframe/Makefile.am b/libctfframe/Makefile.am
index 3a4182c19a6..80e382b101e 100644
--- a/libctfframe/Makefile.am
+++ b/libctfframe/Makefile.am
@@ -25,8 +25,6 @@ AUTOMAKE_OPTIONS = foreign no-texinfo.tex
 
 BASEDIR = $(srcdir)/..
 INCDIR = $(srcdir)/../include
-# include libctf for swap.h
-AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../libctf
 AM_CFLAGS = -std=gnu99 @ac_libctfframe_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@
 
 if INSTALL_LIBBFD
@@ -41,3 +39,14 @@ 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
 
+if HAVE_CTF_FRAME_AS
+  libctfbacktrace_la_SOURCES = ctf-backtrace.c ctf-backtrace-err.c
+  libctfbacktrace_la_CPPFLAGS = -I$(srcdir) -I$(srcdir)/../include
+  libctfbacktrace_la_CFLAGS = -Wa,--gctf-frame
+if INSTALL_LIBBFD
+  lib_LTLIBRARIES += libctfbacktrace.la
+  include_HEADERS += $(INCDIR)/ctf-backtrace-api.h
+else
+  noinst_LTLIBRARIES += libctfbacktrace.la
+endif
+endif
diff --git a/libctfframe/Makefile.in b/libctfframe/Makefile.in
index e1f26aecbb4..c344067d961 100644
--- a/libctfframe/Makefile.in
+++ b/libctfframe/Makefile.in
@@ -107,10 +107,14 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+@HAVE_CTF_FRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@am__append_1 = libctfbacktrace.la
+@HAVE_CTF_FRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@am__append_2 = $(INCDIR)/ctf-backtrace-api.h
+@HAVE_CTF_FRAME_AS_TRUE@@INSTALL_LIBBFD_FALSE@am__append_3 = libctfbacktrace.la
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/ctf-frame.m4 \
 	$(top_srcdir)/../config/depstand.m4 \
 	$(top_srcdir)/../config/jobserver.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
@@ -159,15 +163,29 @@ am__uninstall_files_from_dir = { \
   }
 am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
 LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
+libctfbacktrace_la_LIBADD =
+am__libctfbacktrace_la_SOURCES_DIST = ctf-backtrace.c \
+	ctf-backtrace-err.c
+@HAVE_CTF_FRAME_AS_TRUE@am_libctfbacktrace_la_OBJECTS =  \
+@HAVE_CTF_FRAME_AS_TRUE@	libctfbacktrace_la-ctf-backtrace.lo \
+@HAVE_CTF_FRAME_AS_TRUE@	libctfbacktrace_la-ctf-backtrace-err.lo
+libctfbacktrace_la_OBJECTS = $(am_libctfbacktrace_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libctfbacktrace_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(libctfbacktrace_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+@HAVE_CTF_FRAME_AS_TRUE@@INSTALL_LIBBFD_FALSE@am_libctfbacktrace_la_rpath =
+@HAVE_CTF_FRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@am_libctfbacktrace_la_rpath =  \
+@HAVE_CTF_FRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@	-rpath $(libdir)
 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@)
-am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
-am__v_lt_0 = --silent
-am__v_lt_1 = 
 @INSTALL_LIBBFD_FALSE@am_libctfframe_la_rpath =
 @INSTALL_LIBBFD_TRUE@am_libctfframe_la_rpath = -rpath $(libdir)
 AM_V_P = $(am__v_P_@AM_V@)
@@ -204,8 +222,9 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(libctfframe_la_SOURCES)
-DIST_SOURCES = $(libctfframe_la_SOURCES)
+SOURCES = $(libctfbacktrace_la_SOURCES) $(libctfframe_la_SOURCES)
+DIST_SOURCES = $(am__libctfbacktrace_la_SOURCES_DIST) \
+	$(libctfframe_la_SOURCES)
 RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
 	ctags-recursive dvi-recursive html-recursive info-recursive \
 	install-data-recursive install-dvi-recursive \
@@ -219,8 +238,8 @@ am__can_run_installinfo = \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
-am__include_HEADERS_DIST = $(INCDIR)/ctf-frame.h \
-	$(INCDIR)/ctf-frame-api.h
+am__include_HEADERS_DIST = $(INCDIR)/ctf-backtrace-api.h \
+	$(INCDIR)/ctf-frame.h $(INCDIR)/ctf-frame-api.h
 HEADERS = $(include_HEADERS)
 RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
   distclean-recursive maintainer-clean-recursive
@@ -425,17 +444,20 @@ ACLOCAL_AMFLAGS = -I .. -I ../config
 AUTOMAKE_OPTIONS = foreign no-texinfo.tex
 BASEDIR = $(srcdir)/..
 INCDIR = $(srcdir)/../include
-# include libctf for swap.h
-AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../libctf
 AM_CFLAGS = -std=gnu99 @ac_libctfframe_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@
-@INSTALL_LIBBFD_TRUE@lib_LTLIBRARIES = libctfframe.la
-@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
+@INSTALL_LIBBFD_TRUE@lib_LTLIBRARIES = libctfframe.la $(am__append_1)
+@INSTALL_LIBBFD_FALSE@include_HEADERS = $(am__append_2)
+@INSTALL_LIBBFD_TRUE@include_HEADERS = $(INCDIR)/ctf-frame.h \
+@INSTALL_LIBBFD_TRUE@	$(INCDIR)/ctf-frame-api.h $(am__append_2)
+@INSTALL_LIBBFD_FALSE@noinst_LTLIBRARIES = libctfframe.la \
+@INSTALL_LIBBFD_FALSE@	$(am__append_3)
 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
 
+@HAVE_CTF_FRAME_AS_TRUE@libctfbacktrace_la_SOURCES = ctf-backtrace.c ctf-backtrace-err.c
+@HAVE_CTF_FRAME_AS_TRUE@libctfbacktrace_la_CPPFLAGS = -I$(srcdir) -I$(srcdir)/../include
+@HAVE_CTF_FRAME_AS_TRUE@libctfbacktrace_la_CFLAGS = -Wa,--gctf-frame
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-recursive
 
@@ -536,6 +558,9 @@ clean-noinstLTLIBRARIES:
 	  rm -f $${locs}; \
 	}
 
+libctfbacktrace.la: $(libctfbacktrace_la_OBJECTS) $(libctfbacktrace_la_DEPENDENCIES) $(EXTRA_libctfbacktrace_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libctfbacktrace_la_LINK) $(am_libctfbacktrace_la_rpath) $(libctfbacktrace_la_OBJECTS) $(libctfbacktrace_la_LIBADD) $(LIBS)
+
 libctfframe.la: $(libctfframe_la_OBJECTS) $(libctfframe_la_DEPENDENCIES) $(EXTRA_libctfframe_la_DEPENDENCIES) 
 	$(AM_V_CCLD)$(LINK) $(am_libctfframe_la_rpath) $(libctfframe_la_OBJECTS) $(libctfframe_la_LIBADD) $(LIBS)
 
@@ -545,6 +570,8 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctfbacktrace_la-ctf-backtrace-err.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctfbacktrace_la-ctf-backtrace.Plo@am__quote@
 @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@
@@ -570,6 +597,20 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
+libctfbacktrace_la-ctf-backtrace.lo: ctf-backtrace.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctfbacktrace_la_CPPFLAGS) $(CPPFLAGS) $(libctfbacktrace_la_CFLAGS) $(CFLAGS) -MT libctfbacktrace_la-ctf-backtrace.lo -MD -MP -MF $(DEPDIR)/libctfbacktrace_la-ctf-backtrace.Tpo -c -o libctfbacktrace_la-ctf-backtrace.lo `test -f 'ctf-backtrace.c' || echo '$(srcdir)/'`ctf-backtrace.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libctfbacktrace_la-ctf-backtrace.Tpo $(DEPDIR)/libctfbacktrace_la-ctf-backtrace.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ctf-backtrace.c' object='libctfbacktrace_la-ctf-backtrace.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) $(libctfbacktrace_la_CPPFLAGS) $(CPPFLAGS) $(libctfbacktrace_la_CFLAGS) $(CFLAGS) -c -o libctfbacktrace_la-ctf-backtrace.lo `test -f 'ctf-backtrace.c' || echo '$(srcdir)/'`ctf-backtrace.c
+
+libctfbacktrace_la-ctf-backtrace-err.lo: ctf-backtrace-err.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctfbacktrace_la_CPPFLAGS) $(CPPFLAGS) $(libctfbacktrace_la_CFLAGS) $(CFLAGS) -MT libctfbacktrace_la-ctf-backtrace-err.lo -MD -MP -MF $(DEPDIR)/libctfbacktrace_la-ctf-backtrace-err.Tpo -c -o libctfbacktrace_la-ctf-backtrace-err.lo `test -f 'ctf-backtrace-err.c' || echo '$(srcdir)/'`ctf-backtrace-err.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libctfbacktrace_la-ctf-backtrace-err.Tpo $(DEPDIR)/libctfbacktrace_la-ctf-backtrace-err.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ctf-backtrace-err.c' object='libctfbacktrace_la-ctf-backtrace-err.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) $(libctfbacktrace_la_CPPFLAGS) $(CPPFLAGS) $(libctfbacktrace_la_CFLAGS) $(CFLAGS) -c -o libctfbacktrace_la-ctf-backtrace-err.lo `test -f 'ctf-backtrace-err.c' || echo '$(srcdir)/'`ctf-backtrace-err.c
+
 libctfframe_la-ctf-frame.lo: ctf-frame.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.lo -MD -MP -MF $(DEPDIR)/libctfframe_la-ctf-frame.Tpo -c -o libctfframe_la-ctf-frame.lo `test -f 'ctf-frame.c' || echo '$(srcdir)/'`ctf-frame.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libctfframe_la-ctf-frame.Tpo $(DEPDIR)/libctfframe_la-ctf-frame.Plo
diff --git a/libctfframe/aclocal.m4 b/libctfframe/aclocal.m4
index 3a0b3426ebc..bda656c049c 100644
--- a/libctfframe/aclocal.m4
+++ b/libctfframe/aclocal.m4
@@ -1229,6 +1229,7 @@ AC_SUBST([am__untar])
 
 m4_include([../bfd/acinclude.m4])
 m4_include([../config/acx.m4])
+m4_include([../config/ctf-frame.m4])
 m4_include([../config/depstand.m4])
 m4_include([../config/jobserver.m4])
 m4_include([../config/lead-dot.m4])
diff --git a/libctfframe/configure.ac b/libctfframe/configure.ac
index eafe7bea96a..a35bce4d142 100644
--- a/libctfframe/configure.ac
+++ b/libctfframe/configure.ac
@@ -57,6 +57,13 @@ ACX_PROG_CC_WARNING_ALMOST_PEDANTIC([-Wno-long-long])
 # corrected.
 ACX_PROG_CC_WARNINGS_ARE_ERRORS([manual])
 
+dnl The libctfbacktrace library needs to be built with CTF Frame info.
+dnl If the build assembler is not capable of generate CTF Frame then
+dnl the library is not built.
+
+CTF_CHECK_AS_CTF_FRAME
+AM_CONDITIONAL([HAVE_CTF_FRAME_AS], [test "x$ac_cv_have_ctfframe" = "xyes"])
+
 AM_MAINTAINER_MODE
 AM_INSTALL_LIBBFD
 ACX_PROG_CC_WARNING_OPTS([-Wall], [ac_libctfframe_warn_cflags])
diff --git a/libctfframe/ctf-backtrace-err.c b/libctfframe/ctf-backtrace-err.c
new file mode 100644
index 00000000000..374ceaf3266
--- /dev/null
+++ b/libctfframe/ctf-backtrace-err.c
@@ -0,0 +1,46 @@
+/* ctf-backtrace-err.c - CTF Backtrace Error table.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of libctfbacktrace.
+
+   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 "config.h"
+#include "ctf-backtrace-api.h"
+
+/* CTF backtrace error messages.  */
+static const char *const ctf_bt_errlist[] =
+{
+  "",
+  "File does not contain CTF Frame data",
+  "Iterating shared object reading error",
+  "Failed to malloc memory space",
+  "Failed to realloc memory space",
+  "Failed to open file",
+  "Failed on resolve canonical file name",
+  "Failed to reposition file offset",
+  "Failed to read from a file descriptor",
+  "Failed to get the user context",
+  "Failed to set up decode data",
+  "Illegal CFA offset"
+};
+
+/* ctf_bt_perror -Return the error message associated with the error code.  */
+
+const char *
+ctf_bt_errmsg (enum ctf_bt_errcode ecode)
+{
+  return ctf_bt_errlist[ecode];
+}
diff --git a/libctfframe/ctf-backtrace.c b/libctfframe/ctf-backtrace.c
new file mode 100644
index 00000000000..9d865d185ba
--- /dev/null
+++ b/libctfframe/ctf-backtrace.c
@@ -0,0 +1,619 @@
+/* ctf-backtrace.c - The CTF Frame unwinder.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of libctfbacktrace.
+
+   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/>.  */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "config.h"
+#include <elf.h>
+#include <link.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <execinfo.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ucontext.h>
+#include <stdarg.h>
+#include "ansidecl.h"
+#include "ctf-frame-api.h"
+#include "ctf-backtrace-api.h"
+
+#ifndef PT_CTF_FRAME
+#define PT_CTF_FRAME 0x6474e554		/* FIXME.  */
+#endif
+
+#define _cf_printflike_(string_index,first_to_check) \
+    __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
+
+static int _ctf_unwind_debug;	/* Control for printing out debug info.  */
+static int no_of_entries = 32;
+
+/* CTF decode data for the main module or a DSO.  */
+struct ctf_decode_data
+{
+  char *cdd_data;			/* CTF decode data.  */
+  int cdd_data_size;			/* CTF decode data size.  */
+  uint64_t cdd_text_vma;		/* Text segment's virtual address.  */
+  int cdd_text_size;			/* Text segment's size.  */
+  uint64_t cdd_ctf_vma;			/* CTF segment's virtual address.  */	
+  ctf_frame_decoder_ctx *cdd_ctf_ctx;	/* CTF decoder context.  */
+};
+
+/* List that holds CTF Frame info for the shared libraries.  */
+struct dso_cfi_list
+{
+  int alloced;				/* Entries allocated.  */
+  int used;				/* Entries used.  */
+  struct ctf_decode_data *entry;	/* DSO's decode data.  */
+};
+
+/* Data that's passed through ctf_frame_callback.  */
+struct ctf_unwind_info
+{
+  int cui_fd;				/* File descriptor.  */
+  struct ctf_decode_data cui_ctx;	/* The decode data.  */
+  struct dso_cfi_list cui_dsos;		/* The DSO list.  */
+};
+
+static void
+ctf_unwind_init_debug (void)
+{
+  static int inited;
+
+  if (!inited)
+    {
+      _ctf_unwind_debug = getenv ("CTF_UNWIND_DEBUG") != NULL;
+      inited = 1;
+    }
+}
+
+_cf_printflike_ (1, 2)
+static void
+debug_printf (const char *format, ...)
+{
+  if (_ctf_unwind_debug)
+    {
+      va_list args;
+
+      va_start (args, format);
+      __builtin_vprintf (format, args);
+      va_end (args);
+    }
+}
+
+/* ctf_bt_errno - Check if there is error code in ERRP.  */
+
+static int
+ctf_bt_errno (int *errp)
+{
+  if (errp == NULL)
+    return 0;
+
+  return (*errp != CTF_BT_OK);
+}
+
+/* ctf_bt_set_errno - Store the specified error code ERROR into ERRP if
+   it is non-NULL.  */
+
+static void
+ctf_bt_set_errno (int *errp, int error)
+{
+  if (errp != NULL)
+    *errp = error;
+}
+
+/* ctf_add_dso - Add .ctf_frame info in D_DATA, which is associated with
+   a dynamic shared object, to D_LIST.  */
+
+static void
+ctf_add_dso (struct dso_cfi_list *d_list,
+	     struct ctf_decode_data d_data,
+	     int *errp)
+{
+  if (d_list->alloced == 0)
+    {
+      d_list->entry = malloc (no_of_entries * sizeof (struct ctf_decode_data));
+      if (d_list->entry == NULL)
+	{
+	  ctf_bt_set_errno (errp, CTF_BT_ERR_MALLOC);
+	  return;
+	}
+      memset (d_list->entry, 0,
+	      no_of_entries * sizeof (struct ctf_decode_data));
+      d_list->alloced = no_of_entries;
+    }
+  else if (d_list->used == d_list->alloced)
+    {
+      d_list->entry = realloc (d_list->entry,
+			(d_list->alloced + no_of_entries) *
+			sizeof (struct ctf_decode_data));
+      if (d_list->entry == NULL)
+	{
+	  ctf_bt_set_errno (errp, CTF_BT_ERR_REALLOC);
+	  return;
+	}
+
+      memset (&d_list->entry[d_list->alloced], 0,
+	      no_of_entries * sizeof (struct ctf_decode_data));
+      d_list->alloced += no_of_entries;
+    }
+
+  ctf_bt_set_errno (errp, CTF_BT_OK);
+  d_list->entry[d_list->used++] = d_data;
+}
+
+/* ctf_free_cfi - Free up space allocated for .ctf_frame info for CF.  */
+
+static void
+ctf_free_cfi (struct ctf_unwind_info *cf)
+{
+  struct dso_cfi_list *d_list;
+  int i;
+
+  if (cf == NULL)
+    return;
+
+  free (cf->cui_ctx.cdd_data);
+  ctf_frame_decoder_free (&cf->cui_ctx.cdd_ctf_ctx);
+  close (cf->cui_fd);
+
+  d_list = &cf-> cui_dsos;
+  if (d_list == NULL)
+    return;
+
+  for (i = 0; i < d_list->used; ++i)
+    {
+      free (d_list->entry[i].cdd_data);
+      ctf_frame_decoder_free (&d_list->entry[i].cdd_ctf_ctx);
+    }
+
+  free (d_list->entry);
+}
+
+/* ctf_find_context - Find the decode data that contains ADDR from CF.
+   Return the pointer to the decode data or NULL.  */
+
+static struct ctf_decode_data *
+ctf_find_context (struct ctf_unwind_info *cf, uint64_t addr)
+{
+  struct dso_cfi_list *d_list;
+  int i;
+
+  if (cf == NULL)
+    return NULL;
+
+  if (cf->cui_ctx.cdd_text_vma < addr
+      && cf->cui_ctx.cdd_text_vma + cf->cui_ctx.cdd_text_size > addr)
+    return &cf->cui_ctx;
+
+  d_list = &cf->cui_dsos;
+  for (i = 0; i < cf->cui_dsos.used; ++i)
+    {
+      if (d_list->entry[i].cdd_text_vma <= addr &&
+	  d_list->entry[i].cdd_text_vma
+	  + d_list->entry[i].cdd_text_size >= addr)
+	return &d_list->entry[i];
+    }
+
+  return NULL;
+}
+
+/* ctf_valid_addr - Check if ADDR is valid in CF. The address is considered
+   invalid, with regards to CTF, if it's not in any address range of the main
+   module or any of its DSO's. Return 1 if valid, 0 otherwise.  */
+
+static int
+ctf_valid_addr (struct ctf_unwind_info *cf, uint64_t addr)
+{
+  struct ctf_decode_data *cdp;
+
+  if (cf == NULL)
+    return 0;
+
+  cdp = ctf_find_context (cf, addr);
+  return cdp ? 1 : 0;
+}
+
+/* ctf_load_ctx - Call decoder to create and set up the ctf frame info for
+   either the main module or one of the DSOs from CF, based on the input
+   RADDR argument.  Return the newly created decode context or NULL.  */
+
+static ctf_frame_decoder_ctx *
+ctf_load_ctx (struct ctf_unwind_info *cf, uint64_t raddr)
+{
+  ctf_frame_decoder_ctx *nctx;
+  struct ctf_decode_data *cdp;
+
+  if (cf == NULL)
+    return NULL;
+
+  cdp = ctf_find_context (cf, raddr);
+  if (cdp == NULL)
+    return NULL;
+
+  if (cdp->cdd_ctf_ctx == NULL)
+    {
+      int err; 
+      nctx = ctf_frame_decode (cdp->cdd_data, cdp->cdd_data_size, &err);
+      if (nctx == NULL)
+	return NULL;
+      cdp->cdd_ctf_ctx = nctx;
+      return nctx;
+    }
+
+  return NULL;
+}
+
+/* ctf_update_ctx - Check if need to do a decode context switch, based on
+   the input RADDR argument, from CF. A new decode context will be created
+   and set up if it isn't already done so. Return the new decode context in
+   CTX and vma in CFI_VMA.  */
+
+static void
+ctf_update_ctx (struct ctf_unwind_info *cf, uint64_t raddr,
+		ctf_frame_decoder_ctx **ctx, uint64_t *cfi_vma)
+{
+  ctf_frame_decoder_ctx *nctx;
+  struct ctf_decode_data *cdp;
+
+  cdp = ctf_find_context (cf, raddr);
+  if (cdp != NULL)
+    {
+      if (cdp->cdd_ctf_ctx == NULL)
+	{
+	  int err; 
+	  nctx = ctf_frame_decode (cdp->cdd_data, cdp->cdd_data_size, &err);
+	  if (nctx == NULL)
+	    {
+	      *ctx = NULL;
+	      return;
+	    }
+	  cdp->cdd_ctf_ctx = nctx;
+	}
+	*ctx = cdp->cdd_ctf_ctx;
+	*cfi_vma = cdp->cdd_ctf_vma;
+    }
+}
+
+/* get_contents - Return contents at ADDR from file descriptor FD.  */
+
+static uint64_t
+get_contents (int fd, uint64_t addr, int *errp)
+{
+  uint64_t data;
+  size_t sz;
+
+  ctf_bt_set_errno (errp, CTF_BT_OK);
+  if (lseek (fd, addr, SEEK_SET) == -1)
+    {
+      ctf_bt_set_errno (errp, CTF_BT_ERR_LSEEK);
+      return 0;
+    }
+  sz = read (fd, &data, sizeof (uint64_t));
+  if (sz != sizeof (uint64_t))
+    {
+      ctf_bt_set_errno (errp, CTF_BT_ERR_READ);
+      return 0;
+    }
+
+  return data;
+}
+
+/* ctf_fd_open - Open /proc image associated with the process id and return
+   the file descriptor.  */
+
+static int
+ctf_fd_open (int *errp)
+{
+  char filename[PATH_MAX];
+  pid_t pid;
+  int fd;
+
+  pid = getpid ();
+  snprintf (filename, sizeof filename, "/proc/%d/task/%d/mem", pid, pid);
+  if ((fd = open (filename, O_RDONLY)) == -1)
+    {
+      ctf_bt_set_errno (errp, CTF_BT_ERR_OPEN);
+      return -1;
+    }
+
+  return fd;
+}
+
+/* ctf_frame_callback - The callback from dl_iterate_phdr with header info
+   in INFO.
+   Return CTF Frame info for either the main module or a DSO in DATA.  */
+
+static int
+ctf_frame_callback (struct dl_phdr_info *info,
+		    size_t size ATTRIBUTE_UNUSED,
+		    void *data)
+{
+  struct ctf_unwind_info *cf = (struct ctf_unwind_info *) data;
+  int p_type, i, fd, ctf_err;
+  ssize_t len;
+  uint64_t text_vma = 0;
+  int text_size = 0;
+
+  if (data == NULL || info == NULL)
+    return 1;
+
+  debug_printf ("-- name: %s %14p\n", info->dlpi_name, (void *)info->dlpi_addr);
+
+  for (i = 0; i < info->dlpi_phnum; i++)
+    {
+      debug_printf("    %2d: [%14p; memsz:%7lx] flags: 0x%x; \n", i,
+		   (void *) info->dlpi_phdr[i].p_vaddr,
+		   info->dlpi_phdr[i].p_memsz,
+		   info->dlpi_phdr[i].p_flags);
+
+      p_type = info->dlpi_phdr[i].p_type;
+      if (p_type == PT_LOAD && info->dlpi_phdr[i].p_flags & PF_X)
+	{
+	  text_vma = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
+	  text_size = info->dlpi_phdr[i].p_memsz;
+	  continue;
+	}
+      if (p_type != PT_CTF_FRAME)
+	continue;
+
+      if (info->dlpi_name[0] == '\0')		/* the main module.  */
+	{
+	  fd = ctf_fd_open (&ctf_err);
+	  if (fd == -1)
+	    return 1;
+	  if (lseek (fd, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr,
+		     SEEK_SET) == -1)
+	    {
+	      ctf_bt_set_errno (&ctf_err, CTF_BT_ERR_LSEEK);
+	      return 1;
+	    }
+
+	  cf->cui_ctx.cdd_data = (char *) malloc (info->dlpi_phdr[i].p_memsz);
+	  if (cf->cui_ctx.cdd_data == NULL)
+	    {
+	      ctf_bt_set_errno (&ctf_err, CTF_BT_ERR_MALLOC);
+	      return 1;
+	    }
+
+	  len = read (fd, cf->cui_ctx.cdd_data, info->dlpi_phdr[i].p_memsz);
+	  if (len == -1 || len != (ssize_t) info->dlpi_phdr[i].p_memsz)
+	    {
+	      ctf_bt_set_errno (&ctf_err, CTF_BT_ERR_READ);
+	      return 1;
+	    }
+
+	  assert (text_vma);
+	  cf->cui_ctx.cdd_data_size = len;
+	  cf->cui_ctx.cdd_ctf_vma = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
+	  cf->cui_fd = fd;
+	  cf->cui_ctx.cdd_text_vma = text_vma;
+	  cf->cui_ctx.cdd_text_size = text_size;
+	  text_vma = 0;
+	  return 0;
+	}
+      else
+	{					/* a dynamic shared object.  */
+	  struct ctf_decode_data dt;
+	  memset (&dt, 0, sizeof (struct ctf_decode_data));
+	  assert (cf->cui_fd);
+	  if (lseek (cf->cui_fd, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr,
+		     SEEK_SET) == -1)
+	    {
+	      ctf_bt_set_errno (&ctf_err, CTF_BT_ERR_LSEEK);
+	      return 1;
+	    }
+
+	  dt.cdd_data = (char *) malloc (info->dlpi_phdr[i].p_memsz);
+	  if (dt.cdd_data == NULL)
+	    {
+	      ctf_bt_set_errno (&ctf_err, CTF_BT_ERR_MALLOC);
+	      return 1;
+	    }
+
+	  len = read (cf->cui_fd, dt.cdd_data, info->dlpi_phdr[i].p_memsz);
+	  if (len == -1 || len != (ssize_t) info->dlpi_phdr[i].p_memsz)
+	    {
+	      ctf_bt_set_errno (&ctf_err, CTF_BT_ERR_READ);
+	      return 1;
+	    }
+
+	  assert (text_vma);
+	  dt.cdd_data_size = len;
+	  dt.cdd_ctf_vma = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
+	  dt.cdd_text_vma = text_vma;
+	  dt.cdd_text_size = text_size;
+	  text_vma = 0;
+	  ctf_add_dso (&cf->cui_dsos, dt, &ctf_err);
+	  if (ctf_err != CTF_BT_OK)
+	    return 1;
+	  return 0;
+	}
+    }
+
+    return 0;
+}
+
+/* ctf_frame_unwind - Unwind the stack backtrace for CF. If successful,
+   store the return addresses in RA_LST. The RA_SIZE argument specifies
+   the maximum number of return addresses that can be stored in RA_LST
+   and contains the number of the addresses collected.  */
+
+static void
+ctf_frame_unwind (struct ctf_unwind_info *cf, void **ra_lst,
+		  int *ra_size, int *errp)
+{
+  uint64_t cfa, return_addr, ra_stack_loc, rfp_stack_loc;
+  ctf_frame_decoder_ctx *ctx;
+  int cfa_offset, rfp_offset, errnum, i, count;
+  ctf_frame_row_entry fred, *frep = &fred;
+  uint64_t pc, rfp, rsp, cfi_vma;
+  ucontext_t context, *cp = &context;
+
+  if (cf == NULL || ra_lst == NULL || ra_size == NULL)
+    {
+      ctf_bt_set_errno (errp, CTF_BT_ERR_ARG);
+      return;
+    }
+
+  /* Get the user context for its registers.  */
+  if (getcontext (cp) != 0)
+    {
+      ctf_bt_set_errno (errp, CTF_BT_ERR_GETCONTEXT);
+      return;
+    }
+  ctf_bt_set_errno (errp, CTF_BT_OK);
+
+#ifdef __x86_64__
+  pc = cp->uc_mcontext.gregs[REG_RIP];
+  rsp = cp->uc_mcontext.gregs[REG_RSP];
+  rfp = cp->uc_mcontext.gregs[REG_RBP];
+#else
+#ifdef __aarch64__
+#define UNWIND_AARCH64_X29		29	/* 64-bit frame pointer.  */
+#define UNWIND_AARCH64_X30		30	/* 64-bit link pointer.  */
+  pc = cp->uc_mcontext.pc;
+  rsp = cp->uc_mcontext.sp;
+  rfp = cp->uc_mcontext.regs[UNWIND_AARCH64_X29];
+  uint64_t ra = cp->uc_mcontext.regs[UNWIND_AARCH64_X30];
+#endif
+#endif
+
+  /* Load and set up the decoder.  */
+  ctx = ctf_load_ctx (cf, pc);
+  if (ctx == NULL)
+    {
+      ctf_bt_set_errno (errp, CTF_BT_ERR_DECODE);
+      return;
+    }
+  cfi_vma = cf->cui_ctx.cdd_ctf_vma;
+  count = *ra_size;
+
+  for (i = 0; i < count; ++i)
+    {
+      pc -= cfi_vma;
+      errnum = ctf_frame_find_fre (ctx, pc, frep);
+      if (errnum == 0)
+	{
+	  cfa_offset = ctf_frame_fre_get_cfa_offset (frep, &errnum);
+	  if (errnum == ECTF_FRAME_FREOFFSET_NOPRESENT)
+	    {
+	      ctf_bt_set_errno (errp, CTF_BT_ERR_CFA_OFFSET);
+	      return;
+	    }
+
+	  cfa = ((frep->fre_info & 0x1) == CTF_FRAME_BASE_REG_SP
+	    ? rsp : rfp) + cfa_offset;
+
+#ifdef __x86_64__
+	  /* For x86, read the return address from cfa - 8.  */
+	  ra_stack_loc = cfa - 8;
+	  return_addr = get_contents (cf->cui_fd, ra_stack_loc, errp);
+	  if (ctf_bt_errno (errp))
+	    return;
+#else
+#ifdef __aarch64__
+	  int ra_offset = ctf_frame_fre_get_ra_offset (frep, &errnum);
+	  if (errnum == 0)
+	    {
+	      ra_stack_loc = cfa + ra_offset;
+	      return_addr = get_contents (cf->cui_fd, ra_stack_loc, errp);
+	      if (ctf_bt_errno (errp))
+		return;
+	    }
+	  else
+	    return_addr = ra;
+#endif
+#endif
+
+	  /* Validate and add return address to the list.  */
+	  if (ctf_valid_addr (cf, return_addr) == 0)
+	    {
+	      i -= 1;
+	      goto find_fre_ra_err;
+	    }
+	  if (i != 0)		/* exclude self.  */
+	    ra_lst[i-1] = (void *)return_addr;
+
+	  /* Set up for the next frame.  */
+	  rfp_offset = ctf_frame_fre_get_fp_offset (frep, &errnum);
+	  if (errnum == 0)
+	    {
+	      rfp_stack_loc = cfa + rfp_offset;
+	      rfp = get_contents (cf->cui_fd, rfp_stack_loc, errp);
+	      if (ctf_bt_errno (errp))
+		return;
+	    }
+	  rsp = cfa;
+	  pc = return_addr;
+
+	  /* Check if need to update the decoder context and vma.  */
+	  ctf_update_ctx (cf, return_addr, &ctx, &cfi_vma);
+	  if (ctx == NULL)
+	    {
+	      ctf_bt_set_errno (errp, CTF_BT_ERR_DECODE);
+	      return;
+	    }
+	}
+      else
+	{
+	  i -= 1;
+	  goto find_fre_ra_err;
+	}
+    }
+
+find_fre_ra_err:
+  *ra_size = i;
+}
+
+/* ctf_backtrace - Main API that user program calls to get a backtrace.
+   The BUFFER argument provides space for the list of the return addresses
+   and the SIZE argument specifies the maximum number of addresses that
+   can be stored in the buffer.  Return the number of return addresses
+   collected or -1 if there is any error.  */
+
+int
+ctf_backtrace (void **buffer, int size, int *errp)
+{
+  struct ctf_unwind_info ctfinfo;
+
+  ctf_unwind_init_debug ();
+
+  memset (&ctfinfo, 0, sizeof (struct ctf_unwind_info));
+
+  /* find and set up the .ctf_frame sections.  */
+  (void) dl_iterate_phdr (ctf_frame_callback, (void *)&ctfinfo);
+  if (ctfinfo.cui_fd == 0)
+    {
+      ctf_bt_set_errno (errp, CTF_BT_ERR_NOCTF);
+      return -1;
+    }
+
+  /* Do the stack unwinding.  */
+  ctf_frame_unwind (&ctfinfo, buffer, &size, errp);
+  if (ctf_bt_errno (errp))
+    return -1;
+
+  ctf_free_cfi (&ctfinfo);
+
+  return size;
+}
diff --git a/libctfframe/testsuite/Makefile.in b/libctfframe/testsuite/Makefile.in
index 3a6accc9e53..ec9ba703268 100644
--- a/libctfframe/testsuite/Makefile.in
+++ b/libctfframe/testsuite/Makefile.in
@@ -91,6 +91,7 @@ subdir = testsuite
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/ctf-frame.m4 \
 	$(top_srcdir)/../config/depstand.m4 \
 	$(top_srcdir)/../config/jobserver.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
diff --git a/libctfframe/testsuite/libctfframe.decode/Makefile.in b/libctfframe/testsuite/libctfframe.decode/Makefile.in
index a34cb02191c..f8f84fc7b89 100644
--- a/libctfframe/testsuite/libctfframe.decode/Makefile.in
+++ b/libctfframe/testsuite/libctfframe.decode/Makefile.in
@@ -93,6 +93,7 @@ subdir = testsuite/libctfframe.decode
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/ctf-frame.m4 \
 	$(top_srcdir)/../config/depstand.m4 \
 	$(top_srcdir)/../config/jobserver.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
diff --git a/libctfframe/testsuite/libctfframe.encode/Makefile.in b/libctfframe/testsuite/libctfframe.encode/Makefile.in
index da8702d30c2..06b4052cb70 100644
--- a/libctfframe/testsuite/libctfframe.encode/Makefile.in
+++ b/libctfframe/testsuite/libctfframe.encode/Makefile.in
@@ -92,6 +92,7 @@ subdir = testsuite/libctfframe.encode
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/ctf-frame.m4 \
 	$(top_srcdir)/../config/depstand.m4 \
 	$(top_srcdir)/../config/jobserver.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
diff --git a/libctfframe/ttest.c b/libctfframe/ttest.c
new file mode 100644
index 00000000000..c0b8434aad5
--- /dev/null
+++ b/libctfframe/ttest.c
@@ -0,0 +1,78 @@
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "ctf-backtrace-api.h"
+
+#define BT_BUF_SIZE 100
+
+/* funclist for running "ttest.x 3".  */
+static const char *const func_list[] =
+{
+  "myfunc3",
+  "()",
+  "myfunc",
+  "myfunc",
+  "myfunc",
+  "main"
+};
+
+void
+myfunc3 (void)
+{
+    void *buffer[BT_BUF_SIZE];
+    int j, nptrs, err;
+    char **strings;
+
+    /* Call the unwinder to get an array of return addresses.  */
+    nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+    if (nptrs == -1 || nptrs != 6)
+      {
+	printf ("CTF error: %s\n", ctf_bt_errmsg (err));
+	return;
+      }
+
+    /* Get these addresses symbolically.  */
+    strings = backtrace_symbols (buffer, nptrs);
+    if (strings == NULL) {
+        perror("backtrace_symbols");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Verify the results.  */
+    for (j = 0; j < nptrs; j++)
+      if (!strstr (strings[j], func_list[j]))
+	break;
+
+    free(strings);
+
+    printf ("%s\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+static void   /* "static" means don't export the symbol... */
+myfunc2 (void)
+{
+    myfunc3 ();
+}
+
+void
+myfunc (int ncalls)
+{
+    if (ncalls > 1)
+        myfunc (ncalls - 1);
+    else
+        myfunc2 ();
+}
+
+int
+main (int argc, char *argv[])
+{
+    if (argc != 2) {
+        fprintf (stderr, "%s num-calls\n", argv[0]);
+        exit (EXIT_FAILURE);
+    }
+
+    myfunc (atoi(argv[1]));
+    exit (EXIT_SUCCESS);
+}
-- 
2.37.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V6 09/10] unwinder: Add CTF Frame unwinder tests
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
                   ` (7 preceding siblings ...)
  2022-08-02  8:04 ` [PATCH,V6 08/10] unwinder: generate backtrace using CTF Frame format Indu Bhagat
@ 2022-08-02  8:04 ` Indu Bhagat
  2022-08-15 13:27   ` Nick Clifton
  2022-08-02  8:04 ` [PATCH, V6 10/10] gdb: sim: buildsystem changes to accommodate libctfframe Indu Bhagat
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-08-02  8:04 UTC (permalink / raw)
  To: binutils

From: Weimin Pan <weimin.pan@oracle.com>

[Changes in V6]
 - fixed testcases with more precise checks on the expected number of
   frames in each backtrace.
 - Consistent use of __noinline__+__noclone__ attributes to prevent the
   functions from getting optimized away.
 - Create/delete shared objects in $objdir, instead of $srcdir, and
   changed "expect { -re" to make it run faster for the solib test.
 - Disable unwinder tests from getting run when cross builds are
   performed.
 - Cleaned up CFLAGS_FOR_TARGET when unused.
[End of changes in V6]

[Added new in V5]

Add tests for backtracing using CTF Frame sections.

PS: libctfframe/configure has NOT been included in the patch.  Please
regenerate.

ChangeLog:

	* libctfframe/Makefile.in: Regenerated.
	* libctfframe/configure: Regenerated.  <-- [REMOVED FROM THE
	  PATCH. PLEASE REGENERATE.]
	* libctfframe/configure.ac: Check for cross compilation.
	* libctfframe/testsuite/Makefile.in: Regenerated.
	* libctfframe/testsuite/config/default.exp: Load
	  ctfframe-lib.exp.
	* libctfframe/testsuite/libctfframe.decode/Makefile.in:
	  Regenerated.
	* libctfframe/testsuite/libctfframe.encode/Makefile.in:
	  Regenerated.
	* libctfframe/testsuite/lib/ctfframe-lib.exp: New file.  Add
	  procedures for handling unwinder tests.
	* libctfframe/testsuite/libctfframe.unwind/backtrace.c: New test.
	* libctfframe/testsuite/libctfframe.unwind/backtrace.lk: New test.
	* libctfframe/testsuite/libctfframe.unwind/inline-cmds.c: New test.
	* libctfframe/testsuite/libctfframe.unwind/inline-cmds.lk: New test.
	* libctfframe/testsuite/libctfframe.unwind/inline.c: New test.
	* libctfframe/testsuite/libctfframe.unwind/inline.lk: New test.
	* libctfframe/testsuite/libctfframe.unwind/solib-lib1.c: New test.
	* libctfframe/testsuite/libctfframe.unwind/solib-lib2.c: New test.
	* libctfframe/testsuite/libctfframe.unwind/solib-main.c: New test.
	* libctfframe/testsuite/libctfframe.unwind/solib-main.d: New test.
	* libctfframe/testsuite/libctfframe.unwind/solib.exp: New file.
	* libctfframe/testsuite/libctfframe.unwind/solib_lib1.h: New test.
	* libctfframe/testsuite/libctfframe.unwind/solib_lib2.h: New test.
	* libctfframe/testsuite/libctfframe.unwind/tailcall.c: New test.
	* libctfframe/testsuite/libctfframe.unwind/tailcall.lk: New test.
	* libctfframe/testsuite/libctfframe.unwind/ttest.c: New test.
	* libctfframe/testsuite/libctfframe.unwind/ttest.lk: New test.
	* libctfframe/testsuite/libctfframe.unwind/unwind.exp: New file.
---
 libctfframe/Makefile.in                       |   1 +
 libctfframe/configure.ac                      |  12 ++
 libctfframe/testsuite/Makefile.in             |   1 +
 libctfframe/testsuite/config/default.exp      |   3 +
 libctfframe/testsuite/lib/ctfframe-lib.exp    | 180 ++++++++++++++++
 .../testsuite/libctfframe.decode/Makefile.in  |   1 +
 .../testsuite/libctfframe.encode/Makefile.in  |   1 +
 .../testsuite/libctfframe.unwind/backtrace.c  | 145 +++++++++++++
 .../testsuite/libctfframe.unwind/backtrace.lk |   3 +
 .../libctfframe.unwind/inline-cmds.c          | 135 ++++++++++++
 .../libctfframe.unwind/inline-cmds.lk         |   3 +
 .../testsuite/libctfframe.unwind/inline.c     |  97 +++++++++
 .../testsuite/libctfframe.unwind/inline.lk    |   3 +
 .../testsuite/libctfframe.unwind/solib-lib1.c |   8 +
 .../testsuite/libctfframe.unwind/solib-lib2.c |  51 +++++
 .../testsuite/libctfframe.unwind/solib-main.c |  47 ++++
 .../testsuite/libctfframe.unwind/solib-main.d |   3 +
 .../testsuite/libctfframe.unwind/solib.exp    |  75 +++++++
 .../testsuite/libctfframe.unwind/solib_lib1.h |   3 +
 .../testsuite/libctfframe.unwind/solib_lib2.h |   3 +
 .../testsuite/libctfframe.unwind/tailcall.c   | 103 +++++++++
 .../testsuite/libctfframe.unwind/tailcall.lk  |   3 +
 .../testsuite/libctfframe.unwind/ttest.c      | 127 +++++++++++
 .../testsuite/libctfframe.unwind/ttest.lk     |   3 +
 .../testsuite/libctfframe.unwind/unwind.exp   | 200 ++++++++++++++++++
 25 files changed, 1211 insertions(+)
 create mode 100644 libctfframe/testsuite/lib/ctfframe-lib.exp
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/backtrace.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/backtrace.lk
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/inline-cmds.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/inline-cmds.lk
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/inline.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/inline.lk
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib-lib1.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib-lib2.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib-main.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib-main.d
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib.exp
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib_lib1.h
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/solib_lib2.h
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/tailcall.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/tailcall.lk
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/ttest.c
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/ttest.lk
 create mode 100644 libctfframe/testsuite/libctfframe.unwind/unwind.exp

diff --git a/libctfframe/Makefile.in b/libctfframe/Makefile.in
index c344067d961..c709c12de47 100644
--- a/libctfframe/Makefile.in
+++ b/libctfframe/Makefile.in
@@ -332,6 +332,7 @@ CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CROSS_COMPILE = @CROSS_COMPILE@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
diff --git a/libctfframe/configure.ac b/libctfframe/configure.ac
index a35bce4d142..e831ac7b466 100644
--- a/libctfframe/configure.ac
+++ b/libctfframe/configure.ac
@@ -57,6 +57,18 @@ ACX_PROG_CC_WARNING_ALMOST_PEDANTIC([-Wno-long-long])
 # corrected.
 ACX_PROG_CC_WARNINGS_ARE_ERRORS([manual])
 
+# Determine if we are cross compiling
+AC_CANONICAL_HOST
+is_cross_compiler=
+if test x"${host}" = x"${target}" ; then
+  is_cross_compiler=no
+else
+  is_cross_compiler=yes
+fi
+CROSS_COMPILE=$is_cross_compiler
+AC_SUBST([CROSS_COMPILE])
+
+
 dnl The libctfbacktrace library needs to be built with CTF Frame info.
 dnl If the build assembler is not capable of generate CTF Frame then
 dnl the library is not built.
diff --git a/libctfframe/testsuite/Makefile.in b/libctfframe/testsuite/Makefile.in
index ec9ba703268..70513337d72 100644
--- a/libctfframe/testsuite/Makefile.in
+++ b/libctfframe/testsuite/Makefile.in
@@ -204,6 +204,7 @@ CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CROSS_COMPILE = @CROSS_COMPILE@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
diff --git a/libctfframe/testsuite/config/default.exp b/libctfframe/testsuite/config/default.exp
index c91c01b2265..58d0e1d2cec 100644
--- a/libctfframe/testsuite/config/default.exp
+++ b/libctfframe/testsuite/config/default.exp
@@ -52,3 +52,6 @@ if {![info exists CFLAGS]} {
 if {![info exists CFLAGS_FOR_TARGET]} {
     set CFLAGS_FOR_TARGET $CFLAGS
 }
+
+# load the utility procedures
+load_lib ctfframe-lib.exp
diff --git a/libctfframe/testsuite/lib/ctfframe-lib.exp b/libctfframe/testsuite/lib/ctfframe-lib.exp
new file mode 100644
index 00000000000..bcde1f78983
--- /dev/null
+++ b/libctfframe/testsuite/lib/ctfframe-lib.exp
@@ -0,0 +1,180 @@
+# Support routines for libctfframe testsuite.
+#   Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This file 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+load_file $srcdir/../../ld/testsuite/lib/ld-lib.exp
+
+set unwind_test_file_name ""
+
+proc run_native_host_cmd { command } {
+    global link_output
+    global ld
+
+    verbose -log "$command"
+    set run_output ""
+    try {
+	set run_output [exec "sh" "-c" "$command" "2>@1"]
+	set status 0
+    } trap CHILDSTATUS {results options} {
+	set status [lindex [dict get $options -errorcode] 2]
+	set run_output $results
+    }
+    regsub "\n$" $run_output "" run_output
+    if { [lindex $status 0] != 0 && [string match "" $run_output] } then {
+	append run_output "child process exited abnormally"
+    }
+
+    if [string match "" $run_output] then {
+	return ""
+    }
+
+    verbose -log "$run_output"
+    return "$run_output"
+}
+
+# Compile and link a C source file for execution on the host.
+proc compile_link_one_host_cc { src output additional_args } {
+    global CC
+    global CFLAGS
+
+    return [run_native_host_cmd "../libtool --quiet --tag=CC --mode=link $CC $CFLAGS $src -o $output $additional_args" ]
+}
+
+proc make_unwind_parallel_path { args } {
+    global objdir
+    set joiner [list "file" "join" $objdir]
+    set joiner [concat $joiner $args]
+    return [eval $joiner]
+}
+
+proc standard_output_file {basename} {
+    global objdir subdir unwind_test_file_name
+
+    set dir [make_unwind_parallel_path outputs $subdir $unwind_test_file_name]
+    file mkdir $dir
+    return [file join $dir $basename]
+}
+
+proc standard_testfile {args} {
+    global unwind_test_file_name
+    global subdir
+    global unwind_test_file_last_vars
+
+    # Outputs.
+    global testfile binfile
+
+    set testfile $unwind_test_file_name
+    set binfile [standard_output_file ${testfile}]
+
+    if {[llength $args] == 0} {
+	set args .c
+    }
+
+    # Unset our previous output variables.
+    # This can help catch hidden bugs.
+    if {[info exists unwind_test_file_last_vars]} {
+	foreach varname $unwind_test_file_last_vars {
+	    global $varname
+	    catch {unset $varname}
+	}
+    }
+    # 'executable' is often set by tests.
+    set unwind_test_file_last_vars {executable}
+
+    set suffix ""
+    foreach arg $args {
+	set varname srcfile$suffix
+	global $varname
+
+	# Handle an extension.
+	if {$arg == ""} {
+	    set arg $testfile.c
+	} else {
+	    set first [string range $arg 0 0]
+	    if { $first == "." || $first == "-" } {
+		set arg $testfile$arg
+	    }
+	}
+
+	set $varname $arg
+	lappend unwind_test_file_last_vars $varname
+
+	if {$suffix == ""} {
+	    set suffix 2
+	} else {
+	    incr suffix
+	}
+    }
+}
+
+# Build a shared object DEST from SOURCES.
+proc unwind_compile_so {sources dest} {
+    global CFLAGS
+    set obj_options $CFLAGS
+    lappend obj_options "additional_flags=-fPIC -Wa,--gctf-frame"
+
+    set outdir [file dirname $dest]
+    set objects ""
+    foreach source $sources {
+	set sourcebase [file tail $source]
+	set object ${outdir}/${sourcebase}.o
+
+	if {[target_compile $source $object object \
+		  $obj_options] != ""} {
+	    return -1
+	}
+
+	lappend objects $object
+    }
+
+    set link_options "additional_flags=-shared"
+
+    set destbase [file tail $dest]
+    lappend link_options "additional_flags=-Wl,-soname,$destbase"
+
+    if {[target_compile "${objects}" "${dest}" executable $link_options] != ""} {
+	catch "exec rm ${objects}" status
+	return -1
+    }
+    catch "exec rm ${objects}" status
+    return ""
+}
+
+# Build a binary of TYPE from SOURCE at path DEST.
+proc unwind_compile {source dest type options} {
+    set new_options ""
+
+    foreach opt $options {
+	if {[regexp {^shlib=(.*)} $opt dummy_var shlib_name]
+	    && $type == "executable"} {
+	    lappend source "-Wl,$shlib_name"
+	} else {
+	    lappend new_options $opt
+	}
+    }
+    set options $new_options
+
+    verbose "options are $options"
+    verbose "source is $source $dest $type $options"
+
+    lappend options "additional_flags=-rdynamic -Wa,--gctf-frame ./../.libs/libctfbacktrace.a ./../.libs/libctfframe.a"
+    set result [target_compile $source $dest $type $options]
+
+    return $result
+}
diff --git a/libctfframe/testsuite/libctfframe.decode/Makefile.in b/libctfframe/testsuite/libctfframe.decode/Makefile.in
index f8f84fc7b89..dc6b2e7cb5c 100644
--- a/libctfframe/testsuite/libctfframe.decode/Makefile.in
+++ b/libctfframe/testsuite/libctfframe.decode/Makefile.in
@@ -200,6 +200,7 @@ CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CROSS_COMPILE = @CROSS_COMPILE@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
diff --git a/libctfframe/testsuite/libctfframe.encode/Makefile.in b/libctfframe/testsuite/libctfframe.encode/Makefile.in
index 06b4052cb70..b0700146fa1 100644
--- a/libctfframe/testsuite/libctfframe.encode/Makefile.in
+++ b/libctfframe/testsuite/libctfframe.encode/Makefile.in
@@ -191,6 +191,7 @@ CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CROSS_COMPILE = @CROSS_COMPILE@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
diff --git a/libctfframe/testsuite/libctfframe.unwind/backtrace.c b/libctfframe/testsuite/libctfframe.unwind/backtrace.c
new file mode 100644
index 00000000000..2411153c54c
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/backtrace.c
@@ -0,0 +1,145 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* This is a revised version of gdb/testsuite/gdb.base/backtrace.c.  */
+
+#ifdef __has_attribute
+# if !__has_attribute (noclone)
+#  define ATTRIBUTE_NOCLONE
+# endif
+#endif
+#ifndef ATTRIBUTE_NOCLONE
+# define ATTRIBUTE_NOCLONE __attribute__((noclone))
+#endif
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "ctf-backtrace-api.h"
+
+#define BT_BUF_SIZE 100
+
+/* Expected funclist.  */
+static const char *const func_list[] =
+{
+  "show_bt",
+  "baz",
+  "bar",
+  "foo",
+  "main"
+};
+
+void __attribute__((__noinline__,__noclone__))
+show_bt ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int j, nptrs, err;
+  char **strings;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs != 5)
+    {
+      printf ("CTF error: %s (%d)\n", ctf_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  /* Get these addresses symbolically.  */
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL) {
+      perror("backtrace_symbols");
+      exit(EXIT_FAILURE);
+  }
+
+  /* Verify the results.  */
+  for (j = 0; j < nptrs; j++)
+    if (!strstr (strings[j], func_list[j]))
+      break;
+
+  free(strings);
+
+  printf ("%s: backtrace test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+int __attribute__((__noinline__,__noclone__))
+baz ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("CTF error: %s (%d)\n", ctf_bt_errmsg (err), nptrs);
+      return -1;
+    }
+
+  show_bt ();
+  return 0;
+}
+
+int __attribute__((__noinline__,__noclone__))
+bar ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("CTF error: %s (%d)\n", ctf_bt_errmsg (err), nptrs);
+      return -1;
+    }
+
+  return baz ();
+}
+
+int __attribute__((__noinline__,__noclone__))
+foo ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("CTF error: %s (%d)\n", ctf_bt_errmsg (err), nptrs);
+      return -1;
+    }
+
+  return bar ();
+}
+
+int __attribute__((__noinline__,__noclone__))
+main ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("CTF error: %s (%d)\n", ctf_bt_errmsg (err), nptrs);
+      return -1;
+    }
+
+  return foo ();
+}
diff --git a/libctfframe/testsuite/libctfframe.unwind/backtrace.lk b/libctfframe/testsuite/libctfframe.unwind/backtrace.lk
new file mode 100644
index 00000000000..fdc78ebe34d
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/backtrace.lk
@@ -0,0 +1,3 @@
+# source: backtrace.c
+# link: on
+PASS: backtrace test
diff --git a/libctfframe/testsuite/libctfframe.unwind/inline-cmds.c b/libctfframe/testsuite/libctfframe.unwind/inline-cmds.c
new file mode 100644
index 00000000000..15850527a4f
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/inline-cmds.c
@@ -0,0 +1,135 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* This is only ever run if it is compiled with a new-enough GCC, but
+   we don't want the compilation to fail if compiled by some other
+   compiler.  */
+
+/* This is a revised version of gdb/testsuite/gdb.opt/inline-cmds.c.  */
+
+#ifdef __GNUC__
+#define ATTR __attribute__((always_inline))
+#else
+#define ATTR
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <execinfo.h>
+#include "ctf-backtrace-api.h"
+
+#define BT_BUF_SIZE 10
+
+int x, y;
+volatile int z = 0;
+volatile int result;
+
+void bar(void);
+void marker(void);
+void noinline(void);
+
+inline ATTR int func1(void)
+{
+  bar ();
+  return x * y;
+}
+
+inline ATTR int func2(void)
+{
+  return x * func1 ();
+}
+
+inline ATTR void func3(void)
+{
+  bar ();
+}
+
+inline ATTR void outer_inline1(void)
+{
+  noinline ();
+}
+
+inline ATTR void outer_inline2(void)
+{
+  outer_inline1 ();
+}
+
+int main (void)
+{ /* start of main */
+  int val;
+
+  x = 7;
+  y = 8;
+
+  outer_inline2 ();
+
+  return 0;
+}
+
+
+/* funclist for inline-cmds.  */
+const char *const func_list[] =
+{
+  "noinline",
+  "main"
+};
+
+void bar(void)
+{
+  x += y;
+}
+
+void marker(void)
+{
+  x += y - z;
+}
+
+inline ATTR void inlined_fn(void)
+{
+  x += y + z;
+
+  void *buffer[BT_BUF_SIZE];
+  char **strings;
+  /* Call the unwinder to get an array of return addresses.  */
+  int j, err;
+  int nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1 || nptrs != 2)
+    {
+      printf ("CTF error: %s (%d)\n", ctf_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  /* Get these addresses symbolically.  */
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL) {
+        perror("backtrace_symbols");
+        exit(EXIT_FAILURE);
+  }
+
+  /* Verify the results.  */
+  for (j = 0; j < nptrs; j++)
+    if (!strstr (strings[j], func_list[j]))
+      break;
+
+    free(strings);
+    printf ("%s: inline-cmds test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+void noinline(void)
+{
+  inlined_fn (); /* inlined */
+}
diff --git a/libctfframe/testsuite/libctfframe.unwind/inline-cmds.lk b/libctfframe/testsuite/libctfframe.unwind/inline-cmds.lk
new file mode 100644
index 00000000000..053b66bd683
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/inline-cmds.lk
@@ -0,0 +1,3 @@
+# source: inline-cmds.c
+# link: on
+PASS: inline-cmds test
diff --git a/libctfframe/testsuite/libctfframe.unwind/inline.c b/libctfframe/testsuite/libctfframe.unwind/inline.c
new file mode 100644
index 00000000000..f7054bf8a9f
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/inline.c
@@ -0,0 +1,97 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* This is a revised version of gdb/testsuite/gdb.opt/inline-bt.c.  */
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "ctf-backtrace-api.h"
+
+#define ATTR __attribute__((always_inline))
+
+#define BT_BUF_SIZE 32
+
+int x, y;
+volatile int z = 0;
+volatile int result;
+
+/* funclist.  */
+const char *const flist[] =
+{
+  "main"
+};
+
+void bar(void)
+{
+  x += y;
+}
+
+inline ATTR int func1(void)
+{
+  bar ();
+  return x * y;
+}
+
+inline ATTR int func2(void)
+{
+  void *buffer[BT_BUF_SIZE];
+  int ok = 0, nptrs, err;
+  char **strings;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("CTF error: %s\n", ctf_bt_errmsg (err));
+      return -1;
+    }
+
+  /* Get these addresses symbolically.  */
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL) {
+      perror("backtrace_symbols");
+      exit(EXIT_FAILURE);
+  }
+
+  /* Verify the results.  */
+  if (nptrs == 1 && strstr (strings[0], flist[0]))
+    ok = 1;
+
+  free(strings);
+
+  printf ("%s: unwind test\n", ok == 1 ? "PASS" : "FAIL");
+
+  return x * func1 ();
+}
+
+int main (void)
+{
+  int val;
+
+  x = 7;
+  y = 8;
+  bar ();
+
+  val = func1 ();
+  result = val;
+
+  val = func2 ();
+  result = val;
+
+  return 0;
+}
diff --git a/libctfframe/testsuite/libctfframe.unwind/inline.lk b/libctfframe/testsuite/libctfframe.unwind/inline.lk
new file mode 100644
index 00000000000..88f846b0fce
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/inline.lk
@@ -0,0 +1,3 @@
+# source: inline.c
+# link: on
+PASS: unwind test
diff --git a/libctfframe/testsuite/libctfframe.unwind/solib-lib1.c b/libctfframe/testsuite/libctfframe.unwind/solib-lib1.c
new file mode 100644
index 00000000000..f4eebf927d9
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/solib-lib1.c
@@ -0,0 +1,8 @@
+#include "solib_lib1.h"
+
+unsigned int
+adder(unsigned int a, unsigned int b, int (*call)(int))
+{
+  (void)(*call)(a+b);
+  return (a+b);
+}
diff --git a/libctfframe/testsuite/libctfframe.unwind/solib-lib2.c b/libctfframe/testsuite/libctfframe.unwind/solib-lib2.c
new file mode 100644
index 00000000000..16f1fa9f968
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/solib-lib2.c
@@ -0,0 +1,51 @@
+#include <execinfo.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ctf-backtrace-api.h"
+#include "solib_lib2.h"
+
+#define BT_BUF_SIZE 100
+
+/* funclist for running "ttest.x 3".  */
+static const char *const bt_list[] =
+{
+  "adder2",
+  "bar",
+  "adder",
+  "main"
+};
+
+unsigned int
+adder2 (unsigned int a, unsigned int b, int (*call)(int))
+{
+  void *buffer[BT_BUF_SIZE];
+  int i, nptrs, err;
+  char **strings;
+
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1 || nptrs != 4)
+    {
+/* printf ("bcktrace failed: %d %d\n", nptrs, err); */
+      printf ("CTF error: %s\n", ctf_bt_errmsg (err));
+      return(-1);
+    }
+
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL)
+    {
+       perror("backtrace_symbols");
+       return(-1);
+    }
+
+  /* Verify the results.  */
+  for (i = 0; i < nptrs; i++)
+    if (!strstr (strings[i], bt_list[i]))
+      break;
+
+  free (strings);
+
+  printf ("%s: unwind solib test\n", i == nptrs ? "PASS" : "FAIL");
+
+  (void)(*call) (a+b);
+  return (a+b);
+}
diff --git a/libctfframe/testsuite/libctfframe.unwind/solib-main.c b/libctfframe/testsuite/libctfframe.unwind/solib-main.c
new file mode 100644
index 00000000000..3b9ca175073
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/solib-main.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "ctf-backtrace-api.h"
+#include "solib_lib1.h"
+#include "solib_lib2.h"
+
+#define BT_BUF_SIZE 100
+
+int foo (int x)
+{
+  return ++x;
+}
+
+int bar (int x)
+{
+  x = adder2 (x, x+1, foo);
+
+  return ++x;
+}
+
+int main (void)
+{
+  unsigned int a = 1;
+  unsigned int b = 2;
+  unsigned int result = 0;
+
+  result = adder (a,b, bar);
+
+  return 0;
+}
diff --git a/libctfframe/testsuite/libctfframe.unwind/solib-main.d b/libctfframe/testsuite/libctfframe.unwind/solib-main.d
new file mode 100644
index 00000000000..483ded5a1e5
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/solib-main.d
@@ -0,0 +1,3 @@
+# source: solib-main.c
+# link: on
+PASS: unwind solib test
diff --git a/libctfframe/testsuite/libctfframe.unwind/solib.exp b/libctfframe/testsuite/libctfframe.unwind/solib.exp
new file mode 100644
index 00000000000..3136fdba3e7
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/solib.exp
@@ -0,0 +1,75 @@
+# Copyright 2022 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Run the test only if ctfbacktrace library exists.
+if [catch "exec ls $objdir/../.libs/libctfbacktrace.la" status] then {
+  return;
+}
+
+# Run the tests only if we are not cross compiling.
+if [string equal $CROSS_COMPILE "yes"] {
+    return;
+}
+
+set experimental ""
+
+# Shared object files.
+set libname1 "solib-lib1"
+set srcfile_lib1 ${srcdir}/${subdir}/${libname1}.c
+set binfile_lib1 ${objdir}/${libname1}.so
+set libname2 "solib-lib2"
+set srcfile_lib2 ${srcdir}/${subdir}/${libname2}.c
+set binfile_lib2 ${objdir}/${libname2}.so
+
+# Binary file.
+set testfile "solib-main"
+set srcfile ${srcdir}/${subdir}/${testfile}.c
+set binfile [standard_output_file ${testfile}]
+set bin_flags [list debug shlib=${binfile_lib1} shlib=${binfile_lib2}]
+
+if { [unwind_compile_so ${srcfile_lib1} ${binfile_lib1}] != ""
+     || [unwind_compile_so ${srcfile_lib2} ${binfile_lib2}] != ""
+     || [unwind_compile ${srcfile} ${binfile} executable $bin_flags] != "" } {
+    untested "failed to compile"
+    return -1
+}
+
+if {[info exists env(LD_LIBRARY_PATH)]} {
+    set old_ld_lib $env(LD_LIBRARY_PATH)
+}
+set env(LD_LIBRARY_PATH) "${objdir}"
+
+set solib_output "${binfile} ${binfile_lib1} ${binfile_lib2}"
+set results [run_host_cmd ${binfile} $solib_output]
+
+set f [open "tmpdir/solib.out" "w"]
+puts $f $results
+close $f
+
+if { [regexp_diff "tmpdir/solib.out" "${srcdir}/${subdir}/${testfile}.d"] } then {
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
+
+catch "exec rm ${binfile_lib1}" status
+catch "exec rm ${binfile_lib2}" status
+catch "exec rm tmpdir/solib.out" status
+
+if {[info exists old_ld_lib]} {
+    set env(LD_LIBRARY_PATH) $old_ld_lib
+} else {
+    unset env(LD_LIBRARY_PATH)
+}
diff --git a/libctfframe/testsuite/libctfframe.unwind/solib_lib1.h b/libctfframe/testsuite/libctfframe.unwind/solib_lib1.h
new file mode 100644
index 00000000000..d40eac0769c
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/solib_lib1.h
@@ -0,0 +1,3 @@
+#include<stdio.h>
+
+extern unsigned int adder(unsigned int a, unsigned int b, int (*call)(int));
diff --git a/libctfframe/testsuite/libctfframe.unwind/solib_lib2.h b/libctfframe/testsuite/libctfframe.unwind/solib_lib2.h
new file mode 100644
index 00000000000..61b72122771
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/solib_lib2.h
@@ -0,0 +1,3 @@
+#include<stdio.h>
+
+extern unsigned int adder2(unsigned int a, unsigned int b, int (*call)(int));
diff --git a/libctfframe/testsuite/libctfframe.unwind/tailcall.c b/libctfframe/testsuite/libctfframe.unwind/tailcall.c
new file mode 100644
index 00000000000..1052cb76bcf
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/tailcall.c
@@ -0,0 +1,103 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "ctf-backtrace-api.h"
+
+#ifdef __has_attribute
+# if !__has_attribute (noclone)
+#  define ATTRIBUTE_NOCLONE
+# endif
+#endif
+#ifndef ATTRIBUTE_NOCLONE
+# define ATTRIBUTE_NOCLONE __attribute__((noclone))
+#endif
+
+#define BT_BUF_SIZE 16
+
+/* funclist for running tailcall.  */
+const char *const func_list[] =
+{
+  "show_bt",
+  "dec",
+  "dec",
+  "main"
+};
+
+void show_bt ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int j, nptrs, err;
+  char **strings;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1 || nptrs != 4)
+    {
+      printf ("CTF error: %s (%d)\n", ctf_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  /* Get these addresses symbolically.  */
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL) {
+      perror("backtrace_symbols");
+      exit(EXIT_FAILURE);
+  }
+
+  /* Verify the results.  */
+  for (j = 0; j < nptrs; j++)
+    if (!strstr (strings[j], func_list[j]))
+      break;
+
+  free(strings);
+
+  printf ("%s: tailcall test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+/* An example of tail recursive function.  */
+void __attribute__((__noinline__,__noclone__))
+dec (int n)
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("CTF error: %s (%d)\n", ctf_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  if (n < 0)
+     return;
+
+  if (n == 2)
+    show_bt ();
+
+  /* The last executed statement is recursive call.  */
+  dec (n-1);
+}
+
+int
+main (void)
+{
+  dec (3);
+}
diff --git a/libctfframe/testsuite/libctfframe.unwind/tailcall.lk b/libctfframe/testsuite/libctfframe.unwind/tailcall.lk
new file mode 100644
index 00000000000..3d7ab98ddba
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/tailcall.lk
@@ -0,0 +1,3 @@
+# source: tailcall.c
+# link: on
+PASS: tailcall test
diff --git a/libctfframe/testsuite/libctfframe.unwind/ttest.c b/libctfframe/testsuite/libctfframe.unwind/ttest.c
new file mode 100644
index 00000000000..1bf3dd5d0f8
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/ttest.c
@@ -0,0 +1,127 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* This is the revised version of the example in "man backtrace".  */
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "ctf-backtrace-api.h"
+
+#ifdef __has_attribute
+# if !__has_attribute (noclone)
+#  define ATTRIBUTE_NOCLONE
+# endif
+#endif
+#ifndef ATTRIBUTE_NOCLONE
+# define ATTRIBUTE_NOCLONE __attribute__((noclone))
+#endif
+
+#define BT_BUF_SIZE 100
+
+/* funclist  */
+static const char *const func_list[] =
+{
+  "myfunc3",
+  "()",
+  "myfunc",
+  "myfunc",
+  "myfunc",
+  "main"
+};
+
+void myfunc3 (void)
+{
+  void *buffer[BT_BUF_SIZE];
+  int j, nptrs, err;
+  char **strings;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1 || nptrs != 6)
+    {
+      printf ("CTF error: %s (%d)\n", ctf_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  /* Get these addresses symbolically.  */
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL) {
+    perror("backtrace_symbols");
+    exit(EXIT_FAILURE);
+  }
+
+  /* Verify the results.  */
+  for (j = 0; j < nptrs; j++)
+    if (!strstr (strings[j], func_list[j]))
+      break;
+
+  free(strings);
+
+  printf ("%s: unwind test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+static void __attribute__((__noinline__,__noclone__))
+/* "static" means don't export the symbol.  */
+myfunc2 (void)
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("CTF error: %s (%d)\n", ctf_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  myfunc3 ();
+}
+
+void __attribute__((__noinline__,__noclone__))
+myfunc (int ncalls)
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = ctf_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("CTF error: %s (%d)\n", ctf_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  if (ncalls > 1)
+    myfunc (ncalls - 1);
+  else
+    myfunc2 ();
+}
+
+int
+main (int argc, char *argv[])
+{
+  int cnt;
+  if (argc != 2) {
+    cnt = 3;
+  }
+  else
+    cnt = atoi(argv[1]);
+  myfunc (cnt);
+  exit (EXIT_SUCCESS);
+}
diff --git a/libctfframe/testsuite/libctfframe.unwind/ttest.lk b/libctfframe/testsuite/libctfframe.unwind/ttest.lk
new file mode 100644
index 00000000000..80aa2241402
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/ttest.lk
@@ -0,0 +1,3 @@
+# source: ttest.c
+# link: on
+PASS: unwind test
diff --git a/libctfframe/testsuite/libctfframe.unwind/unwind.exp b/libctfframe/testsuite/libctfframe.unwind/unwind.exp
new file mode 100644
index 00000000000..d58a18c8852
--- /dev/null
+++ b/libctfframe/testsuite/libctfframe.unwind/unwind.exp
@@ -0,0 +1,200 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+# Run the tests only if ctfbacktrace library exists.
+
+if [catch "exec ls $objdir/../.libs/libctfbacktrace.la" status] then {
+  verbose -log "$objdir/../.libs/libctfbacktrace.la not found.";
+  verbose -log "Skipping CTF Frame unwind tests";
+  return;
+}
+
+# Run the tests only if we are not cross compiling.
+if [string equal $CROSS_COMPILE "yes"] {
+    return;
+}
+
+if {[info exists env(LC_ALL)]} {
+    set old_lc_all $env(LC_ALL)
+}
+set env(LC_ALL) "C"
+
+proc run_unwind_test { name } {
+    global CC
+    global CFLAGS
+    global copyfile env runtests srcdir subdir verbose
+
+    # Append additional flags for unwinder to work properly
+    set unwind_cflags "-Wa,--gctf-frame -rdynamic"
+
+    if ![runtest_file_p $runtests $name] then {
+	return
+    }
+
+    if [string match "*/*" $name] {
+	set file $name
+	set name [file tail $name]
+    } else {
+	set file "$srcdir/$subdir/$name"
+    }
+
+    set opt_array [slurp_options "${file}.lk"]
+    if { $opt_array == -1 } {
+	perror "error reading options from $file.lk"
+	unresolved $subdir/$name
+	return
+    }
+    set run_ld 0
+    set shared "-shared"
+    set opts(link) {}
+    set opts(link_flags) {}
+    set opts(nonshared) {}
+    set opts(unwind) {}
+    set opts(name) {}
+    set opts(source) {}
+    set opts(xfail) {}
+
+    foreach i $opt_array {
+	set opt_name [lindex $i 0]
+	set opt_val [lindex $i 1]
+	if { $opt_name == "" } {
+	    set in_extra 1
+	    continue
+	}
+	if ![info exists opts($opt_name)] {
+	    perror "unknown option $opt_name in file $file.lk"
+	    unresolved $subdir/$name
+	    return
+	}
+
+	set opts($opt_name) [concat $opts($opt_name) $opt_val]
+    }
+
+    if { [llength $opts(unwind)] == 0 } {
+	set opts(unwind) "$file.c"
+    } else {
+	set opts(unwind) "[file dirname $file]/$opts(unwind)"
+    }
+
+    if { [llength $opts(name)] == 0 } {
+	set opts(name) $opts(unwind)
+    }
+
+    if { [llength $opts(link)] != 0
+	 || [llength $opts(source)] > 1 } {
+	set run_ld 1
+    }
+
+    if { [llength $opts(nonshared)] != 0 } {
+	set shared ""
+    }
+
+    set testname $opts(name)
+    if { $opts(name) == "" } {
+	set testname "$subdir/$name"
+    }
+
+    # Compile and link the unwind program.
+    set comp_output [compile_link_one_host_cc $opts(unwind) "tmpdir/test_x" "./../.libs/libctfbacktrace.la ./../.libs/libctfframe.la"]
+
+    if { $comp_output != ""} {
+	send_log "compilation of unwind program $opts(unwind) failed with <$comp_output>"
+	perror "compilation of unwind program $opts(unwind) failed"
+	fail $testname
+	return 0
+    }
+
+    # Compile the inputs and posibly link them together.
+
+    set unwind ""
+    if { [llength $opts(source)] > 0 } {
+	set unwind ""
+	if { $run_ld } {
+	    set unwind_output "tmpdir/test_x ./../.libs/libctfbacktrace.a ./../.libs/libctfframe.a"
+	    # set unwind_output "tmpdir/out.so"
+	    # set unwind_flags "-fPIC $shared $opts(link_flags)"
+	} else {
+	    set unwind_output "tmpdir/out.o"
+	    # set unwind_flags "-fPIC -c"
+	}
+	if [board_info [target_info name] exists cflags] {
+	    append unwind_flags " [board_info [target_info name] cflags]"
+	}
+	if [board_info [target_info name] exists ldflags] {
+	    append unwind_flags " [board_info [target_info name] ldflags]"
+	}
+	set src {}
+	foreach sfile $opts(source) {
+	    if [is_remote host] {
+		lappend src [remote_download host [file join [file dirname $file] $sfile]]
+	    } else {
+		lappend src [file join [file dirname $file] $sfile]
+	    }
+	}
+
+	set comp_output [run_host_cmd "$CC" "$CFLAGS $unwind_cflags [concat $src] -o $unwind_output"]
+
+	if { $comp_output != ""} {
+	    send_log "compilation of CTF program [concat $src] failed with <$comp_output>"
+	    fail $testname
+	    return 0
+	}
+    }
+
+    # Time to setup xfailures.
+    foreach targ $opts(xfail) {
+	if [match_target $targ] {
+	    setup_xfail "*-*-*"
+	    break
+	}
+    }
+
+    # Invoke the unwind program on the outputs.
+
+    verbose -log "$srcdir"
+    set results [run_host_cmd tmpdir/test_x $unwind_output]
+
+    set f [open "tmpdir/test_x.out" "w"]
+    puts $f $results
+    close $f
+
+    if { [regexp_diff "tmpdir/test_x.out" "${file}.lk"] } then {
+	fail $testname
+	if { $verbose == 2 } then { verbose "output is [file_contents tmpdir/test_x.out]" 2 }
+	return 0
+    }
+
+    pass $testname
+    return 0
+}
+
+set ctf_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.lk]]
+
+foreach ctf_test $ctf_test_list {
+    verbose [file rootname $ctf_test]
+    verbose running unwind test on $ctf_test
+    run_unwind_test [file rootname $ctf_test]
+}
+
+if {[info exists old_lc_all]} {
+    set env(LC_ALL) $old_lc_all
+} else {
+    unset env(LC_ALL)
+}
-- 
2.37.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH, V6 10/10] gdb: sim: buildsystem changes to accommodate libctfframe
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
                   ` (8 preceding siblings ...)
  2022-08-02  8:04 ` [PATCH,V6 09/10] unwinder: Add CTF Frame unwinder tests Indu Bhagat
@ 2022-08-02  8:04 ` Indu Bhagat
  2022-08-05 14:43   ` Tom Tromey
  2022-08-15 12:18 ` [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Nick Clifton
  2022-08-15 14:25 ` Nick Clifton
  11 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-08-02  8:04 UTC (permalink / raw)
  To: binutils; +Cc: amodra, weimin.pan, Indu Bhagat

[No changes from V5, V4, V3, V2, V1]

Both gdb and sim need buildsystem fixes to now include libctfframe for a
successful build.

gdb/ChangeLog:
	* acinclude.m4: Fix GDB_AC_CHECK_BFD to include libctfframe.
	* Makefile.in: Bring in libctfframe for linking.
	* configure.ac: Check for static or shared.
	* configure: Regenerated.

sim/common/ChangeLog:
	* sim/common/Make-common.in: Bring in libctfframe.a for linking.
---
 gdb/Makefile.in           |  8 ++++++--
 gdb/acinclude.m4          |  4 ++--
 gdb/configure             | 35 +++++++++++++++++++++++++++++++----
 gdb/configure.ac          | 11 +++++++++++
 sim/common/Make-common.in |  7 +++++--
 5 files changed, 55 insertions(+), 10 deletions(-)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2598b81d205..26ed82749eb 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -161,6 +161,10 @@ LIBIBERTY = ../libiberty/libiberty.a
 LIBCTF = @LIBCTF@
 CTF_DEPS = @CTF_DEPS@
 
+# Where is the CTF frame library?  Typically in ../libctfframe.
+LIBCTFFRAME = @LIBCTFFRAME@
+CTFFRAME_DEPS = @CTFFRAME_DEPS@
+
 # Where is the BFD library?  Typically in ../bfd.
 BFD_DIR = ../bfd
 BFD = $(BFD_DIR)/libbfd.a
@@ -647,7 +651,7 @@ INTERNAL_LDFLAGS = \
 # Libraries and corresponding dependencies for compiling gdb.
 # XM_CLIBS, defined in *config files, have host-dependent libs.
 # LIBIBERTY appears twice on purpose.
-CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) \
+CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(LIBCTFFRAME) $(ZLIB) \
         $(LIBSUPPORT) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
 	$(XM_CLIBS) $(GDBTKLIBS)  $(LIBBACKTRACE_LIB) \
 	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
@@ -655,7 +659,7 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) \
 	$(WIN32LIBS) $(LIBGNU) $(LIBGNU_EXTRA_LIBS) $(LIBICONV) \
 	$(LIBMPFR) $(LIBGMP) $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
 	$(DEBUGINFOD_LIBS) $(LIBBABELTRACE_LIB)
-CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(CTF_DEPS) \
+CDEPS = $(NAT_CDEPS) $(SIM) $(CTFFRAME_DEPS) $(BFD) $(READLINE_DEPS) $(CTF_DEPS) \
 	$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) \
 	$(LIBSUPPORT)
 
diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4
index 95ff2b6f35e..f3a4ebba1be 100644
--- a/gdb/acinclude.m4
+++ b/gdb/acinclude.m4
@@ -233,9 +233,9 @@ AC_DEFUN([GDB_AC_CHECK_BFD], [
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty -L../libctfframe/.libs/ $ZLIBDIR $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
-  LIBS="-lbfd -liberty -lz $intl $LIBS"
+  LIBS="-lbfd -liberty -lz -lctfframe $intl $LIBS"
   AC_CACHE_CHECK(
     [$1],
     [$2],
diff --git a/gdb/configure b/gdb/configure
index 4b5e031bff9..773197fe6d6 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -631,6 +631,8 @@ GDB_NM_FILE
 LTLIBXXHASH
 LIBXXHASH
 HAVE_LIBXXHASH
+CTFFRAME_DEPS
+LIBCTFFRAME
 CTF_DEPS
 LIBCTF
 LTLIBBABELTRACE
@@ -936,6 +938,7 @@ with_libbabeltrace_prefix
 with_libbabeltrace_type
 with_xxhash
 enable_libctf
+enable_libctfframe
 with_libxxhash_prefix
 with_libxxhash_type
 enable_unit_tests
@@ -1612,6 +1615,7 @@ Optional Features:
   --enable-libbacktrace   use libbacktrace to write a backtrace after a fatal
                           signal.
   --enable-libctf         Handle .ctf type-info sections [default=yes]
+  --enable-libctfframe    Handle .ctf_frame sections [default=yes]
   --enable-unit-tests     Enable the inclusion of unit tests when compiling
                           GDB
 
@@ -17265,9 +17269,9 @@ WIN32LIBS="$WIN32LIBS $WIN32APILIBS"
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty -L../libctfframe/.libs/ $ZLIBDIR $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
-  LIBS="-lbfd -liberty -lz $intl $LIBS"
+  LIBS="-lbfd -liberty -lz -lctfframe $intl $LIBS"
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF support in BFD" >&5
 $as_echo_n "checking for ELF support in BFD... " >&6; }
 if ${gdb_cv_var_elf+:} false; then :
@@ -17380,9 +17384,9 @@ fi
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty -L../libctfframe/.libs/ $ZLIBDIR $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
-  LIBS="-lbfd -liberty -lz $intl $LIBS"
+  LIBS="-lbfd -liberty -lz -lctfframe $intl $LIBS"
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Mach-O support in BFD" >&5
 $as_echo_n "checking for Mach-O support in BFD... " >&6; }
 if ${gdb_cv_var_macho+:} false; then :
@@ -19347,6 +19351,29 @@ fi
 
 
 
+ # Check whether --enable-libctfframe was given.
+if test "${enable_libctfframe+set}" = set; then :
+  enableval=$enable_libctfframe;
+      case "$enableval" in
+       yes|no) ;;
+       *) as_fn_error $? "Argument to enable/disable libctfframe must be yes or no" "$LINENO" 5 ;;
+      esac
+
+else
+  enable_libctfframe=yes
+fi
+
+
+if test x${enable_static} = xno; then
+  LIBCTFFRAME="-Wl,--rpath,../libctfframe/.libs ../libctfframe/.libs/libctfframe.so"
+  CTFFRAME_DEPS="../libctfframe/.libs/libctfframe.so"
+else
+  LIBCTFFRAME="../libctfframe/.libs/libctfframe.a"
+  CTFFRAME_DEPS="$LIBCTFFRAME"
+fi
+
+
+
 # If nativefile (NAT_FILE) is not set in configure.nat, we link to an
 # empty version.
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index b681988d7a4..40f3dbb658b 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2191,6 +2191,17 @@ fi
 AC_SUBST(LIBCTF)
 AC_SUBST(CTF_DEPS)
 
+GCC_ENABLE([libctfframe], [yes], [], [Handle .ctf_frame sections])
+if test x${enable_static} = xno; then
+  LIBCTFFRAME="-Wl,--rpath,../libctfframe/.libs ../libctfframe/.libs/libctfframe.so"
+  CTFFRAME_DEPS="../libctfframe/.libs/libctfframe.so"
+else
+  LIBCTFFRAME="../libctfframe/.libs/libctfframe.a"
+  CTFFRAME_DEPS="$LIBCTFFRAME"
+fi
+AC_SUBST(LIBCTFFRAME)
+AC_SUBST(CTFFRAME_DEPS)
+
 # If nativefile (NAT_FILE) is not set in configure.nat, we link to an
 # empty version.
 
diff --git a/sim/common/Make-common.in b/sim/common/Make-common.in
index 74e5dad3049..ac974087798 100644
--- a/sim/common/Make-common.in
+++ b/sim/common/Make-common.in
@@ -222,11 +222,14 @@ SIM_HW_DEVICES = cfi core pal glue $(SIM_EXTRA_HW_DEVICES)
 ZLIB = $(zlibdir) -lz
 LIBIBERTY_LIB = ../../libiberty/libiberty.a
 BFD_LIB = ../../bfd/libbfd.a
+LIBCTFFRAME_LIB = ../../libctfframe/.libs/libctfframe.a
 OPCODES_LIB = ../../opcodes/libopcodes.a
 CONFIG_LIBS = $(COMMON_LIBS) @LIBS@ $(ZLIB)
-LIBDEPS = $(BFD_LIB) $(OPCODES_LIB) $(LIBINTL_DEP) $(LIBIBERTY_LIB)
+LIBDEPS = $(BFD_LIB) $(OPCODES_LIB) $(LIBINTL_DEP) $(LIBIBERTY_LIB) \
+	  $(LIBCTFFRAME_LIB)
 EXTRA_LIBS = $(BFD_LIB) $(OPCODES_LIB) $(LIBINTL) $(LIBIBERTY_LIB) \
-	$(CONFIG_LIBS) $(SIM_EXTRA_LIBS) $(LIBDL) $(LIBGNU) $(LIBGNU_EXTRA_LIBS)
+	     $(LIBCTFFRAME_LIB) $(CONFIG_LIBS) $(SIM_EXTRA_LIBS) \
+	     $(LIBDL) $(LIBGNU) $(LIBGNU_EXTRA_LIBS)
 
 COMMON_OBJS_NAMES = \
 	callback.o \
-- 
2.37.1


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH, V6 10/10] gdb: sim: buildsystem changes to accommodate libctfframe
  2022-08-02  8:04 ` [PATCH, V6 10/10] gdb: sim: buildsystem changes to accommodate libctfframe Indu Bhagat
@ 2022-08-05 14:43   ` Tom Tromey
  0 siblings, 0 replies; 51+ messages in thread
From: Tom Tromey @ 2022-08-05 14:43 UTC (permalink / raw)
  To: Indu Bhagat via Binutils; +Cc: Indu Bhagat

>>>>> "Indu" == Indu Bhagat via Binutils <binutils@sourceware.org> writes:

Indu> [No changes from V5, V4, V3, V2, V1]
Indu> Both gdb and sim need buildsystem fixes to now include libctfframe for a
Indu> successful build.

Indu> gdb/ChangeLog:
Indu> 	* acinclude.m4: Fix GDB_AC_CHECK_BFD to include libctfframe.
Indu> 	* Makefile.in: Bring in libctfframe for linking.
Indu> 	* configure.ac: Check for static or shared.
Indu> 	* configure: Regenerated.

gdb does not use ChangeLogs, so you can drop this bit.

Otherwise the gdb changes look fine to me.

Tom

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 01/10] ctf-frame.h: Add CTF Frame format definition
  2022-08-02  8:04 ` [PATCH,V6 01/10] ctf-frame.h: Add CTF Frame format definition Indu Bhagat
@ 2022-08-15 12:04   ` Nick Clifton
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Clifton @ 2022-08-15 12:04 UTC (permalink / raw)
  To: Indu Bhagat, binutils

Hi Indu,

   [Sorry for the delay in reviewing these patches].

> +  uint8_t ctfp_flags;	/* Flags.  */
> +} __attribute__ ((packed)) ctf_frame_preamble;

I would suggest using the ATTRIBUTE_PACKED define here (from ansidecl.h)
so that the header can be compiled with non-gcc compilers if necessary.
(And likewise for the other uses of __attribute__((packed)) in ctf-frame.h).

Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 02/10] gas: add new command line option --gctf-frame
  2022-08-02  8:04 ` [PATCH,V6 02/10] gas: add new command line option --gctf-frame Indu Bhagat
@ 2022-08-15 12:07   ` Nick Clifton
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Clifton @ 2022-08-15 12:07 UTC (permalink / raw)
  To: Indu Bhagat, binutils

Hi Indu,

   This patch looks fine to me.  No revisions requested.

Cheers
   Nick



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 00/10] Definition and Implementation of CTF Frame format
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
                   ` (9 preceding siblings ...)
  2022-08-02  8:04 ` [PATCH, V6 10/10] gdb: sim: buildsystem changes to accommodate libctfframe Indu Bhagat
@ 2022-08-15 12:18 ` Nick Clifton
  2022-08-18  1:38   ` Indu Bhagat
  2022-08-15 14:25 ` Nick Clifton
  11 siblings, 1 reply; 51+ messages in thread
From: Nick Clifton @ 2022-08-15 12:18 UTC (permalink / raw)
  To: Indu Bhagat, binutils

Hi Indu,

   One thing that occurs to me - is the CTF Frame format documented
   somewhere ?  There are some comments about it in ctf-frame.h but
   a proper description in a publicly accessible place would be good.

   If there is a description, then including a URL for it in one of
   the new header files would be a good idea.

Cheers
  Nick



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 03/10] gas: generate .ctf_frame
  2022-08-02  8:04 ` [PATCH,V6 03/10] gas: generate .ctf_frame Indu Bhagat
@ 2022-08-15 12:22   ` Nick Clifton
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Clifton @ 2022-08-15 12:22 UTC (permalink / raw)
  To: Indu Bhagat, binutils

Hi Indu,

> +bool
> +aarch64_support_ctf_frame_p (void)
> +{
> +  if (aarch64_abi == AARCH64_ABI_LP64)
> +    return 1;
> +  return 0;
> +}

Given that this is a bool function, it really ought to return
a bool value.  Either that or just return the equality:

   return (aarch64_abi == AARCh64_ABI_LP64);


> +bool
> +aarch64_ctf_frame_ra_tracking_p (void)
> +{
> +  return 1;
> +}

Likewise:
   return true;


One other thing that I found was that with this patch applied (and
the 01 and 02 patches) but no others, there were several new failures
in the gas testsuite.  This is not really an issue as the problem is
obviously that objdump has not yet been patched to support the --ctf-frame
option.  But it does mean that I cannot perform incremental testing.
ie apply one patch, build, test, apply the next patch, and so on.

Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 04/10] libctfframe: add the CTF Frame library
  2022-08-02  8:04 ` [PATCH,V6 04/10] libctfframe: add the CTF Frame library Indu Bhagat
@ 2022-08-15 12:46   ` Nick Clifton
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Clifton @ 2022-08-15 12:46 UTC (permalink / raw)
  To: Indu Bhagat, binutils

Hi Indu,

I had a strange problem with this patch.  When I tried to apply it by hand
using the "patch" program I received these error messages:

   File libctfframe/testsuite/libctfframe.decode/DATA1: git binary diffs are not supported.
   File libctfframe/testsuite/libctfframe.decode/DATA2: git binary diffs are not supported.
   File libctfframe/testsuite/libctfframe.decode/DATA_BIGE: git binary diffs are not supported.

When I tried to apply it by saving the whole email and using "git apply" I
received:

   error: corrupt patch at line 362

(I think that this is due to a bug in thunderbird which is causing it to
wrap lines when it saves them to files).

Using "git am" did work, although it complained about lots of whitespace
errors.  I am not a fan of git am however as I do not like the fact that
it commits the patch before I have had a chance to review it.  But I can
work around this, so on with the review.

> diff --git a/libctfframe/Makefile.am b/libctfframe/Makefile.am

When you add a new top-level directory like libctfframe you need to update
the src-release.sh file as well.  In particular line 96 contains a list of
the top level directories that will be included in a release, and so you
will want to add your directory there.

In addition it would be nice to include an entry in the binutils/NEWS and/or
gas/NEWS files mentioning the new feature of the binutils.

Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 05/10] libctfframe: add GNU poke pickles for CTF Frame
  2022-08-02  8:04 ` [PATCH,V6 05/10] libctfframe: add GNU poke pickles for CTF Frame Indu Bhagat
@ 2022-08-15 12:50   ` Nick Clifton
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Clifton @ 2022-08-15 12:50 UTC (permalink / raw)
  To: Indu Bhagat, binutils

Hi Indu,

> If you want to use these pickles in GNU poke, following is one way to
> use the pickles.

Nothing to say on this patch really.  I assume that it works,
but being unfamiliar with GNU poke, I do not really know how
to test it.

Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 06/10] bfd: linker: merge .ctf_frame sections
  2022-08-02  8:04 ` [PATCH,V6 06/10] bfd: linker: merge .ctf_frame sections Indu Bhagat
@ 2022-08-15 13:02   ` Nick Clifton
  2022-08-18  2:11     ` Indu Bhagat
  0 siblings, 1 reply; 51+ messages in thread
From: Nick Clifton @ 2022-08-15 13:02 UTC (permalink / raw)
  To: Indu Bhagat, binutils

Hi Indu,


> +ctf_frame_decoder_mark_func_deleted (struct ctf_frame_dec_info *cfd_info,
> +				     unsigned int func_idx)
> +{
> +  BFD_ASSERT (func_idx < cfd_info->cfd_fde_count);
> +  cfd_info->cfd_func_bfdinfo[func_idx].func_deleted_p = true;

Just for the record, I am not a fan of assertions inside library functions.
I believe that libraries should let their users decide what to do when there
is a problem, rather than unilaterally calling abort.  (The better approach
in my opinion is to return an informative error message to the caller).

That said there are plenty of other places in the BFD library where assertions
are used, so I am not going to complain about this.  I just wanted to make
sure that you knew of my feelings on this issue.



> +/* Try to parse .ctf_frame section SEC, which belongs to ABFD.  Store the
> +   information in the section's sec_info field on success.  COOKIE
> +   describes the relocations in SEC.  */
> +
> +void
> +_bfd_elf_parse_ctf_frame (bfd *abfd, struct bfd_link_info *info,
> +			  asection *sec, struct elf_reloc_cookie *cookie)

It seems to me that this function really ought to return a bool,
indicating success or failure.


> +  /* Read the ctf frame unwind information from abfd.  */
> +  if (!bfd_malloc_and_get_section (abfd, sec, &ctfbuf))
> +    goto fail_no_free;

The name of this label seems rather ironic, given that ...

> +fail_no_free:
> +  _bfd_error_handler
> +   (_("error in %pB(%pA); no .ctf_frame will be created"),
> +    abfd, sec);
> +success:
> +  free (ctfbuf);

... it falls through into the free().


Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 07/10] readelf/objdump: support for CTF Frame section
  2022-08-02  8:04 ` [PATCH,V6 07/10] readelf/objdump: support for CTF Frame section Indu Bhagat
@ 2022-08-15 13:11   ` Nick Clifton
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Clifton @ 2022-08-15 13:11 UTC (permalink / raw)
  To: Indu Bhagat, binutils

Hi Indu,

> +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;

Typo - you probably wanted to "return NULL" here....

Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 08/10] unwinder: generate backtrace using CTF Frame format
  2022-08-02  8:04 ` [PATCH,V6 08/10] unwinder: generate backtrace using CTF Frame format Indu Bhagat
@ 2022-08-15 13:16   ` Nick Clifton
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Clifton @ 2022-08-15 13:16 UTC (permalink / raw)
  To: Indu Bhagat, binutils

Hi Indu,

   This patch looks good to me - nothing to comment on.

Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 09/10] unwinder: Add CTF Frame unwinder tests
  2022-08-02  8:04 ` [PATCH,V6 09/10] unwinder: Add CTF Frame unwinder tests Indu Bhagat
@ 2022-08-15 13:27   ` Nick Clifton
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Clifton @ 2022-08-15 13:27 UTC (permalink / raw)
  To: Indu Bhagat, binutils

Hi Indu,

   No problems with this patch either.

Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 00/10] Definition and Implementation of CTF Frame format
  2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
                   ` (10 preceding siblings ...)
  2022-08-15 12:18 ` [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Nick Clifton
@ 2022-08-15 14:25 ` Nick Clifton
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
  11 siblings, 1 reply; 51+ messages in thread
From: Nick Clifton @ 2022-08-15 14:25 UTC (permalink / raw)
  To: Indu Bhagat, binutils

Hi Indu,

   Right - with all of the patches applied I am seeing a build problem
   for 32-bit x86 targets:

bfd/elfxx-x86.c: In function '_bfd_x86_elf_write_ctf_frame_plt':
bfd/elfxx-x86.c:1954:51: error: passing argument 2 of 'ctf_frame_write_encoder' from incompatible pointer type [-Werror=incompatible-pointer-types]
  1954 |   void *contents = ctf_frame_write_encoder (ectx, &sec_size, &err);
       |                                                   ^~~~~~~~~
       |                                                   |
       |                                                   bfd_size_type * {aka long unsigned int *}
In file included from bfd/elfxx-x86.h:33,
                  from bfd/elfxx-x86.c:21:
include/ctf-frame-api.h:207:34: note: expected 'size_t *' {aka 'unsigned int *'} but argument is of type 'bfd_size_type *' {aka 'long unsigned int *'}
   207 |                          size_t *encoded_size, int *errp);
       |                          ~~~~~~~~^~~~~~~~~~~~

And later on:

bfd/elf-ctf-frame.c: In function '_bfd_elf_write_section_ctf_frame':
bfd/elf-ctf-frame.c:511:48: error: passing argument 2 of 'ctf_frame_write_encoder' from incompatible pointer type [-Werror=incompatible-pointer-types]
   511 |   contents = ctf_frame_write_encoder (cfe_ctx, &sec_size, &err);
       |                                                ^~~~~~~~~
       |                                                |
       |                                                bfd_size_type * {aka long unsigned int *}
In file included from bfd/elf-ctf-frame.c:25:
include/ctf-frame-api.h:207:34: note: expected 'size_t *' {aka 'unsigned int *'} but argument is of type 'bfd_size_type *' {aka 'long unsigned int *'}
   207 |                          size_t *encoded_size, int *errp);
       |                          ~~~~~~~~^~~~~~~~~~~~

   This is for a target configured as --target=i686-pc-linux-gnu.

Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 00/10] Definition and Implementation of CTF Frame format
  2022-08-15 12:18 ` [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Nick Clifton
@ 2022-08-18  1:38   ` Indu Bhagat
  0 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-08-18  1:38 UTC (permalink / raw)
  To: Nick Clifton, binutils


On 8/15/22 05:18, Nick Clifton wrote:
> Hi Indu,
>
>   One thing that occurs to me - is the CTF Frame format documented
>   somewhere ?  There are some comments about it in ctf-frame.h but
>   a proper description in a publicly accessible place would be good.
>
>   If there is a description, then including a URL for it in one of
>   the new header files would be a good idea.
>
> Cheers
>  Nick
>
>

Hi Nick,

There is no other description except the ctf-frame.h header file at the 
moment. I will work on this.

Indu


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V6 06/10] bfd: linker: merge .ctf_frame sections
  2022-08-15 13:02   ` Nick Clifton
@ 2022-08-18  2:11     ` Indu Bhagat
  0 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-08-18  2:11 UTC (permalink / raw)
  To: Nick Clifton, binutils


On 8/15/22 06:02, Nick Clifton wrote:
> Hi Indu,
>
>
>> +ctf_frame_decoder_mark_func_deleted (struct ctf_frame_dec_info 
>> *cfd_info,
>> +                     unsigned int func_idx)
>> +{
>> +  BFD_ASSERT (func_idx < cfd_info->cfd_fde_count);
>> +  cfd_info->cfd_func_bfdinfo[func_idx].func_deleted_p = true;
>
> Just for the record, I am not a fan of assertions inside library 
> functions.
> I believe that libraries should let their users decide what to do when 
> there
> is a problem, rather than unilaterally calling abort.  (The better 
> approach
> in my opinion is to return an informative error message to the caller).
>
> That said there are plenty of other places in the BFD library where 
> assertions
> are used, so I am not going to complain about this.  I just wanted to 
> make
> sure that you knew of my feelings on this issue.
>
>

Noted.  I will work out something here.


>
>> +/* Try to parse .ctf_frame section SEC, which belongs to ABFD.  
>> Store the
>> +   information in the section's sec_info field on success. COOKIE
>> +   describes the relocations in SEC.  */
>> +
>> +void
>> +_bfd_elf_parse_ctf_frame (bfd *abfd, struct bfd_link_info *info,
>> +              asection *sec, struct elf_reloc_cookie *cookie)
>
> It seems to me that this function really ought to return a bool,
> indicating success or failure.
>

I will change it to return success/failure.


>
>> +  /* Read the ctf frame unwind information from abfd.  */
>> +  if (!bfd_malloc_and_get_section (abfd, sec, &ctfbuf))
>> +    goto fail_no_free;
>
> The name of this label seems rather ironic, given that ...
>
>> +fail_no_free:
>> +  _bfd_error_handler
>> +   (_("error in %pB(%pA); no .ctf_frame will be created"),
>> +    abfd, sec);
>> +success:
>> +  free (ctfbuf);
>
> ... it falls through into the free().
>

Oops! I will change this.

>
> Cheers
>   Nick
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 00/14] Definition and support for SFrame unwind format
  2022-08-15 14:25 ` Nick Clifton
@ 2022-09-30  0:04   ` Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 01/14] sframe.h: Add SFrame format definition Indu Bhagat
                       ` (16 more replies)
  0 siblings, 17 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

Hello,

This patch series was previously being reviewed in the set "[PATCH,V6 00/10]
Definition and Implementation of CTF Frame format" here
https://sourceware.org/pipermail/binutils/2022-August/122147.html

(Posting links here of previous posting with old name "CTF Frame" for easy
 lookup:

 Initial (V1) posting contains necessary introductions:
 https://sourceware.org/pipermail/binutils/2022-May/120731.html
 V2 posting with some improvements:
 https://sourceware.org/pipermail/binutils/2022-May/120899.html
 V3 posting with further improvements:
 https://sourceware.org/pipermail/binutils/2022-June/121245.html
 V4 posting with further improvements and bugfixes:
 https://sourceware.org/pipermail/binutils/2022-June/121478.html
 V5 posting:
 https://sourceware.org/pipermail/binutils/2022-July/121839.html
)

After the discussions at LPC and GNU Tools Cauldron this year, it seemed like
the format needed a more suitable name.  The previous name was justifiably
bringing up some questions around: 1. How tied is the proposed frame format
with CTF (Compact C-Type Format), and 2. Is the format applicable for only
applications written in C.  The answers to these questions are: 1. It is
independent of the CTF debug format, and 2. No.  So, we think the format needed
a more appropriate name.  The new chosen name is "Simple Frame format", or
"SFrame" format for plain vanilla backtracing.

This patch series has addressed the review comments sent earlier in August 2022
(and apologies for the long delay in sending this series):
  - include/sframe.h uses ansidecl.h and ATTRIBUTE_PACKED
  - gas patches have been split up. The gas testsuite is now a separate patch,
    hopefully it eases some pain around testing each patch as the gas
    testsuite needs the readelf/objdump support. The bfd/linker patch still 
    has the testsuite combined in it though ...
  - bfd/elf-sframe.c now uses less BFD_ASSERTs. Some of them remain and I will
    deal with them over time.
  - fixes made for the compile-time warnings around incompatible pointer type
    [-Werror=incompatible-pointer-types] noted on i686 build.
  - other fixes around return type of some APIs, goofy labels and like.
  - added binutils/NEWS, gas/NEWS and updated the src-release.sh

The format specification document still mains a TODO at this time. I plan to
resume working on this after I have tackled the task of SFrame generation for
PLT/veneers in aarch64.

Another comment/feedback received at Cauldron was around the representation of
the SFrame Frame Row Entries: Can SFrame FREs be made fixed length and hence,
possibly compacted further such that all SFrame FREs across functions can then
possibly share the SP/FP/RA offset records.  This still remains to be
experimented with.

PS: libsframe/configure has been REMOVED from the patch series, as it causes
the size of some patches to go beyond the allowed limit.  Please regenerate
libsframe/configure after applying the series.

Testing notes:
 - Tested natively on x86_64-linux, aarch64-linux and i686-linux with
 '--enable-shared'.
 - Cross builds for various targets on x86_64 host with no explicit
 '--enable-shared'.  Ran a regression script that checks for failures in gas,
 ld, binutils, libctf with no reported regressions. libsframe tests ran as
 expected. libsframebt (the backtracer) tests (which are present in
 libsframe/testsuite/libsframe.unwind) have been disabled with host != target.

What is SFrame format and why do we need it
-------------------------------------------
SFrame format is the Simple Frame format.  It can be used to represent the
minimal necessary information for backtracing.  As such, it only encodes how to
recover the CFA (based on SP/FP) and the return address (RA) for all
instructions of a program.

The format is supported on AMD64 and AARCH64 ABIs only.  The information stored
in the .sframe section is a subset of what .eh_frame can convey: .eh_frame can
convey how to resurrect all callee-saved registers, if need be; but .sframe
does not.

SFrame format is intended for usecases where fast virtual stack unwind is
needed, along with a need for a small simple unwinder. So, those applications
which struggle with the following two complaints will want to consider SFrame
format:
  - EH Frame based unwinders are complex and slow to manage with
  - EH Frame based unwinders are large as they need to deal with DWARF 
  opcodes via a stack machine implementation

More details about the format are available in include/sframe.h, please see
commit "sframe.h: Add SFrame format definition".

Our not-so-exhaustive experiments (basically binutils programs built with
-Wa,--gsframe) show that SFrame/EH Frame section ratio to be an average of 0.8x
for x86_64 and 0.7x for aarch64.

Support in binutils
-------------------

This patch series adds support for SFrame format in GNU as, ld, readelf and
objdump. Two new libraries are being added:
  - libsframe - provides means to decode, encode/write, and probe SFrame
    sections. This is used by GNU ld and libsframebt.
  - libsframebt - small backtracer based on SFrame format.

More details on each of these components are provided in the respective commit
message.

Thanks,

Indu Bhagat (11):
  sframe.h: Add SFrame format definition
  gas: add new command line option --gsframe
  gas: generate .sframe from CFI directives
  gas: testsuite: add new tests for SFrame unwind info
  bfd: linker: merge .sframe sections
  readelf/objdump: support for SFrame section
  gdb: sim: buildsystem changes to accommodate libsframe
  libctf: add libsframe to LDFLAGS and LIBS
  src-release.sh: Add libsframe
  binutils/NEWS: add text for SFrame support
  gas/NEWS: add text about new command line option and SFrame support

Weimin Pan (3):
  libsframe: add the SFrame library
  unwinder: generate backtrace using SFrame format
  unwinder: Add SFrame unwinder tests

 Makefile.def                                  |    6 +
 Makefile.in                                   | 1299 +++++++++++++-
 bfd/Makefile.am                               |    6 +-
 bfd/Makefile.in                               |    7 +-
 bfd/bfd-in2.h                                 |    1 +
 bfd/configure                                 |    2 +-
 bfd/configure.ac                              |    2 +-
 bfd/elf-bfd.h                                 |   54 +
 bfd/elf-sframe.c                              |  533 ++++++
 bfd/elf.c                                     |   32 +
 bfd/elf64-x86-64.c                            |   97 +-
 bfd/elflink.c                                 |   52 +
 bfd/elfxx-x86.c                               |  377 +++-
 bfd/elfxx-x86.h                               |   46 +
 bfd/section.c                                 |    1 +
 binutils/Makefile.am                          |   10 +-
 binutils/Makefile.in                          |    9 +-
 binutils/NEWS                                 |    2 +
 binutils/doc/binutils.texi                    |    4 +
 binutils/doc/sframe.options.texi              |   10 +
 binutils/objdump.c                            |   76 +
 binutils/readelf.c                            |   47 +
 config/sframe.m4                              |   16 +
 configure                                     |    2 +-
 configure.ac                                  |    2 +-
 gas/Makefile.am                               |    3 +
 gas/Makefile.in                               |   22 +-
 gas/NEWS                                      |    3 +
 gas/as.c                                      |   10 +-
 gas/as.h                                      |   13 +-
 gas/config/tc-aarch64.c                       |   41 +
 gas/config/tc-aarch64.h                       |   29 +
 gas/config/tc-i386.c                          |   44 +
 gas/config/tc-i386.h                          |   26 +
 gas/config/tc-xtensa.c                        |    1 +
 gas/doc/as.texi                               |   19 +-
 gas/dw2gencfi.c                               |   30 +
 gas/dw2gencfi.h                               |    1 +
 gas/gen-sframe.c                              | 1300 ++++++++++++++
 gas/gen-sframe.h                              |  141 ++
 gas/sframe-opt.c                              |  158 ++
 .../gas/cfi-sframe/cfi-sframe-aarch64-1.d     |   20 +
 .../gas/cfi-sframe/cfi-sframe-aarch64-1.s     |   61 +
 .../gas/cfi-sframe/cfi-sframe-common-1.d      |   17 +
 .../gas/cfi-sframe/cfi-sframe-common-1.s      |    3 +
 .../gas/cfi-sframe/cfi-sframe-common-2.d      |   17 +
 .../gas/cfi-sframe/cfi-sframe-common-2.s      |    2 +
 .../gas/cfi-sframe/cfi-sframe-common-3.d      |   17 +
 .../gas/cfi-sframe/cfi-sframe-common-3.s      |    4 +
 .../gas/cfi-sframe/cfi-sframe-common-4.d      |   21 +
 .../gas/cfi-sframe/cfi-sframe-common-4.s      |    8 +
 .../gas/cfi-sframe/cfi-sframe-common-5.d      |   21 +
 .../gas/cfi-sframe/cfi-sframe-common-5.s      |    7 +
 .../gas/cfi-sframe/cfi-sframe-common-6.d      |   21 +
 .../gas/cfi-sframe/cfi-sframe-common-6.s      |    7 +
 .../gas/cfi-sframe/cfi-sframe-common-7.d      |   21 +
 .../gas/cfi-sframe/cfi-sframe-common-7.s      |    7 +
 .../gas/cfi-sframe/cfi-sframe-common-8.d      |   20 +
 .../gas/cfi-sframe/cfi-sframe-common-8.s      |   12 +
 .../gas/cfi-sframe/cfi-sframe-x86_64-1.d      |   22 +
 .../gas/cfi-sframe/cfi-sframe-x86_64-1.s      |   30 +
 gas/testsuite/gas/cfi-sframe/cfi-sframe.exp   |   58 +
 gas/testsuite/gas/cfi-sframe/common-empty-1.d |   14 +
 gas/testsuite/gas/cfi-sframe/common-empty-1.s |    5 +
 gas/testsuite/gas/cfi-sframe/common-empty-2.d |   14 +
 gas/testsuite/gas/cfi-sframe/common-empty-2.s |    8 +
 gas/testsuite/gas/cfi-sframe/common-empty-3.d |   14 +
 gas/testsuite/gas/cfi-sframe/common-empty-3.s |    9 +
 gas/testsuite/gas/cfi-sframe/common-empty-4.d |   14 +
 gas/testsuite/gas/cfi-sframe/common-empty-4.s |   17 +
 gas/write.c                                   |   13 +
 gdb/Makefile.in                               |    8 +-
 gdb/acinclude.m4                              |    4 +-
 gdb/configure                                 |   35 +-
 gdb/configure.ac                              |   11 +
 include/elf/common.h                          |    1 +
 include/elf/internal.h                        |    1 +
 include/sframe-api.h                          |  214 +++
 include/sframe-backtrace-api.h                |   57 +
 include/sframe.h                              |  281 +++
 ld/Makefile.am                                |    2 +
 ld/Makefile.in                                |    2 +
 ld/configure                                  |    8 +-
 ld/configure.ac                               |    3 +
 ld/ld.texi                                    |    4 +-
 ld/scripttempl/elf.sc                         |    2 +
 ld/testsuite/ld-aarch64/aarch64-elf.exp       |    2 +
 ld/testsuite/ld-aarch64/sframe-bar.s          |    7 +
 ld/testsuite/ld-aarch64/sframe-foo.s          |   10 +
 ld/testsuite/ld-aarch64/sframe-simple-1.d     |   26 +
 ld/testsuite/ld-bootstrap/bootstrap.exp       |    8 +-
 ld/testsuite/ld-sframe/discard.d              |   10 +
 ld/testsuite/ld-sframe/discard.ld             |    9 +
 ld/testsuite/ld-sframe/discard.s              |   13 +
 ld/testsuite/ld-sframe/sframe-empty.d         |   10 +
 ld/testsuite/ld-sframe/sframe-empty.s         |    2 +
 ld/testsuite/ld-sframe/sframe.exp             |   47 +
 ld/testsuite/ld-x86-64/sframe-bar.s           |   31 +
 ld/testsuite/ld-x86-64/sframe-foo.s           |   37 +
 ld/testsuite/ld-x86-64/sframe-plt-1.d         |   29 +
 ld/testsuite/ld-x86-64/sframe-simple-1.d      |   35 +
 ld/testsuite/ld-x86-64/x86-64.exp             |    2 +
 ld/testsuite/lib/ld-lib.exp                   |   45 +
 libctf/configure                              |    4 +-
 libctf/configure.ac                           |    4 +-
 libsframe/Makefile.am                         |   54 +
 libsframe/Makefile.in                         | 1100 ++++++++++++
 libsframe/aclocal.m4                          | 1242 +++++++++++++
 libsframe/config.h.in                         |  144 ++
 libsframe/configure.ac                        |   97 +
 libsframe/sframe-backtrace-err.c              |   46 +
 libsframe/sframe-backtrace.c                  |  619 +++++++
 libsframe/sframe-dump.c                       |  181 ++
 libsframe/sframe-error.c                      |   49 +
 libsframe/sframe-impl.h                       |   55 +
 libsframe/sframe.c                            | 1584 +++++++++++++++++
 libsframe/testsuite/Makefile.am               |   23 +
 libsframe/testsuite/Makefile.in               |  684 +++++++
 libsframe/testsuite/config/default.exp        |   57 +
 libsframe/testsuite/lib/sframe-lib.exp        |  180 ++
 libsframe/testsuite/libsframe.decode/DATA1    |  Bin 0 -> 59 bytes
 libsframe/testsuite/libsframe.decode/DATA2    |  Bin 0 -> 91 bytes
 .../testsuite/libsframe.decode/DATA_BIGE      |  Bin 0 -> 59 bytes
 .../testsuite/libsframe.decode/Makefile.am    |   14 +
 .../testsuite/libsframe.decode/Makefile.in    |  663 +++++++
 .../libsframe.decode/bigendian_data.c         |  107 ++
 .../testsuite/libsframe.decode/decode.exp     |   41 +
 .../testsuite/libsframe.decode/frecnt_1.c     |   99 ++
 .../testsuite/libsframe.decode/frecnt_2.c     |  103 ++
 .../testsuite/libsframe.encode/Makefile.am    |    6 +
 .../testsuite/libsframe.encode/Makefile.in    |  610 +++++++
 .../testsuite/libsframe.encode/encode.exp     |   25 +
 .../testsuite/libsframe.encode/encode_1.c     |  182 ++
 .../testsuite/libsframe.unwind/backtrace.c    |  145 ++
 .../testsuite/libsframe.unwind/backtrace.lk   |    3 +
 .../testsuite/libsframe.unwind/inline-cmds.c  |  136 ++
 .../testsuite/libsframe.unwind/inline-cmds.lk |    3 +
 libsframe/testsuite/libsframe.unwind/inline.c |   97 +
 .../testsuite/libsframe.unwind/inline.lk      |    3 +
 .../testsuite/libsframe.unwind/solib-lib1.c   |    8 +
 .../testsuite/libsframe.unwind/solib-lib2.c   |   51 +
 .../testsuite/libsframe.unwind/solib-main.c   |   47 +
 .../testsuite/libsframe.unwind/solib-main.d   |    3 +
 .../testsuite/libsframe.unwind/solib.exp      |   75 +
 .../testsuite/libsframe.unwind/solib_lib1.h   |    3 +
 .../testsuite/libsframe.unwind/solib_lib2.h   |    3 +
 .../testsuite/libsframe.unwind/tailcall.c     |  103 ++
 .../testsuite/libsframe.unwind/tailcall.lk    |    3 +
 libsframe/testsuite/libsframe.unwind/ttest.c  |  127 ++
 libsframe/testsuite/libsframe.unwind/ttest.lk |    3 +
 .../testsuite/libsframe.unwind/unwind.exp     |  200 +++
 sim/common/Make-common.in                     |    7 +-
 src-release.sh                                |    4 +-
 153 files changed, 14927 insertions(+), 64 deletions(-)
 create mode 100644 bfd/elf-sframe.c
 create mode 100644 binutils/doc/sframe.options.texi
 create mode 100644 config/sframe.m4
 create mode 100644 gas/gen-sframe.c
 create mode 100644 gas/gen-sframe.h
 create mode 100644 gas/sframe-opt.c
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-1.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-2.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-2.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-3.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-3.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-4.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-4.s
 create mode 100644 include/sframe-api.h
 create mode 100644 include/sframe-backtrace-api.h
 create mode 100644 include/sframe.h
 create mode 100644 ld/testsuite/ld-aarch64/sframe-bar.s
 create mode 100644 ld/testsuite/ld-aarch64/sframe-foo.s
 create mode 100644 ld/testsuite/ld-aarch64/sframe-simple-1.d
 create mode 100644 ld/testsuite/ld-sframe/discard.d
 create mode 100644 ld/testsuite/ld-sframe/discard.ld
 create mode 100644 ld/testsuite/ld-sframe/discard.s
 create mode 100644 ld/testsuite/ld-sframe/sframe-empty.d
 create mode 100644 ld/testsuite/ld-sframe/sframe-empty.s
 create mode 100644 ld/testsuite/ld-sframe/sframe.exp
 create mode 100644 ld/testsuite/ld-x86-64/sframe-bar.s
 create mode 100644 ld/testsuite/ld-x86-64/sframe-foo.s
 create mode 100644 ld/testsuite/ld-x86-64/sframe-plt-1.d
 create mode 100644 ld/testsuite/ld-x86-64/sframe-simple-1.d
 create mode 100644 libsframe/Makefile.am
 create mode 100644 libsframe/Makefile.in
 create mode 100644 libsframe/aclocal.m4
 create mode 100644 libsframe/config.h.in
 create mode 100644 libsframe/configure.ac
 create mode 100644 libsframe/sframe-backtrace-err.c
 create mode 100644 libsframe/sframe-backtrace.c
 create mode 100644 libsframe/sframe-dump.c
 create mode 100644 libsframe/sframe-error.c
 create mode 100644 libsframe/sframe-impl.h
 create mode 100644 libsframe/sframe.c
 create mode 100644 libsframe/testsuite/Makefile.am
 create mode 100644 libsframe/testsuite/Makefile.in
 create mode 100644 libsframe/testsuite/config/default.exp
 create mode 100644 libsframe/testsuite/lib/sframe-lib.exp
 create mode 100644 libsframe/testsuite/libsframe.decode/DATA1
 create mode 100644 libsframe/testsuite/libsframe.decode/DATA2
 create mode 100644 libsframe/testsuite/libsframe.decode/DATA_BIGE
 create mode 100644 libsframe/testsuite/libsframe.decode/Makefile.am
 create mode 100644 libsframe/testsuite/libsframe.decode/Makefile.in
 create mode 100644 libsframe/testsuite/libsframe.decode/bigendian_data.c
 create mode 100644 libsframe/testsuite/libsframe.decode/decode.exp
 create mode 100644 libsframe/testsuite/libsframe.decode/frecnt_1.c
 create mode 100644 libsframe/testsuite/libsframe.decode/frecnt_2.c
 create mode 100644 libsframe/testsuite/libsframe.encode/Makefile.am
 create mode 100644 libsframe/testsuite/libsframe.encode/Makefile.in
 create mode 100644 libsframe/testsuite/libsframe.encode/encode.exp
 create mode 100644 libsframe/testsuite/libsframe.encode/encode_1.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/backtrace.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/backtrace.lk
 create mode 100644 libsframe/testsuite/libsframe.unwind/inline-cmds.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/inline-cmds.lk
 create mode 100644 libsframe/testsuite/libsframe.unwind/inline.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/inline.lk
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib-lib1.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib-lib2.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib-main.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib-main.d
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib.exp
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib_lib1.h
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib_lib2.h
 create mode 100644 libsframe/testsuite/libsframe.unwind/tailcall.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/tailcall.lk
 create mode 100644 libsframe/testsuite/libsframe.unwind/ttest.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/ttest.lk
 create mode 100644 libsframe/testsuite/libsframe.unwind/unwind.exp

-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 01/14] sframe.h: Add SFrame format definition
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 02/14] gas: add new command line option --gsframe Indu Bhagat
                       ` (15 subsequent siblings)
  16 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

The header sframe.h defines the SFrame format.

The SFrame format is the Simple Frame format.  It can be used to
represent the minimal necessary unwind information required for
backtracing.  The current version supports AMD64 and AARCH64.

More details of the SFrame format are included in the documentation
of the header file in this patch.

include/ChangeLog:
	* sframe.h: New file.
---
 include/sframe.h | 281 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 281 insertions(+)
 create mode 100644 include/sframe.h

diff --git a/include/sframe.h b/include/sframe.h
new file mode 100644
index 00000000000..b761be6e297
--- /dev/null
+++ b/include/sframe.h
@@ -0,0 +1,281 @@
+/* SFrame format description.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of libsframe.
+
+   libsframe 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, 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; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_SFRAME_H
+#define	_SFRAME_H
+
+#include <sys/types.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include "ansidecl.h"
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+/* SFrame format.
+
+   SFrame format is a simple format to represent the information needed
+   for vanilla virtual stack unwinding.  SFrame format keeps track of the
+   minimal necessary information needed for stack unwinding:
+     - Canonical Frame Address (CFA)
+     - Frame Pointer (FP)
+     - Return Address (RA)
+
+   The SFrame section itself has the following structure:
+
+       +--------+------------+---------+
+       |  file  |  function  | frame   |
+       | header | descriptor |  row    |
+       |        |   entries  | entries |
+       +--------+------------+---------+
+
+   The file header stores a magic number and version information, flags, and
+   the byte offset of each of the sections relative to the end of the header
+   itself.  The file header also specifies the total number of Function
+   Descriptor Entries, Frame Row Entries and length of the FRE sub-section.
+
+   Following the header is a list of Function Descriptor Entries (FDEs).
+   This list may be sorted if the flags in the file header indicate it to be
+   so.  The sort order, if applicable, is the order of functions in the
+   .text.* sections in the resulting binary artifact.  Each Function
+   Descriptor Entry specifies the start PC of a function, the size in bytes
+   of the function and an offset to its first Frame Row Entry (FRE).  Each FDE
+   additionally also specifies the type of FRE it uses to encode the unwind
+   information.
+
+   Next, the Frame Row Entry section is a list of variable size records,
+   each of which represent SFrame unwind information for a set of PCs.  A
+   singular Frame Row Entry is a self-sufficient record with information on
+   how to virtually unwind the stack for the applicable set of PCs.
+
+   */
+
+
+/* SFrame format versions.  */
+#define SFRAME_VERSION_1	1
+/* SFrame magic number.  */
+#define SFRAME_MAGIC		0xdee2
+/* Current version of SFrame format.  */
+#define SFRAME_VERSION	SFRAME_VERSION_1
+
+/* Various flags for SFrame.  */
+
+/* Function Descriptor Entries are sorted on PC.  */
+#define SFRAME_F_FDE_SORTED	0x1
+/* Frame-pointer based unwinding.  */
+#define SFRAME_F_FRAME_POINTER 0x2
+
+#define SFRAME_CFA_FIXED_FP_INVALID 0
+#define SFRAME_CFA_FIXED_RA_INVALID 0
+
+/* Supported ABIs/Arch.  */
+#define SFRAME_ABI_AARCH64_ENDIAN_BIG      1 /* AARCH64 big endian.  */
+#define SFRAME_ABI_AARCH64_ENDIAN_LITTLE   2 /* AARCH64 little endian.  */
+#define SFRAME_ABI_AMD64_ENDIAN_LITTLE     3 /* AMD64 little endian.  */
+
+/* SFrame FRE types.  */
+#define SFRAME_FRE_TYPE_ADDR1	1
+#define SFRAME_FRE_TYPE_ADDR2	2
+#define SFRAME_FRE_TYPE_ADDR4	3
+
+/* SFrame Function Descriptor Entry types.
+
+   The SFrame format has two possible representations for functions.  The
+   choice of which type to use is made according to the instruction patterns
+   in the relevant program stub.
+
+   A SFrame FDE of type SFRAME_FDE_TYPE_PCINC is an indication
+   that the PCs in the FREs should be treated as increments in bytes.  This is
+   used for a bulk of the executable code of a program, which contains
+   instructions with no specific pattern.
+
+   A SFrame FDE of type SFRAME_FDE_TYPE_PCMASK is an indication
+   that the PCs in the FREs should be treated as masks.  This type is useful
+   for the cases when a small pattern of instructions in a program stub is
+   repeatedly to cover a specific functionality.  Typical usescases are pltN
+   entries, trampolines etc.  */
+
+/* Unwinders perform a (PC >= FRE_START_ADDR) to look up a matching FRE.  */
+#define SFRAME_FDE_TYPE_PCINC   0
+/* Unwinders perform a (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK)
+   to look up a matching FRE.  */
+#define SFRAME_FDE_TYPE_PCMASK  1
+
+typedef struct sframe_preamble
+{
+  uint16_t sfp_magic;	/* Magic number (SFRAME_MAGIC).  */
+  uint8_t sfp_version;	/* Data format version number (SFRAME_VERSION).  */
+  uint8_t sfp_flags;	/* Flags.  */
+} ATTRIBUTE_PACKED sframe_preamble;
+
+typedef struct sframe_header
+{
+  sframe_preamble sfh_preamble;
+  /* Information about the arch (endianness) and ABI.  */
+  uint8_t sfh_abi_arch;
+  /* Offset for the Frame Pointer (FP) from CFA may be fixed for some
+     ABIs (e.g, in AMD64 when -fno-omit-frame-pointer is used).  When fixed,
+     this field specifies the fixed stack frame offset and the individual
+     FREs do not need to track it.  When not fixed, it is set to
+     SFRAME_CFA_FIXED_FP_INVALID, and the individual FREs may provide
+     the applicable stack frame offset, if any.  */
+  int8_t sfh_cfa_fixed_fp_offset;
+  /* Offset for the Return Address from CFA is fixed for some ABIs
+     (e.g., AMD64 has it as CFA-8).  When fixed, the header specifies the
+     fixed stack frame offset and the individual FREs do not track it.  When
+     not fixed, it is set to SFRAME_CFA_FIXED_RA_INVALID, and individual
+     FREs provide the applicable stack frame offset, if any.  */
+  int8_t sfh_cfa_fixed_ra_offset;
+  /* Number of SFrame FDEs in this SFrame section.  */
+  uint32_t sfh_num_fdes;
+  /* Number of SFrame Frame Row Entries.  */
+  uint32_t sfh_num_fres;
+  /* Number of bytes in the SFrame Frame Row Entry section. */
+  uint32_t sfh_fre_len;
+  /* Offset of SFrame Function Descriptor Entry section.  */
+  uint32_t sfh_fdeoff;
+  /* Offset of SFrame Frame Row Entry section.  */
+  uint32_t sfh_freoff;
+} ATTRIBUTE_PACKED sframe_header;
+
+typedef struct sframe_func_desc_entry
+{
+  /* Function start address.  Encoded as a signed offset, relative to the
+     beginning of the current FDE.  */
+  int32_t sfde_func_start_address;
+  /* Size of the function in bytes.  */
+  uint32_t sfde_func_size;
+  /* Offset of the first SFrame Frame Row Entry of the function, relative to the
+     beginning of the SFrame Frame Row Entry sub-section.  */
+  uint32_t sfde_func_start_fre_off;
+  /* Number of frame row entries for the function.  */
+  uint32_t sfde_func_num_fres;
+  /* Additional information for deciphering the unwind information for the
+     function.
+     - 4-bits: Identify the FRE type used for the function.
+     - 1-bit: Identify the FDE type of the function - mask or inc.
+     - 3-bits: Unused.
+     --------------------------------------------
+     |     Unused    |  FDE type |   FRE type   |
+     --------------------------------------------
+     8               5           4              0     */
+  uint8_t sfde_func_info;
+} ATTRIBUTE_PACKED sframe_func_desc_entry;
+
+/* Macros to compose and decompose function info in FDE.  */
+
+#define SFRAME_V1_FUNC_INFO(fde_type, fre_enc_type) \
+  (((fde_type) & 0x1) << 4 | (fre_enc_type))
+
+#define SFRAME_V1_FUNC_FRE_TYPE(data)	  ((data) & 0xf)
+#define SFRAME_V1_FUNC_FDE_TYPE(data)	  ((data >> 4) & 0x1)
+
+/* Size of stack frame offsets in an SFrame Frame Row Entry.  A single
+   SFrame FRE has all offsets of the same size.  Offset size may vary
+   across frame row entries.  */
+#define SFRAME_FRE_OFFSET_1B	  0
+#define SFRAME_FRE_OFFSET_2B	  1
+#define SFRAME_FRE_OFFSET_4B	  2
+
+/* A SFrame Frame Row Entry can be SP or FP based.  */
+#define SFRAME_BASE_REG_FP	0
+#define SFRAME_BASE_REG_SP	1
+
+/* The index at which a specific offset is presented in the variable length
+   bytes of an FRE.  */
+#define SFRAME_FRE_CFA_OFFSET_IDX  0
+#define SFRAME_FRE_FP_OFFSET_IDX   1
+#define SFRAME_FRE_RA_OFFSET_IDX   2
+
+typedef struct sframe_fre_info
+{
+  /* Information about
+     - 1 bit: base reg for CFA
+     - 4 bits: Number of offsets (N).  A value of upto 3 is allowed to track
+     all three of CFA, FP and RA (fixed implicit order).
+     - 2 bits: information about size of the offsets (S) in bytes.
+     Valid values are SFRAME_FRE_OFFSET_1B, SFRAME_FRE_OFFSET_2B,
+     SFRAME_FRE_OFFSET_4B
+     - 1 bit: Unused.
+     -----------------------------------------------------------------------
+     |  Unused  |  Size of offsets   |   Number of offsets    |   base_reg |
+     -----------------------------------------------------------------------
+     8          7                    5                        1            0
+
+     */
+  uint8_t fre_info;
+} sframe_fre_info;
+
+/* Macros to compose and decompose FRE info.  */
+
+#define SFRAME_V1_FRE_INFO(base_reg_id, offset_num, offset_size) \
+  ((offset_size << 5) | (offset_num << 1) | (base_reg_id))
+
+#define SFRAME_V1_FRE_CFA_BASE_REG_ID(data)	  ((data) & 0x1)
+#define SFRAME_V1_FRE_OFFSET_COUNT(data)	  (((data) >> 1) & 0xf)
+#define SFRAME_V1_FRE_OFFSET_SIZE(data)	  (((data) >> 5) & 0x3)
+
+/* SFrame Frame Row Entry definitions.
+
+   Used for both AMD64 and AARCH64.
+
+   A SFrame Frame Row Entry is a self-sufficient record containing SFrame
+   unwind info for a range of addresses, starting at the specified offset in
+   the function.  Each SFrame Frame Row Entry is followed by S*N bytes, where:
+     S is the size of the stack frame offset for the FRE, and
+     N is the number of stack frame offsets in the FRE
+
+   The offsets are interpreted in order as follows:
+   offset1 (interpreted as CFA = BASE_REG + offset1)
+   offset2 (interpreted as FP = CFA + offset2)
+   offset3 (interpreted as RA = CFA + offset3)
+*/
+
+typedef struct sframe_frame_row_entry_addr1
+{
+  /* Start address of the frame row entry.  Encoded as an 1-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint8_t sfre_start_address;
+  sframe_fre_info sfre_info;
+} ATTRIBUTE_PACKED sframe_frame_row_entry_addr1;
+
+typedef struct sframe_frame_row_entry_addr2
+{
+  /* Start address of the frame row entry.  Encoded as an 2-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint16_t sfre_start_address;
+  sframe_fre_info sfre_info;
+} ATTRIBUTE_PACKED sframe_frame_row_entry_addr2;
+
+typedef struct sframe_frame_row_entry_addr4
+{
+  /* Start address of the frame row entry.  Encoded as a 4-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint32_t sfre_start_address;
+  sframe_fre_info sfre_info;
+} ATTRIBUTE_PACKED sframe_frame_row_entry_addr4;
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _SFRAME_H */
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 02/14] gas: add new command line option --gsframe
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 01/14] sframe.h: Add SFrame format definition Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 03/14] gas: generate .sframe from CFI directives Indu Bhagat
                       ` (14 subsequent siblings)
  16 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

When --gsframe is specified, the assembler will generate a .sframe
section from the CFI directives in the assembly.

ChangeLog:

	* gas/as.c (parse_args): Parse args and set flag_gen_sframe.
	* gas/as.h: Introduce skeleton for --gsframe.
	* gas/doc/as.texi: document --gsframe.
---
 gas/as.c        | 10 +++++++++-
 gas/as.h        |  3 +++
 gas/doc/as.texi |  5 +++++
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/gas/as.c b/gas/as.c
index 35ad6b3ab3b..561d082eb36 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -318,6 +318,8 @@ Options:\n\
 #endif
   fprintf (stream, _("\
                           generate GNU Build notes if none are present in the input\n"));
+  fprintf (stream, _("\
+  --gsframe               generate SFrame unwind info\n"));
 #endif /* OBJ_ELF */
 
   fprintf (stream, _("\
@@ -491,7 +493,8 @@ parse_args (int * pargc, char *** pargv)
       OPTION_COMPRESS_DEBUG,
       OPTION_NOCOMPRESS_DEBUG,
       OPTION_NO_PAD_SECTIONS,
-      OPTION_MULTIBYTE_HANDLING  /* = STD_BASE + 40 */
+      OPTION_MULTIBYTE_HANDLING,  /* = STD_BASE + 40 */
+      OPTION_SFRAME
     /* When you add options here, check that they do
        not collide with OPTION_MD_BASE.  See as.h.  */
     };
@@ -522,6 +525,7 @@ parse_args (int * pargc, char *** pargv)
     ,{"elf-stt-common", required_argument, NULL, OPTION_ELF_STT_COMMON}
     ,{"sectname-subst", no_argument, NULL, OPTION_SECTNAME_SUBST}
     ,{"generate-missing-build-notes", required_argument, NULL, OPTION_ELF_BUILD_NOTES}
+    ,{"gsframe", no_argument, NULL, OPTION_SFRAME}
 #endif
     ,{"fatal-warnings", no_argument, NULL, OPTION_WARN_FATAL}
     ,{"gdwarf-2", no_argument, NULL, OPTION_GDWARF_2}
@@ -996,6 +1000,10 @@ This program has absolutely no warranty.\n"));
 		      optarg);
 	  break;
 
+	case OPTION_SFRAME:
+	  flag_gen_sframe = 1;
+	  break;
+
 #endif /* OBJ_ELF */
 
 	case 'Z':
diff --git a/gas/as.h b/gas/as.h
index 730e134dce6..1b924071938 100644
--- a/gas/as.h
+++ b/gas/as.h
@@ -337,6 +337,9 @@ COMMON int flag_execstack;
 /* TRUE if .note.GNU-stack section with SEC_CODE should be created */
 COMMON int flag_noexecstack;
 
+/* TRUE if .sframe section should be created.  */
+COMMON int flag_gen_sframe;
+
 /* name of emitted object file */
 COMMON const char *out_file_name;
 
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index 01f49434021..40f48b733af 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -245,6 +245,7 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
  [@b{--sectname-subst}] [@b{--size-check=[error|warning]}]
  [@b{--elf-stt-common=[no|yes]}]
  [@b{--generate-missing-build-notes=[no|yes]}]
+ [@b{--gsframe}]
  [@b{--multibyte-handling=[allow|warn|warn-sym-only]}]
  [@b{--target-help}] [@var{target-options}]
  [@b{--}|@var{files} @dots{}]
@@ -828,6 +829,10 @@ attribute notes if none are present in the input sources.
 The default can be controlled by the @option{--enable-generate-build-notes}
 configure option.
 
+@item --gsframe
+@itemx --gsframe
+Create @var{.sframe} section from CFI directives.
+
 @end ifset
 
 @item --help
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 03/14] gas: generate .sframe from CFI directives
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 01/14] sframe.h: Add SFrame format definition Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 02/14] gas: add new command line option --gsframe Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 04/14] gas: testsuite: add new tests for SFrame unwind info Indu Bhagat
                       ` (13 subsequent siblings)
  16 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

Currently supported for x86_64 and aarch64 only.

[PS: Currently, the compiler has not been adapted to generate
".cfi_sections" with ".sframe" in it.  The newly added command line
option of --gsframe provides an easy way to try out .sframe support
in the toolchain.]

gas interprets the CFI directives to generate DWARF-based .eh_frame
info.  These internal DWARF structures are now consumed by
gen-sframe.[ch] sub-system to, in turn, create the SFrame unwind
information.  These internal DWARF structures are read-only for the
purpose of SFrame unwind info generation.

SFrame unwind info generation does not impact .eh_frame unwind info
generation.  Both .eh_frame and .sframe can co-exist in an ELF file,
if so desired by the user.

Recall that SFrame unwind information only contains the minimal
necessary information to generate backtraces and does not provide
information to recover all callee-saved registers.  The reason being
that callee-saved registers other than FP are not needed for stack
unwinding, and hence are not included in the .sframe section.

Consequently, gen-sframe.[ch] only needs to interpret a subset of
DWARF opcodes in gas.  More details follow.

[Set 1, Interpreted] The following opcodes are interpreted:
- DW_CFA_advance_loc
- DW_CFA_def_cfa
- DW_CFA_def_cfa_register
- DW_CFA_def_cfa_offset
- DW_CFA_offset
- DW_CFA_remember_state
- DW_CFA_restore_state
- DW_CFA_restore

[Set 2, Bypassed] The following opcodes are acknowledged but are not
necessary for generating SFrame unwind info:
- DW_CFA_undefined
- DW_CFA_same_value

Anything else apart from the two above-mentioned sets is skipped
altogether.  This means that any function containing a CFI directive not
in Set 1 or Set 2 above, will not have any SFrame unwind information
generated for them.  Holes in instructions covered by FREs of a single
FDE are not representable in the SFrame unwind format.

As few examples, following opcodes are not processed for .sframe
generation, and are skipped:
- .cfi_personality*
- .cfi_*lsda
- .cfi_escape
- .cfi_negate_ra_state
- ...

Not processing .cfi_escape, .cfi_negate_ra_state will cause SFrame
unwind information to be absent for SFrame FDEs that contain these CFI
directives, hence affecting the asynchronicity.

x86-64 and aarch64 backends need to have a few new definitions and
functions for .sframe generation.  These provide gas with architecture
specific information like the SP/FP/RA register numbers and an
SFrame-specific ABI marker.

Lastly, the patch also implements an optimization for size, where
specific fragments containing SFrame FRE start address and SFrame FDE
function are fixed up.  This is similar to other similar optimizations
in gas, where fragments are sized and fixed up when the associated
symbols can be resolved.  This optimization is controlled by a #define
SFRAME_FRE_TYPE_SELECTION_OPT and should be easy to turn off if needed.
The optimization is on by default for both x86_64 and aarch64.

ChangeLog:

	* gas/Makefile.am: Include gen-sframe.c and sframe-opt.c.
	* gas/Makefile.in: Regenerated.
	* gas/as.h (enum _relax_state): Add new state rs_sframe.
	(sframe_estimate_size_before_relax): New function.
	(sframe_relax_frag): Likewise.
	(sframe_convert_frag): Likewise.
	* gas/config/tc-aarch64.c (aarch64_support_sframe_p): New
	definition.
	(aarch64_sframe_ra_tracking_p): Likewise.
	(aarch64_sframe_cfa_ra_offset): Likewise.
	(aarch64_sframe_get_abi_arch): Likewise.
	(md_begin): Set values of sp/fp/ra registers.
	* gas/config/tc-aarch64.h (aarch64_support_sframe_p): New
	declaration.
	(support_sframe_p): Likewise.
	(SFRAME_CFA_SP_REG): Likewise.
	(SFRAME_CFA_FP_REG): Likewise.
	(SFRAME_CFA_RA_REG): Likewise.
	(aarch64_sframe_ra_tracking_p): Likewise.
	(sframe_ra_tracking_p): Likewise.
	(aarch64_sframe_cfa_ra_offset): Likewise.
	(sframe_cfa_ra_offset): Likewise.
	(aarch64_sframe_get_abi_arch): Likewise.
	(sframe_get_abi_arch): Likewise.
	* gas/config/tc-i386.c (x86_support_sframe_p): New definition.
	(x86_sframe_ra_tracking_p): Likewise.
	(x86_sframe_cfa_ra_offset): Likewise.
	(x86_sframe_get_abi_arch): Likewise.
	* gas/config/tc-i386.h (x86_support_sframe_p): New declaration.
	(support_sframe_p): Likewise.
	(SFRAME_CFA_SP_REG): Likewise.
	(SFRAME_CFA_FP_REG): Likewise.
	(x86_sframe_ra_tracking_p): Likewise.
	(sframe_ra_tracking_p): Likewise.
	(x86_sframe_cfa_ra_offset): Likewise.
	(sframe_cfa_ra_offset): Likewise.
	(x86_sframe_get_abi_arch): Likewise.
	(sframe_get_abi_arch): Likewise.
	* gas/config/tc-xtensa.c (unrelaxed_frag_max_size): Add case for
	rs_sframe.
	* gas/doc/as.texi: Add .sframe to the documentation for
	.cfi_sections.
	* gas/dw2gencfi.c (cfi_finish): Create a .sframe section.
	* gas/dw2gencfi.h (CFI_EMIT_sframe): New definition.
	* gas/write.c (cvt_frag_to_fill): Handle rs_sframe.
	(relax_segment): Likewise.
	* gas/gen-sframe.c: New file.
	* gas/gen-sframe.h: New file.
	* gas/sframe-opt.c: New file.
---
 gas/Makefile.am         |    3 +
 gas/Makefile.in         |   22 +-
 gas/as.h                |   10 +-
 gas/config/tc-aarch64.c |   41 ++
 gas/config/tc-aarch64.h |   29 +
 gas/config/tc-i386.c    |   44 ++
 gas/config/tc-i386.h    |   26 +
 gas/config/tc-xtensa.c  |    1 +
 gas/doc/as.texi         |   14 +-
 gas/dw2gencfi.c         |   30 +
 gas/dw2gencfi.h         |    1 +
 gas/gen-sframe.c        | 1300 +++++++++++++++++++++++++++++++++++++++
 gas/gen-sframe.h        |  141 +++++
 gas/sframe-opt.c        |  158 +++++
 gas/write.c             |   13 +
 15 files changed, 1819 insertions(+), 14 deletions(-)
 create mode 100644 gas/gen-sframe.c
 create mode 100644 gas/gen-sframe.h
 create mode 100644 gas/sframe-opt.c

diff --git a/gas/Makefile.am b/gas/Makefile.am
index 5f0f24abf8d..f92bfd0a0c8 100644
--- a/gas/Makefile.am
+++ b/gas/Makefile.am
@@ -70,6 +70,8 @@ GAS_CFILES = \
 	atof-generic.c \
 	compress-debug.c \
 	cond.c \
+	sframe-opt.c \
+	gen-sframe.c \
 	depend.c \
 	dwarf2dbg.c \
 	dw2gencfi.c \
@@ -105,6 +107,7 @@ HFILES = \
 	bit_fix.h \
 	cgen.h \
 	compress-debug.h \
+	gen-sframe.h \
 	dwarf2dbg.h \
 	dw2gencfi.h \
 	ecoff.h \
diff --git a/gas/Makefile.in b/gas/Makefile.in
index 5a4dd702252..f62d2af2afe 100644
--- a/gas/Makefile.in
+++ b/gas/Makefile.in
@@ -162,14 +162,15 @@ CONFIG_CLEAN_FILES = gdb.ini .gdbinit po/Makefile.in
 CONFIG_CLEAN_VPATH_FILES =
 PROGRAMS = $(noinst_PROGRAMS)
 am__objects_1 = app.$(OBJEXT) as.$(OBJEXT) atof-generic.$(OBJEXT) \
-	compress-debug.$(OBJEXT) cond.$(OBJEXT) depend.$(OBJEXT) \
-	dwarf2dbg.$(OBJEXT) dw2gencfi.$(OBJEXT) ecoff.$(OBJEXT) \
-	ehopt.$(OBJEXT) expr.$(OBJEXT) flonum-copy.$(OBJEXT) \
-	flonum-konst.$(OBJEXT) flonum-mult.$(OBJEXT) frags.$(OBJEXT) \
-	hash.$(OBJEXT) input-file.$(OBJEXT) input-scrub.$(OBJEXT) \
-	listing.$(OBJEXT) literal.$(OBJEXT) macro.$(OBJEXT) \
-	messages.$(OBJEXT) output-file.$(OBJEXT) read.$(OBJEXT) \
-	remap.$(OBJEXT) sb.$(OBJEXT) stabs.$(OBJEXT) subsegs.$(OBJEXT) \
+	compress-debug.$(OBJEXT) cond.$(OBJEXT) sframe-opt.$(OBJEXT) \
+	gen-sframe.$(OBJEXT) depend.$(OBJEXT) dwarf2dbg.$(OBJEXT) \
+	dw2gencfi.$(OBJEXT) ecoff.$(OBJEXT) ehopt.$(OBJEXT) \
+	expr.$(OBJEXT) flonum-copy.$(OBJEXT) flonum-konst.$(OBJEXT) \
+	flonum-mult.$(OBJEXT) frags.$(OBJEXT) hash.$(OBJEXT) \
+	input-file.$(OBJEXT) input-scrub.$(OBJEXT) listing.$(OBJEXT) \
+	literal.$(OBJEXT) macro.$(OBJEXT) messages.$(OBJEXT) \
+	output-file.$(OBJEXT) read.$(OBJEXT) remap.$(OBJEXT) \
+	sb.$(OBJEXT) stabs.$(OBJEXT) subsegs.$(OBJEXT) \
 	symbols.$(OBJEXT) write.$(OBJEXT)
 am_as_new_OBJECTS = $(am__objects_1)
 am__dirstamp = $(am__leading_dot)dirstamp
@@ -556,6 +557,8 @@ GAS_CFILES = \
 	atof-generic.c \
 	compress-debug.c \
 	cond.c \
+	sframe-opt.c \
+	gen-sframe.c \
 	depend.c \
 	dwarf2dbg.c \
 	dw2gencfi.c \
@@ -590,6 +593,7 @@ HFILES = \
 	bit_fix.h \
 	cgen.h \
 	compress-debug.h \
+	gen-sframe.h \
 	dwarf2dbg.h \
 	dw2gencfi.h \
 	ecoff.h \
@@ -1302,6 +1306,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flonum-konst.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flonum-mult.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/frags.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gen-sframe.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/input-file.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/input-scrub.Po@am__quote@
@@ -1316,6 +1321,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remap.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sframe-opt.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stabs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subsegs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symbols.Po@am__quote@
diff --git a/gas/as.h b/gas/as.h
index 1b924071938..23542e452b6 100644
--- a/gas/as.h
+++ b/gas/as.h
@@ -261,7 +261,10 @@ enum _relax_state
   rs_cfa,
 
   /* Cross-fragment dwarf2 line number optimization.  */
-  rs_dwarf2dbg
+  rs_dwarf2dbg,
+
+  /* SFrame FRE type selection optimization.  */
+  rs_sframe
 };
 
 typedef enum _relax_state relax_stateT;
@@ -528,6 +531,11 @@ int eh_frame_relax_frag (fragS *);
 void eh_frame_convert_frag (fragS *);
 int generic_force_reloc (struct fix *);
 
+/* SFrame FRE optimization.  */
+int sframe_estimate_size_before_relax (fragS *);
+int sframe_relax_frag (fragS *);
+void sframe_convert_frag (fragS *);
+
 #include "expr.h"		/* Before targ-*.h */
 
 /* This one starts the chain of target dependent headers.  */
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 98a7ca5878f..db1d38e2e55 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -31,6 +31,7 @@
 #ifdef OBJ_ELF
 #include "elf/aarch64.h"
 #include "dw2gencfi.h"
+#include "gen-sframe.h"
 #endif
 
 #include "dwarf2dbg.h"
@@ -70,6 +71,11 @@ enum aarch64_abi_type
   AARCH64_ABI_ILP32 = 2
 };
 
+unsigned int aarch64_sframe_cfa_sp_reg;
+/* The other CFA base register for SFrame unwind info.  */
+unsigned int aarch64_sframe_cfa_fp_reg;
+unsigned int aarch64_sframe_cfa_ra_reg;
+
 #ifndef DEFAULT_ARCH
 #define DEFAULT_ARCH "aarch64"
 #endif
@@ -8402,6 +8408,35 @@ tc_aarch64_frame_initial_instructions (void)
 {
   cfi_add_CFA_def_cfa (REG_SP, 0);
 }
+
+bool
+aarch64_support_sframe_p (void)
+{
+  /* At this time, SFrame is supported for aarch64 only.  */
+  return (aarch64_abi == AARCH64_ABI_LP64);
+}
+
+bool
+aarch64_sframe_ra_tracking_p (void)
+{
+  return true;
+}
+
+offsetT
+aarch64_sframe_cfa_ra_offset (void)
+{
+  return (offsetT)0;
+}
+
+unsigned char
+aarch64_sframe_get_abi_arch (void)
+{
+  if (aarch64_support_sframe_p ())
+    return sframe_get_abi_arch_callback ("aarch64", target_big_endian);
+  else
+    return 0;
+}
+
 #endif /* OBJ_ELF */
 
 /* Convert REGNAME to a DWARF-2 register number.  */
@@ -9665,6 +9700,12 @@ md_begin (void)
   mach = ilp32_p ? bfd_mach_aarch64_ilp32 : bfd_mach_aarch64;
 
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
+#ifdef OBJ_ELF
+  /* FIXME - is there a better way to do it ?  */
+  aarch64_sframe_cfa_sp_reg = 31;
+  aarch64_sframe_cfa_fp_reg = 29; /* x29.  */
+  aarch64_sframe_cfa_ra_reg = 30;
+#endif
 }
 
 /* Command line processing.  */
diff --git a/gas/config/tc-aarch64.h b/gas/config/tc-aarch64.h
index f5c17523796..da038f5d06a 100644
--- a/gas/config/tc-aarch64.h
+++ b/gas/config/tc-aarch64.h
@@ -235,6 +235,35 @@ struct aarch64_segment_info_type
 /* We want .cfi_* pseudo-ops for generating unwind info.  */
 #define TARGET_USE_CFIPOP              1
 
+/* Whether SFrame unwind info is supported.  */
+extern bool aarch64_support_sframe_p (void);
+#define support_sframe_p aarch64_support_sframe_p
+
+/* The stack-pointer register number for SFrame unwind info.  */
+extern unsigned int aarch64_sframe_cfa_sp_reg;
+#define SFRAME_CFA_SP_REG aarch64_sframe_cfa_sp_reg
+
+/* The base-pointer register number for CFA unwind info.  */
+extern unsigned int aarch64_sframe_cfa_fp_reg;
+#define SFRAME_CFA_FP_REG aarch64_sframe_cfa_fp_reg
+
+/* The return address register number for CFA unwind info.  */
+extern unsigned int aarch64_sframe_cfa_ra_reg;
+#define SFRAME_CFA_RA_REG aarch64_sframe_cfa_ra_reg
+
+/* Specify if RA tracking is needed.  */
+extern bool aarch64_sframe_ra_tracking_p (void);
+#define sframe_ra_tracking_p aarch64_sframe_ra_tracking_p
+
+/* Specify the fixed offset to recover RA from CFA.
+   (useful only when RA tracking is not needed).  */
+extern offsetT aarch64_sframe_cfa_ra_offset (void);
+#define sframe_cfa_ra_offset aarch64_sframe_cfa_ra_offset
+
+/* The abi/arch indentifier for SFrame.  */
+unsigned char aarch64_sframe_get_abi_arch (void);
+#define sframe_get_abi_arch aarch64_sframe_get_abi_arch
+
 /* CFI hooks.  */
 #define tc_regname_to_dw2regnum            tc_aarch64_regname_to_dw2regnum
 #define tc_cfi_frame_initial_instructions  tc_aarch64_frame_initial_instructions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 6598b0e52f1..f8872e593fc 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -30,6 +30,7 @@
 #include "subsegs.h"
 #include "dwarf2dbg.h"
 #include "dw2gencfi.h"
+#include "gen-sframe.h"
 #include "elf/x86-64.h"
 #include "opcodes/i386-init.h"
 #include <limits.h>
@@ -587,6 +588,12 @@ static int use_big_obj = 0;
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 /* 1 if generating code for a shared library.  */
 static int shared = 0;
+
+unsigned int x86_sframe_cfa_sp_reg;
+/* The other CFA base register for SFrame unwind info.  */
+unsigned int x86_sframe_cfa_fp_reg;
+unsigned int x86_sframe_cfa_ra_reg;
+
 #endif
 
 /* 1 for intel syntax,
@@ -3078,6 +3085,10 @@ md_begin (void)
       x86_dwarf2_return_column = 16;
 #endif
       x86_cie_data_alignment = -8;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+      x86_sframe_cfa_sp_reg = 7;
+      x86_sframe_cfa_fp_reg = 6;
+#endif
     }
   else
     {
@@ -9131,6 +9142,39 @@ x86_cleanup (void)
   if (seg && subseg)
     subseg_set (seg, subseg);
 }
+
+bool
+x86_support_sframe_p (void)
+{
+  /* At this time, SFrame unwind is supported for AMD64 ABI only.  */
+  return (x86_elf_abi == X86_64_ABI);
+}
+
+bool
+x86_sframe_ra_tracking_p (void)
+{
+  /* In AMD64, return address is always stored on the stack at a fixed offset
+     from the CFA (provided via x86_sframe_cfa_ra_offset ()).
+     Do not track explicitly via an SFrame Frame Row Entry.  */
+  return false;
+}
+
+offsetT
+x86_sframe_cfa_ra_offset (void)
+{
+  gas_assert (x86_elf_abi == X86_64_ABI);
+  return (offsetT)-8;
+}
+
+unsigned char
+x86_sframe_get_abi_arch (void)
+{
+  if (x86_support_sframe_p ())
+    return sframe_get_abi_arch_callback ("x86-64", target_big_endian);
+  else
+    return 0;
+}
+
 #endif
 
 static unsigned int
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
index a6e096ee110..90037269eea 100644
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -362,6 +362,32 @@ extern bfd_vma x86_64_section_letter (int, const char **);
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 extern void x86_cleanup (void);
 #define md_cleanup() x86_cleanup ()
+
+/* Whether SFrame unwind info is supported.  */
+extern bool x86_support_sframe_p (void);
+#define support_sframe_p x86_support_sframe_p
+
+/* The stack-pointer register number for SFrame unwind info.  */
+extern unsigned int x86_sframe_cfa_sp_reg;
+#define SFRAME_CFA_SP_REG x86_sframe_cfa_sp_reg
+
+/* The frame-pointer register number for CFA unwind info.  */
+extern unsigned int x86_sframe_cfa_fp_reg;
+#define SFRAME_CFA_FP_REG x86_sframe_cfa_fp_reg
+
+/* Specify if RA tracking is needed.  */
+extern bool x86_sframe_ra_tracking_p (void);
+#define sframe_ra_tracking_p x86_sframe_ra_tracking_p
+
+/* Specify the fixed offset to recover RA from CFA.
+   (useful only when RA tracking is not needed).  */
+extern offsetT x86_sframe_cfa_ra_offset (void);
+#define sframe_cfa_ra_offset x86_sframe_cfa_ra_offset
+
+/* The abi/arch indentifier for SFrame.  */
+extern unsigned char x86_sframe_get_abi_arch (void);
+#define sframe_get_abi_arch x86_sframe_get_abi_arch
+
 #endif
 
 #ifdef TE_PE
diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
index b7403ac45d4..f7a28d32d0c 100644
--- a/gas/config/tc-xtensa.c
+++ b/gas/config/tc-xtensa.c
@@ -8616,6 +8616,7 @@ unrelaxed_frag_max_size (fragS *fragP)
     case rs_leb128:
     case rs_cfa:
     case rs_dwarf2dbg:
+    case rs_sframe:
       /* No further adjustments needed.  */
       break;
     case rs_machine_dependent:
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index 40f48b733af..c969ed20d47 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -4850,11 +4850,15 @@ Each expression is assembled into the next byte.
 @subsection @code{.cfi_sections @var{section_list}}
 @cindex @code{cfi_sections} directive
 @code{.cfi_sections} may be used to specify whether CFI directives
-should emit @code{.eh_frame} section and/or @code{.debug_frame} section.
-If @var{section_list} is @code{.eh_frame}, @code{.eh_frame} is emitted,
-if @var{section_list} is @code{.debug_frame}, @code{.debug_frame} is emitted.
-To emit both use @code{.eh_frame, .debug_frame}.  The default if this
-directive is not used is @code{.cfi_sections .eh_frame}.
+should emit @code{.eh_frame} section, @code{.debug_frame} section and/or
+@code{.sframe} section.  If @var{section_list} contains @code{.eh_frame},
+@code{.eh_frame} is emitted, if @var{section_list} contains
+@code{.debug_frame}, @code{.debug_frame} is emitted, and finally, if
+@var{section_list} contains @code{.sframe}, @code{.sframe} is emitted.
+To emit multiple sections, specify them together in a list.  For example, to
+emit both @code{.eh_frame} and @code{.debug_frame}, use
+@code{.eh_frame, .debug_frame}.  The default if this directive is not used
+is @code{.cfi_sections .eh_frame}.
 
 On targets that support compact unwinding tables these can be generated
 by specifying @code{.eh_frame_entry} instead of @code{.eh_frame}.
diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c
index 6be8cb50495..2dda9986755 100644
--- a/gas/dw2gencfi.c
+++ b/gas/dw2gencfi.c
@@ -23,6 +23,7 @@
 #include "dw2gencfi.h"
 #include "subsegs.h"
 #include "dwarf2dbg.h"
+#include "gen-sframe.h"
 
 #ifdef TARGET_USE_CFIPOP
 
@@ -1231,6 +1232,8 @@ dot_cfi_sections (int ignored ATTRIBUTE_UNUSED)
 	else if (strcmp (name, tc_cfi_section_name) == 0)
 	  sections |= CFI_EMIT_target;
 #endif
+	else if (startswith (name, ".sframe"))
+	    sections |= CFI_EMIT_sframe;
 	else
 	  {
 	    *input_line_pointer = c;
@@ -2471,6 +2474,33 @@ cfi_finish (void)
       flag_traditional_format = save_flag_traditional_format;
     }
 
+  cfi_sections_set = true;
+  // FIXME - remove this commented line once the compiler can specify
+  // .sframe for .cfi_sections directive
+  // if ((all_cfi_sections & CFI_EMIT_sframe) != 0)
+  if (flag_gen_sframe || (all_cfi_sections & CFI_EMIT_sframe) != 0)
+    {
+#ifdef support_sframe_p
+      if (support_sframe_p ())
+	{
+	  segT sframe_seg;
+	  int alignment = ffs (DWARF2_ADDR_SIZE (stdoutput)) - 1;
+
+	  if (!SUPPORT_FRAME_LINKONCE)
+	    sframe_seg = get_cfi_seg (NULL, ".sframe",
+					 (SEC_ALLOC | SEC_LOAD | SEC_DATA
+					  | DWARF2_EH_FRAME_READ_ONLY),
+					 alignment);
+	  output_sframe (sframe_seg);
+	}
+      else
+	as_warn (_(".sframe not supported for target"));
+
+#else
+	as_warn (_(".sframe not supported for target"));
+#endif
+    }
+
   cfi_sections_set = true;
   if ((all_cfi_sections & CFI_EMIT_debug_frame) != 0)
     {
diff --git a/gas/dw2gencfi.h b/gas/dw2gencfi.h
index d570cdb8db3..3863ec37a53 100644
--- a/gas/dw2gencfi.h
+++ b/gas/dw2gencfi.h
@@ -200,5 +200,6 @@ extern struct fde_entry *all_fde_data;
 #define CFI_EMIT_debug_frame            (1 << 1)
 #define CFI_EMIT_target                 (1 << 2)
 #define CFI_EMIT_eh_frame_compact       (1 << 3)
+#define CFI_EMIT_sframe              (1 << 4)
 
 #endif /* DW2GENCFI_H */
diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
new file mode 100644
index 00000000000..1ad7856ffc9
--- /dev/null
+++ b/gas/gen-sframe.c
@@ -0,0 +1,1300 @@
+/* gen-sframe.c - Support for generating SFrame section.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS 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, or (at your option)
+   any later version.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#include "as.h"
+#include "subsegs.h"
+#include "sframe.h"
+#include "gen-sframe.h"
+#include "dw2gencfi.h"
+
+#ifdef support_sframe_p
+
+/* By default, use 32-bit relocations from .sframe into .text.  */
+#ifndef SFRAME_RELOC_SIZE
+# define SFRAME_RELOC_SIZE 4
+#endif
+
+/* Whether frame row entries track RA.
+
+   A target may not need return address tracking for stack unwinding.  If it
+   does need the same, SFRAME_CFA_RA_REG must be defined with the return
+   address register number.  */
+
+#if defined (sframe_ra_tracking_p) && defined (SFRAME_CFA_RA_REG)
+# ifndef SFRAME_FRE_RA_TRACKING
+# define SFRAME_FRE_RA_TRACKING 1
+# endif
+#endif
+
+/* SFrame FRE type selection optimization is an optimization for size.
+
+   There are three flavors of SFrame FRE representation in the binary format:
+     - sframe_frame_row_entry_addr1 where the FRE start address is 1 byte.
+     - sframe_frame_row_entry_addr2 where the FRE start address is 2 bytes.
+     - sframe_frame_row_entry_addr4 where the FRE start address is 4 bytes.
+
+   Note that in the SFrame format, all SFrame FREs of a function use one
+   single representation.  The SFrame FRE type itself is identified via the
+   information in the SFrame FDE function info.
+
+   Now, to select the minimum required one from the list above, one needs to
+   make a decision based on the size (in bytes) of the function.
+
+   As a result, for this optimization, some fragments (generated with a new
+   type rs_sframe) for the SFrame section are fixed up later.
+
+   This optimization (for size) is enabled by default.  */
+
+#ifndef SFRAME_FRE_TYPE_SELECTION_OPT
+# define SFRAME_FRE_TYPE_SELECTION_OPT 1
+#endif
+
+/* Emit a single byte into the current segment.  */
+
+static inline void
+out_one (int byte)
+{
+  FRAG_APPEND_1_CHAR (byte);
+}
+
+/* Emit a two-byte word into the current segment.  */
+
+static inline void
+out_two (int data)
+{
+  md_number_to_chars (frag_more (2), data, 2);
+}
+
+/* Emit a four byte word into the current segment.  */
+
+static inline void
+out_four (int data)
+{
+  md_number_to_chars (frag_more (4), data, 4);
+}
+
+/* Get the start address symbol from the DWARF FDE.  */
+
+static symbolS*
+get_dw_fde_start_addrS (const struct fde_entry *dw_fde)
+{
+  return dw_fde->start_address;
+}
+
+/* Get the start address symbol from the DWARF FDE.  */
+
+static symbolS*
+get_dw_fde_end_addrS (const struct fde_entry *dw_fde)
+{
+  return dw_fde->end_address;
+}
+
+/* Callback to create the abi/arch identifier for SFrame section.  */
+
+unsigned char
+sframe_get_abi_arch_callback (const char *target_arch,
+			      int big_endian_p)
+{
+  unsigned char sframe_abi_arch = 0;
+
+  if (strcmp (target_arch, "aarch64") == 0)
+    {
+      sframe_abi_arch = big_endian_p
+	? SFRAME_ABI_AARCH64_ENDIAN_BIG
+	: SFRAME_ABI_AARCH64_ENDIAN_LITTLE;
+    }
+  else if (strcmp (target_arch, "x86-64") == 0)
+    {
+      gas_assert (!big_endian_p);
+      sframe_abi_arch = SFRAME_ABI_AMD64_ENDIAN_LITTLE;
+    }
+  else
+    {
+      /* Other abi/arch are not supported.  Should be unreachable.  */
+      printf (_("SFrame Unsupported abi or arch\n"));
+      abort ();
+    }
+
+  return sframe_abi_arch;
+}
+
+/* SFrame Frame Row Entry (FRE) related functions.  */
+
+static void
+sframe_fre_set_begin_addr (struct sframe_row_entry *fre, symbolS *beginS)
+{
+  fre->pc_begin = beginS;
+}
+
+static void
+sframe_fre_set_end_addr (struct sframe_row_entry *fre, symbolS *endS)
+{
+  fre->pc_end = endS;
+}
+
+static void
+sframe_fre_set_cfa_base_reg (struct sframe_row_entry *fre,
+			     unsigned int cfa_base_reg)
+{
+  fre->cfa_base_reg = cfa_base_reg;
+  fre->merge_candidate = false;
+}
+
+static void
+sframe_fre_set_cfa_offset (struct sframe_row_entry *fre,
+			   offsetT cfa_offset)
+{
+  fre->cfa_offset = cfa_offset;
+  fre->merge_candidate = false;
+}
+
+#ifdef SFRAME_FRE_RA_TRACKING
+static void
+sframe_fre_set_ra_track (struct sframe_row_entry *fre, offsetT ra_offset)
+{
+  fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK;
+  fre->ra_offset = ra_offset;
+  fre->merge_candidate = false;
+}
+#endif
+
+static void
+sframe_fre_set_bp_track (struct sframe_row_entry *fre, offsetT bp_offset)
+{
+  fre->bp_loc = SFRAME_FRE_ELEM_LOC_STACK;
+  fre->bp_offset = bp_offset;
+  fre->merge_candidate = false;
+}
+
+/* All stack offset values within an FRE are uniformly encoded in the same
+   number of bytes.  The size of the stack offset values will, however, vary
+   across FREs.  */
+
+#define VALUE_8BIT  0x7f
+#define VALUE_16BIT 0x7fff
+#define VALUE_32BIT 0x7fffffff
+#define VALUE_64BIT 0x7fffffffffffffff
+
+/* Given a signed offset, return the size in bytes needed to represent it.  */
+
+static unsigned int
+get_offset_size_in_bytes (offsetT value)
+{
+  unsigned int size = 0;
+
+  if (value <= VALUE_8BIT && value >= (long)-VALUE_8BIT)
+    size = 1;
+  else if (value <= VALUE_16BIT && value >= (long)-VALUE_16BIT)
+    size = 2;
+  else if (value <= VALUE_32BIT && value >= (long)-VALUE_32BIT)
+    size = 4;
+  else if (value <= VALUE_64BIT && value >= (long)-VALUE_64BIT)
+    size = 8;
+
+  return size;
+}
+
+#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B  0 /* SFRAME_FRE_OFFSET_1B.  */
+#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B  1 /* SFRAME_FRE_OFFSET_2B.  */
+#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B  2 /* SFRAME_FRE_OFFSET_4B.  */
+#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B  3 /* Not supported in SFrame.  */
+#define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B
+
+/* Helper struct for mapping offset size to output functions.  */
+
+struct sframe_fre_offset_func_map
+{
+  unsigned int offset_size;
+  void (*out_func)(int);
+};
+
+/* Given an OFFSET_SIZE, return the size in bytes needed to represent it.  */
+
+static unsigned int
+sframe_fre_offset_func_map_index (unsigned int offset_size)
+{
+  unsigned int index = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX;
+
+  switch (offset_size)
+    {
+      case SFRAME_FRE_OFFSET_1B:
+	index = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B;
+	break;
+      case SFRAME_FRE_OFFSET_2B:
+	index = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B;
+	break;
+      case SFRAME_FRE_OFFSET_4B:
+	index = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B;
+	break;
+      default:
+	/* Not supported in SFrame.  */
+	break;
+    }
+
+  return index;
+}
+
+/* Mapping from offset size to the output function to emit the value.  */
+
+static const
+struct sframe_fre_offset_func_map
+fre_offset_func_map[SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX+1] =
+{
+  { SFRAME_FRE_OFFSET_1B, out_one },
+  { SFRAME_FRE_OFFSET_2B, out_two },
+  { SFRAME_FRE_OFFSET_4B, out_four },
+  { -1, NULL } /* Not Supported in SFrame.  */
+};
+
+/* SFrame version specific operations access.  */
+
+static struct sframe_version_ops sframe_ver_ops;
+
+/* SFrame (SFRAME_VERSION_1) set FRE info.  */
+
+static unsigned char
+sframe_v1_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
+			unsigned int offset_size)
+{
+  unsigned char fre_info;
+  fre_info = SFRAME_V1_FRE_INFO (base_reg, num_offsets, offset_size);
+  return fre_info;
+}
+
+/* SFrame (SFRAME_VERSION_1) set function info.  */
+static unsigned char
+sframe_v1_set_func_info (unsigned int fde_type, unsigned int fre_type)
+{
+  unsigned char func_info;
+  func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
+  return func_info;
+}
+
+/* SFrame version specific operations setup.  */
+
+static void
+sframe_set_version (uint32_t sframe_version __attribute__((unused)))
+{
+  sframe_ver_ops.format_version = SFRAME_VERSION_1;
+
+  sframe_ver_ops.set_fre_info = sframe_v1_set_fre_info;
+
+  sframe_ver_ops.set_func_info = sframe_v1_set_func_info;
+}
+
+/* SFrame set FRE info.  */
+
+static unsigned char
+sframe_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
+		     unsigned int offset_size)
+{
+  return sframe_ver_ops.set_fre_info (base_reg, num_offsets,
+					 offset_size);
+}
+
+/* SFrame set func info. */
+
+ATTRIBUTE_UNUSED static unsigned char
+sframe_set_func_info (unsigned int fde_type, unsigned int fre_type)
+{
+  return sframe_ver_ops.set_func_info (fde_type, fre_type);
+}
+
+/* Get the number of SFrame FDEs for the current file.  */
+
+static unsigned int
+get_num_sframe_fdes (void);
+
+/* Get the number of SFrame frame row entries for the current file.  */
+
+static unsigned int
+get_num_sframe_fres (void);
+
+/* Get CFA base register ID as represented in SFrame Frame Row Entry.  */
+
+static unsigned int
+get_fre_base_reg_id (struct sframe_row_entry *sframe_fre)
+{
+  unsigned int cfi_insn_cfa_base_reg = sframe_fre->cfa_base_reg;
+  unsigned fre_base_reg = SFRAME_BASE_REG_SP;
+
+  if (cfi_insn_cfa_base_reg == SFRAME_CFA_FP_REG)
+    fre_base_reg = SFRAME_BASE_REG_FP;
+
+  /* Only one bit is reserved in SFRAME_VERSION_1.  */
+  gas_assert (fre_base_reg == SFRAME_BASE_REG_SP
+	      || fre_base_reg == SFRAME_BASE_REG_FP);
+
+  return fre_base_reg;
+}
+
+/* Get number of offsets necessary for the SFrame Frame Row Entry.  */
+
+static unsigned int
+get_fre_num_offsets (struct sframe_row_entry *sframe_fre)
+{
+  /* Atleast 1 must always be present (to recover CFA).  */
+  unsigned int fre_num_offsets = 1;
+
+  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
+    fre_num_offsets++;
+#ifdef SFRAME_FRE_RA_TRACKING
+  if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
+    fre_num_offsets++;
+#endif
+  return fre_num_offsets;
+}
+
+/* Get the minimum necessary offset size (in bytes) for this
+   SFrame frame row entry.  */
+
+static unsigned int
+sframe_get_fre_offset_size (struct sframe_row_entry *sframe_fre)
+{
+  unsigned int max_offset_size = 0;
+  unsigned int cfa_offset_size = 0;
+  unsigned int bp_offset_size = 0;
+  unsigned int ra_offset_size = 0;
+
+  unsigned int fre_offset_size = 0;
+
+  /* What size of offsets appear in this frame row entry.  */
+  cfa_offset_size = get_offset_size_in_bytes (sframe_fre->cfa_offset);
+  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
+    bp_offset_size = get_offset_size_in_bytes (sframe_fre->bp_offset);
+#ifdef SFRAME_FRE_RA_TRACKING
+  if (sframe_ra_tracking_p ()
+      && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
+    ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
+#endif
+
+  /* Get the maximum size needed to represent the offsets.  */
+  max_offset_size = cfa_offset_size;
+  if (bp_offset_size > max_offset_size)
+    max_offset_size = bp_offset_size;
+  if (ra_offset_size > max_offset_size)
+    max_offset_size = ra_offset_size;
+
+  gas_assert (max_offset_size);
+
+  switch (max_offset_size)
+    {
+    case 1:
+      fre_offset_size = SFRAME_FRE_OFFSET_1B;
+      break;
+    case 2:
+      fre_offset_size = SFRAME_FRE_OFFSET_2B;
+      break;
+    case 4:
+      fre_offset_size = SFRAME_FRE_OFFSET_4B;
+      break;
+    default:
+      /* Offset of size 8 bytes is not supported in SFrame format
+	 version 1.  */
+      printf (_("SFrame unsupported offset value\n"));
+      abort ();
+      break;
+    }
+
+  return fre_offset_size;
+}
+
+#if SFRAME_FRE_TYPE_SELECTION_OPT
+
+/* Create a composite exression CEXP (for SFrame FRE start address) such that:
+
+      exp = <val> OP_absent <width>, where,
+
+    - <val> and <width> are themselves expressionS.
+    - <val> stores the expression which when evaluated gives the value of the
+      start address offset of the FRE.
+    - <width> stores the expression when when evaluated gives the number of
+      bytes needed to encode the start address offset of the FRE.
+
+   The use of OP_absent as the X_op_symbol helps identify this expression
+   later when fragments are fixed up.  */
+
+static void
+create_fre_start_addr_exp (expressionS *cexp, symbolS *fre_pc_begin,
+			   symbolS *fde_start_address,
+			   symbolS *fde_end_address)
+{
+  expressionS val;
+  expressionS width;
+
+  /* val expression stores the FDE start address offset from the start PC
+     of function.  */
+  val.X_op = O_subtract;
+  val.X_add_symbol = fre_pc_begin;
+  val.X_op_symbol = fde_start_address;
+  val.X_add_number = 0;
+
+  /* width expressions stores the size of the function.  This is used later
+     to determine the number of bytes to be used to encode the FRE start
+     address of each FRE of the function.  */
+  width.X_op = O_subtract;
+  width.X_add_symbol = fde_end_address;
+  width.X_op_symbol = fde_start_address;
+  width.X_add_number = 0;
+
+  cexp->X_op = O_absent;
+  cexp->X_add_symbol = make_expr_symbol (&val);
+  cexp->X_op_symbol = make_expr_symbol (&width);
+  cexp->X_add_number = 0;
+}
+
+#endif
+
+static void
+output_sframe_row_entry (symbolS *fde_start_addr,
+			 symbolS *fde_end_addr,
+			 struct sframe_row_entry *sframe_fre)
+{
+  unsigned char fre_info;
+  unsigned int fre_num_offsets;
+  unsigned int fre_offset_size;
+  unsigned int fre_base_reg;
+  expressionS exp;
+  unsigned int fre_addr_size;
+
+  unsigned int index = 0;
+  unsigned int fre_write_offsets = 0;
+
+  fre_addr_size = 4; /* 4 bytes by default.   FIXME tie it to fre_type? */
+
+  /* SFrame FRE Start Address.  */
+#if SFRAME_FRE_TYPE_SELECTION_OPT
+  create_fre_start_addr_exp (&exp, sframe_fre->pc_begin, fde_start_addr,
+			     fde_end_addr);
+  frag_grow (fre_addr_size);
+  frag_var (rs_sframe, fre_addr_size, 0, (relax_substateT) 0,
+	    make_expr_symbol (&exp), 0, (char *) frag_now);
+#else
+  gas_assert (fde_end_addr);
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = sframe_fre->pc_begin; /* to.  */
+  exp.X_op_symbol = fde_start_addr; /* from.  */
+  exp.X_add_number = 0;
+  emit_expr (&exp, fre_addr_size);
+#endif
+
+  /* Create the fre_info using the CFA base register, number of offsets and max
+     size of offset in this frame row entry.  */
+  fre_base_reg = get_fre_base_reg_id (sframe_fre);
+  fre_num_offsets = get_fre_num_offsets (sframe_fre);
+  fre_offset_size = sframe_get_fre_offset_size (sframe_fre);
+  fre_info = sframe_set_fre_info (fre_base_reg, fre_num_offsets,
+				     fre_offset_size);
+  out_one (fre_info);
+
+  index = sframe_fre_offset_func_map_index (fre_offset_size);
+  gas_assert (index < SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX);
+
+  /* Write out the offsets in order - cfa, bp, ra.  */
+  fre_offset_func_map[index].out_func (sframe_fre->cfa_offset);
+  fre_write_offsets++;
+
+  if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
+    {
+      fre_offset_func_map[index].out_func (sframe_fre->bp_offset);
+      fre_write_offsets++;
+    }
+
+#ifdef SFRAME_FRE_RA_TRACKING
+  if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
+    {
+      fre_offset_func_map[index].out_func (sframe_fre->ra_offset);
+      fre_write_offsets++;
+    }
+#endif
+  /* Check if the expected number offsets have been written out
+     in this FRE.  */
+  gas_assert (fre_write_offsets == fre_num_offsets);
+}
+
+static void
+output_sframe_funcdesc (symbolS *start_of_fre_section,
+			symbolS *fre_symbol,
+			struct sframe_func_entry *sframe_fde)
+{
+  expressionS exp;
+  unsigned int addr_size;
+  symbolS *dw_fde_start_addrS, *dw_fde_end_addrS;
+
+  addr_size = SFRAME_RELOC_SIZE;
+  dw_fde_start_addrS = get_dw_fde_start_addrS (sframe_fde->dw_fde);
+  dw_fde_end_addrS = get_dw_fde_end_addrS (sframe_fde->dw_fde);
+
+  /* Start address of the function.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = dw_fde_start_addrS; /* to location.  */
+  exp.X_op_symbol = symbol_temp_new_now (); /* from location.  */
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  /* Size of the function in bytes.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = dw_fde_end_addrS;
+  exp.X_op_symbol = dw_fde_start_addrS;
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  /* Offset to the first frame row entry.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = fre_symbol; /* Minuend.  */
+  exp.X_op_symbol = start_of_fre_section; /* Subtrahend.  */
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  /* Number of FREs.  */
+  out_four (sframe_fde->num_fres);
+
+  /* SFrame FDE function info.  */
+#if SFRAME_FRE_TYPE_SELECTION_OPT
+  expressionS width;
+  width.X_op = O_subtract;
+  width.X_add_symbol = dw_fde_end_addrS;
+  width.X_op_symbol = dw_fde_start_addrS;
+  width.X_add_number = 0;
+  frag_grow (1); /* Size of func info is unsigned char.  */
+  frag_var (rs_sframe, 1, 0, (relax_substateT) 0,
+	    make_expr_symbol (&width), 0, (char *) frag_now);
+#else
+  unsigned char func_info;
+  func_info = sframe_set_func_info (SFRAME_FDE_TYPE_PCINC,
+				    SFRAME_FRE_TYPE_ADDR4);
+  out_one (func_info);
+#endif
+}
+
+static void
+output_sframe_internal (void)
+{
+  expressionS exp;
+  unsigned int i = 0;
+
+  symbolS *end_of_frame_hdr;
+  symbolS *end_of_frame_section;
+  symbolS *start_of_func_desc_section;
+  symbolS *start_of_fre_section;
+  struct sframe_func_entry *sframe_fde;
+  struct sframe_row_entry *sframe_fre;
+  unsigned char abi_arch = 0;
+  int fixed_bp_offset = SFRAME_CFA_FIXED_FP_INVALID;
+  int fixed_ra_offset = SFRAME_CFA_FIXED_RA_INVALID;
+  unsigned int addr_size;
+
+  addr_size = SFRAME_RELOC_SIZE;
+
+  /* The function desciptor entries as dumped by the assembler are not
+     sorted on PCs.  */
+  unsigned char sframe_flags = 0;
+  sframe_flags |= !SFRAME_F_FDE_SORTED;
+
+  unsigned int num_fdes = get_num_sframe_fdes ();
+  unsigned int num_fres = get_num_sframe_fres ();
+  symbolS **fre_symbols = XNEWVEC (symbolS *, num_fres);
+  for (i = 0; i < num_fres; i++)
+    fre_symbols[i] = symbol_temp_make ();
+
+  end_of_frame_hdr = symbol_temp_make ();
+  start_of_fre_section = symbol_temp_make ();
+  start_of_func_desc_section = symbol_temp_make ();
+  end_of_frame_section = symbol_temp_make ();
+
+  /* Output the preamble of SFrame section.  */
+  out_two (SFRAME_MAGIC);
+  out_one (SFRAME_VERSION);
+  out_one (sframe_flags);
+  /* abi/arch.  */
+#ifdef sframe_get_abi_arch
+  abi_arch = sframe_get_abi_arch ();
+#endif
+  gas_assert (abi_arch);
+  out_one (abi_arch);
+
+  /* Offset for the BP register from CFA.  Neither of the AMD64 or AAPCS64
+     ABIs have a fixed offset for the BP register from the CFA.  This may be
+     useful in future (but not without additional support in the toolchain)
+     for specialized handling/encoding for cases where, for example,
+     -fno-omit-frame-pointer is used.  */
+  out_one (fixed_bp_offset);
+
+  /* Offset for the return address from CFA is fixed for some ABIs
+     (e.g., AMD64), output a zero otherwise.  */
+#ifdef SFRAME_FRE_RA_TRACKING
+  if (!sframe_ra_tracking_p ())
+    fixed_ra_offset = sframe_cfa_ra_offset ();
+#endif
+  out_one (fixed_ra_offset);
+
+  out_four (num_fdes); /* Number of FDEs.  */
+  out_four (num_fres); /* Number of FREs.  */
+
+  /* FRE sub-section len.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = end_of_frame_section;
+  exp.X_op_symbol = start_of_fre_section;
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  /* Offset of Function Index sub-section.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = end_of_frame_hdr;
+  exp.X_op_symbol = start_of_func_desc_section;
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  /* Offset of FRE sub-section.  */
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = start_of_fre_section;
+  exp.X_op_symbol = end_of_frame_hdr;
+  exp.X_add_number = 0;
+  emit_expr (&exp, addr_size);
+
+  symbol_set_value_now (end_of_frame_hdr);
+  symbol_set_value_now (start_of_func_desc_section);
+
+  /* Output the SFrame function descriptor entries.  */
+  i = 0;
+  for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
+    {
+      output_sframe_funcdesc (start_of_fre_section,
+			      fre_symbols[i], sframe_fde);
+      i += sframe_fde->num_fres;
+    }
+
+  symbol_set_value_now (start_of_fre_section);
+
+  /* Output the SFrame FREs.  */
+  i = 0;
+  sframe_fde = all_sframe_fdes;
+
+  for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
+    {
+      for (sframe_fre = sframe_fde->sframe_fres;
+	   sframe_fre;
+	   sframe_fre = sframe_fre->next)
+	{
+	  symbol_set_value_now (fre_symbols[i]);
+	  output_sframe_row_entry (get_dw_fde_start_addrS (sframe_fde->dw_fde),
+				   get_dw_fde_end_addrS (sframe_fde->dw_fde),
+				   sframe_fre);
+	  i++;
+	}
+    }
+
+  symbol_set_value_now (end_of_frame_section);
+
+  gas_assert (i == num_fres);
+
+  free (fre_symbols);
+  fre_symbols = NULL;
+}
+
+/* List of SFrame FDE entries.  */
+
+struct sframe_func_entry *all_sframe_fdes;
+
+/* Tail of the list to add to.  */
+
+static struct sframe_func_entry **last_sframe_fde = &all_sframe_fdes;
+
+static unsigned int
+get_num_sframe_fdes (void)
+{
+  struct sframe_func_entry *sframe_fde;
+  unsigned int total_fdes = 0;
+
+  for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
+    total_fdes++;
+
+  return total_fdes;
+}
+
+/* Get the total number of SFrame row entries across the FDEs.  */
+
+static unsigned int
+get_num_sframe_fres (void)
+{
+  struct sframe_func_entry *sframe_fde;
+  unsigned int total_fres = 0;
+
+  for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
+    total_fres += sframe_fde->num_fres;
+
+  return total_fres;
+}
+
+/* Allocate an SFrame FDE.  */
+
+static struct sframe_func_entry*
+sframe_fde_alloc (void)
+{
+  struct sframe_func_entry *sframe_fde = XCNEW (struct sframe_func_entry);
+  return sframe_fde;
+}
+
+/* Link the SFrame FDE in.  */
+
+static int
+sframe_fde_link (struct sframe_func_entry *sframe_fde)
+{
+  *last_sframe_fde = sframe_fde;
+  last_sframe_fde = &sframe_fde->next;
+
+  return 0;
+}
+
+/* Free up the SFrame FDE.  */
+
+static void
+sframe_fde_free (struct sframe_func_entry *sframe_fde)
+{
+  XDELETE (sframe_fde);
+  sframe_fde = NULL;
+}
+
+/* SFrame translation context functions.  */
+
+/* Allocate a new SFrame translation context.  */
+
+static struct sframe_xlate_ctx*
+sframe_xlate_ctx_alloc (void)
+{
+  struct sframe_xlate_ctx* xlate_ctx = XCNEW (struct sframe_xlate_ctx);
+  return xlate_ctx;
+}
+
+/* Initialize the given SFrame translation context.  */
+
+static void
+sframe_xlate_ctx_init (struct sframe_xlate_ctx *xlate_ctx)
+{
+  xlate_ctx->dw_fde = NULL;
+  xlate_ctx->first_fre = NULL;
+  xlate_ctx->last_fre = NULL;
+  xlate_ctx->cur_fre = NULL;
+  xlate_ctx->remember_fre = NULL;
+  xlate_ctx->num_xlate_fres = 0;
+}
+
+/* Cleanup the given SFrame translation context.  */
+
+static void
+sframe_xlate_ctx_cleanup (struct sframe_xlate_ctx *xlate_ctx)
+{
+  struct sframe_row_entry *fre, *fre_next;
+
+  if (xlate_ctx->num_xlate_fres)
+  {
+    fre = xlate_ctx->first_fre;
+    while (fre)
+    {
+      fre_next = fre->next;
+      XDELETE (fre);
+      fre = fre_next;
+    }
+  }
+
+  sframe_xlate_ctx_init (xlate_ctx);
+}
+
+/* Transfer the state from the SFrame translation context to the SFrame FDE.  */
+
+static void
+sframe_xlate_ctx_finalize (struct sframe_xlate_ctx *xlate_ctx,
+			   struct sframe_func_entry *sframe_fde)
+{
+  sframe_fde->dw_fde = xlate_ctx->dw_fde;
+  sframe_fde->sframe_fres = xlate_ctx->first_fre;
+  sframe_fde->num_fres = xlate_ctx->num_xlate_fres;
+}
+
+static struct sframe_row_entry*
+sframe_row_entry_new (void)
+{
+  struct sframe_row_entry *fre = XCNEW (struct sframe_row_entry);
+  /* Reset cfa_base_reg to -1.  A value of 0 will imply some valid register
+     for the supported arches.  */
+  fre->cfa_base_reg = -1;
+  fre->merge_candidate = true;
+
+  return fre;
+}
+
+/* Add the given FRE in the list of frame row entries in the given FDE
+   translation context.  */
+
+static void
+sframe_xlate_ctx_add_fre (struct sframe_xlate_ctx *xlate_ctx,
+			 struct sframe_row_entry *fre)
+{
+  gas_assert (xlate_ctx && fre);
+
+  /* Add the frame row entry.  */
+  if (!xlate_ctx->first_fre)
+    xlate_ctx->first_fre = fre;
+  else if (xlate_ctx->last_fre)
+    xlate_ctx->last_fre->next = fre;
+
+  xlate_ctx->last_fre = fre;
+
+  /* Keep track of the total number of SFrame frame row entries.  */
+  xlate_ctx->num_xlate_fres++;
+}
+
+/* A SFrame Frame Row Entry is self-sufficient in terms of unwind information
+   for a given PC.  It contains information assimilated from multiple CFI
+   instructions, and hence, a new SFrame FRE is initialized with the data from
+   the previous known FRE, if any.
+
+   Understandably, not all information (especially the instruction begin
+   and end boundaries) needs to be relayed.  Hence, the caller of this API
+   must set the pc_begin and pc_end as applicable.  */
+
+static void
+sframe_row_entry_initialize (struct sframe_row_entry *cur_fre,
+			     struct sframe_row_entry *prev_fre)
+{
+  gas_assert (prev_fre);
+  cur_fre->cfa_base_reg = prev_fre->cfa_base_reg;
+  cur_fre->cfa_offset = prev_fre->cfa_offset;
+  cur_fre->bp_loc = prev_fre->bp_loc;
+  cur_fre->bp_offset = prev_fre->bp_offset;
+  cur_fre->ra_loc = prev_fre->ra_loc;
+  cur_fre->ra_offset = prev_fre->ra_offset;
+}
+
+static int
+sframe_xlate_do_advance_loc (struct sframe_xlate_ctx *xlate_ctx,
+			     struct cfi_insn_data *cfi_insn)
+{
+  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
+  /* Get the scratchpad FRE currently being updated as the cfi_insn's
+     get interpreted.  This FRE eventually gets linked in into the
+     list of FREs for the specific function.  */
+  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  if (cur_fre)
+    {
+      if (!cur_fre->merge_candidate)
+	{
+	  sframe_fre_set_end_addr (cur_fre, cfi_insn->u.ll.lab2);
+
+	  sframe_xlate_ctx_add_fre (xlate_ctx, cur_fre);
+	  last_fre = xlate_ctx->last_fre;
+
+	  xlate_ctx->cur_fre = sframe_row_entry_new ();
+	  cur_fre = xlate_ctx->cur_fre;
+
+	  if (last_fre)
+	    sframe_row_entry_initialize (cur_fre, last_fre);
+	}
+      else
+	{
+	  sframe_fre_set_end_addr (last_fre, cfi_insn->u.ll.lab2);
+	  gas_assert (last_fre->merge_candidate == false);
+	}
+    }
+  else
+    {
+      xlate_ctx->cur_fre = sframe_row_entry_new ();
+      cur_fre = xlate_ctx->cur_fre;
+    }
+
+  gas_assert (cur_fre);
+  sframe_fre_set_begin_addr (cur_fre, cfi_insn->u.ll.lab2);
+
+  return 0;
+}
+
+static int
+sframe_xlate_do_def_cfa (struct sframe_xlate_ctx *xlate_ctx,
+			 struct cfi_insn_data *cfi_insn)
+
+{
+  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
+  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+  if (!cur_fre)
+  {
+    xlate_ctx->cur_fre = sframe_row_entry_new ();
+    cur_fre = xlate_ctx->cur_fre;
+    sframe_fre_set_begin_addr (cur_fre,
+			       get_dw_fde_start_addrS (xlate_ctx->dw_fde));
+  }
+  /* Define the current CFA rule to use the provided register and
+     offset.  */
+  sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
+  sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.ri.offset);
+  cur_fre->merge_candidate = false;
+
+  return 0;
+}
+
+static int
+sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
+				  struct cfi_insn_data *cfi_insn)
+{
+  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
+  /* Get the scratchpad FRE.  This FRE will eventually get linked in.  */
+  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+  gas_assert (cur_fre);
+  /* Define the current CFA rule to use the provided register (but to
+     keep the old offset).  */
+  sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
+  sframe_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
+  cur_fre->merge_candidate = false;
+
+  return 0;
+}
+
+static int
+sframe_xlate_do_def_cfa_offset (struct sframe_xlate_ctx *xlate_ctx,
+				struct cfi_insn_data *cfi_insn)
+{
+  /* The scratchpad FRE currently being updated with each cfi_insn
+     being interpreted.  This FRE eventually gets linked in into the
+     list of FREs for the specific function.  */
+  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  gas_assert (cur_fre);
+  /*  Define the current CFA rule to use the provided offset (but to keep
+      the old register).  However, if the old register is not FP/SP,
+      skip creating SFrame unwind info for the function. */
+  if ((cur_fre->cfa_base_reg == SFRAME_CFA_FP_REG)
+      || (cur_fre->cfa_base_reg == SFRAME_CFA_SP_REG))
+    {
+      sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.i);
+      cur_fre->merge_candidate = false;
+    }
+  else
+    return -1;
+
+  return 0;
+}
+
+static int
+sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
+			struct cfi_insn_data *cfi_insn)
+{
+  /* The scratchpad FRE currently being updated with each cfi_insn
+     being interpreted.  This FRE eventually gets linked in into the
+     list of FREs for the specific function.  */
+  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  gas_assert (cur_fre);
+  /* Change the rule for the register indicated by the register number to
+     be the specified offset.  */
+  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
+    {
+      gas_assert (!cur_fre->base_reg);
+      sframe_fre_set_bp_track (cur_fre, cfi_insn->u.ri.offset);
+      cur_fre->merge_candidate = false;
+    }
+#ifdef SFRAME_FRE_RA_TRACKING
+  else if (sframe_ra_tracking_p ()
+	   && cfi_insn->u.r == SFRAME_CFA_RA_REG)
+    {
+      sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
+      cur_fre->merge_candidate = false;
+    }
+#endif
+  /* This is used to track changes to non-rsp registers, skip all others
+     except FP / RA for now.  */
+  return 0;
+}
+
+static int
+sframe_xlate_do_val_offset (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
+			    struct cfi_insn_data *cfi_insn)
+{
+  /* Previous value of register is CFA + offset.  However, if the specified
+     register is not interesting (FP or RA reg), the current DW_CFA_val_offset
+     instruction can be safely skipped without sacrificing the asynchonicity of
+     unwind information.  */
+  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
+    return 1; /* Not represented.  */
+#ifdef SFRAME_FRE_RA_TRACKING
+  else if (sframe_ra_tracking_p ()
+	   && cfi_insn->u.r == SFRAME_CFA_RA_REG)
+    return 1; /* Not represented.  */
+#endif
+
+  /* Safe to skip.  */
+  return 0;
+}
+
+
+static int
+sframe_xlate_do_remember_state (struct sframe_xlate_ctx *xlate_ctx)
+{
+  struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
+
+  /* If there is no FRE state to remember, nothing to do here.  Return
+     early with non-zero error code, this will cause no SFrame unwind info
+     for the function involved.  */
+  if (!last_fre)
+    return -1;
+
+  if (!xlate_ctx->remember_fre)
+    xlate_ctx->remember_fre = sframe_row_entry_new ();
+  sframe_row_entry_initialize (xlate_ctx->remember_fre, last_fre);
+
+  return 0;
+}
+
+static int
+sframe_xlate_do_restore_state (struct sframe_xlate_ctx *xlate_ctx)
+{
+  /* The scratchpad FRE currently being updated with each cfi_insn
+     being interpreted.  This FRE eventually gets linked in into the
+     list of FREs for the specific function.  */
+  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  gas_assert (xlate_ctx->remember_fre);
+  gas_assert (cur_fre && cur_fre->merge_candidate);
+
+  /* Get the CFA state from the DW_CFA_remember_state insn.  */
+  sframe_row_entry_initialize (cur_fre, xlate_ctx->remember_fre);
+  /* The PC boundaries of the current SFrame FRE are updated
+     via other machinery.  */
+  cur_fre->merge_candidate = false;
+  return 0;
+}
+
+static int
+sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
+			 struct cfi_insn_data *cfi_insn)
+{
+  struct sframe_row_entry *cie_fre = xlate_ctx->first_fre;
+  /* The scratchpad FRE currently being updated with each cfi_insn
+     being interpreted.  This FRE eventually gets linked in into the
+     list of FREs for the specific function.  */
+  struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
+
+  /* Change the rule for the indicated register to the rule assigned to
+     it by the initial_instructions in the CIE.  */
+  gas_assert (cie_fre);
+  /* SFrame FREs track only CFA and FP / RA for backtracing purposes;
+     skip the other .cfi_restore directives.  */
+  if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
+    {
+      gas_assert (cur_fre);
+      cur_fre->bp_loc = cie_fre->bp_loc;
+      cur_fre->bp_offset = cie_fre->bp_offset;
+      cur_fre->merge_candidate = false;
+    }
+#ifdef SFRAME_FRE_RA_TRACKING
+  else if (sframe_ra_tracking_p ()
+	   && cfi_insn->u.r == SFRAME_CFA_RA_REG)
+    {
+      gas_assert (cur_fre);
+      cur_fre->ra_loc = cie_fre->ra_loc;
+      cur_fre->ra_offset = cie_fre->ra_offset;
+      cur_fre->merge_candidate = false;
+    }
+#endif
+  return 0;
+}
+
+/* Process CFI_INSN and update the translation context with the FRE
+   information.
+
+   Returns an error code if CFI_INSN is not successfully processed.  */
+
+static int
+sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
+		    struct cfi_insn_data *cfi_insn)
+{
+  int err = 0;
+
+  /* Atleast one cfi_insn per FDE is expected.  */
+  gas_assert (cfi_insn);
+  int op = cfi_insn->insn;
+
+  switch (op)
+    {
+    case DW_CFA_advance_loc:
+      err = sframe_xlate_do_advance_loc (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_def_cfa:
+      err = sframe_xlate_do_def_cfa (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_def_cfa_register:
+      err = sframe_xlate_do_def_cfa_register (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_def_cfa_offset:
+      err = sframe_xlate_do_def_cfa_offset (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_offset:
+      err = sframe_xlate_do_offset (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_val_offset:
+      err = sframe_xlate_do_val_offset (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_remember_state:
+      err = sframe_xlate_do_remember_state (xlate_ctx);
+      break;
+    case DW_CFA_restore_state:
+      err = sframe_xlate_do_restore_state (xlate_ctx);
+      break;
+    case DW_CFA_restore:
+      err = sframe_xlate_do_restore (xlate_ctx, cfi_insn);
+      break;
+    case DW_CFA_undefined:
+    case DW_CFA_same_value:
+      break;
+    default:
+      {
+	/* Other CFI opcodes are not processed at this time.
+	   These do not impact the coverage of the basic stack unwinding
+	   information as conveyed in the SFrame format.
+	    - DW_CFA_register,
+	    - ...
+
+	   Following skipped operations do, however, impact the asynchronicity:
+	     - CFI_escape,
+	     - DW_CFA_GNU_window_save,
+	     - DW_CFA_AARCH64_negate_ra_state (multiplexed with
+	       DW_CFA_GNU_window_save)  */
+
+	err = 1;
+	// printf (_("SFrame Unsupported or unknown Dwarf CFI number: %#x\n"), op);
+      }
+    }
+
+  return err;
+}
+
+static int sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
+			  const struct fde_entry *dw_fde)
+{
+  struct cfi_insn_data *cfi_insn;
+
+  xlate_ctx->dw_fde = dw_fde;
+
+  /* If the return column is not RIP, SFrame format cannot represent it.  */
+  if (xlate_ctx->dw_fde->return_column != DWARF2_DEFAULT_RETURN_COLUMN)
+    return 1;
+
+  /* Iterate over the CFIs and create SFrame FREs.  */
+  for (cfi_insn = dw_fde->data; cfi_insn; cfi_insn = cfi_insn->next)
+    {
+      /* Translate each CFI, and buffer the state in translation context.  */
+      if (sframe_do_cfi_insn (xlate_ctx, cfi_insn))
+	{
+	  /* Skip generating SFrame unwind info for the function if any
+	     offending CFI is encountered by sframe_do_cfi_insn ().  */
+	  /* FIXME - get a detailed look at the individual cases.  */
+	  // printf ("WATCH THIS ONE! sframe_do_cfi_insn skipped. \n");
+	  return 1;  /* Error.  */
+	}
+    }
+
+  /* No errors encountered.  */
+
+  /* Link in the scratchpad FRE that the last few CFI insns helped create.  */
+  if (xlate_ctx->cur_fre)
+    {
+      sframe_xlate_ctx_add_fre (xlate_ctx, xlate_ctx->cur_fre);
+      xlate_ctx->cur_fre = NULL;
+    }
+  /* Designate the end of the last SFrame FRE.  */
+  if (xlate_ctx->last_fre)
+    {
+      xlate_ctx->last_fre->pc_end
+	= get_dw_fde_end_addrS (xlate_ctx->dw_fde);
+    }
+
+  return 0;
+}
+
+/* Create SFrame unwind info for all functions.
+
+   This function consumes the already generated FDEs (by dw2gencfi) and
+   generates unwind data in SFrame format.  */
+
+static void create_sframe_all (void)
+{
+  struct fde_entry *dw_fde = NULL;
+  struct sframe_func_entry *sframe_fde = NULL;
+
+  struct sframe_xlate_ctx *xlate_ctx = sframe_xlate_ctx_alloc ();
+
+  for (dw_fde = all_fde_data; dw_fde ; dw_fde = dw_fde->next)
+    {
+      /* FIXME - enable this assert once the compiler is generating
+	 .cfi_sections with .sframe enabled.  */
+      // gas_assert ((fde->sections & CFI_EMIT_sframe));
+      sframe_fde = sframe_fde_alloc ();
+      /* Initialize the translation context with information anew.  */
+      sframe_xlate_ctx_init (xlate_ctx);
+
+      /* Process and link SFrame FDEs if no error.  Also skip adding an SFrame
+	 FDE if it does not contain any SFrame FREs.  There is little use of an
+	 SFrame FDE if there is no unwind information about the function.  */
+      int err = sframe_do_fde (xlate_ctx, dw_fde);
+      if (err || xlate_ctx->num_xlate_fres == 0)
+	{
+	  sframe_xlate_ctx_cleanup (xlate_ctx);
+	  sframe_fde_free (sframe_fde);
+	}
+      else
+	{
+	  /* All done.  Transfer the state from the SFrame translation
+	     context to the SFrame FDE.  */
+	  sframe_xlate_ctx_finalize (xlate_ctx, sframe_fde);
+	  sframe_fde_link (sframe_fde);
+	}
+    }
+}
+
+void output_sframe (segT sframe_seg)
+{
+  (void) sframe_seg;
+
+  /* Setup the version specific access functions.  */
+  sframe_set_version (SFRAME_VERSION_1);
+
+  /* Process all fdes and create SFrame unwind information.  */
+  create_sframe_all ();
+
+  output_sframe_internal ();
+}
+
+#else  /*  support_sframe_p  */
+
+/* Callback to create the abi/arch identifier for SFrame section.  */
+
+unsigned char
+sframe_get_abi_arch_callback (const char *tarch __attribute__((unused)),
+			      int big_endian_p __attribute__((unused)))
+{
+  unsigned char sframe_abi_arch = 0;
+
+  return sframe_abi_arch;
+}
+
+void output_sframe (segT sframe_seg __attribute__((unused)))
+{
+}
+
+#endif /*  support_sframe_p  */
diff --git a/gas/gen-sframe.h b/gas/gen-sframe.h
new file mode 100644
index 00000000000..3cd1fa2a643
--- /dev/null
+++ b/gas/gen-sframe.h
@@ -0,0 +1,141 @@
+/* gen-sframe.h - Support for generating SFrame.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS 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, or (at your option)
+   any later version.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#ifndef GENSFRAME_H
+#define GENSFRAME_H
+
+#define SFRAME_FRE_ELEM_LOC_REG		0
+#define SFRAME_FRE_ELEM_LOC_STACK	1
+
+/* SFrame Frame Row Entry (FRE).
+
+   A frame row entry is a slice of the frame and can be valid for a set of
+   program instructions.  It keeps all information needed to retrieve the CFA
+   and the Return Address (RA) if tracked.
+
+   A frame row entry effectively stores accumulated information gathered by
+   interpreting multiple CFI instructions.  More precisely, it is a
+   self-sufficient record in its own right.  Only the subset of information
+   necessary for unwinding is stored: Given a PC, how to retrieve the CFA and
+   the RA.
+*/
+
+struct sframe_row_entry
+{
+  /* A linked list.  */
+  struct sframe_row_entry *next;
+
+  /* Start and end of the frame row entry.  */
+  symbolS *pc_begin;
+  symbolS *pc_end;
+
+  /* A frame row entry is a merge candidate if new information can be updated
+     on it.  */
+  bool merge_candidate;
+
+  /* Track CFA base (architectural) register ID.  */
+  unsigned int cfa_base_reg;
+  /* Offset from the CFA base register for recovering CFA.  */
+  offsetT cfa_offset;
+
+  /* Track the other register used as base register for CFA.  Specify whether
+     it is in register or memory.  */
+  unsigned int base_reg;
+  unsigned int bp_loc;
+  /* If the other register is stashed on stack, note the offset.  */
+  offsetT bp_offset;
+
+  /* Track RA location.  Specify whether it is in register or memory.  */
+  unsigned int ra_loc;
+  /* If RA is stashed on stack, note the offset.  */
+  offsetT ra_offset;
+};
+
+/* SFrame Function Description Entry.  */
+
+struct sframe_func_entry
+{
+  /* A linked list.  */
+  struct sframe_func_entry *next;
+
+  /* Reference to the FDE created from CFI in dw2gencfi.  Some information
+     like the start_address and the segment is made available via this
+     member.  */
+  const struct fde_entry *dw_fde;
+
+  /* Reference to the first FRE for this function.  */
+  struct sframe_row_entry *sframe_fres;
+
+  unsigned int num_fres;
+};
+
+/* SFrame Function Description Entry Translation Context.  */
+
+struct sframe_xlate_ctx
+{
+  /* Reference to the FDE created from CFI in dw2gencfi.  Information
+     like the FDE start_address, end_address and the cfi insns are
+     made available via this member.  */
+  const struct fde_entry *dw_fde;
+
+  /* List of FREs in the current FDE translation context, bounded by first_fre
+     and last_fre.  */
+
+  /* Keep track of the first FRE for the purpose of restoring state if
+     necessary (for DW_CFA_restore).  */
+  struct sframe_row_entry *first_fre;
+  /* The last FRE in the list.  */
+  struct sframe_row_entry *last_fre;
+
+  /* The current FRE under construction.  */
+  struct sframe_row_entry *cur_fre;
+  /* Remember FRE for an eventual restore.  */
+  struct sframe_row_entry *remember_fre;
+
+  unsigned num_xlate_fres;
+};
+
+/* Callback to create the abi/arch identifier for SFrame section.  */
+
+unsigned char
+sframe_get_abi_arch_callback (const char *target_arch,
+			      int big_endian_p);
+
+/* The list of all FDEs with data in SFrame internal representation.  */
+
+extern struct sframe_func_entry *all_sframe_fdes;
+
+/* SFrame version specific operations structure.  */
+
+struct sframe_version_ops
+{
+  unsigned char format_version;    /* SFrame format version.  */
+  /* set SFrame FRE info.  */
+  unsigned char (*set_fre_info) (unsigned int, unsigned int, unsigned int);
+  /* set SFrame Func info.  */
+  unsigned char (*set_func_info) (unsigned int, unsigned int);
+};
+
+/* Generate SFrame unwind info and prepare contents for the output.
+   outout_sframe ()  is called at the end of file.  */
+
+extern void output_sframe (segT sframe_seg);
+
+#endif /* GENSFRAME_H */
diff --git a/gas/sframe-opt.c b/gas/sframe-opt.c
new file mode 100644
index 00000000000..c17fd6b8332
--- /dev/null
+++ b/gas/sframe-opt.c
@@ -0,0 +1,158 @@
+/* sframe-opt.c - optimize FRE and FDE information in SFrame.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS 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, or (at your option)
+   any later version.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#include "as.h"
+#include "sframe.h"
+
+/* The function estimates the size of a rs_sframe variant frag based on
+   the current values of the symbols.  It is called before the
+   relaxation loop.  We set fr_subtype{0:2} to the expected length.  */
+
+int
+sframe_estimate_size_before_relax (fragS *frag)
+{
+  offsetT width;
+  expressionS *exp;
+  symbolS *widthS;
+  int ret;
+
+  /* We are dealing with two different kind of fragments here which need
+     to be fixed up:
+       - first, FRE start address in each FRE, and
+       - second, Function info in each FDE (function info stores the FRE type)
+     The two kind of fragments can be differentiated based on the opcode
+     of the symbol.  */
+  exp = symbol_get_value_expression (frag->fr_symbol);
+  gas_assert ((exp->X_op == O_subtract) || (exp->X_op == O_absent));
+  /* Fragment for function info in an SFrame FDE will always write
+     only one byte.  */
+  if (exp->X_op == O_subtract)
+    ret = 1;
+  /* Fragment for the start address in an SFrame FRE may write out
+     1/2/4 bytes depending on the value of the diff.  */
+  else
+    {
+      /* Get the width expression from the symbol.  */
+      widthS = exp->X_op_symbol;
+      width = resolve_symbol_value (widthS);
+
+      if (width < 0x100)
+	ret = 1;
+      else if (width < 0x10000)
+	ret = 2;
+      else
+	ret = 4;
+    }
+
+  frag->fr_subtype = (frag->fr_subtype & ~7) | (ret & 7);
+
+  return ret;
+}
+
+/* This function relaxes a rs_sframe variant frag based on the current
+   values of the symbols.  fr_subtype{0:2} is the current length of
+   the frag.  This returns the change in frag length.  */
+
+int
+sframe_relax_frag (fragS *frag)
+{
+  int oldsize, newsize;
+
+  oldsize = frag->fr_subtype & 7;
+  if (oldsize == 7)
+    oldsize = -1;
+  newsize = sframe_estimate_size_before_relax (frag);
+  return newsize - oldsize;
+}
+
+/* This function converts a rs_sframe variant frag into a normal fill
+   frag.  This is called after all relaxation has been done.
+   fr_subtype{0:2} will be the desired length of the frag.  */
+
+void
+sframe_convert_frag (fragS *frag)
+{
+  offsetT fsize;
+  offsetT diff;
+  offsetT value;
+  unsigned char func_info = SFRAME_FRE_TYPE_ADDR4;
+  expressionS *exp;
+  symbolS *fsizeS, *diffS;
+
+  /* We are dealing with two different kind of fragments here which need
+     to be fixed up:
+       - first, FRE start address in each FRE, and
+       - second, Function info in each FDE (function info stores the FRE type)
+     The two kind of fragments can be differentiated based on the opcode
+     of the symbol.  */
+  exp = symbol_get_value_expression (frag->fr_symbol);
+  gas_assert ((exp->X_op == O_subtract) || (exp->X_op == O_absent));
+  /* Fragment for function info in an SFrame FDE.  */
+  if (exp->X_op == O_subtract)
+    {
+      fsizeS = frag->fr_symbol;
+      fsize = resolve_symbol_value (fsizeS);
+      if (fsize < 0x100)
+	func_info = SFRAME_FRE_TYPE_ADDR1;
+      else if (fsize < 0x10000)
+	func_info = SFRAME_FRE_TYPE_ADDR2;
+      else
+	func_info = SFRAME_FRE_TYPE_ADDR4;
+      value = func_info;
+
+      frag->fr_literal[frag->fr_fix] = value;
+    }
+  /* Fragment for the start address in an SFrame FRE.  */
+  else
+    {
+      /* Get the fsize expression from the symbol.  */
+      fsizeS = exp->X_op_symbol;
+      fsize = resolve_symbol_value (fsizeS);
+      /* Get the diff expression from the symbol.  */
+      diffS= exp->X_add_symbol;
+      diff = resolve_symbol_value (diffS);
+      value = diff;
+
+      switch (frag->fr_subtype & 7)
+	{
+	case 1:
+	  gas_assert (fsize < 0x100);
+	  frag->fr_literal[frag->fr_fix] = diff;
+	  break;
+	case 2:
+	  gas_assert (fsize < 0x10000);
+	  md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2);
+	  break;
+	case 4:
+	  md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4);
+	  break;
+	default:
+	  abort ();
+	}
+    }
+
+  frag->fr_fix += frag->fr_subtype & 7;
+  frag->fr_type = rs_fill;
+  frag->fr_subtype = 0;
+  frag->fr_offset = 0;
+  /* FIXME do this now because we have evaluated and fixed up the fragments
+     manually ?  */
+  frag->fr_symbol = 0;
+}
diff --git a/gas/write.c b/gas/write.c
index 0e49df7c03f..ae0ee60c6bd 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -487,6 +487,10 @@ cvt_frag_to_fill (segT sec ATTRIBUTE_UNUSED, fragS *fragP)
       dwarf2dbg_convert_frag (fragP);
       break;
 
+    case rs_sframe:
+      sframe_convert_frag (fragP);
+      break;
+
     case rs_machine_dependent:
       md_convert_frag (stdoutput, sec, fragP);
 
@@ -2790,6 +2794,11 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
 	  address += dwarf2dbg_estimate_size_before_relax (fragP);
 	  break;
 
+	case rs_sframe:
+	  /* Initial estimate can be set to atleast 1 byte.  */
+	  address += sframe_estimate_size_before_relax (fragP);
+	  break;
+
 	default:
 	  BAD_CASE (fragP->fr_type);
 	  break;
@@ -3133,6 +3142,10 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass)
 		growth = dwarf2dbg_relax_frag (fragP);
 		break;
 
+	      case rs_sframe:
+		growth = sframe_relax_frag (fragP);
+		break;
+
 	      default:
 		BAD_CASE (fragP->fr_type);
 		break;
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 04/14] gas: testsuite: add new tests for SFrame unwind info
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (2 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 03/14] gas: generate .sframe from CFI directives Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 05/14] libsframe: add the SFrame library Indu Bhagat
                       ` (12 subsequent siblings)
  16 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

Earlier these tests were in the same commit as previous which adds the
support in GNU assembler to generate .sframe section from CFI
directives.  Splitting this out here for ease of applying and testing.

ChangeLog:

	* gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.d: New file.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/cfi-sframe.exp: Likewise.
	* gas/testsuite/gas/cfi-sframe/common-empty-1.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/common-empty-1.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/common-empty-2.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/common-empty-2.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/common-empty-3.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/common-empty-3.s: Likewise.
	* gas/testsuite/gas/cfi-sframe/common-empty-4.d: Likewise.
	* gas/testsuite/gas/cfi-sframe/common-empty-4.s: Likewise.
---
 .../gas/cfi-sframe/cfi-sframe-aarch64-1.d     | 20 ++++++
 .../gas/cfi-sframe/cfi-sframe-aarch64-1.s     | 61 +++++++++++++++++++
 .../gas/cfi-sframe/cfi-sframe-common-1.d      | 17 ++++++
 .../gas/cfi-sframe/cfi-sframe-common-1.s      |  3 +
 .../gas/cfi-sframe/cfi-sframe-common-2.d      | 17 ++++++
 .../gas/cfi-sframe/cfi-sframe-common-2.s      |  2 +
 .../gas/cfi-sframe/cfi-sframe-common-3.d      | 17 ++++++
 .../gas/cfi-sframe/cfi-sframe-common-3.s      |  4 ++
 .../gas/cfi-sframe/cfi-sframe-common-4.d      | 21 +++++++
 .../gas/cfi-sframe/cfi-sframe-common-4.s      |  8 +++
 .../gas/cfi-sframe/cfi-sframe-common-5.d      | 21 +++++++
 .../gas/cfi-sframe/cfi-sframe-common-5.s      |  7 +++
 .../gas/cfi-sframe/cfi-sframe-common-6.d      | 21 +++++++
 .../gas/cfi-sframe/cfi-sframe-common-6.s      |  7 +++
 .../gas/cfi-sframe/cfi-sframe-common-7.d      | 21 +++++++
 .../gas/cfi-sframe/cfi-sframe-common-7.s      |  7 +++
 .../gas/cfi-sframe/cfi-sframe-common-8.d      | 20 ++++++
 .../gas/cfi-sframe/cfi-sframe-common-8.s      | 12 ++++
 .../gas/cfi-sframe/cfi-sframe-x86_64-1.d      | 22 +++++++
 .../gas/cfi-sframe/cfi-sframe-x86_64-1.s      | 30 +++++++++
 gas/testsuite/gas/cfi-sframe/cfi-sframe.exp   | 58 ++++++++++++++++++
 gas/testsuite/gas/cfi-sframe/common-empty-1.d | 14 +++++
 gas/testsuite/gas/cfi-sframe/common-empty-1.s |  5 ++
 gas/testsuite/gas/cfi-sframe/common-empty-2.d | 14 +++++
 gas/testsuite/gas/cfi-sframe/common-empty-2.s |  8 +++
 gas/testsuite/gas/cfi-sframe/common-empty-3.d | 14 +++++
 gas/testsuite/gas/cfi-sframe/common-empty-3.s |  9 +++
 gas/testsuite/gas/cfi-sframe/common-empty-4.d | 14 +++++
 gas/testsuite/gas/cfi-sframe/common-empty-4.s | 17 ++++++
 29 files changed, 491 insertions(+)
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-1.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-2.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-2.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-3.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-3.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-4.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/common-empty-4.s

diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.d
new file mode 100644
index 00000000000..aeefbc9cdef
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.d
@@ -0,0 +1,20 @@
+#as:
+#objdump: --sframe=.sframe
+#name: SFrame generation on aarch64
+#...
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 3
+
+  Function Index :
+
+    func idx \[0\]: pc = 0x0, size = 80 bytes
+    STARTPC +CFA +FP +RA +
+    0+0000 +sp\+0 +u +u +
+    0+0004 +sp\+144 +u +u +
+    0+004c +sp\+0 +u +u +
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.s
new file mode 100644
index 00000000000..082c8a32046
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-1.s
@@ -0,0 +1,61 @@
+        .cfi_sections .sframe
+	.cfi_startproc
+	stp	x19, x20, [sp, -144]!
+	.cfi_def_cfa_offset 144
+	.cfi_offset 19, -144
+	.cfi_offset 20, -136
+	stp	x21, x22, [sp, 16]
+	stp	x23, x24, [sp, 32]
+	stp	x25, x26, [sp, 48]
+	stp	x27, x28, [sp, 64]
+	stp	d8, d9, [sp, 80]
+	stp	d10, d11, [sp, 96]
+	stp	d12, d13, [sp, 112]
+	stp	d14, d15, [sp, 128]
+	.cfi_offset 21, -128
+	.cfi_offset 22, -120
+	.cfi_offset 23, -112
+	.cfi_offset 24, -104
+	.cfi_offset 25, -96
+	.cfi_offset 26, -88
+	.cfi_offset 27, -80
+	.cfi_offset 28, -72
+	.cfi_offset 72, -64
+	.cfi_offset 73, -56
+	.cfi_offset 74, -48
+	.cfi_offset 75, -40
+	.cfi_offset 76, -32
+	.cfi_offset 77, -24
+	.cfi_offset 78, -16
+	.cfi_offset 79, -8
+	nop
+	ldp	x21, x22, [sp, 16]
+	ldp	x23, x24, [sp, 32]
+	ldp	x25, x26, [sp, 48]
+	ldp	x27, x28, [sp, 64]
+	ldp	d8, d9, [sp, 80]
+	ldp	d10, d11, [sp, 96]
+	ldp	d12, d13, [sp, 112]
+	ldp	d14, d15, [sp, 128]
+	ldp	x19, x20, [sp], 144
+	.cfi_restore 20
+	.cfi_restore 19
+	.cfi_restore 78
+	.cfi_restore 79
+	.cfi_restore 76
+	.cfi_restore 77
+	.cfi_restore 74
+	.cfi_restore 75
+	.cfi_restore 72
+	.cfi_restore 73
+	.cfi_restore 27
+	.cfi_restore 28
+	.cfi_restore 25
+	.cfi_restore 26
+	.cfi_restore 23
+	.cfi_restore 24
+	.cfi_restore 21
+	.cfi_restore 22
+	.cfi_def_cfa_offset 0
+	ret
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.d
new file mode 100644
index 00000000000..7d97383bb90
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.d
@@ -0,0 +1,17 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame generation using CFI directive .cfi_sections
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 1
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 0 bytes
+    STARTPC + CFA + FP + RA +
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.s
new file mode 100644
index 00000000000..ac9c6ca2cf3
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-1.s
@@ -0,0 +1,3 @@
+	.cfi_sections .sframe
+	.cfi_startproc
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.d
new file mode 100644
index 00000000000..fc7d5c440db
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.d
@@ -0,0 +1,17 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: Command line option for generating SFrame
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 1
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 0 bytes
+    STARTPC + CFA + FP + RA +
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.s
new file mode 100644
index 00000000000..659b3b9d99b
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-2.s
@@ -0,0 +1,2 @@
+	.cfi_startproc
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.d
new file mode 100644
index 00000000000..95954508e3d
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.d
@@ -0,0 +1,17 @@
+#as:
+#objdump: --sframe=.sframe
+#name: SFrame can co-exist with EH Frame
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 1
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 0 bytes
+    STARTPC + CFA + FP + RA +
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.s
new file mode 100644
index 00000000000..36d31fe5348
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-3.s
@@ -0,0 +1,4 @@
+	.cfi_sections .eh_frame
+	.cfi_sections .sframe
+	.cfi_startproc
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.d
new file mode 100644
index 00000000000..8eb97fac4d9
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.d
@@ -0,0 +1,21 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame - cfi_def_cfa_offset test
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 3
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 12 bytes
+    STARTPC + CFA + FP + RA +
+#...
+    0+0004 +sp\+16 +u +u +
+    0+0008 +sp\+32 +u +u +
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.s
new file mode 100644
index 00000000000..0d026bba71a
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-4.s
@@ -0,0 +1,8 @@
+## Testcase for cfi_def_cfa_offset
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 16
+	.long 0
+	.cfi_def_cfa_offset 32
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.d
new file mode 100644
index 00000000000..d2bef7507c2
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.d
@@ -0,0 +1,21 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame cfi_adjust_cfa_offset test
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 3
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 12 bytes
+    STARTPC + CFA + FP + RA +
+#...
+    0+0004 +sp\+16 +u +u +
+    0+0008 +sp\+24 +u +u +
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.s
new file mode 100644
index 00000000000..c985c39af9d
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-5.s
@@ -0,0 +1,7 @@
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 16
+	.long 0
+	.cfi_adjust_cfa_offset 8
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.d
new file mode 100644
index 00000000000..f915ac5f234
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.d
@@ -0,0 +1,21 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame cfi_offset test
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 3
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 12 bytes
+    STARTPC + CFA + FP + RA +
+#...
+    0+0004 +sp\+8 +u +u +
+    0+0008 +sp\+8 +u +u +
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.s
new file mode 100644
index 00000000000..389f324dc5f
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-6.s
@@ -0,0 +1,7 @@
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 8
+	.long 0
+	.cfi_offset 0, 8
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.d
new file mode 100644
index 00000000000..cab19d5bc25
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.d
@@ -0,0 +1,21 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame cfi_rel_offset test
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 3
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 12 bytes
+    STARTPC + CFA + FP + RA +
+#...
+    0+0004 +sp\+8 +u +u +
+    0+0008 +sp\+8 +u +u +
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.s
new file mode 100644
index 00000000000..21fa031fb30
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-7.s
@@ -0,0 +1,7 @@
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 8
+	.long 0
+	.cfi_rel_offset 1, 8
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.d
new file mode 100644
index 00000000000..c0a4a8de250
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.d
@@ -0,0 +1,20 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame cfi_val_offset test
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 2
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 8 bytes
+    STARTPC + CFA + FP + RA +
+#...
+    0+0004 +sp\+16 +u +u +
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.s
new file mode 100644
index 00000000000..f2083e6a106
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.s
@@ -0,0 +1,12 @@
+## cfi_val_offset when used with "not interesting" registers (from the
+## perspective of SFrame section, non FP/RA registers are not
+## interesting) does not affect the asynchronicity of the SFrame
+## unwind information.  Such CFI directives can be skipped for SFrame
+## unwind info generation.
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 16
+	.cfi_val_offset 1, 8
+	.cfi_val_offset 2, -32
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.d
new file mode 100644
index 00000000000..bba3b5920f1
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.d
@@ -0,0 +1,22 @@
+#as: -O0
+#objdump: --sframe=.sframe
+#name: SFrame generation on x86_64
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 1
+    Num FREs: 4
+
+  Function Index :
+
+    func idx \[0\]: pc = 0x0, size = 25 bytes
+    STARTPC +CFA +FP +RA +
+    0+0000 +sp\+8 +u +u +
+    0+0001 +sp\+16 +c\-16 +u +
+    0+0004 +fp\+16 +c\-16 +u +
+    0+0018 +sp\+8 +c\-16 +u +
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.s
new file mode 100644
index 00000000000..77f3578f0d8
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-1.s
@@ -0,0 +1,30 @@
+        .cfi_sections .sframe
+	.cfi_startproc
+        pushq   %rbp
+        .cfi_def_cfa_offset 16
+        .cfi_offset 6, -16
+        movq    %rsp, %rbp
+        .cfi_def_cfa_register 6
+        pushq   %r15
+        pushq   %r14
+        pushq   %r13
+        pushq   %r12
+        pushq   %rbx
+  ## These CFI opcodes are not interesting
+  ## for SFrame generation and will be
+  ## skipped.
+        .cfi_offset 15, -24
+        .cfi_offset 14, -32
+        .cfi_offset 13, -40
+        .cfi_offset 12, -48
+        .cfi_offset 3, -56
+        nop
+        popq    %rbx
+        popq    %r12
+        popq    %r13
+        popq    %r14
+        popq    %r15
+        popq    %rbp
+        .cfi_def_cfa 7, 8
+        ret
+        .cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
new file mode 100644
index 00000000000..ca344c9e252
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
@@ -0,0 +1,58 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+if { ![is_elf_format] } then {
+    return
+}
+
+proc gas_x86_64_check { } {
+    global NM
+    global NMFLAGS
+
+    set status [gas_host_run "$NM $NMFLAGS --help" ""]
+    return [regexp "targets:.*x86-64" [lindex $status 1]];
+}
+
+if  { [istarget "x86_64-*-*"] || [istarget "aarch64-*-*"] } then {
+
+    global ASFLAGS
+    set old_ASFLAGS "$ASFLAGS"
+
+    run_dump_test "cfi-sframe-common-1"
+    run_dump_test "cfi-sframe-common-2"
+    run_dump_test "cfi-sframe-common-3"
+    run_dump_test "cfi-sframe-common-4"
+    run_dump_test "cfi-sframe-common-5"
+    run_dump_test "cfi-sframe-common-6"
+    run_dump_test "cfi-sframe-common-7"
+    run_dump_test "cfi-sframe-common-8"
+
+    run_dump_test "common-empty-1"
+    run_dump_test "common-empty-2"
+    run_dump_test "common-empty-3"
+    run_dump_test "common-empty-4"
+
+    if { [gas_x86_64_check] } then {
+	set ASFLAGS "$ASFLAGS --64"
+	run_dump_test "cfi-sframe-x86_64-1"
+	set ASFLAGS "$old_ASFLAGS"
+    }
+}
+
+# aarch64 specific tests
+if { [istarget "aarch64-*-*"] } then {
+    run_dump_test "cfi-sframe-aarch64-1"
+}
diff --git a/gas/testsuite/gas/cfi-sframe/common-empty-1.d b/gas/testsuite/gas/cfi-sframe/common-empty-1.d
new file mode 100644
index 00000000000..0b09799826c
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/common-empty-1.d
@@ -0,0 +1,14 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: Uninteresting cfi directives generate an empty SFrame section
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/common-empty-1.s b/gas/testsuite/gas/cfi-sframe/common-empty-1.s
new file mode 100644
index 00000000000..e26e998189f
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/common-empty-1.s
@@ -0,0 +1,5 @@
+      .cfi_sections .sframe
+      .cfi_startproc
+      .cfi_remember_state
+      .cfi_restore_state
+      .cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/common-empty-2.d b/gas/testsuite/gas/cfi-sframe/common-empty-2.d
new file mode 100644
index 00000000000..e566c078249
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/common-empty-2.d
@@ -0,0 +1,14 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame supports only FP/SP based CFA
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/common-empty-2.s b/gas/testsuite/gas/cfi-sframe/common-empty-2.s
new file mode 100644
index 00000000000..146c53de785
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/common-empty-2.s
@@ -0,0 +1,8 @@
+## CFA register is not defined to be SP/FP.
+## No SFrame unwind info for this function will be generated.
+	.cfi_startproc simple
+	.long 0
+	.long 0
+	.cfi_adjust_cfa_offset 16
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/common-empty-3.d b/gas/testsuite/gas/cfi-sframe/common-empty-3.d
new file mode 100644
index 00000000000..f7a6062d392
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/common-empty-3.d
@@ -0,0 +1,14 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame supports only default return column
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/common-empty-3.s b/gas/testsuite/gas/cfi-sframe/common-empty-3.s
new file mode 100644
index 00000000000..982fe0c851d
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/common-empty-3.s
@@ -0,0 +1,9 @@
+## The return column is not the default value.
+## No SFrame unwind info for this function will be generated.
+	.cfi_startproc
+	.cfi_return_column 0
+	.long 0
+	.long 0
+	.cfi_adjust_cfa_offset 16
+	.long 0
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/common-empty-4.d b/gas/testsuite/gas/cfi-sframe/common-empty-4.d
new file mode 100644
index 00000000000..f7a6062d392
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/common-empty-4.d
@@ -0,0 +1,14 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame supports only default return column
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: NONE
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/common-empty-4.s b/gas/testsuite/gas/cfi-sframe/common-empty-4.s
new file mode 100644
index 00000000000..f97ca2f7ff9
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/common-empty-4.s
@@ -0,0 +1,17 @@
+## ARMv8.3 addded support a new security feature named Pointer Authentication. The
+## main idea behind this is to use the unused bits in the pointer values.
+## Each pointer is patched with a PAC before writing to memory, and is verified
+## before using it.
+## When the pointers are mangled, the unwinder needs to know so it can mask off
+## the PAC from the pointer value to recover the return address, and
+## conversely, skip doing so if the pointers are not mangled.
+##
+## .cfi_negate_ra_state CFI directive is used to convey this information.
+##
+## SFrame does not have any means to represent this information at this time.
+	.cfi_startproc
+	.long 0
+	.cfi_def_cfa_offset 16
+	.cfi_negate_ra_state
+	.long 0
+	.cfi_endproc
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 05/14] libsframe: add the SFrame library
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (3 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 04/14] gas: testsuite: add new tests for SFrame unwind info Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 06/14] bfd: linker: merge .sframe sections Indu Bhagat
                       ` (11 subsequent siblings)
  16 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan

From: Weimin Pan <weimin.pan@oracle.com>

libsframe is a library that allows you to:
- decode a .sframe section
- probe and inspect a .sframe section
- encode (and eventually write) a .sframe section.

This library is currently being used by the linker, readelf, objdump and
the unwinder.

The file include/sframe-api.h defines the user-facing APIs for decoding,
encoding and probing .sframe sections. A set of error codes together
with their error message strings are also defined.

Endian flipping is performed automatically at read and write time, if
cross-endianness is detected.

PS: libsframe/configure has NOT been included in the patch.  Please
regenerate.

ChangeLog:

	* Makefile.def: Add libsframe as new module with its
	dependencies.
	* Makefile.in: Regenerated.
	* binutils/Makefile.am: Add libsframe.
	* binutils/Makefile.in: Regenerated.
	* configure: Regenerated
	* configure.ac: Add libsframe to host_libs.
	* libsframe/Makefile.am: New file.
	* libsframe/Makefile.in: New file.
	* libsframe/aclocal.m4: New file.
	* libsframe/config.h.in: New file.
	* libsframe/configure: New file. <-- [REMOVED FROM THIS PATCH.
	PLEASE REGENERATE.]
	* libsframe/configure.ac: New file.
	* libsframe/sframe-error.c: New file.
	* libsframe/sframe-impl.h: New file.
	* libsframe/sframe.c: New file.

include/ChangeLog:

	* sframe-api.h: New file.

testsuite/ChangeLog:

	* libsframe/testsuite/Makefile.am: New file.
	* libsframe/testsuite/Makefile.in: Regenerated.
	* libsframe/testsuite/libsframe.decode/Makefile.am: New
	  file.
	* libsframe/testsuite/libsframe.decode/Makefile.in:
	  Regenerated.
	* libsframe/testsuite/libsframe.decode/decode.exp: New file.
	* libsframe/testsuite/libsframe.encode/Makefile.am:
	  Likewise.
	* libsframe/testsuite/libsframe.encode/Makefile.in:
	  Regenerated.
	* libsframe/testsuite/libsframe.encode/encode.exp: New file.
	* libsframe/testsuite/libsframe.decode/bigendian_data.c:
	  Likewise.
	* libsframe/testsuite/libsframe.decode/frecnt_1.c: Likewise.
	* libsframe/testsuite/libsframe.decode/frecnt_2.c: Likewise.
---
 Makefile.def                                  |    2 +
 Makefile.in                                   | 1288 +++++++++++++-
 binutils/Makefile.am                          |    2 +
 binutils/Makefile.in                          |    1 +
 configure                                     |    2 +-
 configure.ac                                  |    2 +-
 include/sframe-api.h                          |  211 +++
 libsframe/Makefile.am                         |   43 +
 libsframe/Makefile.in                         | 1047 +++++++++++
 libsframe/aclocal.m4                          | 1241 +++++++++++++
 libsframe/config.h.in                         |  144 ++
 libsframe/configure.ac                        |   78 +
 libsframe/sframe-error.c                      |   49 +
 libsframe/sframe-impl.h                       |   55 +
 libsframe/sframe.c                            | 1566 +++++++++++++++++
 libsframe/testsuite/Makefile.am               |   23 +
 libsframe/testsuite/Makefile.in               |  682 +++++++
 libsframe/testsuite/config/default.exp        |   54 +
 libsframe/testsuite/libsframe.decode/DATA1    |  Bin 0 -> 59 bytes
 libsframe/testsuite/libsframe.decode/DATA2    |  Bin 0 -> 91 bytes
 .../testsuite/libsframe.decode/DATA_BIGE      |  Bin 0 -> 59 bytes
 .../testsuite/libsframe.decode/Makefile.am    |   14 +
 .../testsuite/libsframe.decode/Makefile.in    |  661 +++++++
 .../libsframe.decode/bigendian_data.c         |  107 ++
 .../testsuite/libsframe.decode/decode.exp     |   41 +
 .../testsuite/libsframe.decode/frecnt_1.c     |   99 ++
 .../testsuite/libsframe.decode/frecnt_2.c     |  103 ++
 .../testsuite/libsframe.encode/Makefile.am    |    6 +
 .../testsuite/libsframe.encode/Makefile.in    |  608 +++++++
 .../testsuite/libsframe.encode/encode.exp     |   25 +
 .../testsuite/libsframe.encode/encode_1.c     |  182 ++
 31 files changed, 8329 insertions(+), 7 deletions(-)
 create mode 100644 include/sframe-api.h
 create mode 100644 libsframe/Makefile.am
 create mode 100644 libsframe/Makefile.in
 create mode 100644 libsframe/aclocal.m4
 create mode 100644 libsframe/config.h.in
 create mode 100644 libsframe/configure.ac
 create mode 100644 libsframe/sframe-error.c
 create mode 100644 libsframe/sframe-impl.h
 create mode 100644 libsframe/sframe.c
 create mode 100644 libsframe/testsuite/Makefile.am
 create mode 100644 libsframe/testsuite/Makefile.in
 create mode 100644 libsframe/testsuite/config/default.exp
 create mode 100644 libsframe/testsuite/libsframe.decode/DATA1
 create mode 100644 libsframe/testsuite/libsframe.decode/DATA2
 create mode 100644 libsframe/testsuite/libsframe.decode/DATA_BIGE
 create mode 100644 libsframe/testsuite/libsframe.decode/Makefile.am
 create mode 100644 libsframe/testsuite/libsframe.decode/Makefile.in
 create mode 100644 libsframe/testsuite/libsframe.decode/bigendian_data.c
 create mode 100644 libsframe/testsuite/libsframe.decode/decode.exp
 create mode 100644 libsframe/testsuite/libsframe.decode/frecnt_1.c
 create mode 100644 libsframe/testsuite/libsframe.decode/frecnt_2.c
 create mode 100644 libsframe/testsuite/libsframe.encode/Makefile.am
 create mode 100644 libsframe/testsuite/libsframe.encode/Makefile.in
 create mode 100644 libsframe/testsuite/libsframe.encode/encode.exp
 create mode 100644 libsframe/testsuite/libsframe.encode/encode_1.c

diff --git a/Makefile.def b/Makefile.def
index acdcd625ed6..1b39c910447 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -149,6 +149,7 @@ host_modules= { module= lto-plugin; bootstrap=true;
 host_modules= { module= libcc1; extra_configure_flags=--enable-shared; };
 host_modules= { module= gotools; };
 host_modules= { module= libctf; bootstrap=true; };
+host_modules= { module= libsframe; bootstrap=true; };
 
 target_modules = { module= libstdc++-v3;
 		   bootstrap=true;
@@ -478,6 +479,7 @@ dependencies = { module=all-binutils; on=all-intl; };
 dependencies = { module=all-binutils; on=all-gas; };
 dependencies = { module=all-binutils; on=all-libctf; };
 dependencies = { module=all-ld; on=all-libctf; };
+dependencies = { module=all-binutils; on=all-libsframe; };
 
 // We put install-opcodes before install-binutils because the installed
 // binutils might be on PATH, and they might need the shared opcodes
diff --git a/Makefile.in b/Makefile.in
index cb39e4790d6..b26f778a94a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1109,7 +1109,8 @@ configure-host:  \
     maybe-configure-lto-plugin \
     maybe-configure-libcc1 \
     maybe-configure-gotools \
-    maybe-configure-libctf
+    maybe-configure-libctf \
+    maybe-configure-libsframe
 .PHONY: configure-target
 configure-target:  \
     maybe-configure-target-libstdc++-v3 \
@@ -1290,6 +1291,9 @@ all-host: maybe-all-gotools
 @if libctf-no-bootstrap
 all-host: maybe-all-libctf
 @endif libctf-no-bootstrap
+@if libsframe-no-bootstrap
+all-host: maybe-all-libsframe
+@endif libsframe-no-bootstrap
 
 .PHONY: all-target
 
@@ -1396,6 +1400,7 @@ info-host: maybe-info-lto-plugin
 info-host: maybe-info-libcc1
 info-host: maybe-info-gotools
 info-host: maybe-info-libctf
+info-host: maybe-info-libsframe
 
 .PHONY: info-target
 
@@ -1487,6 +1492,7 @@ dvi-host: maybe-dvi-lto-plugin
 dvi-host: maybe-dvi-libcc1
 dvi-host: maybe-dvi-gotools
 dvi-host: maybe-dvi-libctf
+dvi-host: maybe-dvi-libsframe
 
 .PHONY: dvi-target
 
@@ -1578,6 +1584,7 @@ pdf-host: maybe-pdf-lto-plugin
 pdf-host: maybe-pdf-libcc1
 pdf-host: maybe-pdf-gotools
 pdf-host: maybe-pdf-libctf
+pdf-host: maybe-pdf-libsframe
 
 .PHONY: pdf-target
 
@@ -1669,6 +1676,7 @@ html-host: maybe-html-lto-plugin
 html-host: maybe-html-libcc1
 html-host: maybe-html-gotools
 html-host: maybe-html-libctf
+html-host: maybe-html-libsframe
 
 .PHONY: html-target
 
@@ -1760,6 +1768,7 @@ TAGS-host: maybe-TAGS-lto-plugin
 TAGS-host: maybe-TAGS-libcc1
 TAGS-host: maybe-TAGS-gotools
 TAGS-host: maybe-TAGS-libctf
+TAGS-host: maybe-TAGS-libsframe
 
 .PHONY: TAGS-target
 
@@ -1851,6 +1860,7 @@ install-info-host: maybe-install-info-lto-plugin
 install-info-host: maybe-install-info-libcc1
 install-info-host: maybe-install-info-gotools
 install-info-host: maybe-install-info-libctf
+install-info-host: maybe-install-info-libsframe
 
 .PHONY: install-info-target
 
@@ -1942,6 +1952,7 @@ install-dvi-host: maybe-install-dvi-lto-plugin
 install-dvi-host: maybe-install-dvi-libcc1
 install-dvi-host: maybe-install-dvi-gotools
 install-dvi-host: maybe-install-dvi-libctf
+install-dvi-host: maybe-install-dvi-libsframe
 
 .PHONY: install-dvi-target
 
@@ -2033,6 +2044,7 @@ install-pdf-host: maybe-install-pdf-lto-plugin
 install-pdf-host: maybe-install-pdf-libcc1
 install-pdf-host: maybe-install-pdf-gotools
 install-pdf-host: maybe-install-pdf-libctf
+install-pdf-host: maybe-install-pdf-libsframe
 
 .PHONY: install-pdf-target
 
@@ -2124,6 +2136,7 @@ install-html-host: maybe-install-html-lto-plugin
 install-html-host: maybe-install-html-libcc1
 install-html-host: maybe-install-html-gotools
 install-html-host: maybe-install-html-libctf
+install-html-host: maybe-install-html-libsframe
 
 .PHONY: install-html-target
 
@@ -2215,6 +2228,7 @@ installcheck-host: maybe-installcheck-lto-plugin
 installcheck-host: maybe-installcheck-libcc1
 installcheck-host: maybe-installcheck-gotools
 installcheck-host: maybe-installcheck-libctf
+installcheck-host: maybe-installcheck-libsframe
 
 .PHONY: installcheck-target
 
@@ -2306,6 +2320,7 @@ mostlyclean-host: maybe-mostlyclean-lto-plugin
 mostlyclean-host: maybe-mostlyclean-libcc1
 mostlyclean-host: maybe-mostlyclean-gotools
 mostlyclean-host: maybe-mostlyclean-libctf
+mostlyclean-host: maybe-mostlyclean-libsframe
 
 .PHONY: mostlyclean-target
 
@@ -2397,6 +2412,7 @@ clean-host: maybe-clean-lto-plugin
 clean-host: maybe-clean-libcc1
 clean-host: maybe-clean-gotools
 clean-host: maybe-clean-libctf
+clean-host: maybe-clean-libsframe
 
 .PHONY: clean-target
 
@@ -2488,6 +2504,7 @@ distclean-host: maybe-distclean-lto-plugin
 distclean-host: maybe-distclean-libcc1
 distclean-host: maybe-distclean-gotools
 distclean-host: maybe-distclean-libctf
+distclean-host: maybe-distclean-libsframe
 
 .PHONY: distclean-target
 
@@ -2579,6 +2596,7 @@ maintainer-clean-host: maybe-maintainer-clean-lto-plugin
 maintainer-clean-host: maybe-maintainer-clean-libcc1
 maintainer-clean-host: maybe-maintainer-clean-gotools
 maintainer-clean-host: maybe-maintainer-clean-libctf
+maintainer-clean-host: maybe-maintainer-clean-libsframe
 
 .PHONY: maintainer-clean-target
 
@@ -2727,7 +2745,8 @@ check-host:  \
     maybe-check-lto-plugin \
     maybe-check-libcc1 \
     maybe-check-gotools \
-    maybe-check-libctf
+    maybe-check-libctf \
+    maybe-check-libsframe
 
 .PHONY: check-target
 check-target:  \
@@ -2865,7 +2884,8 @@ install-host-nogcc:  \
     maybe-install-lto-plugin \
     maybe-install-libcc1 \
     maybe-install-gotools \
-    maybe-install-libctf
+    maybe-install-libctf \
+    maybe-install-libsframe
 
 .PHONY: install-host
 install-host:  \
@@ -2921,7 +2941,8 @@ install-host:  \
     maybe-install-lto-plugin \
     maybe-install-libcc1 \
     maybe-install-gotools \
-    maybe-install-libctf
+    maybe-install-libctf \
+    maybe-install-libsframe
 
 .PHONY: install-target
 install-target:  \
@@ -3032,7 +3053,8 @@ install-strip-host:  \
     maybe-install-strip-lto-plugin \
     maybe-install-strip-libcc1 \
     maybe-install-strip-gotools \
-    maybe-install-strip-libctf
+    maybe-install-strip-libctf \
+    maybe-install-strip-libsframe
 
 .PHONY: install-strip-target
 install-strip-target:  \
@@ -44044,6 +44066,1146 @@ maintainer-clean-libctf:
 
 
 
+.PHONY: configure-libsframe maybe-configure-libsframe
+maybe-configure-libsframe:
+@if gcc-bootstrap
+configure-libsframe: stage_current
+@endif gcc-bootstrap
+@if libsframe
+maybe-configure-libsframe: configure-libsframe
+configure-libsframe: 
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	test ! -f $(HOST_SUBDIR)/libsframe/Makefile || exit 0; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe; \
+	$(HOST_EXPORTS)  \
+	echo Configuring in $(HOST_SUBDIR)/libsframe; \
+	cd "$(HOST_SUBDIR)/libsframe" || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libsframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libsframe; \
+	$(SHELL) \
+	  $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias}  \
+	  || exit 1
+@endif libsframe
+
+
+
+.PHONY: configure-stage1-libsframe maybe-configure-stage1-libsframe
+maybe-configure-stage1-libsframe:
+@if libsframe-bootstrap
+maybe-configure-stage1-libsframe: configure-stage1-libsframe
+configure-stage1-libsframe:
+	@[ $(current_stage) = stage1 ] || $(MAKE) stage1-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE1_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libsframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	CFLAGS="$(STAGE1_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE1_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(LIBCFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 1 in $(HOST_SUBDIR)/libsframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe; \
+	cd $(HOST_SUBDIR)/libsframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libsframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libsframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	   \
+	  $(STAGE1_CONFIGURE_FLAGS)
+@endif libsframe-bootstrap
+
+.PHONY: configure-stage2-libsframe maybe-configure-stage2-libsframe
+maybe-configure-stage2-libsframe:
+@if libsframe-bootstrap
+maybe-configure-stage2-libsframe: configure-stage2-libsframe
+configure-stage2-libsframe:
+	@[ $(current_stage) = stage2 ] || $(MAKE) stage2-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE2_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libsframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGE2_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE2_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGE2_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 2 in $(HOST_SUBDIR)/libsframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe; \
+	cd $(HOST_SUBDIR)/libsframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libsframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libsframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGE2_CONFIGURE_FLAGS)
+@endif libsframe-bootstrap
+
+.PHONY: configure-stage3-libsframe maybe-configure-stage3-libsframe
+maybe-configure-stage3-libsframe:
+@if libsframe-bootstrap
+maybe-configure-stage3-libsframe: configure-stage3-libsframe
+configure-stage3-libsframe:
+	@[ $(current_stage) = stage3 ] || $(MAKE) stage3-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE3_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libsframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGE3_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE3_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGE3_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 3 in $(HOST_SUBDIR)/libsframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe; \
+	cd $(HOST_SUBDIR)/libsframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libsframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libsframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGE3_CONFIGURE_FLAGS)
+@endif libsframe-bootstrap
+
+.PHONY: configure-stage4-libsframe maybe-configure-stage4-libsframe
+maybe-configure-stage4-libsframe:
+@if libsframe-bootstrap
+maybe-configure-stage4-libsframe: configure-stage4-libsframe
+configure-stage4-libsframe:
+	@[ $(current_stage) = stage4 ] || $(MAKE) stage4-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE4_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libsframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGE4_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGE4_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGE4_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage 4 in $(HOST_SUBDIR)/libsframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe; \
+	cd $(HOST_SUBDIR)/libsframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libsframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libsframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGE4_CONFIGURE_FLAGS)
+@endif libsframe-bootstrap
+
+.PHONY: configure-stageprofile-libsframe maybe-configure-stageprofile-libsframe
+maybe-configure-stageprofile-libsframe:
+@if libsframe-bootstrap
+maybe-configure-stageprofile-libsframe: configure-stageprofile-libsframe
+configure-stageprofile-libsframe:
+	@[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEprofile_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libsframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEprofile_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEprofile_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEprofile_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage profile in $(HOST_SUBDIR)/libsframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe; \
+	cd $(HOST_SUBDIR)/libsframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libsframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libsframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEprofile_CONFIGURE_FLAGS)
+@endif libsframe-bootstrap
+
+.PHONY: configure-stagetrain-libsframe maybe-configure-stagetrain-libsframe
+maybe-configure-stagetrain-libsframe:
+@if libsframe-bootstrap
+maybe-configure-stagetrain-libsframe: configure-stagetrain-libsframe
+configure-stagetrain-libsframe:
+	@[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEtrain_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libsframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEtrain_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEtrain_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEtrain_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage train in $(HOST_SUBDIR)/libsframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe; \
+	cd $(HOST_SUBDIR)/libsframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libsframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libsframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEtrain_CONFIGURE_FLAGS)
+@endif libsframe-bootstrap
+
+.PHONY: configure-stagefeedback-libsframe maybe-configure-stagefeedback-libsframe
+maybe-configure-stagefeedback-libsframe:
+@if libsframe-bootstrap
+maybe-configure-stagefeedback-libsframe: configure-stagefeedback-libsframe
+configure-stagefeedback-libsframe:
+	@[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEfeedback_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libsframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEfeedback_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEfeedback_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEfeedback_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage feedback in $(HOST_SUBDIR)/libsframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe; \
+	cd $(HOST_SUBDIR)/libsframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libsframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libsframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEfeedback_CONFIGURE_FLAGS)
+@endif libsframe-bootstrap
+
+.PHONY: configure-stageautoprofile-libsframe maybe-configure-stageautoprofile-libsframe
+maybe-configure-stageautoprofile-libsframe:
+@if libsframe-bootstrap
+maybe-configure-stageautoprofile-libsframe: configure-stageautoprofile-libsframe
+configure-stageautoprofile-libsframe:
+	@[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEautoprofile_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libsframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEautoprofile_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEautoprofile_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEautoprofile_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage autoprofile in $(HOST_SUBDIR)/libsframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe; \
+	cd $(HOST_SUBDIR)/libsframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libsframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libsframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEautoprofile_CONFIGURE_FLAGS)
+@endif libsframe-bootstrap
+
+.PHONY: configure-stageautofeedback-libsframe maybe-configure-stageautofeedback-libsframe
+maybe-configure-stageautofeedback-libsframe:
+@if libsframe-bootstrap
+maybe-configure-stageautofeedback-libsframe: configure-stageautofeedback-libsframe
+configure-stageautofeedback-libsframe:
+	@[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start
+	@$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEautofeedback_TFLAGS)"; \
+	test ! -f $(HOST_SUBDIR)/libsframe/Makefile || exit 0; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS) \
+	CFLAGS="$(STAGEautofeedback_CFLAGS)"; export CFLAGS; \
+	CXXFLAGS="$(STAGEautofeedback_CXXFLAGS)"; export CXXFLAGS; \
+	LIBCFLAGS="$(STAGEautofeedback_CFLAGS)"; export LIBCFLAGS;  \
+	echo Configuring stage autofeedback in $(HOST_SUBDIR)/libsframe; \
+	$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/libsframe; \
+	cd $(HOST_SUBDIR)/libsframe || exit 1; \
+	case $(srcdir) in \
+	  /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+	  *) topdir=`echo $(HOST_SUBDIR)/libsframe/ | \
+		sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+	esac; \
+	module_srcdir=libsframe; \
+	$(SHELL) $$s/$$module_srcdir/configure \
+	  --srcdir=$${topdir}/$$module_srcdir \
+	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+	  --target=${target_alias} \
+	  --with-build-libsubdir=$(HOST_SUBDIR) \
+	  $(STAGEautofeedback_CONFIGURE_FLAGS)
+@endif libsframe-bootstrap
+
+
+
+
+
+.PHONY: all-libsframe maybe-all-libsframe
+maybe-all-libsframe:
+@if gcc-bootstrap
+all-libsframe: stage_current
+@endif gcc-bootstrap
+@if libsframe
+TARGET-libsframe=all
+maybe-all-libsframe: all-libsframe
+all-libsframe: configure-libsframe
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS)  \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_HOST_FLAGS) $(STAGE1_FLAGS_TO_PASS)  \
+		$(TARGET-libsframe))
+@endif libsframe
+
+
+
+.PHONY: all-stage1-libsframe maybe-all-stage1-libsframe
+.PHONY: clean-stage1-libsframe maybe-clean-stage1-libsframe
+maybe-all-stage1-libsframe:
+maybe-clean-stage1-libsframe:
+@if libsframe-bootstrap
+maybe-all-stage1-libsframe: all-stage1-libsframe
+all-stage1: all-stage1-libsframe
+TARGET-stage1-libsframe = $(TARGET-libsframe)
+all-stage1-libsframe: configure-stage1-libsframe
+	@[ $(current_stage) = stage1 ] || $(MAKE) stage1-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE1_TFLAGS)"; \
+	$(HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libsframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE1_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGE1_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGE1_CXXFLAGS)" \
+		LIBCFLAGS="$(LIBCFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS)  \
+		$(STAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE1_TFLAGS)"  \
+		$(TARGET-stage1-libsframe)
+
+maybe-clean-stage1-libsframe: clean-stage1-libsframe
+clean-stage1: clean-stage1-libsframe
+clean-stage1-libsframe:
+	@if [ $(current_stage) = stage1 ]; then \
+	  [ -f $(HOST_SUBDIR)/libsframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage1-libsframe/Makefile ] || exit 0; \
+	  $(MAKE) stage1-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libsframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS)  \
+	$(STAGE1_FLAGS_TO_PASS)  clean
+@endif libsframe-bootstrap
+
+
+.PHONY: all-stage2-libsframe maybe-all-stage2-libsframe
+.PHONY: clean-stage2-libsframe maybe-clean-stage2-libsframe
+maybe-all-stage2-libsframe:
+maybe-clean-stage2-libsframe:
+@if libsframe-bootstrap
+maybe-all-stage2-libsframe: all-stage2-libsframe
+all-stage2: all-stage2-libsframe
+TARGET-stage2-libsframe = $(TARGET-libsframe)
+all-stage2-libsframe: configure-stage2-libsframe
+	@[ $(current_stage) = stage2 ] || $(MAKE) stage2-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE2_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libsframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE2_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGE2_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGE2_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGE2_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE2_TFLAGS)"  \
+		$(TARGET-stage2-libsframe)
+
+maybe-clean-stage2-libsframe: clean-stage2-libsframe
+clean-stage2: clean-stage2-libsframe
+clean-stage2-libsframe:
+	@if [ $(current_stage) = stage2 ]; then \
+	  [ -f $(HOST_SUBDIR)/libsframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage2-libsframe/Makefile ] || exit 0; \
+	  $(MAKE) stage2-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libsframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libsframe-bootstrap
+
+
+.PHONY: all-stage3-libsframe maybe-all-stage3-libsframe
+.PHONY: clean-stage3-libsframe maybe-clean-stage3-libsframe
+maybe-all-stage3-libsframe:
+maybe-clean-stage3-libsframe:
+@if libsframe-bootstrap
+maybe-all-stage3-libsframe: all-stage3-libsframe
+all-stage3: all-stage3-libsframe
+TARGET-stage3-libsframe = $(TARGET-libsframe)
+all-stage3-libsframe: configure-stage3-libsframe
+	@[ $(current_stage) = stage3 ] || $(MAKE) stage3-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE3_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libsframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE3_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGE3_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGE3_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGE3_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE3_TFLAGS)"  \
+		$(TARGET-stage3-libsframe)
+
+maybe-clean-stage3-libsframe: clean-stage3-libsframe
+clean-stage3: clean-stage3-libsframe
+clean-stage3-libsframe:
+	@if [ $(current_stage) = stage3 ]; then \
+	  [ -f $(HOST_SUBDIR)/libsframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage3-libsframe/Makefile ] || exit 0; \
+	  $(MAKE) stage3-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libsframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libsframe-bootstrap
+
+
+.PHONY: all-stage4-libsframe maybe-all-stage4-libsframe
+.PHONY: clean-stage4-libsframe maybe-clean-stage4-libsframe
+maybe-all-stage4-libsframe:
+maybe-clean-stage4-libsframe:
+@if libsframe-bootstrap
+maybe-all-stage4-libsframe: all-stage4-libsframe
+all-stage4: all-stage4-libsframe
+TARGET-stage4-libsframe = $(TARGET-libsframe)
+all-stage4-libsframe: configure-stage4-libsframe
+	@[ $(current_stage) = stage4 ] || $(MAKE) stage4-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGE4_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libsframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGE4_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGE4_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGE4_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGE4_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGE4_TFLAGS)"  \
+		$(TARGET-stage4-libsframe)
+
+maybe-clean-stage4-libsframe: clean-stage4-libsframe
+clean-stage4: clean-stage4-libsframe
+clean-stage4-libsframe:
+	@if [ $(current_stage) = stage4 ]; then \
+	  [ -f $(HOST_SUBDIR)/libsframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stage4-libsframe/Makefile ] || exit 0; \
+	  $(MAKE) stage4-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libsframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libsframe-bootstrap
+
+
+.PHONY: all-stageprofile-libsframe maybe-all-stageprofile-libsframe
+.PHONY: clean-stageprofile-libsframe maybe-clean-stageprofile-libsframe
+maybe-all-stageprofile-libsframe:
+maybe-clean-stageprofile-libsframe:
+@if libsframe-bootstrap
+maybe-all-stageprofile-libsframe: all-stageprofile-libsframe
+all-stageprofile: all-stageprofile-libsframe
+TARGET-stageprofile-libsframe = $(TARGET-libsframe)
+all-stageprofile-libsframe: configure-stageprofile-libsframe
+	@[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEprofile_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libsframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEprofile_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGEprofile_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGEprofile_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEprofile_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEprofile_TFLAGS)"  \
+		$(TARGET-stageprofile-libsframe)
+
+maybe-clean-stageprofile-libsframe: clean-stageprofile-libsframe
+clean-stageprofile: clean-stageprofile-libsframe
+clean-stageprofile-libsframe:
+	@if [ $(current_stage) = stageprofile ]; then \
+	  [ -f $(HOST_SUBDIR)/libsframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stageprofile-libsframe/Makefile ] || exit 0; \
+	  $(MAKE) stageprofile-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libsframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libsframe-bootstrap
+
+
+.PHONY: all-stagetrain-libsframe maybe-all-stagetrain-libsframe
+.PHONY: clean-stagetrain-libsframe maybe-clean-stagetrain-libsframe
+maybe-all-stagetrain-libsframe:
+maybe-clean-stagetrain-libsframe:
+@if libsframe-bootstrap
+maybe-all-stagetrain-libsframe: all-stagetrain-libsframe
+all-stagetrain: all-stagetrain-libsframe
+TARGET-stagetrain-libsframe = $(TARGET-libsframe)
+all-stagetrain-libsframe: configure-stagetrain-libsframe
+	@[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEtrain_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libsframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEtrain_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGEtrain_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGEtrain_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEtrain_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEtrain_TFLAGS)"  \
+		$(TARGET-stagetrain-libsframe)
+
+maybe-clean-stagetrain-libsframe: clean-stagetrain-libsframe
+clean-stagetrain: clean-stagetrain-libsframe
+clean-stagetrain-libsframe:
+	@if [ $(current_stage) = stagetrain ]; then \
+	  [ -f $(HOST_SUBDIR)/libsframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stagetrain-libsframe/Makefile ] || exit 0; \
+	  $(MAKE) stagetrain-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libsframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libsframe-bootstrap
+
+
+.PHONY: all-stagefeedback-libsframe maybe-all-stagefeedback-libsframe
+.PHONY: clean-stagefeedback-libsframe maybe-clean-stagefeedback-libsframe
+maybe-all-stagefeedback-libsframe:
+maybe-clean-stagefeedback-libsframe:
+@if libsframe-bootstrap
+maybe-all-stagefeedback-libsframe: all-stagefeedback-libsframe
+all-stagefeedback: all-stagefeedback-libsframe
+TARGET-stagefeedback-libsframe = $(TARGET-libsframe)
+all-stagefeedback-libsframe: configure-stagefeedback-libsframe
+	@[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEfeedback_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libsframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEfeedback_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGEfeedback_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGEfeedback_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEfeedback_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEfeedback_TFLAGS)"  \
+		$(TARGET-stagefeedback-libsframe)
+
+maybe-clean-stagefeedback-libsframe: clean-stagefeedback-libsframe
+clean-stagefeedback: clean-stagefeedback-libsframe
+clean-stagefeedback-libsframe:
+	@if [ $(current_stage) = stagefeedback ]; then \
+	  [ -f $(HOST_SUBDIR)/libsframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stagefeedback-libsframe/Makefile ] || exit 0; \
+	  $(MAKE) stagefeedback-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libsframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libsframe-bootstrap
+
+
+.PHONY: all-stageautoprofile-libsframe maybe-all-stageautoprofile-libsframe
+.PHONY: clean-stageautoprofile-libsframe maybe-clean-stageautoprofile-libsframe
+maybe-all-stageautoprofile-libsframe:
+maybe-clean-stageautoprofile-libsframe:
+@if libsframe-bootstrap
+maybe-all-stageautoprofile-libsframe: all-stageautoprofile-libsframe
+all-stageautoprofile: all-stageautoprofile-libsframe
+TARGET-stageautoprofile-libsframe = $(TARGET-libsframe)
+all-stageautoprofile-libsframe: configure-stageautoprofile-libsframe
+	@[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEautoprofile_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libsframe && \
+	$$s/gcc/config/i386/$(AUTO_PROFILE) \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEautoprofile_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGEautoprofile_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGEautoprofile_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEautoprofile_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEautoprofile_TFLAGS)"  \
+		$(TARGET-stageautoprofile-libsframe)
+
+maybe-clean-stageautoprofile-libsframe: clean-stageautoprofile-libsframe
+clean-stageautoprofile: clean-stageautoprofile-libsframe
+clean-stageautoprofile-libsframe:
+	@if [ $(current_stage) = stageautoprofile ]; then \
+	  [ -f $(HOST_SUBDIR)/libsframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stageautoprofile-libsframe/Makefile ] || exit 0; \
+	  $(MAKE) stageautoprofile-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libsframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libsframe-bootstrap
+
+
+.PHONY: all-stageautofeedback-libsframe maybe-all-stageautofeedback-libsframe
+.PHONY: clean-stageautofeedback-libsframe maybe-clean-stageautofeedback-libsframe
+maybe-all-stageautofeedback-libsframe:
+maybe-clean-stageautofeedback-libsframe:
+@if libsframe-bootstrap
+maybe-all-stageautofeedback-libsframe: all-stageautofeedback-libsframe
+all-stageautofeedback: all-stageautofeedback-libsframe
+TARGET-stageautofeedback-libsframe = $(TARGET-libsframe)
+all-stageautofeedback-libsframe: configure-stageautofeedback-libsframe
+	@[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	TFLAGS="$(STAGEautofeedback_TFLAGS)"; \
+	$(HOST_EXPORTS) \
+	$(POSTSTAGE1_HOST_EXPORTS)  \
+	cd $(HOST_SUBDIR)/libsframe && \
+	 \
+	$(MAKE) $(BASE_FLAGS_TO_PASS) \
+		CFLAGS="$(STAGEautofeedback_CFLAGS)" \
+		GENERATOR_CFLAGS="$(STAGEautofeedback_GENERATOR_CFLAGS)" \
+		CXXFLAGS="$(STAGEautofeedback_CXXFLAGS)" \
+		LIBCFLAGS="$(STAGEautofeedback_CFLAGS)" \
+		CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \
+		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
+		LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \
+		$(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  \
+		TFLAGS="$(STAGEautofeedback_TFLAGS)" PERF_DATA=perf.data \
+		$(TARGET-stageautofeedback-libsframe)
+
+maybe-clean-stageautofeedback-libsframe: clean-stageautofeedback-libsframe
+clean-stageautofeedback: clean-stageautofeedback-libsframe
+clean-stageautofeedback-libsframe:
+	@if [ $(current_stage) = stageautofeedback ]; then \
+	  [ -f $(HOST_SUBDIR)/libsframe/Makefile ] || exit 0; \
+	else \
+	  [ -f $(HOST_SUBDIR)/stageautofeedback-libsframe/Makefile ] || exit 0; \
+	  $(MAKE) stageautofeedback-start; \
+	fi; \
+	cd $(HOST_SUBDIR)/libsframe && \
+	$(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS)  clean
+@endif libsframe-bootstrap
+
+
+
+
+
+.PHONY: check-libsframe maybe-check-libsframe
+maybe-check-libsframe:
+@if libsframe
+maybe-check-libsframe: check-libsframe
+
+check-libsframe:
+	@: $(MAKE); $(unstage)
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) $(EXTRA_HOST_EXPORTS) \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(FLAGS_TO_PASS)  $(EXTRA_BOOTSTRAP_FLAGS) check)
+
+@endif libsframe
+
+.PHONY: install-libsframe maybe-install-libsframe
+maybe-install-libsframe:
+@if libsframe
+maybe-install-libsframe: install-libsframe
+
+install-libsframe: installdirs
+	@: $(MAKE); $(unstage)
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(FLAGS_TO_PASS)  install)
+
+@endif libsframe
+
+.PHONY: install-strip-libsframe maybe-install-strip-libsframe
+maybe-install-strip-libsframe:
+@if libsframe
+maybe-install-strip-libsframe: install-strip-libsframe
+
+install-strip-libsframe: installdirs
+	@: $(MAKE); $(unstage)
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(FLAGS_TO_PASS)  install-strip)
+
+@endif libsframe
+
+# Other targets (info, dvi, pdf, etc.)
+
+.PHONY: maybe-info-libsframe info-libsframe
+maybe-info-libsframe:
+@if libsframe
+maybe-info-libsframe: info-libsframe
+
+info-libsframe: \
+    configure-libsframe 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing info in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          info) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-dvi-libsframe dvi-libsframe
+maybe-dvi-libsframe:
+@if libsframe
+maybe-dvi-libsframe: dvi-libsframe
+
+dvi-libsframe: \
+    configure-libsframe 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing dvi in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          dvi) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-pdf-libsframe pdf-libsframe
+maybe-pdf-libsframe:
+@if libsframe
+maybe-pdf-libsframe: pdf-libsframe
+
+pdf-libsframe: \
+    configure-libsframe 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing pdf in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          pdf) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-html-libsframe html-libsframe
+maybe-html-libsframe:
+@if libsframe
+maybe-html-libsframe: html-libsframe
+
+html-libsframe: \
+    configure-libsframe 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing html in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          html) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-TAGS-libsframe TAGS-libsframe
+maybe-TAGS-libsframe:
+@if libsframe
+maybe-TAGS-libsframe: TAGS-libsframe
+
+TAGS-libsframe: \
+    configure-libsframe 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing TAGS in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          TAGS) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-install-info-libsframe install-info-libsframe
+maybe-install-info-libsframe:
+@if libsframe
+maybe-install-info-libsframe: install-info-libsframe
+
+install-info-libsframe: \
+    configure-libsframe \
+    info-libsframe 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing install-info in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          install-info) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-install-dvi-libsframe install-dvi-libsframe
+maybe-install-dvi-libsframe:
+@if libsframe
+maybe-install-dvi-libsframe: install-dvi-libsframe
+
+install-dvi-libsframe: \
+    configure-libsframe \
+    dvi-libsframe 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing install-dvi in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          install-dvi) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-install-pdf-libsframe install-pdf-libsframe
+maybe-install-pdf-libsframe:
+@if libsframe
+maybe-install-pdf-libsframe: install-pdf-libsframe
+
+install-pdf-libsframe: \
+    configure-libsframe \
+    pdf-libsframe 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing install-pdf in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          install-pdf) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-install-html-libsframe install-html-libsframe
+maybe-install-html-libsframe:
+@if libsframe
+maybe-install-html-libsframe: install-html-libsframe
+
+install-html-libsframe: \
+    configure-libsframe \
+    html-libsframe 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing install-html in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          install-html) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-installcheck-libsframe installcheck-libsframe
+maybe-installcheck-libsframe:
+@if libsframe
+maybe-installcheck-libsframe: installcheck-libsframe
+
+installcheck-libsframe: \
+    configure-libsframe 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing installcheck in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          installcheck) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-mostlyclean-libsframe mostlyclean-libsframe
+maybe-mostlyclean-libsframe:
+@if libsframe
+maybe-mostlyclean-libsframe: mostlyclean-libsframe
+
+mostlyclean-libsframe: 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing mostlyclean in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          mostlyclean) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-clean-libsframe clean-libsframe
+maybe-clean-libsframe:
+@if libsframe
+maybe-clean-libsframe: clean-libsframe
+
+clean-libsframe: 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing clean in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          clean) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-distclean-libsframe distclean-libsframe
+maybe-distclean-libsframe:
+@if libsframe
+maybe-distclean-libsframe: distclean-libsframe
+
+distclean-libsframe: 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing distclean in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          distclean) \
+	  || exit 1
+
+@endif libsframe
+
+.PHONY: maybe-maintainer-clean-libsframe maintainer-clean-libsframe
+maybe-maintainer-clean-libsframe:
+@if libsframe
+maybe-maintainer-clean-libsframe: maintainer-clean-libsframe
+
+maintainer-clean-libsframe: 
+	@[ -f ./libsframe/Makefile ] || exit 0; \
+	r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) \
+	for flag in $(EXTRA_HOST_FLAGS) ; do \
+	  eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+	done; \
+	echo "Doing maintainer-clean in libsframe"; \
+	(cd $(HOST_SUBDIR)/libsframe && \
+	  $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+	          "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+	          "RANLIB=$${RANLIB}" \
+	          "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+	          maintainer-clean) \
+	  || exit 1
+
+@endif libsframe
+
+
+
 # ---------------------------------------
 # Modules which run on the target machine
 # ---------------------------------------
@@ -59280,6 +60442,11 @@ stage1-start::
 	  mkdir stage1-libctf; \
 	mv stage1-libctf libctf
 @endif libctf
+@if libsframe
+	@cd $(HOST_SUBDIR); [ -d stage1-libsframe ] || \
+	  mkdir stage1-libsframe; \
+	mv stage1-libsframe libsframe
+@endif libsframe
 	@[ -d stage1-$(TARGET_SUBDIR) ] || \
 	  mkdir stage1-$(TARGET_SUBDIR); \
 	mv stage1-$(TARGET_SUBDIR) $(TARGET_SUBDIR)
@@ -59405,6 +60572,11 @@ stage1-end::
 	  cd $(HOST_SUBDIR); mv libctf stage1-libctf; \
 	fi
 @endif libctf
+@if libsframe
+	@if test -d $(HOST_SUBDIR)/libsframe; then \
+	  cd $(HOST_SUBDIR); mv libsframe stage1-libsframe; \
+	fi
+@endif libsframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage1-$(TARGET_SUBDIR); \
 	fi
@@ -59597,6 +60769,12 @@ stage2-start::
 	mv stage2-libctf libctf; \
 	mv stage1-libctf prev-libctf || test -f stage1-lean 
 @endif libctf
+@if libsframe
+	@cd $(HOST_SUBDIR); [ -d stage2-libsframe ] || \
+	  mkdir stage2-libsframe; \
+	mv stage2-libsframe libsframe; \
+	mv stage1-libsframe prev-libsframe || test -f stage1-lean 
+@endif libsframe
 	@[ -d stage2-$(TARGET_SUBDIR) ] || \
 	  mkdir stage2-$(TARGET_SUBDIR); \
 	mv stage2-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -59747,6 +60925,12 @@ stage2-end::
 	  mv prev-libctf stage1-libctf; : ; \
 	fi
 @endif libctf
+@if libsframe
+	@if test -d $(HOST_SUBDIR)/libsframe; then \
+	  cd $(HOST_SUBDIR); mv libsframe stage2-libsframe; \
+	  mv prev-libsframe stage1-libsframe; : ; \
+	fi
+@endif libsframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage2-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage1-$(TARGET_SUBDIR); : ; \
@@ -59963,6 +61147,12 @@ stage3-start::
 	mv stage3-libctf libctf; \
 	mv stage2-libctf prev-libctf || test -f stage2-lean 
 @endif libctf
+@if libsframe
+	@cd $(HOST_SUBDIR); [ -d stage3-libsframe ] || \
+	  mkdir stage3-libsframe; \
+	mv stage3-libsframe libsframe; \
+	mv stage2-libsframe prev-libsframe || test -f stage2-lean 
+@endif libsframe
 	@[ -d stage3-$(TARGET_SUBDIR) ] || \
 	  mkdir stage3-$(TARGET_SUBDIR); \
 	mv stage3-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -60113,6 +61303,12 @@ stage3-end::
 	  mv prev-libctf stage2-libctf; : ; \
 	fi
 @endif libctf
+@if libsframe
+	@if test -d $(HOST_SUBDIR)/libsframe; then \
+	  cd $(HOST_SUBDIR); mv libsframe stage3-libsframe; \
+	  mv prev-libsframe stage2-libsframe; : ; \
+	fi
+@endif libsframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage3-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage2-$(TARGET_SUBDIR); : ; \
@@ -60385,6 +61581,12 @@ stage4-start::
 	mv stage4-libctf libctf; \
 	mv stage3-libctf prev-libctf || test -f stage3-lean 
 @endif libctf
+@if libsframe
+	@cd $(HOST_SUBDIR); [ -d stage4-libsframe ] || \
+	  mkdir stage4-libsframe; \
+	mv stage4-libsframe libsframe; \
+	mv stage3-libsframe prev-libsframe || test -f stage3-lean 
+@endif libsframe
 	@[ -d stage4-$(TARGET_SUBDIR) ] || \
 	  mkdir stage4-$(TARGET_SUBDIR); \
 	mv stage4-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -60535,6 +61737,12 @@ stage4-end::
 	  mv prev-libctf stage3-libctf; : ; \
 	fi
 @endif libctf
+@if libsframe
+	@if test -d $(HOST_SUBDIR)/libsframe; then \
+	  cd $(HOST_SUBDIR); mv libsframe stage4-libsframe; \
+	  mv prev-libsframe stage3-libsframe; : ; \
+	fi
+@endif libsframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stage4-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage3-$(TARGET_SUBDIR); : ; \
@@ -60795,6 +62003,12 @@ stageprofile-start::
 	mv stageprofile-libctf libctf; \
 	mv stage1-libctf prev-libctf || test -f stage1-lean 
 @endif libctf
+@if libsframe
+	@cd $(HOST_SUBDIR); [ -d stageprofile-libsframe ] || \
+	  mkdir stageprofile-libsframe; \
+	mv stageprofile-libsframe libsframe; \
+	mv stage1-libsframe prev-libsframe || test -f stage1-lean 
+@endif libsframe
 	@[ -d stageprofile-$(TARGET_SUBDIR) ] || \
 	  mkdir stageprofile-$(TARGET_SUBDIR); \
 	mv stageprofile-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -60945,6 +62159,12 @@ stageprofile-end::
 	  mv prev-libctf stage1-libctf; : ; \
 	fi
 @endif libctf
+@if libsframe
+	@if test -d $(HOST_SUBDIR)/libsframe; then \
+	  cd $(HOST_SUBDIR); mv libsframe stageprofile-libsframe; \
+	  mv prev-libsframe stage1-libsframe; : ; \
+	fi
+@endif libsframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stageprofile-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage1-$(TARGET_SUBDIR); : ; \
@@ -61138,6 +62358,12 @@ stagetrain-start::
 	mv stagetrain-libctf libctf; \
 	mv stageprofile-libctf prev-libctf || test -f stageprofile-lean 
 @endif libctf
+@if libsframe
+	@cd $(HOST_SUBDIR); [ -d stagetrain-libsframe ] || \
+	  mkdir stagetrain-libsframe; \
+	mv stagetrain-libsframe libsframe; \
+	mv stageprofile-libsframe prev-libsframe || test -f stageprofile-lean 
+@endif libsframe
 	@[ -d stagetrain-$(TARGET_SUBDIR) ] || \
 	  mkdir stagetrain-$(TARGET_SUBDIR); \
 	mv stagetrain-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -61288,6 +62514,12 @@ stagetrain-end::
 	  mv prev-libctf stageprofile-libctf; : ; \
 	fi
 @endif libctf
+@if libsframe
+	@if test -d $(HOST_SUBDIR)/libsframe; then \
+	  cd $(HOST_SUBDIR); mv libsframe stagetrain-libsframe; \
+	  mv prev-libsframe stageprofile-libsframe; : ; \
+	fi
+@endif libsframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stagetrain-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stageprofile-$(TARGET_SUBDIR); : ; \
@@ -61481,6 +62713,12 @@ stagefeedback-start::
 	mv stagefeedback-libctf libctf; \
 	mv stagetrain-libctf prev-libctf || test -f stagetrain-lean 
 @endif libctf
+@if libsframe
+	@cd $(HOST_SUBDIR); [ -d stagefeedback-libsframe ] || \
+	  mkdir stagefeedback-libsframe; \
+	mv stagefeedback-libsframe libsframe; \
+	mv stagetrain-libsframe prev-libsframe || test -f stagetrain-lean 
+@endif libsframe
 	@[ -d stagefeedback-$(TARGET_SUBDIR) ] || \
 	  mkdir stagefeedback-$(TARGET_SUBDIR); \
 	mv stagefeedback-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -61631,6 +62869,12 @@ stagefeedback-end::
 	  mv prev-libctf stagetrain-libctf; : ; \
 	fi
 @endif libctf
+@if libsframe
+	@if test -d $(HOST_SUBDIR)/libsframe; then \
+	  cd $(HOST_SUBDIR); mv libsframe stagefeedback-libsframe; \
+	  mv prev-libsframe stagetrain-libsframe; : ; \
+	fi
+@endif libsframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stagefeedback-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stagetrain-$(TARGET_SUBDIR); : ; \
@@ -61847,6 +63091,12 @@ stageautoprofile-start::
 	mv stageautoprofile-libctf libctf; \
 	mv stage1-libctf prev-libctf || test -f stage1-lean 
 @endif libctf
+@if libsframe
+	@cd $(HOST_SUBDIR); [ -d stageautoprofile-libsframe ] || \
+	  mkdir stageautoprofile-libsframe; \
+	mv stageautoprofile-libsframe libsframe; \
+	mv stage1-libsframe prev-libsframe || test -f stage1-lean 
+@endif libsframe
 	@[ -d stageautoprofile-$(TARGET_SUBDIR) ] || \
 	  mkdir stageautoprofile-$(TARGET_SUBDIR); \
 	mv stageautoprofile-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -61997,6 +63247,12 @@ stageautoprofile-end::
 	  mv prev-libctf stage1-libctf; : ; \
 	fi
 @endif libctf
+@if libsframe
+	@if test -d $(HOST_SUBDIR)/libsframe; then \
+	  cd $(HOST_SUBDIR); mv libsframe stageautoprofile-libsframe; \
+	  mv prev-libsframe stage1-libsframe; : ; \
+	fi
+@endif libsframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stageautoprofile-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stage1-$(TARGET_SUBDIR); : ; \
@@ -62190,6 +63446,12 @@ stageautofeedback-start::
 	mv stageautofeedback-libctf libctf; \
 	mv stageautoprofile-libctf prev-libctf || test -f stageautoprofile-lean 
 @endif libctf
+@if libsframe
+	@cd $(HOST_SUBDIR); [ -d stageautofeedback-libsframe ] || \
+	  mkdir stageautofeedback-libsframe; \
+	mv stageautofeedback-libsframe libsframe; \
+	mv stageautoprofile-libsframe prev-libsframe || test -f stageautoprofile-lean 
+@endif libsframe
 	@[ -d stageautofeedback-$(TARGET_SUBDIR) ] || \
 	  mkdir stageautofeedback-$(TARGET_SUBDIR); \
 	mv stageautofeedback-$(TARGET_SUBDIR) $(TARGET_SUBDIR); \
@@ -62340,6 +63602,12 @@ stageautofeedback-end::
 	  mv prev-libctf stageautoprofile-libctf; : ; \
 	fi
 @endif libctf
+@if libsframe
+	@if test -d $(HOST_SUBDIR)/libsframe; then \
+	  cd $(HOST_SUBDIR); mv libsframe stageautofeedback-libsframe; \
+	  mv prev-libsframe stageautoprofile-libsframe; : ; \
+	fi
+@endif libsframe
 	@if test -d $(TARGET_SUBDIR); then \
 	  mv $(TARGET_SUBDIR) stageautofeedback-$(TARGET_SUBDIR); \
 	  mv prev-$(TARGET_SUBDIR) stageautoprofile-$(TARGET_SUBDIR); : ; \
@@ -63259,6 +64527,16 @@ all-stagetrain-ld: maybe-all-stagetrain-libctf
 all-stagefeedback-ld: maybe-all-stagefeedback-libctf
 all-stageautoprofile-ld: maybe-all-stageautoprofile-libctf
 all-stageautofeedback-ld: maybe-all-stageautofeedback-libctf
+all-binutils: maybe-all-libsframe
+all-stage1-binutils: maybe-all-stage1-libsframe
+all-stage2-binutils: maybe-all-stage2-libsframe
+all-stage3-binutils: maybe-all-stage3-libsframe
+all-stage4-binutils: maybe-all-stage4-libsframe
+all-stageprofile-binutils: maybe-all-stageprofile-libsframe
+all-stagetrain-binutils: maybe-all-stagetrain-libsframe
+all-stagefeedback-binutils: maybe-all-stagefeedback-libsframe
+all-stageautoprofile-binutils: maybe-all-stageautoprofile-libsframe
+all-stageautofeedback-binutils: maybe-all-stageautofeedback-libsframe
 install-binutils: maybe-install-opcodes
 install-strip-binutils: maybe-install-strip-opcodes
 install-libctf: maybe-install-bfd
diff --git a/binutils/Makefile.am b/binutils/Makefile.am
index 751fbacce12..b93684d9a65 100644
--- a/binutils/Makefile.am
+++ b/binutils/Makefile.am
@@ -176,6 +176,8 @@ LIBCTF =
 LIBCTF_NOBFD =
 endif
 
+LIBSFRAME = ../libsframe/libsframe.la
+
 LIBIBERTY = ../libiberty/libiberty.a
 
 POTFILES = $(CFILES) $(DEBUG_SRCS) $(HFILES)
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index 6de4e239408..6cbdba1da26 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -741,6 +741,7 @@ OPCODES = ../opcodes/libopcodes.la
 @ENABLE_LIBCTF_TRUE@LIBCTF = ../libctf/libctf.la
 @ENABLE_LIBCTF_FALSE@LIBCTF_NOBFD = 
 @ENABLE_LIBCTF_TRUE@LIBCTF_NOBFD = ../libctf/libctf-nobfd.la
+LIBSFRAME = ../libsframe/libsframe.la
 LIBIBERTY = ../libiberty/libiberty.a
 POTFILES = $(CFILES) $(DEBUG_SRCS) $(HFILES)
 EXPECT = expect
diff --git a/configure b/configure
index f14e0efd675..720eedca3a2 100755
--- a/configure
+++ b/configure
@@ -2790,7 +2790,7 @@ build_tools="build-texinfo build-flex build-bison build-m4 build-fixincludes"
 
 # these libraries are used by various programs built for the host environment
 #f
-host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv libctf"
+host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv libctf libsframe"
 
 # these tools are built for the host environment
 # Note, the powerpc-eabi build depends on sim occurring before gdb in order to
diff --git a/configure.ac b/configure.ac
index 0152c69292e..7df8c076cf6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -132,7 +132,7 @@ build_tools="build-texinfo build-flex build-bison build-m4 build-fixincludes"
 
 # these libraries are used by various programs built for the host environment
 #f
-host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv libctf"
+host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktrace libcpp libdecnumber gmp mpfr mpc isl libelf libiconv libctf libsframe"
 
 # these tools are built for the host environment
 # Note, the powerpc-eabi build depends on sim occurring before gdb in order to
diff --git a/include/sframe-api.h b/include/sframe-api.h
new file mode 100644
index 00000000000..0c77cd4284a
--- /dev/null
+++ b/include/sframe-api.h
@@ -0,0 +1,211 @@
+/* Public API to SFrame.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of libsframe.
+
+   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/>.  */
+
+#ifndef	_SFRAME_API_H
+#define	_SFRAME_API_H
+
+#include <sframe.h>
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+typedef struct sframe_decoder_ctx sframe_decoder_ctx;
+typedef struct sframe_encoder_ctx sframe_encoder_ctx;
+
+#define MAX_OFFSET_BYTES (SFRAME_FRE_OFFSET_4B * 2 * 3)
+
+/* User interfacing SFrame Row Entry.
+   An abstraction provided by libsframe so the consumer is decoupled from
+   the binary format representation of the same.  */
+
+typedef struct sframe_frame_row_entry
+{
+  uint32_t fre_start_addr;
+  unsigned char fre_info;
+  unsigned char fre_offsets[MAX_OFFSET_BYTES];
+} sframe_frame_row_entry;
+
+#define SFRAME_ERR ((int) -1)
+
+/* This macro holds information about all the available SFrame
+   errors.  It is used to form both an enum holding all the error
+   constants, and also the error strings themselves.  To use, define
+   _SFRAME_FIRST and _SFRAME_ITEM to expand as you like, then
+   mention the macro name.  See the enum after this for an example.  */
+#define _SFRAME_ERRORS \
+  _SFRAME_FIRST (ESFRAME_VERSION_INVAL, "SFrame version not supported.") \
+  _SFRAME_ITEM (ESFRAME_NOMEM, "Out of Memory.")			\
+  _SFRAME_ITEM (ESFRAME_INVAL, "Corrupt SFrame.")		\
+  _SFRAME_ITEM (ESFRAME_BUF_INVAL, "Corrupt SFrame buffer.")	\
+  _SFRAME_ITEM (ESFRAME_DCTX_INVAL, "Corrupt SFrame decoder.") \
+  _SFRAME_ITEM (ESFRAME_ECTX_INVAL, "Corrupt SFrame encoder.")	\
+  _SFRAME_ITEM (ESFRAME_FDE_INVAL, "Corrput FDE.")		\
+  _SFRAME_ITEM (ESFRAME_FRE_INVAL, "Corrupt FRE.")		\
+  _SFRAME_ITEM (ESFRAME_FDE_NOTFOUND,"FDE not found.")		\
+  _SFRAME_ITEM (ESFRAME_FDE_NOTSORTED, "FDEs not sorted.")	\
+  _SFRAME_ITEM (ESFRAME_FRE_NOTFOUND,"FRE not found.")		\
+  _SFRAME_ITEM (ESFRAME_FREOFFSET_NOPRESENT,"FRE offset not present.")
+
+#define	ESFRAME_BASE	2000	/* Base value for libsframe errnos.  */
+
+enum
+  {
+#define _SFRAME_FIRST(NAME, STR) NAME = ESFRAME_BASE
+#define _SFRAME_ITEM(NAME, STR) , NAME
+_SFRAME_ERRORS
+#undef _SFRAME_ITEM
+#undef _SFRAME_FIRST
+  };
+
+/* Count of SFrame errors.  */
+#define ESFRAME_NERR (ESFRAME_NOMEM - ESFRAME_BASE + 1)
+
+/* Get the error message string.  */
+
+extern const char *
+sframe_errmsg (int error);
+
+/* Get FDE function info given a FRE_TYPE.  */
+
+extern unsigned char
+sframe_fde_func_info (unsigned int fre_type, unsigned int fde_type);
+
+/* Gather the FRE type given the function size.  */
+
+extern unsigned int
+sframe_calc_fre_type (unsigned int func_size);
+
+/* The SFrame Decoder.  */
+
+/* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
+   new SFrame decoder context.  Sets ERRP for the caller if any error.  */
+extern sframe_decoder_ctx *
+sframe_decode (const char *cf_buf, size_t cf_size, int *errp);
+
+/* Free the decoder context.  */
+extern void
+sframe_decoder_free (sframe_decoder_ctx **dctx);
+
+/* Get the SFrame's abi/arch info.  */
+extern unsigned char
+sframe_decoder_get_abi_arch (sframe_decoder_ctx *dctx);
+
+/* Return the number of function descriptor entries in the SFrame decoder
+   DCTX.  */
+unsigned int
+sframe_decoder_get_num_fidx (sframe_decoder_ctx *dctx);
+
+/* Find the function descriptor entry which contains the specified address.  */
+extern sframe_func_desc_entry *
+sframe_get_funcdesc_with_addr (sframe_decoder_ctx *dctx,
+				  int32_t addr, int *errp);
+
+/* Find the SFrame Frame Row Entry which contains the PC.  Returns
+   SFRAME_ERR if failure.  */
+
+extern int
+sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
+		    sframe_frame_row_entry *frep);
+
+/* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
+   index entry in the SFrame decoder CTX.  Returns error code as
+   applicable.  */
+extern int
+sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
+			   unsigned int func_idx,
+			   unsigned int fre_idx,
+			   sframe_frame_row_entry *fre);
+
+/* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
+   descriptor entry at index I'th in the decoder CTX.  If failed,
+   return error code.  */
+extern int
+sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
+				unsigned int i,
+				uint32_t *num_fres,
+				uint32_t *func_size,
+				int32_t *func_start_address,
+				unsigned char *func_info);
+
+
+/* Get the base reg id from the FRE info.  Sets errp if fails.  */
+extern unsigned int
+sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre, int *errp);
+
+/* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
+extern int32_t
+sframe_fre_get_cfa_offset (sframe_frame_row_entry *fre, int *errp);
+
+/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
+extern int32_t
+sframe_fre_get_fp_offset (sframe_frame_row_entry *fre, int *errp);
+
+/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
+extern int32_t
+sframe_fre_get_ra_offset (sframe_frame_row_entry *fre, int *errp);
+
+/* The SFrame Encoder.  */
+
+/* Create an encoder context with the given SFrame format version VER, FLAGS
+   and ABI information.  Sets errp if failure.  */
+extern sframe_encoder_ctx *
+sframe_encode (unsigned char ver, unsigned char flags, int abi, int *errp);
+
+/* Free the encoder context.  */
+extern void
+sframe_free_encoder (sframe_encoder_ctx *encoder);
+
+/* Get the abi/arch info from the SFrame encoder context CTX.  */
+extern unsigned char
+sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder);
+
+/* Return the number of function descriptor entries in the SFrame encoder
+   ENCODER.  */
+extern unsigned int
+sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder);
+
+/* Add an FRE to function at FUNC_IDX'th function descriptor index entry in
+   the encoder context.  */
+extern int
+sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
+			   unsigned int func_idx,
+			   sframe_frame_row_entry *frep);
+
+/* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
+   to the encoder.  */
+extern int
+sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
+				int32_t start_addr,
+				uint32_t func_size,
+				unsigned char func_info,
+				uint32_t num_fres);
+
+/* Serialize the contents of the encoder and return the buffer.  ENCODED_SIZE
+   is updated to the size of the buffer.  Sets ERRP if failure.  */
+extern char  *
+sframe_write_encoder (sframe_encoder_ctx *encoder,
+			 size_t *encoded_size, int *errp);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _SFRAME_API_H */
diff --git a/libsframe/Makefile.am b/libsframe/Makefile.am
new file mode 100644
index 00000000000..3a2218f1e5e
--- /dev/null
+++ b/libsframe/Makefile.am
@@ -0,0 +1,43 @@
+## Process this file with automake to produce Makefile.in.
+#
+#   Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file 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 2 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; see the file COPYING.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+
+SUBDIRS = testsuite
+
+ACLOCAL_AMFLAGS = -I .. -I ../config
+
+AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+
+BASEDIR = $(srcdir)/..
+INCDIR = $(srcdir)/../include
+# include libctf for swap.h
+AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../libctf
+AM_CFLAGS = -std=gnu99 @ac_libsframe_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@
+
+if INSTALL_LIBBFD
+lib_LTLIBRARIES = libsframe.la
+include_HEADERS = $(INCDIR)/sframe.h $(INCDIR)/sframe-api.h
+else
+include_HEADERS =
+noinst_LTLIBRARIES = libsframe.la
+endif
+
+libsframe_la_SOURCES = sframe.c sframe-error.c
+libsframe_la_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include \
+			-I$(srcdir)/../libctf
+
diff --git a/libsframe/Makefile.in b/libsframe/Makefile.in
new file mode 100644
index 00000000000..79ea3a9209d
--- /dev/null
+++ b/libsframe/Makefile.in
@@ -0,0 +1,1047 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+#   Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file 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 2 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; see the file COPYING.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
+	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/depstand.m4 \
+	$(top_srcdir)/../config/jobserver.m4 \
+	$(top_srcdir)/../config/lead-dot.m4 \
+	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/warnings.m4 \
+	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
+	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
+	$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+	$(am__configure_deps) $(am__include_HEADERS_DIST) \
+	$(am__DIST_COMMON)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
+libsframe_la_LIBADD =
+am_libsframe_la_OBJECTS = libsframe_la-sframe.lo \
+	libsframe_la-sframe-error.lo
+libsframe_la_OBJECTS = $(am_libsframe_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+@INSTALL_LIBBFD_FALSE@am_libsframe_la_rpath =
+@INSTALL_LIBBFD_TRUE@am_libsframe_la_rpath = -rpath $(libdir)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libsframe_la_SOURCES)
+DIST_SOURCES = $(libsframe_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__include_HEADERS_DIST = $(INCDIR)/sframe.h $(INCDIR)/sframe-api.h
+HEADERS = $(include_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	cscope distdir dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+	$(LISP)config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+	$(top_srcdir)/../ar-lib $(top_srcdir)/../compile \
+	$(top_srcdir)/../config.guess $(top_srcdir)/../config.sub \
+	$(top_srcdir)/../depcomp $(top_srcdir)/../install-sh \
+	$(top_srcdir)/../ltmain.sh $(top_srcdir)/../missing \
+	$(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  if test -d "$(distdir)"; then \
+    find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+      && rm -rf "$(distdir)" \
+      || { sleep 5 && rm -rf "$(distdir)"; }; \
+  else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+  | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_PEDANTIC = @WARN_PEDANTIC@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_libsframe_warn_cflags = @ac_libsframe_warn_cflags@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_warn = @c_warn@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_noncanonical = @host_noncanonical@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+target_noncanonical = @target_noncanonical@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+warn = @warn@
+SUBDIRS = testsuite
+ACLOCAL_AMFLAGS = -I .. -I ../config
+AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+BASEDIR = $(srcdir)/..
+INCDIR = $(srcdir)/../include
+# include libctf for swap.h
+AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../libctf
+AM_CFLAGS = -std=gnu99 @ac_libsframe_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@
+@INSTALL_LIBBFD_TRUE@lib_LTLIBRARIES = libsframe.la
+@INSTALL_LIBBFD_FALSE@include_HEADERS = 
+@INSTALL_LIBBFD_TRUE@include_HEADERS = $(INCDIR)/sframe.h $(INCDIR)/sframe-api.h
+@INSTALL_LIBBFD_FALSE@noinst_LTLIBRARIES = libsframe.la
+libsframe_la_SOURCES = sframe.c sframe-error.c
+libsframe_la_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include \
+			-I$(srcdir)/../libctf
+
+all: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+am--refresh: Makefile
+	@:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+	@test -f $@ || rm -f stamp-h1
+	@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f config.h stamp-h1
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libsframe.la: $(libsframe_la_OBJECTS) $(libsframe_la_DEPENDENCIES) $(EXTRA_libsframe_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK) $(am_libsframe_la_rpath) $(libsframe_la_OBJECTS) $(libsframe_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframe_la-sframe-error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframe_la-sframe.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libsframe_la-sframe.lo: sframe.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsframe_la-sframe.lo -MD -MP -MF $(DEPDIR)/libsframe_la-sframe.Tpo -c -o libsframe_la-sframe.lo `test -f 'sframe.c' || echo '$(srcdir)/'`sframe.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libsframe_la-sframe.Tpo $(DEPDIR)/libsframe_la-sframe.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sframe.c' object='libsframe_la-sframe.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) $(libsframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsframe_la-sframe.lo `test -f 'sframe.c' || echo '$(srcdir)/'`sframe.c
+
+libsframe_la-sframe-error.lo: sframe-error.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsframe_la-sframe-error.lo -MD -MP -MF $(DEPDIR)/libsframe_la-sframe-error.Tpo -c -o libsframe_la-sframe-error.lo `test -f 'sframe-error.c' || echo '$(srcdir)/'`sframe-error.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libsframe_la-sframe-error.Tpo $(DEPDIR)/libsframe_la-sframe-error.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sframe-error.c' object='libsframe_la-sframe-error.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) $(libsframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsframe_la-sframe-error.lo `test -f 'sframe-error.c' || echo '$(srcdir)/'`sframe-error.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool config.lt
+install-includeHEADERS: $(include_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+	done
+
+uninstall-includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+	test ! -s cscope.files \
+	  || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+	-rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	test -d "$(distdir)" || mkdir "$(distdir)"
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	-test -n "$(am__skip_mode_fix)" \
+	|| find "$(distdir)" -type d ! -perm -755 \
+		-exec chmod u+rwx,go+rx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
+	$(am__post_remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+	$(am__post_remove_distdir)
+
+dist-lzip: distdir
+	tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+	$(am__post_remove_distdir)
+
+dist-xz: distdir
+	tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+	$(am__post_remove_distdir)
+
+dist-tarZ: distdir
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__post_remove_distdir)
+
+dist-shar: distdir
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
+	$(am__post_remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__post_remove_distdir)
+
+dist dist-all:
+	$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+	$(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lz*) \
+	  lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+	*.tar.xz*) \
+	  xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir)
+	chmod u+w $(distdir)
+	mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+	chmod a-w $(distdir)
+	test -d $(distdir)/_build || exit 0; \
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && am__cwd=`pwd` \
+	  && $(am__cd) $(distdir)/_build/sub \
+	  && ../../configure \
+	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	    --srcdir=../.. --prefix="$$dc_install_base" \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+	  && cd "$$am__cwd" \
+	  || exit 1
+	$(am__post_remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@test -n '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: trying to run $@ with an empty' \
+	       '$$(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	$(am__cd) '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-includeHEADERS
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
+
+.MAKE: $(am__recursive_targets) all install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+	am--refresh check check-am clean clean-cscope clean-generic \
+	clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \
+	cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
+	dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \
+	distcheck distclean distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags distcleancheck \
+	distdir distuninstallcheck dvi dvi-am html html-am info \
+	info-am install install-am install-data install-data-am \
+	install-dvi install-dvi-am install-exec install-exec-am \
+	install-html install-html-am install-includeHEADERS \
+	install-info install-info-am install-libLTLIBRARIES \
+	install-man install-pdf install-pdf-am install-ps \
+	install-ps-am install-strip installcheck installcheck-am \
+	installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am uninstall-includeHEADERS \
+	uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libsframe/aclocal.m4 b/libsframe/aclocal.m4
new file mode 100644
index 00000000000..3a0b3426ebc
--- /dev/null
+++ b/libsframe/aclocal.m4
@@ -0,0 +1,1241 @@
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.15'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.15.1], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_AR([ACT-IF-FAIL])
+# -------------------------
+# Try to determine the archiver interface, and trigger the ar-lib wrapper
+# if it is needed.  If the detection of archiver interface fails, run
+# ACT-IF-FAIL (default is to abort configure with a proper error message).
+AC_DEFUN([AM_PROG_AR],
+[AC_BEFORE([$0], [LT_INIT])dnl
+AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([ar-lib])dnl
+AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false])
+: ${AR=ar}
+
+AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface],
+  [AC_LANG_PUSH([C])
+   am_cv_ar_interface=ar
+   AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])],
+     [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([am_ar_try])
+      if test "$ac_status" -eq 0; then
+        am_cv_ar_interface=ar
+      else
+        am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+        AC_TRY_EVAL([am_ar_try])
+        if test "$ac_status" -eq 0; then
+          am_cv_ar_interface=lib
+        else
+          am_cv_ar_interface=unknown
+        fi
+      fi
+      rm -f conftest.lib libconftest.a
+     ])
+   AC_LANG_POP([C])])
+
+case $am_cv_ar_interface in
+ar)
+  ;;
+lib)
+  # Microsoft lib, so override with the ar-lib wrapper script.
+  # FIXME: It is wrong to rewrite AR.
+  # But if we don't then we get into trouble of one sort or another.
+  # A longer-term fix would be to have automake use am__AR in this case,
+  # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+  # similar.
+  AR="$am_aux_dir/ar-lib $AR"
+  ;;
+unknown)
+  m4_default([$1],
+             [AC_MSG_ERROR([could not determine $AR interface])])
+  ;;
+esac
+AC_SUBST([AR])dnl
+])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC],   [depcc="$CC"   am_compiler_list=],
+      [$1], [CXX],  [depcc="$CXX"  am_compiler_list=],
+      [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+      [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+      [$1], [UPC],  [depcc="$UPC"  am_compiler_list=],
+      [$1], [GCJ],  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                    [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  am__universal=false
+  m4_case([$1], [CC],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac],
+    [CXX],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac])
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+  [--enable-dependency-tracking],
+  [do not reject slow dependency extractors])
+AS_HELP_STRING(
+  [--disable-dependency-tracking],
+  [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`AS_DIRNAME("$mf")`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`AS_DIRNAME(["$file"])`
+      AS_MKDIR_P([$dirpart/$fdir])
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+             [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+  [ok:ok],,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+	      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+			     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+		  [_AM_DEPENDENCIES([CC])],
+		  [m4_define([AC_PROG_CC],
+			     m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+		  [_AM_DEPENDENCIES([CXX])],
+		  [m4_define([AC_PROG_CXX],
+			     m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+		  [_AM_DEPENDENCIES([OBJC])],
+		  [m4_define([AC_PROG_OBJC],
+			     m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+		  [_AM_DEPENDENCIES([OBJCXX])],
+		  [m4_define([AC_PROG_OBJCXX],
+			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+  fi
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST([install_sh])])
+
+# Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless 'enable' is passed literally.
+# For symmetry, 'disable' may be passed as well.  Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+       [enable], [m4_define([am_maintainer_other], [disable])],
+       [disable], [m4_define([am_maintainer_other], [enable])],
+       [m4_define([am_maintainer_other], [enable])
+        m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+  dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+  AC_ARG_ENABLE([maintainer-mode],
+    [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
+      am_maintainer_other[ make rules and dependencies not useful
+      (and sometimes confusing) to the casual installer])],
+    [USE_MAINTAINER_MODE=$enableval],
+    [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+  AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+  AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+  MAINT=$MAINTAINER_MODE_TRUE
+  AC_SUBST([MAINT])dnl
+]
+)
+
+# Check to see how 'make' treats includes.	            -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake.  We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+  [whether $CC understands -c and -o together],
+  [am_cv_prog_cc_c_o],
+  [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \	]]*)
+    AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$[*]" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$[*]" != "X $srcdir/configure conftest.file" \
+	&& test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment])
+     fi
+     if test "$[2]" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+  [AC_MSG_CHECKING([that generated files are newer than configure])
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+  [--enable-silent-rules],
+  [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+  [--disable-silent-rules],
+  [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+   [am_cv_make_support_nested_variables],
+   [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+  dnl Using '$V' instead of '$(V)' breaks IRIX make.
+  AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+  [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+  [m4_case([$1],
+    [ustar],
+     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+      # There is notably a 21 bits limit for the UID and the GID.  In fact,
+      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+      # and bug#13588).
+      am_max_uid=2097151 # 2^21 - 1
+      am_max_gid=$am_max_uid
+      # The $UID and $GID variables are not portable, so we need to resort
+      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls
+      # below are definitely unexpected, so allow the users to see them
+      # (that is, avoid stderr redirection).
+      am_uid=`id -u || echo unknown`
+      am_gid=`id -g || echo unknown`
+      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+      if test $am_uid -le $am_max_uid; then
+         AC_MSG_RESULT([yes])
+      else
+         AC_MSG_RESULT([no])
+         _am_tools=none
+      fi
+      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+      if test $am_gid -le $am_max_gid; then
+         AC_MSG_RESULT([yes])
+      else
+        AC_MSG_RESULT([no])
+        _am_tools=none
+      fi],
+
+  [pax],
+    [],
+
+  [m4_fatal([Unknown tar format])])
+
+  AC_MSG_CHECKING([how to create a $1 tar archive])
+
+  # Go ahead even if we have the value already cached.  We do so because we
+  # need to set the values for the 'am__tar' and 'am__untar' variables.
+  _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+  for _am_tool in $_am_tools; do
+    case $_am_tool in
+    gnutar)
+      for _am_tar in tar gnutar gtar; do
+        AM_RUN_LOG([$_am_tar --version]) && break
+      done
+      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      am__untar="$_am_tar -xf -"
+      ;;
+    plaintar)
+      # Must skip GNU tar: if it does not support --format= it doesn't create
+      # ustar tarball either.
+      (tar --version) >/dev/null 2>&1 && continue
+      am__tar='tar chf - "$$tardir"'
+      am__tar_='tar chf - "$tardir"'
+      am__untar='tar xf -'
+      ;;
+    pax)
+      am__tar='pax -L -x $1 -w "$$tardir"'
+      am__tar_='pax -L -x $1 -w "$tardir"'
+      am__untar='pax -r'
+      ;;
+    cpio)
+      am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+      am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+      am__untar='cpio -i -H $1 -d'
+      ;;
+    none)
+      am__tar=false
+      am__tar_=false
+      am__untar=false
+      ;;
+    esac
+
+    # If the value was cached, stop now.  We just wanted to have am__tar
+    # and am__untar set.
+    test -n "${am_cv_prog_tar_$1}" && break
+
+    # tar/untar a dummy directory, and stop if the command works.
+    rm -rf conftest.dir
+    mkdir conftest.dir
+    echo GrepMe > conftest.dir/file
+    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+    rm -rf conftest.dir
+    if test -s conftest.tar; then
+      AM_RUN_LOG([$am__untar <conftest.tar])
+      AM_RUN_LOG([cat conftest.dir/file])
+      grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+    fi
+  done
+  rm -rf conftest.dir
+
+  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+  AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([../bfd/acinclude.m4])
+m4_include([../config/acx.m4])
+m4_include([../config/depstand.m4])
+m4_include([../config/jobserver.m4])
+m4_include([../config/lead-dot.m4])
+m4_include([../config/override.m4])
+m4_include([../config/warnings.m4])
+m4_include([../libtool.m4])
+m4_include([../ltoptions.m4])
+m4_include([../ltsugar.m4])
+m4_include([../ltversion.m4])
+m4_include([../lt~obsolete.m4])
diff --git a/libsframe/config.h.in b/libsframe/config.h.in
new file mode 100644
index 00000000000..6712ff1cc81
--- /dev/null
+++ b/libsframe/config.h.in
@@ -0,0 +1,144 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <byteswap.h> header file. */
+#undef HAVE_BYTESWAP_H
+
+/* Define to 1 if you have the declaration of `asprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_ASPRINTF
+
+/* Define to 1 if you have the declaration of `bswap_16', and to 0 if you
+   don't. */
+#undef HAVE_DECL_BSWAP_16
+
+/* Define to 1 if you have the declaration of `bswap_32', and to 0 if you
+   don't. */
+#undef HAVE_DECL_BSWAP_32
+
+/* Define to 1 if you have the declaration of `bswap_64', and to 0 if you
+   don't. */
+#undef HAVE_DECL_BSWAP_64
+
+/* Define to 1 if you have the declaration of `stpcpy', and to 0 if you don't.
+   */
+#undef HAVE_DECL_STPCPY
+
+/* Define to 1 if you have the declaration of `vasprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_VASPRINTF
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <endian.h> header file. */
+#undef HAVE_ENDIAN_H
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#undef VERSION
+
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
diff --git a/libsframe/configure.ac b/libsframe/configure.ac
new file mode 100644
index 00000000000..d2f32ae2ebd
--- /dev/null
+++ b/libsframe/configure.ac
@@ -0,0 +1,78 @@
+dnl                                            -*- Autoconf -*-
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl   Copyright (C) 2022 Free Software Foundation, Inc.
+dnl
+dnl This file is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; see the file COPYING.  If not see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_INIT([libsframe], BFD_VERSION)
+AC_CONFIG_SRCDIR(sframe.c)
+AC_CONFIG_MACRO_DIR(..)
+AC_CONFIG_MACRO_DIR(../config)
+AC_CONFIG_MACRO_DIR(../bfd)
+AC_USE_SYSTEM_EXTENSIONS
+AM_INIT_AUTOMAKE
+
+# Checks for programs.
+AC_PROG_MAKE_SET
+AC_PROG_CC
+AC_PROG_RANLIB
+AM_PROG_AR
+
+dnl Default to a non shared library.  This may be overridden by the
+dnl configure option --enable-shared.
+AC_DISABLE_SHARED
+
+LT_INIT
+AC_SYS_LARGEFILE
+
+MISSING=`cd $ac_aux_dir && ${PWDCMD-pwd}`/missing
+AC_CHECK_PROGS([ACLOCAL], [aclocal], [$MISSING aclocal])
+AC_CHECK_PROGS([AUTOCONF], [autoconf], [$MISSING autoconf])
+AC_CHECK_PROGS([AUTOHEADER], [autoheader], [$MISSING autoheader])
+
+# Figure out what compiler warnings we can enable.
+# See config/warnings.m4 for details.
+
+ACX_PROG_CC_WARNING_OPTS([-W -Wall -Wno-narrowing -Wwrite-strings \
+			  -Wmissing-format-attribute], [warn])
+ACX_PROG_CC_WARNING_OPTS([-Wstrict-prototypes -Wmissing-prototypes \
+			  -Wold-style-definition], [c_warn])
+ACX_PROG_CC_WARNING_ALMOST_PEDANTIC([-Wno-long-long])
+
+# Only enable with --enable-werror-always until existing warnings are
+# corrected.
+ACX_PROG_CC_WARNINGS_ARE_ERRORS([manual])
+
+AM_MAINTAINER_MODE
+AM_INSTALL_LIBBFD
+ACX_PROG_CC_WARNING_OPTS([-Wall], [ac_libsframe_warn_cflags])
+
+AC_FUNC_MMAP
+AC_CHECK_HEADERS(byteswap.h endian.h)
+
+dnl Check for bswap_{16,32,64}
+AC_CHECK_DECLS([bswap_16, bswap_32, bswap_64], [], [], [[#include <byteswap.h>]])
+AC_CHECK_DECLS([asprintf, vasprintf, stpcpy])
+
+AC_CONFIG_FILES(Makefile
+		testsuite/Makefile
+		testsuite/libsframe.decode/Makefile
+		testsuite/libsframe.encode/Makefile)
+AC_CONFIG_HEADERS(config.h)
+AC_OUTPUT
+
+GNU_MAKE_JOBSERVER
diff --git a/libsframe/sframe-error.c b/libsframe/sframe-error.c
new file mode 100644
index 00000000000..292fdb3f131
--- /dev/null
+++ b/libsframe/sframe-error.c
@@ -0,0 +1,49 @@
+/* sframe-error.c - Error messages.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   his file is part of libsframe.
+
+   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 "sframe-api.h"
+#include <stddef.h>
+#include <string.h>
+
+/* In this file, we want to treat the first item of the SFrame error
+   macro like subsequent items.  */
+#define _SFRAME_FIRST(NAME, VALUE) _SFRAME_ITEM(NAME, VALUE)
+
+/* The error message strings, each in a unique structure member precisely big
+   enough for that error, plus a str member to access them all as a string
+   table.  */
+
+static const char *const _sframe_errlist[] = {
+#define _SFRAME_ITEM(n, s) s,
+_SFRAME_ERRORS
+#undef _SFRAME_ITEM
+};
+
+const char *
+sframe_errmsg (int error)
+{
+  const char *str;
+
+  if (error >= ESFRAME_BASE && (error - ESFRAME_BASE) < ESFRAME_NERR)
+    str = _sframe_errlist[error - ESFRAME_BASE];
+  else
+    str = (const char *) strerror (error);
+
+  return (str ? str : "Unknown error");
+}
diff --git a/libsframe/sframe-impl.h b/libsframe/sframe-impl.h
new file mode 100644
index 00000000000..0e61c977886
--- /dev/null
+++ b/libsframe/sframe-impl.h
@@ -0,0 +1,55 @@
+/* Implementation header.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of libsframe.
+
+   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/>.  */
+
+#ifndef _SFRAME_IMPL_H
+#define _SFRAME_IMPL_H
+
+#include "sframe-api.h"
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+#include <assert.h>
+#define sframe_assert(expr) (assert (expr))
+
+struct sframe_decoder_ctx
+{
+  sframe_header sfd_header;	      /* SFrame header.  */
+  uint32_t *sfd_funcdesc;	      /* SFrame function desc entries table.  */
+  void *sfd_fres;		      /* SFrame FRE table.  */
+  int sfd_fre_nbytes;		      /* Number of bytes needed for SFrame FREs.  */
+};
+
+struct sframe_encoder_ctx
+{
+  sframe_header sfe_header;		/* SFrame header.  */
+  uint32_t *sfe_funcdesc;		/* SFrame function desc entries table.  */
+  sframe_frame_row_entry *sfe_fres;	/* SFrame FRE table.  */
+  uint32_t sfe_fre_nbytes;		/* Number of bytes needed for SFrame FREs.  */
+  char *sfe_data;			/* SFrame data buffer.  */
+  size_t sfe_data_size;			/* Size of the SFrame data buffer.  */
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _SFRAME_IMPL_H */
diff --git a/libsframe/sframe.c b/libsframe/sframe.c
new file mode 100644
index 00000000000..13cf5686f30
--- /dev/null
+++ b/libsframe/sframe.c
@@ -0,0 +1,1566 @@
+/* sframe.c - SFrame decoder/encoder.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of libsframe.
+
+   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 "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include "sframe-impl.h"
+#include "swap.h"
+
+typedef struct sf_funidx_tbl
+{
+  unsigned int count;
+  unsigned int alloced;
+  sframe_func_desc_entry entry[1];
+} sf_funidx_tbl;
+
+typedef struct sf_fre_tbl
+{
+  unsigned int count;
+  unsigned int alloced;
+  sframe_frame_row_entry entry[1];
+} sf_fre_tbl;
+
+#define _sf_printflike_(string_index,first_to_check) \
+    __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
+
+static void debug_printf (const char *, ...);
+
+static int _sframe_debug;	/* Control for printing out debug info.  */
+static int number_of_entries = 64;
+
+static void
+sframe_init_debug (void)
+{
+  static int inited;
+
+  if (!inited)
+    {
+      _sframe_debug = getenv ("SFRAME_DEBUG") != NULL;
+      inited = 1;
+    }
+}
+
+_sf_printflike_ (1, 2)
+static void debug_printf (const char *format, ...)
+{
+  if (_sframe_debug)
+    {
+      va_list args;
+
+      va_start (args, format);
+      vfprintf (stderr, format, args);
+      va_end (args);
+    }
+}
+
+/* Generate bitmask of given size in bytes.  This is used for
+   some checks on the FRE start address.
+   SFRAME_FRE_TYPE_ADDR1 => 1 byte => [ bitmask = 0xff ]
+   SFRAME_FRE_TYPE_ADDR2 => 2 byte => [ bitmask = 0xffff ]
+   SFRAME_FRE_TYPE_ADDR4 => 4 byte => [ bitmask = 0xffffffff ].  */
+#define SFRAME_BITMASK_OF_SIZE(size_in_bytes) \
+  (((uint64_t)1 << (size_in_bytes*8)) - 1)
+
+/* Store the specified error code into errp if it is non-NULL.
+   Return SFRAME_ERR.  */
+
+static int
+sframe_set_errno (int *errp, int error)
+{
+  if (errp != NULL)
+    *errp = error;
+  return SFRAME_ERR;
+}
+
+/* Store the specified error code into errp if it is non-NULL.
+   Return NULL.  */
+
+static void *
+sframe_ret_set_errno (int *errp, int error)
+{
+  if (errp != NULL)
+    *errp = error;
+  return NULL;
+}
+
+/* Access functions for frame row entry data.  */
+
+static unsigned int
+sframe_fre_get_offset_count (unsigned char fre_info)
+{
+  return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
+}
+
+static unsigned int
+sframe_fre_get_offset_size (unsigned char fre_info)
+{
+  return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
+}
+
+/* Access functions for info from function descriptor entry.  */
+
+static unsigned int
+sframe_get_fre_type (sframe_func_desc_entry *fdep)
+{
+  unsigned int fre_type = 0;
+  if (fdep)
+    fre_type = SFRAME_V1_FUNC_FRE_TYPE (fdep->sfde_func_info);
+  return fre_type;
+}
+
+static unsigned int
+sframe_get_fde_type (sframe_func_desc_entry *fdep)
+{
+  unsigned int fde_type = 0;
+  if (fdep)
+    fde_type = SFRAME_V1_FUNC_FDE_TYPE (fdep->sfde_func_info);
+  return fde_type;
+}
+
+/* Check if flipping is needed, based on ENDIAN.  */
+
+static int
+need_swapping (int endian)
+{
+  unsigned int ui = 1;
+  char *c = (char *)&ui;
+  int is_little = (int)*c;
+
+  switch (endian)
+    {
+      case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:
+      case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
+	return !is_little;
+      case SFRAME_ABI_AARCH64_ENDIAN_BIG:
+	return is_little;
+      default:
+	break;
+    }
+
+  return 0;
+}
+
+/* Flip the endianness of the SFrame header.  */
+
+static void
+flip_header (sframe_header *sfheader)
+{
+  swap_thing (sfheader->sfh_preamble.sfp_magic);
+  swap_thing (sfheader->sfh_preamble.sfp_version);
+  swap_thing (sfheader->sfh_preamble.sfp_flags);
+  swap_thing (sfheader->sfh_cfa_fixed_fp_offset);
+  swap_thing (sfheader->sfh_cfa_fixed_ra_offset);
+  swap_thing (sfheader->sfh_num_fdes);
+  swap_thing (sfheader->sfh_num_fres);
+  swap_thing (sfheader->sfh_fre_len);
+  swap_thing (sfheader->sfh_fdeoff);
+  swap_thing (sfheader->sfh_freoff);
+}
+
+static void
+flip_fde (sframe_func_desc_entry *fdep)
+{
+  swap_thing (fdep->sfde_func_start_address);
+  swap_thing (fdep->sfde_func_size);
+  swap_thing (fdep->sfde_func_start_fre_off);
+  swap_thing (fdep->sfde_func_num_fres);
+}
+
+/* Check if SFrame header has valid data.  */
+
+static int
+sframe_header_sanity_check_p (sframe_header *hp)
+{
+  unsigned char all_flags = SFRAME_F_FDE_SORTED | SFRAME_F_FRAME_POINTER;
+  /* Check preamble is valid.  */
+  if ((hp->sfh_preamble.sfp_magic != SFRAME_MAGIC)
+      || (hp->sfh_preamble.sfp_version != SFRAME_VERSION)
+      || ((hp->sfh_preamble.sfp_flags | all_flags)
+	  != all_flags))
+    return 0;
+
+  /* Check offsets are valid.  */
+  if (hp->sfh_fdeoff > hp->sfh_freoff)
+    return 0;
+
+  return 1;
+}
+
+/* Flip the start address pointed to by FP.  */
+
+static void
+flip_fre_start_address (char *fp, unsigned int fre_type)
+{
+  void *start = (void*)fp;
+  if (fre_type == SFRAME_FRE_TYPE_ADDR2)
+    {
+      unsigned short *start_addr = (unsigned short *)(start);
+      swap_thing (*start_addr);
+    }
+  else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
+    {
+      uint32_t *start_addr = (uint32_t *)(start);
+      swap_thing (*start_addr);
+    }
+}
+
+static void
+flip_fre_stack_offsets (char *fp, unsigned char offset_size,
+			unsigned char offset_cnt)
+{
+  int j;
+  void *offsets = (void *)fp;
+
+  if (offset_size == SFRAME_FRE_OFFSET_2B)
+    {
+      unsigned short *ust = (unsigned short *)offsets;
+      for (j = offset_cnt; j > 0; ust++, j--)
+	swap_thing (*ust);
+    }
+  else if (offset_size == SFRAME_FRE_OFFSET_4B)
+    {
+      uint32_t *uit = (uint32_t *)offsets;
+      for (j = offset_cnt; j > 0; uit++, j--)
+	swap_thing (*uit);
+    }
+}
+
+/* Get the FRE start address size, given the FRE_TYPE.  */
+
+static size_t
+sframe_fre_start_addr_size (unsigned int fre_type)
+{
+  size_t addr_size = 0;
+  switch (fre_type)
+    {
+    case SFRAME_FRE_TYPE_ADDR1:
+      addr_size = 1;
+      break;
+    case SFRAME_FRE_TYPE_ADDR2:
+      addr_size = 2;
+      break;
+    case SFRAME_FRE_TYPE_ADDR4:
+      addr_size = 4;
+      break;
+    default:
+      /* No other value is expected.  */
+      sframe_assert (0);
+      break;
+    }
+  return addr_size;
+}
+
+/* Check if the FREP has valid data.  */
+
+static int
+sframe_fre_sanity_check_p (sframe_frame_row_entry *frep)
+{
+  unsigned int offset_size, offset_cnt;
+  unsigned int fre_info;
+
+  if (frep == NULL)
+    return 0;
+
+  fre_info = frep->fre_info;
+  offset_size = sframe_fre_get_offset_size (fre_info);
+
+  if (offset_size != SFRAME_FRE_OFFSET_1B
+      && offset_size != SFRAME_FRE_OFFSET_2B
+      && offset_size != SFRAME_FRE_OFFSET_4B)
+    return 0;
+
+  offset_cnt = sframe_fre_get_offset_count (fre_info);
+  if (offset_cnt > 3)
+    return 0;
+
+  return 1;
+}
+
+/* Get FRE_INFO's offset size in bytes.  */
+
+static size_t
+sframe_fre_offset_bytes_size (unsigned char fre_info)
+{
+  unsigned int offset_size, offset_cnt;
+
+  offset_size = sframe_fre_get_offset_size (fre_info);
+
+  debug_printf ("offset_size =  %u\n", offset_size);
+
+  offset_cnt = sframe_fre_get_offset_count (fre_info);
+
+  if (offset_size == SFRAME_FRE_OFFSET_2B
+      || offset_size == SFRAME_FRE_OFFSET_4B)	/* 2 or 4 bytes.  */
+    return (offset_cnt * (offset_size * 2));
+
+  return (offset_cnt);
+}
+
+/* Get total size in bytes to represent FREP in the binary format.  This
+   includes the starting address, FRE info, and all the offsets.  */
+
+static size_t
+sframe_fre_entry_size (sframe_frame_row_entry *frep, unsigned int fre_type)
+{
+  if (frep == NULL)
+    return 0;
+
+  unsigned char fre_info = frep->fre_info;
+  size_t addr_size = sframe_fre_start_addr_size (fre_type);
+
+  return (addr_size + sizeof (frep->fre_info)
+	  + sframe_fre_offset_bytes_size (fre_info));
+}
+
+static int
+flip_fre (char *fp, unsigned int fre_type, size_t *fre_size)
+{
+  unsigned char fre_info;
+  unsigned int offset_size, offset_cnt;
+  size_t addr_size, fre_info_size = 0;
+  int err = 0;
+
+  if (fre_size == NULL)
+    return sframe_set_errno (&err, EINVAL);
+
+  flip_fre_start_address (fp, fre_type);
+
+  /* Advance the buffer pointer to where the FRE info is.  */
+  addr_size = sframe_fre_start_addr_size (fre_type);
+  fp += addr_size;
+
+  /* FRE info is unsigned char.  No need to flip.  */
+  fre_info = *(unsigned char*)fp;
+  offset_size = sframe_fre_get_offset_size (fre_info);
+  offset_cnt = sframe_fre_get_offset_count (fre_info);
+
+  /* Advance the buffer pointer to where the stack offsets are.  */
+  fre_info_size = sizeof (unsigned char);
+  fp += fre_info_size;
+  flip_fre_stack_offsets (fp, offset_size, offset_cnt);
+
+  *fre_size
+    = addr_size + fre_info_size + sframe_fre_offset_bytes_size (fre_info);
+
+  return 0;
+}
+
+/* Endian flip the contents of FRAME_BUF of size BUF_SIZE.
+   The SFrame header in the FRAME_BUF must be endian flipped prior to
+   calling flip_sframe.  If an error code is returned, the buffer should
+   not be used.  */
+
+static int
+flip_sframe (char *frame_buf, size_t buf_size)
+{
+  unsigned int i, j, prev_frep_index;
+  sframe_header *ihp;
+  char *fdes;
+  char *fp = NULL;
+  sframe_func_desc_entry *fdep;
+  unsigned int num_fdes, num_fres;
+  unsigned int fre_type;
+  size_t esz;
+  int err = 0;
+
+  /* Header must have been flipped by now.  */
+  ihp = (sframe_header *)frame_buf;
+
+  if (!sframe_header_sanity_check_p (ihp))
+    return sframe_set_errno (&err, ESFRAME_BUF_INVAL);
+
+  /* The contents of the SFrame header are safe to read.  Get the number of
+     FDEs and the first FDE in the buffer.  */
+  num_fdes = ihp->sfh_num_fdes;
+  fdes = frame_buf + sizeof (sframe_header) + ihp->sfh_fdeoff;
+  fdep = (sframe_func_desc_entry *)fdes;
+
+  j = 0;
+  prev_frep_index = 0;
+  for (i = 0; i < num_fdes; fdep++, i++)
+    {
+      flip_fde (fdep);
+
+      num_fres = fdep->sfde_func_num_fres;
+      fre_type = sframe_get_fre_type (fdep);
+
+      fp = frame_buf + sizeof (sframe_header) + ihp->sfh_freoff;
+      fp += fdep->sfde_func_start_fre_off;
+      for (; j < prev_frep_index + num_fres; j++)
+	{
+	  if (flip_fre (fp, fre_type, &esz))
+	    goto bad;
+
+	  if (esz == 0)
+	    goto bad;
+	  fp += esz;
+	}
+      prev_frep_index = j;
+    }
+  /* All FREs must have been endian flipped by now.  */
+  if (j != ihp->sfh_num_fres)
+    goto bad;
+  /* All contents must have been processed by now.  */
+  if ((frame_buf + buf_size) != (void*)fp)
+    goto bad;
+
+  /* Success.  */
+  return 0;
+bad:
+  return SFRAME_ERR;
+}
+
+/* The SFrame Decoder.  */
+
+/* Compare function for qsort'ing the FDE table.  */
+
+static int
+fde_func (const void *p1, const void *p2)
+{
+  const sframe_func_desc_entry *aa = p1;
+  const sframe_func_desc_entry *bb = p2;
+
+  if (aa->sfde_func_start_address < bb->sfde_func_start_address)
+    return -1;
+  else if (aa->sfde_func_start_address > bb->sfde_func_start_address)
+    return 1;
+  return 0;
+}
+
+/* Get IDX'th offset from FRE.  Set errp as applicable.  */
+
+static int32_t
+sframe_get_fre_offset (sframe_frame_row_entry *fre, int idx, int *errp)
+{
+  int offset_cnt, offset_size;
+
+  if (fre == NULL || !sframe_fre_sanity_check_p (fre))
+    return sframe_set_errno (errp, ESFRAME_FRE_INVAL);
+
+  offset_cnt = sframe_fre_get_offset_count (fre->fre_info);
+  offset_size = sframe_fre_get_offset_size (fre->fre_info);
+
+  if (offset_cnt < idx + 1)
+    return sframe_set_errno (errp, ESFRAME_FREOFFSET_NOPRESENT);
+
+  if (errp)
+    *errp = 0; /* Offset Valid.  */
+
+  if (offset_size == SFRAME_FRE_OFFSET_1B)
+    {
+      int8_t *sp = (int8_t *)fre->fre_offsets;
+      return sp[idx];
+    }
+  else if (offset_size == SFRAME_FRE_OFFSET_2B)
+    {
+      int16_t *sp = (int16_t *)fre->fre_offsets;
+      return sp[idx];
+    }
+  else
+    {
+      int32_t *ip = (int32_t *)fre->fre_offsets;
+      return ip[idx];
+    }
+}
+
+/* Free the decoder context.  */
+
+void
+sframe_decoder_free (sframe_decoder_ctx **decoder)
+{
+  if (decoder != NULL)
+    {
+      sframe_decoder_ctx *dctx = *decoder;
+      if (dctx == NULL)
+	return;
+
+      if (dctx->sfd_funcdesc != NULL)
+	{
+	  free (dctx->sfd_funcdesc);
+	  dctx->sfd_funcdesc = NULL;
+	}
+      if (dctx->sfd_fres != NULL)
+	{
+	  free (dctx->sfd_fres);
+	  dctx->sfd_fres = NULL;
+	}
+
+      free (*decoder);
+      *decoder = NULL;
+    }
+}
+
+/* Create a FDE function info byte given an FRE_TYPE and an FDE_TYPE.  */
+/* FIXME API for linker.  Revisit if its better placed somewhere else?  */
+
+unsigned char
+sframe_fde_func_info (unsigned int fre_type,
+			 unsigned int fde_type)
+{
+  unsigned char func_info;
+  sframe_assert (fre_type == SFRAME_FRE_TYPE_ADDR1
+		   || fre_type == SFRAME_FRE_TYPE_ADDR2
+		   || fre_type == SFRAME_FRE_TYPE_ADDR4);
+  sframe_assert (fde_type == SFRAME_FDE_TYPE_PCINC
+		    || fde_type == SFRAME_FDE_TYPE_PCMASK);
+  func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
+  return func_info;
+}
+
+/* Get the FRE type given the function size.  */
+/* FIXME API for linker.  Revisit if its better placed somewhere else?  */
+
+unsigned int
+sframe_calc_fre_type (unsigned int func_size)
+{
+  unsigned int fre_type = 0;
+  if (func_size <= 0xff)
+    fre_type = SFRAME_FRE_TYPE_ADDR1;
+  else if (func_size <= 0xffff)
+    fre_type = SFRAME_FRE_TYPE_ADDR2;
+  else if (func_size <= 0xffffffff)
+    fre_type = SFRAME_FRE_TYPE_ADDR4;
+  return fre_type;
+}
+
+/* Get the base reg id from the FRE info.  Set errp if failure.  */
+
+unsigned int
+sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre, int *errp)
+{
+  if (fre == NULL)
+    return sframe_set_errno (errp, ESFRAME_FRE_INVAL);
+
+  unsigned int fre_info = fre->fre_info;
+  return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
+}
+
+/* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+sframe_fre_get_cfa_offset (sframe_frame_row_entry *fre, int *errp)
+{
+  return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, errp);
+}
+
+/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+sframe_fre_get_fp_offset (sframe_frame_row_entry *fre, int *errp)
+{
+  return sframe_get_fre_offset (fre, SFRAME_FRE_FP_OFFSET_IDX, errp);
+}
+
+/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+sframe_fre_get_ra_offset (sframe_frame_row_entry *fre, int *errp)
+{
+  return sframe_get_fre_offset (fre, SFRAME_FRE_RA_OFFSET_IDX, errp);
+}
+
+static int
+sframe_frame_row_entry_copy (sframe_frame_row_entry *dst, sframe_frame_row_entry *src)
+{
+  int err = 0;
+
+  if (dst == NULL || src == NULL)
+    return sframe_set_errno (&err, EINVAL);
+
+  memcpy (dst, src, sizeof (sframe_frame_row_entry));
+  return 0;
+}
+
+static int
+sframe_decode_fre_start_address (const char *fre_buf,
+				    uint32_t *fre_start_addr,
+				    unsigned int fre_type)
+{
+  uint32_t saddr = 0;
+  int err = 0;
+
+  if (fre_type == SFRAME_FRE_TYPE_ADDR1)
+    {
+      uint8_t *uc = (uint8_t *)fre_buf;
+      saddr = (uint32_t)*uc;
+    }
+  else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
+    {
+      uint16_t *ust = (uint16_t *)fre_buf;
+      saddr = (uint32_t)*ust;
+    }
+  else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
+    {
+      uint32_t *uit = (uint32_t *)fre_buf;
+      saddr = (uint32_t)*uit;
+    }
+  else
+    return sframe_set_errno (&err, EINVAL);
+
+  *fre_start_addr = saddr;
+  return 0;
+}
+
+/* Decode a frame row entry FRE which starts at location FRE_BUF.  The function
+   updates ESZ to the size of the FRE as stored in the binary format.
+
+   This function works closely with the SFrame binary format.
+
+   Returns SFRAME_ERR if failure.  */
+
+static int
+sframe_decode_fre (const char *fre_buf, sframe_frame_row_entry *fre,
+		      unsigned int fre_type,
+		      size_t *esz)
+{
+  int err = 0;
+  void *stack_offsets = NULL;
+  size_t stack_offsets_sz;
+  size_t addr_size;
+  size_t fre_size;
+
+  if (fre_buf == NULL || fre == NULL || esz == NULL)
+    return sframe_set_errno (&err, EINVAL);
+
+  /* Copy over the FRE start address.  */
+  sframe_decode_fre_start_address (fre_buf, &fre->fre_start_addr, fre_type);
+
+  addr_size = sframe_fre_start_addr_size (fre_type);
+  fre->fre_info = *(unsigned char *)(fre_buf + addr_size);
+  /* Sanity check as the API works closely with the binary format.  */
+  sframe_assert (sizeof (fre->fre_info) == sizeof (unsigned char));
+
+  /* Cleanup the space for fre_offsets first, then copy over the valid
+     bytes.  */
+  memset (fre->fre_offsets, 0, MAX_OFFSET_BYTES);
+  /* Get offsets size.  */
+  stack_offsets_sz = sframe_fre_offset_bytes_size (fre->fre_info);
+  stack_offsets = (unsigned char *)fre_buf + addr_size + sizeof (fre->fre_info);
+  memcpy (fre->fre_offsets, stack_offsets, stack_offsets_sz);
+
+  /* The FRE has been decoded.  Use it to perform one last sanity check.  */
+  fre_size = sframe_fre_entry_size (fre, fre_type);
+  sframe_assert (fre_size == (addr_size + sizeof (fre->fre_info)
+				 + stack_offsets_sz));
+  *esz = fre_size;
+
+  return 0;
+}
+
+/* Decode the specified SFrame buffer CF_BUF of size CF_SIZE and return the
+   new SFrame decoder context.
+
+   Sets ERRP for the caller if any error.  Frees up the allocated memory in
+   case of error.  */
+
+sframe_decoder_ctx *
+sframe_decode (const char *sf_buf, size_t sf_size, int *errp)
+{
+  const sframe_preamble *sfp;
+  size_t hdrsz = sizeof (sframe_header);
+  sframe_header *sfheaderp;
+  sframe_decoder_ctx *dctx;
+  char *frame_buf;
+  char *tempbuf = NULL;
+
+  int fidx_size;
+  uint32_t fre_bytes;
+  int foreign_endian = 0;
+
+  sframe_init_debug ();
+
+  if ((sf_buf == NULL) || (!sf_size))
+    return sframe_ret_set_errno (errp, ESFRAME_INVAL);
+  else if (sf_size < hdrsz)
+    return sframe_ret_set_errno (errp, ESFRAME_BUF_INVAL);
+
+  sfp = (const sframe_preamble *) sf_buf;
+
+  debug_printf ("sframe_decode: magic=0x%x version=%u flags=%u\n",
+		sfp->sfp_magic, sfp->sfp_version, sfp->sfp_flags);
+
+  /* Check for foreign endianness.  */
+  if (sfp->sfp_magic != SFRAME_MAGIC)
+    {
+      if (sfp->sfp_magic == bswap_16 (SFRAME_MAGIC))
+	foreign_endian = 1;
+      else
+	return sframe_ret_set_errno (errp, ESFRAME_BUF_INVAL);
+    }
+
+  /* Initialize a new decoder context.  */
+  if ((dctx = malloc (sizeof (sframe_decoder_ctx))) == NULL)
+    return sframe_ret_set_errno (errp, ESFRAME_NOMEM);
+  memset (dctx, 0, sizeof (sframe_decoder_ctx));
+
+  if (foreign_endian)
+    {
+      /* Allocate a new buffer and initialize it.  */
+      tempbuf = (char *) malloc (sf_size * sizeof (char));
+      if (tempbuf == NULL)
+	return sframe_ret_set_errno (errp, ESFRAME_NOMEM);
+      memcpy (tempbuf, sf_buf, sf_size);
+
+      /* Flip the header.  */
+      sframe_header *ihp = (sframe_header *) tempbuf;
+      flip_header (ihp);
+      /* Flip the rest of the SFrame section data buffer.  */
+      if (flip_sframe (tempbuf, sf_size))
+	{
+	  free (tempbuf);
+	  return sframe_ret_set_errno (errp, ESFRAME_BUF_INVAL);
+	}
+      frame_buf = tempbuf;
+    }
+  else
+    frame_buf = (char *)sf_buf;
+
+  /* Handle the SFrame header.  */
+  dctx->sfd_header = *(sframe_header *) frame_buf;
+  /* Validate the contents of SFrame header.  */
+  sfheaderp = &dctx->sfd_header;
+  if (!sframe_header_sanity_check_p (sfheaderp))
+    {
+      sframe_ret_set_errno (errp, ESFRAME_NOMEM);
+      goto decode_fail_free;
+    }
+  frame_buf += hdrsz;
+
+  /* Handle the SFrame Function Descriptor Entry section.  */
+  fidx_size
+    = sfheaderp->sfh_num_fdes * sizeof (sframe_func_desc_entry);
+  dctx->sfd_funcdesc = malloc (fidx_size);
+  if (dctx->sfd_funcdesc == NULL)
+    {
+      sframe_ret_set_errno (errp, ESFRAME_NOMEM);
+      goto decode_fail_free;
+    }
+  memcpy (dctx->sfd_funcdesc, frame_buf, fidx_size);
+
+  debug_printf ("%u total fidx size\n", fidx_size);
+
+  frame_buf += (fidx_size);
+
+  /* Handle the SFrame Frame Row Entry section.  */
+  dctx->sfd_fres = malloc (sfheaderp->sfh_fre_len);
+  if (dctx->sfd_fres == NULL)
+    {
+      sframe_ret_set_errno (errp, ESFRAME_NOMEM);
+      goto decode_fail_free;
+    }
+  memcpy (dctx->sfd_fres, frame_buf, sfheaderp->sfh_fre_len);
+
+  fre_bytes = sfheaderp->sfh_fre_len;
+  dctx->sfd_fre_nbytes = fre_bytes;
+
+  debug_printf ("%u total fre bytes\n", fre_bytes);
+
+  return dctx;
+
+decode_fail_free:
+  if (foreign_endian && tempbuf != NULL)
+    free (tempbuf);
+  sframe_decoder_free (&dctx);
+  dctx = NULL;
+  return dctx;
+}
+
+/* Get DECODER's SFrame header.  */
+
+static sframe_header *
+sframe_decoder_get_header (sframe_decoder_ctx *decoder)
+{
+  sframe_header *hp = NULL;
+  if (decoder != NULL)
+    hp = &decoder->sfd_header;
+  return hp;
+}
+
+/* Get the SFrame's abi/arch info.  */
+
+unsigned char
+sframe_decoder_get_abi_arch (sframe_decoder_ctx *ctx)
+{
+  sframe_header *sframe_header;
+  sframe_header = sframe_decoder_get_header (ctx);
+  return sframe_header->sfh_abi_arch;
+}
+
+/* Find the function descriptor entry starting which contains the specified
+   address ADDR.  */
+
+sframe_func_desc_entry *
+sframe_get_funcdesc_with_addr (sframe_decoder_ctx *ctx,
+			       int32_t addr, int *errp)
+{
+  sframe_header *dhp;
+  sframe_func_desc_entry *fdp;
+  int low, high, cnt;
+
+  if (ctx == NULL)
+    return sframe_ret_set_errno (errp, EINVAL);
+
+  dhp = sframe_decoder_get_header (ctx);
+
+  if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
+    return sframe_ret_set_errno (errp, ESFRAME_DCTX_INVAL);
+  /* If the FDE sub-section is not sorted on PCs, skip the lookup because
+     binary search cannot be used.  */
+  if ((dhp->sfh_preamble.sfp_flags & SFRAME_F_FDE_SORTED) == 0)
+    return sframe_ret_set_errno (errp, ESFRAME_FDE_NOTSORTED);
+
+  /* Do the binary search.  */
+  fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
+  low = 0;
+  high = dhp->sfh_num_fdes;
+  cnt = high;
+  while (low <= high)
+    {
+      int mid = low + (high - low) / 2;
+
+      if (fdp[mid].sfde_func_start_address == addr)
+	return fdp + mid;
+
+      if (fdp[mid].sfde_func_start_address < addr)
+	{
+	  if (mid == (cnt - 1)) 	/* Check if it's the last one.  */
+	    return fdp + (cnt - 1) ;
+	  else if (fdp[mid+1].sfde_func_start_address > addr)
+	    return fdp + mid;
+	  low = mid + 1;
+	}
+      else
+	high = mid - 1;
+    }
+
+  return sframe_ret_set_errno (errp, ESFRAME_FDE_NOTFOUND);
+}
+
+/* Find the SFrame Row Entry which contains the PC.  Returns
+   SFRAME_ERR if failure.  */
+
+int
+sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
+		 sframe_frame_row_entry *frep)
+{
+  sframe_func_desc_entry *fdep;
+  uint32_t start_address, i;
+  sframe_frame_row_entry cur_fre, next_fre;
+  unsigned char *sp;
+  unsigned int fre_type, fde_type;
+  size_t esz;
+  int err = 0;
+  size_t size = 0;
+  /* For regular FDEs (i.e. fde_type SFRAME_FDE_TYPE_PCINC),
+     where the start address in the FRE is an offset from start pc,
+     use a bitmask with all bits set so that none of the address bits are
+     ignored.  In this case, we need to return the FRE where
+     (PC >= FRE_START_ADDR) */
+  uint64_t bitmask = 0xffffffff;
+
+  if ((ctx == NULL) || (frep == NULL))
+    return sframe_set_errno (&err, EINVAL);
+
+  /* Find the FDE which contains the PC, then scan its fre entries.  */
+  fdep = sframe_get_funcdesc_with_addr (ctx, pc, &err);
+  if (fdep == NULL || ctx->sfd_fres == NULL)
+    return sframe_set_errno (&err, ESFRAME_DCTX_INVAL);
+
+  fre_type = sframe_get_fre_type (fdep);
+  fde_type = sframe_get_fde_type (fdep);
+
+  /* For FDEs for repetitive pattern of insns, we need to return the FRE
+     such that (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK).
+     so, update the bitmask to the start address.  */
+  /* FIXME - the bitmask should be picked per ABI or encoded in the format
+     somehow. For AMD64, the pltN entry stub is 16 bytes. */
+  if (fde_type == SFRAME_FDE_TYPE_PCMASK)
+    bitmask = 0xff;
+
+  sp = (unsigned char *) ctx->sfd_fres + fdep->sfde_func_start_fre_off;
+  for (i = 0; i < fdep->sfde_func_num_fres; i++)
+   {
+     err = sframe_decode_fre ((const char *)sp, &next_fre,
+				 fre_type, &esz);
+     start_address = next_fre.fre_start_addr;
+
+     if (((fdep->sfde_func_start_address
+	   + (int32_t) start_address) & bitmask) <= (pc & bitmask))
+       {
+	 sframe_frame_row_entry_copy (&cur_fre, &next_fre);
+
+	 /* Get the next FRE in sequence.  */
+	 if (i < fdep->sfde_func_num_fres - 1)
+	   {
+	     sp += esz;
+	     err = sframe_decode_fre ((const char*)sp, &next_fre,
+					 fre_type, &esz);
+
+	     /* Sanity check the next FRE.  */
+	     if (!sframe_fre_sanity_check_p (&next_fre))
+	       return sframe_set_errno (&err, ESFRAME_FRE_INVAL);
+
+	     size = next_fre.fre_start_addr;
+	   }
+	 else size = fdep->sfde_func_size;
+
+	 /* If the cur FRE is the one that contains the PC, return it.  */
+	 if (((fdep->sfde_func_start_address
+	       + (int32_t)size) & bitmask) > (pc & bitmask))
+	   {
+	     sframe_frame_row_entry_copy (frep, &cur_fre);
+	     return 0;
+	   }
+       }
+     else
+       return sframe_set_errno (&err, ESFRAME_FRE_INVAL);
+   }
+  return sframe_set_errno (&err, ESFRAME_FDE_INVAL);
+}
+
+/* Return the number of function descriptor entries in the SFrame decoder
+   DCTX.  */
+
+unsigned int
+sframe_decoder_get_num_fidx (sframe_decoder_ctx *ctx)
+{
+  unsigned int num_fdes = 0;
+  sframe_header *dhp = NULL;
+  dhp = sframe_decoder_get_header (ctx);
+  if (dhp)
+    num_fdes = dhp->sfh_num_fdes;
+  return num_fdes;
+}
+
+/* Get the data (NUM_FRES, FUNC_START_ADDRESS) from the function
+   descriptor entry at index I'th in the decoder CTX.  If failed,
+   return error code.  */
+/* FIXME - consolidate the args and return a
+   sframe_func_desc_index_elem rather?  */
+
+int
+sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
+				unsigned int i,
+				uint32_t *num_fres,
+				uint32_t *func_size,
+				int32_t *func_start_address,
+				unsigned char *func_info)
+{
+  sframe_func_desc_entry *fdp;
+  unsigned int num_fdes;
+  int err = 0;
+
+  if (ctx == NULL || func_start_address == NULL || num_fres == NULL
+      || func_size == NULL)
+    return sframe_set_errno (&err, EINVAL);
+
+  num_fdes = sframe_decoder_get_num_fidx (ctx);
+  if (num_fdes == 0
+      || i >= num_fdes
+      || ctx->sfd_funcdesc == NULL)
+    return sframe_set_errno (&err, ESFRAME_DCTX_INVAL);
+
+  fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc + i;
+  *num_fres = fdp->sfde_func_num_fres;
+  *func_start_address = fdp->sfde_func_start_address;
+  *func_size = fdp->sfde_func_size;
+  *func_info = fdp->sfde_func_info;
+
+  return 0;
+}
+
+/* Get the function descriptor entry at index FUNC_IDX in the decoder
+   context CTX.  */
+
+static sframe_func_desc_entry *
+sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx *ctx,
+					 uint32_t func_idx)
+{
+  /* Invalid argument.  No FDE will be found.  */
+  if (func_idx >= sframe_decoder_get_num_fidx (ctx))
+    return NULL;
+
+  sframe_func_desc_entry *fdep;
+  fdep = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
+  return fdep + func_idx;
+}
+
+/* Get the FRE_IDX'th FRE of the function at FUNC_IDX'th function
+   descriptor entry in the SFrame decoder CTX.  Returns error code as
+   applicable.  */
+
+int
+sframe_decoder_get_fre (sframe_decoder_ctx *ctx,
+			   unsigned int func_idx,
+			   unsigned int fre_idx,
+			   sframe_frame_row_entry *fre)
+{
+  sframe_func_desc_entry *fdep;
+  sframe_frame_row_entry ifre;
+  unsigned char *sp;
+  uint32_t i;
+  unsigned int fre_type;
+  size_t esz = 0;
+  int err = 0;
+
+  if (ctx == NULL || fre == NULL)
+    return sframe_set_errno (&err, EINVAL);
+
+  /* Get function descriptor entry at index func_idx.  */
+  fdep = sframe_decoder_get_funcdesc_at_index (ctx, func_idx);
+
+  if (fdep == NULL)
+    return sframe_set_errno (&err, ESFRAME_FDE_NOTFOUND);
+
+  fre_type = sframe_get_fre_type (fdep);
+  /* Now scan the FRE entries.  */
+  sp = (unsigned char *) ctx->sfd_fres + fdep->sfde_func_start_fre_off;
+  for (i = 0; i < fdep->sfde_func_num_fres; i++)
+   {
+     /* Decode the FRE at the current position.  Return it if valid.  */
+     err = sframe_decode_fre ((const char *)sp, &ifre, fre_type, &esz);
+     if (i == fre_idx)
+       {
+	 if (!sframe_fre_sanity_check_p (&ifre))
+	   return sframe_set_errno (&err, ESFRAME_FRE_INVAL);
+
+	 sframe_frame_row_entry_copy (fre, &ifre);
+
+	 if (fdep->sfde_func_size)
+	   sframe_assert (fre->fre_start_addr < fdep->sfde_func_size);
+	 else
+	   /* A SFrame FDE with func size equal to zero is possible.  */
+	   sframe_assert (fre->fre_start_addr == fdep->sfde_func_size);
+
+	 return 0;
+       }
+     /* Next FRE.  */
+     sp += esz;
+   }
+
+  return sframe_set_errno (&err, ESFRAME_FDE_NOTFOUND);
+}
+
+
+/* SFrame Encoder.  */
+
+/* Get a reference to the ENCODER's SFrame header.  */
+
+static sframe_header *
+sframe_encoder_get_header (sframe_encoder_ctx *encoder)
+{
+  sframe_header *hp = NULL;
+  if (encoder)
+    hp = &encoder->sfe_header;
+  return hp;
+}
+
+static sframe_func_desc_entry *
+sframe_encoder_get_funcdesc_at_index (sframe_encoder_ctx *encoder,
+					 uint32_t func_idx)
+{
+  sframe_func_desc_entry *fde = NULL;
+  if (func_idx < sframe_encoder_get_num_fidx (encoder))
+    {
+      sf_funidx_tbl *func_tbl = (sf_funidx_tbl *) encoder->sfe_funcdesc;
+      fde = func_tbl->entry + func_idx;
+    }
+  return fde;
+}
+
+/* Create an encoder context with the given SFrame format version VER, FLAGS
+   and ABI information.  Sets errp if failure.  */
+
+sframe_encoder_ctx *
+sframe_encode (unsigned char ver, unsigned char flags, int abi_arch,
+		  int *errp)
+{
+  sframe_header *hp;
+  sframe_encoder_ctx *fp;
+
+  if (ver != SFRAME_VERSION)
+    return sframe_ret_set_errno (errp, ESFRAME_VERSION_INVAL);
+
+  if ((fp = malloc (sizeof (sframe_encoder_ctx))) == NULL)
+    return sframe_ret_set_errno (errp, ESFRAME_NOMEM);
+
+  memset (fp, 0, sizeof (sframe_encoder_ctx));
+
+  /* Get the SFrame header and update it.  */
+  hp = sframe_encoder_get_header (fp);
+  hp->sfh_preamble.sfp_version = ver;
+  hp->sfh_preamble.sfp_magic = SFRAME_MAGIC;
+  hp->sfh_preamble.sfp_flags = flags;
+  hp->sfh_abi_arch = abi_arch;
+
+  return fp;
+}
+
+/* Free the encoder context.  */
+
+void
+sframe_free_encoder (sframe_encoder_ctx *encoder)
+{
+  if (encoder != NULL)
+    {
+      free (encoder->sfe_funcdesc);
+      free (encoder->sfe_fres);
+      free (encoder->sfe_data);
+      free (encoder);
+    }
+}
+
+/* Get the abi/arch info from the SFrame encoder context ENCODER.  */
+
+unsigned char
+sframe_encoder_get_abi_arch (sframe_encoder_ctx *encoder)
+{
+  unsigned char abi_arch = 0;
+  sframe_header *ehp;
+  ehp = sframe_encoder_get_header (encoder);
+  if (ehp)
+    abi_arch = ehp->sfh_abi_arch;
+  return abi_arch;
+}
+
+/* Return the number of function descriptor entries in the SFrame encoder
+   ENCODER.  */
+
+unsigned int
+sframe_encoder_get_num_fidx (sframe_encoder_ctx *encoder)
+{
+  unsigned int num_fdes = 0;
+  sframe_header *ehp = NULL;
+  ehp = sframe_encoder_get_header (encoder);
+  if (ehp)
+    num_fdes = ehp->sfh_num_fdes;
+  return num_fdes;
+}
+
+/* Add an FRE to function at FUNC_IDX'th function descriptor entry in
+   the encoder context.  */
+
+int
+sframe_encoder_add_fre (sframe_encoder_ctx *encoder,
+			   unsigned int func_idx,
+			   sframe_frame_row_entry *frep)
+{
+  sframe_header *ehp;
+  sframe_func_desc_entry *fdep;
+  sframe_frame_row_entry *ectx_frep;
+  size_t offsets_sz, esz;
+  unsigned int fre_type;
+  size_t fre_tbl_sz;
+  int err = 0;
+
+  if (encoder == NULL || frep == NULL)
+    return sframe_set_errno (&err, EINVAL);
+  if (!sframe_fre_sanity_check_p (frep))
+    return sframe_set_errno (&err, ESFRAME_FRE_INVAL);
+
+  /* Use func_idx to gather the function descriptor entry.  */
+  fdep = sframe_encoder_get_funcdesc_at_index (encoder, func_idx);
+
+  if (fdep == NULL)
+    return sframe_set_errno (&err, ESFRAME_FDE_NOTFOUND);
+
+  fre_type = sframe_get_fre_type (fdep);
+  sf_fre_tbl *fre_tbl = (sf_fre_tbl *) encoder->sfe_fres;
+
+  if (fre_tbl == NULL)
+    {
+      fre_tbl_sz = (sizeof (sf_fre_tbl)
+		    + (number_of_entries * sizeof (sframe_frame_row_entry)));
+      fre_tbl = malloc (fre_tbl_sz);
+
+      if (fre_tbl == NULL)
+	{
+	  sframe_set_errno (&err, ESFRAME_NOMEM);
+	  goto bad;		/* OOM.  */
+	}
+      memset (fre_tbl, 0, fre_tbl_sz);
+      fre_tbl->alloced = number_of_entries;
+    }
+  else if (fre_tbl->count == fre_tbl->alloced)
+    {
+      fre_tbl_sz = (sizeof (sf_fre_tbl)
+		    + ((fre_tbl->alloced + number_of_entries)
+		       * sizeof (sframe_frame_row_entry)));
+      fre_tbl = realloc (fre_tbl, fre_tbl_sz);
+      if (fre_tbl == NULL)
+	{
+	  sframe_set_errno (&err, ESFRAME_NOMEM);
+	  goto bad;		/* OOM.  */
+	}
+
+      memset (&fre_tbl->entry[fre_tbl->alloced], 0,
+	      number_of_entries * sizeof (sframe_frame_row_entry));
+      fre_tbl->alloced += number_of_entries;
+    }
+
+  ectx_frep = &fre_tbl->entry[fre_tbl->count];
+  ectx_frep->fre_start_addr
+    = frep->fre_start_addr;
+  ectx_frep->fre_info = frep->fre_info;
+
+  if (fdep->sfde_func_size)
+    sframe_assert (frep->fre_start_addr < fdep->sfde_func_size);
+  else
+    /* A SFrame FDE with func size equal to zero is possible.  */
+    sframe_assert (frep->fre_start_addr == fdep->sfde_func_size);
+
+  /* frep has already been sanity check'd.  Get offsets size.  */
+  offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
+  memcpy (&ectx_frep->fre_offsets, &frep->fre_offsets, offsets_sz);
+
+  esz = sframe_fre_entry_size (frep, fre_type);
+  fre_tbl->count++;
+
+  encoder->sfe_fres = (void *) fre_tbl;
+  encoder->sfe_fre_nbytes += esz;
+
+  ehp = sframe_encoder_get_header (encoder);
+  ehp->sfh_num_fres = fre_tbl->count;
+
+  /* Update the value of the number of FREs for the function.  */
+  fdep->sfde_func_num_fres++;
+
+  return 0;
+
+bad:
+  if (fre_tbl != NULL)
+    free (fre_tbl);
+  encoder->sfe_fres = NULL;
+  encoder->sfe_fre_nbytes = 0;
+  return -1;
+}
+
+/* Add a new function descriptor entry with START_ADDR, FUNC_SIZE and NUM_FRES
+   to the encoder.  */
+
+int
+sframe_encoder_add_funcdesc (sframe_encoder_ctx *encoder,
+			      int32_t start_addr,
+			      uint32_t func_size,
+			      unsigned char func_info,
+			      uint32_t num_fres __attribute__ ((unused)))
+{
+  sframe_header *ehp;
+  sf_funidx_tbl *fd_info;
+  size_t fd_tbl_sz;
+  int err = 0;
+
+  /* FIXME book-keep num_fres for error checking.  */
+  if (encoder == NULL)
+    return sframe_set_errno (&err, EINVAL);
+
+  fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
+  ehp = sframe_encoder_get_header (encoder);
+
+  if (fd_info == NULL)
+    {
+      fd_tbl_sz = (sizeof (sf_funidx_tbl)
+		   + (number_of_entries * sizeof (sframe_func_desc_entry)));
+      fd_info = malloc (fd_tbl_sz);
+      if (fd_info == NULL)
+	{
+	  sframe_set_errno (&err, ESFRAME_NOMEM);
+	  goto bad;		/* OOM.  */
+	}
+      memset (fd_info, 0, fd_tbl_sz);
+      fd_info->alloced = number_of_entries;
+    }
+  else if (fd_info->count == fd_info->alloced)
+    {
+      fd_tbl_sz = (sizeof (sf_funidx_tbl)
+		   + ((fd_info->alloced + number_of_entries)
+		      * sizeof (sframe_func_desc_entry)));
+      fd_info = realloc (fd_info, fd_tbl_sz);
+      if (fd_info == NULL)
+	{
+	  sframe_set_errno (&err, ESFRAME_NOMEM);
+	  goto bad;		/* OOM.  */
+	}
+
+      memset (&fd_info->entry[fd_info->alloced], 0,
+	      number_of_entries * sizeof (sframe_func_desc_entry));
+      fd_info->alloced += number_of_entries;
+    }
+
+  fd_info->entry[fd_info->count].sfde_func_start_address = start_addr;
+  /* Num FREs is updated as FREs are added for the function later via
+     sframe_encoder_add_fre.  */
+  fd_info->entry[fd_info->count].sfde_func_size = func_size;
+  fd_info->entry[fd_info->count].sfde_func_start_fre_off
+    = encoder->sfe_fre_nbytes;
+#if 0
+  // Linker optimization test code cleanup later ibhagat TODO FIXME
+  unsigned int fre_type = sframe_calc_fre_type (func_size);
+
+  fd_info->entry[fd_info->count].sfde_func_info
+    = sframe_fde_func_info (fre_type);
+#endif
+  fd_info->entry[fd_info->count].sfde_func_info = func_info;
+  fd_info->count++;
+  encoder->sfe_funcdesc = (void *) fd_info;
+  ehp->sfh_num_fdes++;
+  return 0;
+
+bad:
+  if (fd_info != NULL)
+    free (fd_info);
+  encoder->sfe_funcdesc = NULL;
+  ehp->sfh_num_fdes = 0;
+  return -1;
+}
+
+static int
+sframe_sort_funcdesc (sframe_encoder_ctx *encoder)
+{
+  sframe_header *ehp;
+
+  ehp = sframe_encoder_get_header (encoder);
+  /* Sort and write out the FDE table.  */
+  sf_funidx_tbl *fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
+  if (fd_info)
+    {
+      qsort (fd_info->entry, fd_info->count,
+	     sizeof (sframe_func_desc_entry), fde_func);
+      /* Update preamble's flags.  */
+      ehp->sfh_preamble.sfp_flags |= SFRAME_F_FDE_SORTED;
+    }
+  return 0;
+}
+
+/* Write a frame row entry pointed to by FREP into the buffer CONTENTS.  The
+   size in bytes written out are updated in ESZ.
+
+   This function works closely with the SFrame binary format.
+
+   Returns SFRAME_ERR if failure.  */
+
+static int
+sframe_encoder_write_fre (char *contents, sframe_frame_row_entry *frep,
+			     unsigned int fre_type, size_t *esz)
+{
+  size_t fre_size;
+  size_t fre_start_addr_sz;
+  size_t fre_stack_offsets_sz;
+  int err = 0;
+
+  if (!sframe_fre_sanity_check_p (frep))
+    return sframe_set_errno (&err, ESFRAME_FRE_INVAL);
+
+  fre_start_addr_sz = sframe_fre_start_addr_size (fre_type);
+  fre_stack_offsets_sz = sframe_fre_offset_bytes_size (frep->fre_info);
+
+  /* The FRE start address must be encodable in the available number of
+     bytes.  */
+  uint64_t bitmask = SFRAME_BITMASK_OF_SIZE (fre_start_addr_sz);
+  sframe_assert ((uint64_t)frep->fre_start_addr <= bitmask);
+
+  memcpy (contents,
+	  &frep->fre_start_addr,
+	  fre_start_addr_sz);
+  contents += fre_start_addr_sz;
+
+  memcpy (contents,
+	  &frep->fre_info,
+	  sizeof (frep->fre_info));
+  contents += sizeof (frep->fre_info);
+
+  memcpy (contents,
+	  frep->fre_offsets,
+	  fre_stack_offsets_sz);
+  contents+= fre_stack_offsets_sz;
+
+  fre_size = sframe_fre_entry_size (frep, fre_type);
+  /* Sanity checking.  */
+  sframe_assert ((fre_start_addr_sz
+		     + sizeof (frep->fre_info)
+		     + fre_stack_offsets_sz) == fre_size);
+
+  *esz = fre_size;
+
+  return 0;
+}
+
+/* Serialize the core contents of the SFrame section and write out to the
+   output buffer held in the ENCODER.  Return SFRAME_ERR if failure.  */
+
+static int
+sframe_encoder_write_sframe (sframe_encoder_ctx *encoder)
+{
+  char *contents;
+  size_t buf_size;
+  size_t hdr_size;
+  size_t all_fdes_size;
+  size_t fre_size;
+  size_t esz = 0;
+  sframe_header *ehp;
+  unsigned char flags;
+  sf_funidx_tbl *fd_info;
+  sf_fre_tbl *fr_info;
+  uint32_t i, num_fdes;
+  uint32_t j, num_fres;
+  sframe_func_desc_entry *fdep;
+  sframe_frame_row_entry *frep;
+
+  unsigned int fre_type;
+  int err = 0;
+
+  contents = encoder->sfe_data;
+  buf_size = encoder->sfe_data_size;
+  hdr_size = sizeof (sframe_header);
+  num_fdes = sframe_encoder_get_num_fidx (encoder);
+  all_fdes_size = num_fdes * sizeof (sframe_func_desc_entry);
+  ehp = sframe_encoder_get_header (encoder);
+
+  fd_info = (sf_funidx_tbl *) encoder->sfe_funcdesc;
+  fr_info = (sf_fre_tbl *) encoder->sfe_fres;
+
+  /* Sanity checks:
+     - buffers must be malloc'd by the caller.  */
+  if ((contents == NULL) || (buf_size < hdr_size))
+    return sframe_set_errno (&err, ESFRAME_BUF_INVAL);
+  if (fr_info == NULL)
+    return sframe_set_errno (&err, ESFRAME_FRE_INVAL);
+
+  /* Write out the FRE table first.
+
+     Recall that read/write of FREs needs information from the corresponding
+     FDE; the latter stores the information about the FRE type record used for
+     the function.  Also note that sorting of FDEs does NOT impact the order
+     in which FREs are stored in the SFrame's FRE sub-section.  This means
+     that writing out FREs after sorting of FDEs will need some additional
+     book-keeping.  At this time, we can afford to avoid it by writing out
+     the FREs first to the output buffer.  */
+  fre_size = 0;
+  uint32_t global = 0;
+  uint32_t fre_index = 0;
+
+  contents += hdr_size + all_fdes_size;
+  for (i = 0; i < num_fdes; i++)
+    {
+      fdep = &fd_info->entry[i];
+      fre_type = sframe_get_fre_type (fdep);
+      num_fres = fdep->sfde_func_num_fres;
+
+      for (j = 0; j < num_fres; j++)
+	{
+	  fre_index = global + j;
+	  frep = &fr_info->entry[fre_index];
+
+	  sframe_encoder_write_fre (contents, frep, fre_type, &esz);
+	  contents += esz;
+	  fre_size += esz; /* For debugging only.  */
+	}
+      global += j;
+    }
+
+  sframe_assert (fre_size == ehp->sfh_fre_len);
+  sframe_assert (global == ehp->sfh_num_fres);
+  sframe_assert ((size_t)(contents - encoder->sfe_data) == buf_size);
+
+  /* Sort the FDE table */
+  sframe_sort_funcdesc (encoder);
+
+  /* Sanity checks:
+     - the FDE section must have been sorted by now on the start address
+     of each function.  */
+  flags = ehp->sfh_preamble.sfp_flags;
+  if (!(flags & SFRAME_F_FDE_SORTED)
+      || (fd_info == NULL))
+    return sframe_set_errno (&err, ESFRAME_FDE_INVAL);
+
+  contents = encoder->sfe_data;
+  /* Write out the SFrame header.  The SFrame header in the encoder
+     object has already been updated with correct offsets by the caller.  */
+  memcpy (contents, ehp, hdr_size);
+  contents += hdr_size;
+
+  /* Write out the FDE table sorted on funtion start address.  */
+  memcpy (contents, fd_info->entry, all_fdes_size);
+  contents += all_fdes_size;
+
+  return 0;
+}
+
+/* Serialize the contents of the encoder and return the buffer.  ENCODED_SIZE
+   is updated to the size of the buffer.  */
+
+char *
+sframe_write_encoder (sframe_encoder_ctx *encoder,
+			 size_t *encoded_size, int *errp)
+{
+  sframe_header *ehp;
+  size_t hdrsize, fsz, fresz, bufsize;
+  int foreign_endian;
+
+  /* Initialize the encoded_size to zero.  This makes it simpler to just
+     return from the function in case of failure.  Free'ing up of
+     encoder->sfe_data is the responsibility of the caller.  */
+  *encoded_size = 0;
+
+  if (encoder == NULL || encoded_size == NULL || errp == NULL)
+    return sframe_ret_set_errno (errp, EINVAL);
+
+  hdrsize = sizeof (sframe_header);
+  fsz = sframe_encoder_get_num_fidx (encoder)
+    * sizeof (sframe_func_desc_entry);
+  fresz = encoder->sfe_fre_nbytes;
+
+  /* The total size of buffer is the sum of header, SFrame Function Descriptor
+     Entries section and the FRE section.  */
+  bufsize = hdrsize + fsz + fresz;
+  encoder->sfe_data = (char *) malloc (bufsize);
+  if (encoder->sfe_data == NULL)
+    return sframe_ret_set_errno (errp, ESFRAME_NOMEM);
+  encoder->sfe_data_size = bufsize;
+
+  /* Update the header information.  */
+  ehp = sframe_encoder_get_header (encoder);
+  /* SFrame FDE section follows immediately after the header.  */
+  ehp->sfh_fdeoff = 0;
+  /* SFrame FRE section follows immediately after the SFrame FDE section.  */
+  ehp->sfh_freoff = fsz;
+  ehp->sfh_fre_len = fresz;
+  /* FIXME - sfh_cfa_fixed_fp_offset sfh_cfa_fixed_ra_offset?? */
+
+  foreign_endian = need_swapping (ehp->sfh_abi_arch);
+
+  /* Write out the FDE Index and the FRE table. */
+  if (sframe_encoder_write_sframe (encoder))
+    return sframe_ret_set_errno (errp, ESFRAME_BUF_INVAL);
+
+  /* Endian flip the contents if necessary.  */
+  if (foreign_endian)
+    {
+      flip_header ((sframe_header*)encoder->sfe_data);
+      if (flip_sframe (encoder->sfe_data, bufsize))
+	return sframe_ret_set_errno (errp, ESFRAME_BUF_INVAL);
+    }
+
+  *encoded_size = bufsize;
+  return encoder->sfe_data;
+}
diff --git a/libsframe/testsuite/Makefile.am b/libsframe/testsuite/Makefile.am
new file mode 100644
index 00000000000..1455eba83c7
--- /dev/null
+++ b/libsframe/testsuite/Makefile.am
@@ -0,0 +1,23 @@
+AUTOMAKE_OPTIONS = dejagnu foreign
+
+SUBDIRS = libsframe.decode libsframe.encode
+
+# Setup the testing framework
+EXPECT = expect
+RUNTEST = runtest
+RUNTESTFLAGS =
+
+check-DEJAGNU: site.exp
+	srcroot=`cd $(srcdir) && pwd`; export srcroot; \
+	r=`pwd`; export r; \
+	LC_ALL=C; export LC_ALL; \
+	EXPECT=$(EXPECT); export EXPECT; \
+	runtest=$(RUNTEST); \
+	if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
+	  $$runtest --tool $(DEJATOOL) \
+		CC="$(CC)" \
+		CROSS_COMPILE="$(CROSS_COMPILE)" \
+		CFLAGS="$(CFLAGS) -I$(top_srcdir)/../include -I$(top_srcdir) -I$(top_builddir)" \
+		$(RUNTESTFLAGS); \
+	else echo "WARNING: could not find \`runtest'" 1>&2; :;\
+	fi
diff --git a/libsframe/testsuite/Makefile.in b/libsframe/testsuite/Makefile.in
new file mode 100644
index 00000000000..f97c4330eb7
--- /dev/null
+++ b/libsframe/testsuite/Makefile.in
@@ -0,0 +1,682 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = testsuite
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
+	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/depstand.m4 \
+	$(top_srcdir)/../config/jobserver.m4 \
+	$(top_srcdir)/../config/lead-dot.m4 \
+	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/warnings.m4 \
+	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
+	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
+	$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DEJATOOL = $(PACKAGE)
+RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_PEDANTIC = @WARN_PEDANTIC@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_libsframe_warn_cflags = @ac_libsframe_warn_cflags@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_warn = @c_warn@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_noncanonical = @host_noncanonical@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+target_noncanonical = @target_noncanonical@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+warn = @warn@
+AUTOMAKE_OPTIONS = dejagnu foreign
+SUBDIRS = libsframe.decode libsframe.encode
+
+# Setup the testing framework
+EXPECT = expect
+RUNTEST = runtest
+RUNTESTFLAGS = 
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign testsuite/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+site.exp: Makefile $(EXTRA_DEJAGNU_SITE_CONFIG)
+	@echo 'Making a new site.exp file ...'
+	@echo '## these variables are automatically generated by make ##' >site.tmp
+	@echo '# Do not edit here.  If you wish to override these values' >>site.tmp
+	@echo '# edit the last section' >>site.tmp
+	@echo 'set srcdir "$(srcdir)"' >>site.tmp
+	@echo "set objdir `pwd`" >>site.tmp
+	@echo 'set build_alias "$(build_alias)"' >>site.tmp
+	@echo 'set build_triplet $(build_triplet)' >>site.tmp
+	@echo 'set host_alias "$(host_alias)"' >>site.tmp
+	@echo 'set host_triplet $(host_triplet)' >>site.tmp
+	@list='$(EXTRA_DEJAGNU_SITE_CONFIG)'; for f in $$list; do \
+	  echo "## Begin content included from file $$f.  Do not modify. ##" \
+	   && cat `test -f "$$f" || echo '$(srcdir)/'`$$f \
+	   && echo "## End content included from file $$f. ##" \
+	   || exit 1; \
+	 done >> site.tmp
+	@echo "## End of auto-generated content; you can edit from here. ##" >> site.tmp
+	@if test -f site.exp; then \
+	   sed -e '1,/^## End of auto-generated content.*##/d' site.exp >> site.tmp; \
+	 fi
+	@-rm -f site.bak
+	@test ! -f site.exp || mv site.exp site.bak
+	@mv site.tmp site.exp
+
+distclean-DEJAGNU:
+	-rm -f site.exp site.bak
+	-l='$(DEJATOOL)'; for tool in $$l; do \
+	  rm -f $$tool.sum $$tool.log; \
+	done
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f Makefile
+distclean-am: clean-am distclean-DEJAGNU distclean-generic \
+	distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+	check-DEJAGNU check-am clean clean-generic clean-libtool \
+	cscopelist-am ctags ctags-am distclean distclean-DEJAGNU \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-data install-data-am install-dvi install-dvi-am \
+	install-exec install-exec-am install-html install-html-am \
+	install-info install-info-am install-man install-pdf \
+	install-pdf-am install-ps install-ps-am install-strip \
+	installcheck installcheck-am installdirs installdirs-am \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+check-DEJAGNU: site.exp
+	srcroot=`cd $(srcdir) && pwd`; export srcroot; \
+	r=`pwd`; export r; \
+	LC_ALL=C; export LC_ALL; \
+	EXPECT=$(EXPECT); export EXPECT; \
+	runtest=$(RUNTEST); \
+	if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
+	  $$runtest --tool $(DEJATOOL) \
+		CC="$(CC)" \
+		CROSS_COMPILE="$(CROSS_COMPILE)" \
+		CFLAGS="$(CFLAGS) -I$(top_srcdir)/../include -I$(top_srcdir) -I$(top_builddir)" \
+		$(RUNTESTFLAGS); \
+	else echo "WARNING: could not find \`runtest'" 1>&2; :;\
+	fi
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libsframe/testsuite/config/default.exp b/libsframe/testsuite/config/default.exp
new file mode 100644
index 00000000000..c45e25d3357
--- /dev/null
+++ b/libsframe/testsuite/config/default.exp
@@ -0,0 +1,54 @@
+# Basic expect script for libsframe decoder tests.
+#   Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This file 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Written by Jeffrey Wheat (cassidy@cygnus.com)
+#
+
+if ![info exists ld] then {
+    set ld [findfile $base_dir/../ld/ld-new $base_dir/../ld/ld-new [transform ld]]
+}
+
+if ![info exists as] then {
+    set as [findfile $base_dir/../gas/as-new $base_dir/../gas/as-new [transform as]]
+}
+
+remote_exec host "mkdir -p tmpdir"
+
+# Make symlinks from tmpdir/libsframe to the linker and assembler in the
+# build tree, so that we can use a -B option to gcc to force it to use
+# the newly built linker and assembler.
+if {![file isdirectory tmpdir/libsframe]} then {
+    catch "exec mkdir tmpdir/libsframe" status
+    catch "exec ln -s ../../../ld/ld-new tmpdir/libsframe/ld" status
+    catch "exec ln -s ld tmpdir/libsframe/collect-ld" status
+    catch "exec ln -s ../../../gas/as-new tmpdir/libsframe/as" status
+}
+set gcc_B_opt "-B[pwd]/tmpdir/libsframe/"
+set ld_L_opt ""
+
+if {![info exists CC]} {
+    set CC gcc
+}
+if {![info exists CFLAGS]} {
+    set CFLAGS "-g -O2"
+}
+if {![info exists CFLAGS_FOR_TARGET]} {
+    set CFLAGS_FOR_TARGET $CFLAGS
+}
diff --git a/libsframe/testsuite/libsframe.decode/DATA1 b/libsframe/testsuite/libsframe.decode/DATA1
new file mode 100644
index 0000000000000000000000000000000000000000..8a6d4a3b68f6be1d67c42b78c3d88807249c3a56
GIT binary patch
literal 59
zcmaEKkCBm?fq{{Mfq?~x`GFV&1cCV9`~Ux?!90i@BLg!BBdfp%78ZdIQmh;w0QnIK
ACIA2c

literal 0
HcmV?d00001

diff --git a/libsframe/testsuite/libsframe.decode/DATA2 b/libsframe/testsuite/libsframe.decode/DATA2
new file mode 100644
index 0000000000000000000000000000000000000000..71c3be0a8497df2b2055484d45c89d3b0e53e815
GIT binary patch
literal 91
zcmaEKkCBm?fq{vEfq?^v<$xFjlz{l!`~Ux?!8`^A79h>|5hx%4WbgwqSb%|<gOOF>
S0}G452PsyL4@g{oAQu3xLl8;;

literal 0
HcmV?d00001

diff --git a/libsframe/testsuite/libsframe.decode/DATA_BIGE b/libsframe/testsuite/libsframe.decode/DATA_BIGE
new file mode 100644
index 0000000000000000000000000000000000000000..37c3f39a4bad0afccc09d693bf16a8ee6a2d4c50
GIT binary patch
literal 59
zcmccjh>?+z0R%uK3lQ^zI6xry|Nr}cKw28i1IjTnFmo`n3VdK;5%?g*%JBgJ_vQ&C

literal 0
HcmV?d00001

diff --git a/libsframe/testsuite/libsframe.decode/Makefile.am b/libsframe/testsuite/libsframe.decode/Makefile.am
new file mode 100644
index 00000000000..a79a678014b
--- /dev/null
+++ b/libsframe/testsuite/libsframe.decode/Makefile.am
@@ -0,0 +1,14 @@
+check_PROGRAMS = bigendian_data frecnt_1 frecnt_2
+
+bigendian_data_SOURCES = bigendian_data.c
+bigendian_data_LDADD = ${top_builddir}/libsframe.la 
+bigendian_data_CPPFLAGS = -I${top_srcdir}/../include -Wall
+
+frecnt_1_SOURCES = frecnt_1.c
+frecnt_1_LDADD = ${top_builddir}/libsframe.la 
+frecnt_1_CPPFLAGS = -I${top_srcdir}/../include -Wall
+
+frecnt_2_SOURCES = frecnt_2.c
+frecnt_2_LDADD = ${top_builddir}/libsframe.la 
+frecnt_2_CPPFLAGS = -I${top_srcdir}/../include -Wall
+
diff --git a/libsframe/testsuite/libsframe.decode/Makefile.in b/libsframe/testsuite/libsframe.decode/Makefile.in
new file mode 100644
index 00000000000..f4a1e43c374
--- /dev/null
+++ b/libsframe/testsuite/libsframe.decode/Makefile.in
@@ -0,0 +1,661 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = bigendian_data$(EXEEXT) frecnt_1$(EXEEXT) \
+	frecnt_2$(EXEEXT)
+subdir = testsuite/libsframe.decode
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
+	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/depstand.m4 \
+	$(top_srcdir)/../config/jobserver.m4 \
+	$(top_srcdir)/../config/lead-dot.m4 \
+	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/warnings.m4 \
+	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
+	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
+	$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_bigendian_data_OBJECTS = bigendian_data-bigendian_data.$(OBJEXT)
+bigendian_data_OBJECTS = $(am_bigendian_data_OBJECTS)
+bigendian_data_DEPENDENCIES = ${top_builddir}/libsframe.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+am_frecnt_1_OBJECTS = frecnt_1-frecnt_1.$(OBJEXT)
+frecnt_1_OBJECTS = $(am_frecnt_1_OBJECTS)
+frecnt_1_DEPENDENCIES = ${top_builddir}/libsframe.la
+am_frecnt_2_OBJECTS = frecnt_2-frecnt_2.$(OBJEXT)
+frecnt_2_OBJECTS = $(am_frecnt_2_OBJECTS)
+frecnt_2_DEPENDENCIES = ${top_builddir}/libsframe.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(bigendian_data_SOURCES) $(frecnt_1_SOURCES) \
+	$(frecnt_2_SOURCES)
+DIST_SOURCES = $(bigendian_data_SOURCES) $(frecnt_1_SOURCES) \
+	$(frecnt_2_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../depcomp \
+	$(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_PEDANTIC = @WARN_PEDANTIC@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_libsframe_warn_cflags = @ac_libsframe_warn_cflags@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_warn = @c_warn@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_noncanonical = @host_noncanonical@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+target_noncanonical = @target_noncanonical@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+warn = @warn@
+bigendian_data_SOURCES = bigendian_data.c
+bigendian_data_LDADD = ${top_builddir}/libsframe.la 
+bigendian_data_CPPFLAGS = -I${top_srcdir}/../include -Wall
+frecnt_1_SOURCES = frecnt_1.c
+frecnt_1_LDADD = ${top_builddir}/libsframe.la 
+frecnt_1_CPPFLAGS = -I${top_srcdir}/../include -Wall
+frecnt_2_SOURCES = frecnt_2.c
+frecnt_2_LDADD = ${top_builddir}/libsframe.la 
+frecnt_2_CPPFLAGS = -I${top_srcdir}/../include -Wall
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/libsframe.decode/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign testsuite/libsframe.decode/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+bigendian_data$(EXEEXT): $(bigendian_data_OBJECTS) $(bigendian_data_DEPENDENCIES) $(EXTRA_bigendian_data_DEPENDENCIES) 
+	@rm -f bigendian_data$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(bigendian_data_OBJECTS) $(bigendian_data_LDADD) $(LIBS)
+
+frecnt_1$(EXEEXT): $(frecnt_1_OBJECTS) $(frecnt_1_DEPENDENCIES) $(EXTRA_frecnt_1_DEPENDENCIES) 
+	@rm -f frecnt_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(frecnt_1_OBJECTS) $(frecnt_1_LDADD) $(LIBS)
+
+frecnt_2$(EXEEXT): $(frecnt_2_OBJECTS) $(frecnt_2_DEPENDENCIES) $(EXTRA_frecnt_2_DEPENDENCIES) 
+	@rm -f frecnt_2$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(frecnt_2_OBJECTS) $(frecnt_2_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bigendian_data-bigendian_data.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/frecnt_1-frecnt_1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/frecnt_2-frecnt_2.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+bigendian_data-bigendian_data.o: bigendian_data.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bigendian_data_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bigendian_data-bigendian_data.o -MD -MP -MF $(DEPDIR)/bigendian_data-bigendian_data.Tpo -c -o bigendian_data-bigendian_data.o `test -f 'bigendian_data.c' || echo '$(srcdir)/'`bigendian_data.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/bigendian_data-bigendian_data.Tpo $(DEPDIR)/bigendian_data-bigendian_data.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bigendian_data.c' object='bigendian_data-bigendian_data.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bigendian_data_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bigendian_data-bigendian_data.o `test -f 'bigendian_data.c' || echo '$(srcdir)/'`bigendian_data.c
+
+bigendian_data-bigendian_data.obj: bigendian_data.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bigendian_data_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bigendian_data-bigendian_data.obj -MD -MP -MF $(DEPDIR)/bigendian_data-bigendian_data.Tpo -c -o bigendian_data-bigendian_data.obj `if test -f 'bigendian_data.c'; then $(CYGPATH_W) 'bigendian_data.c'; else $(CYGPATH_W) '$(srcdir)/bigendian_data.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/bigendian_data-bigendian_data.Tpo $(DEPDIR)/bigendian_data-bigendian_data.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='bigendian_data.c' object='bigendian_data-bigendian_data.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bigendian_data_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bigendian_data-bigendian_data.obj `if test -f 'bigendian_data.c'; then $(CYGPATH_W) 'bigendian_data.c'; else $(CYGPATH_W) '$(srcdir)/bigendian_data.c'; fi`
+
+frecnt_1-frecnt_1.o: frecnt_1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT frecnt_1-frecnt_1.o -MD -MP -MF $(DEPDIR)/frecnt_1-frecnt_1.Tpo -c -o frecnt_1-frecnt_1.o `test -f 'frecnt_1.c' || echo '$(srcdir)/'`frecnt_1.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/frecnt_1-frecnt_1.Tpo $(DEPDIR)/frecnt_1-frecnt_1.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='frecnt_1.c' object='frecnt_1-frecnt_1.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o frecnt_1-frecnt_1.o `test -f 'frecnt_1.c' || echo '$(srcdir)/'`frecnt_1.c
+
+frecnt_1-frecnt_1.obj: frecnt_1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT frecnt_1-frecnt_1.obj -MD -MP -MF $(DEPDIR)/frecnt_1-frecnt_1.Tpo -c -o frecnt_1-frecnt_1.obj `if test -f 'frecnt_1.c'; then $(CYGPATH_W) 'frecnt_1.c'; else $(CYGPATH_W) '$(srcdir)/frecnt_1.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/frecnt_1-frecnt_1.Tpo $(DEPDIR)/frecnt_1-frecnt_1.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='frecnt_1.c' object='frecnt_1-frecnt_1.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o frecnt_1-frecnt_1.obj `if test -f 'frecnt_1.c'; then $(CYGPATH_W) 'frecnt_1.c'; else $(CYGPATH_W) '$(srcdir)/frecnt_1.c'; fi`
+
+frecnt_2-frecnt_2.o: frecnt_2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT frecnt_2-frecnt_2.o -MD -MP -MF $(DEPDIR)/frecnt_2-frecnt_2.Tpo -c -o frecnt_2-frecnt_2.o `test -f 'frecnt_2.c' || echo '$(srcdir)/'`frecnt_2.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/frecnt_2-frecnt_2.Tpo $(DEPDIR)/frecnt_2-frecnt_2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='frecnt_2.c' object='frecnt_2-frecnt_2.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o frecnt_2-frecnt_2.o `test -f 'frecnt_2.c' || echo '$(srcdir)/'`frecnt_2.c
+
+frecnt_2-frecnt_2.obj: frecnt_2.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT frecnt_2-frecnt_2.obj -MD -MP -MF $(DEPDIR)/frecnt_2-frecnt_2.Tpo -c -o frecnt_2-frecnt_2.obj `if test -f 'frecnt_2.c'; then $(CYGPATH_W) 'frecnt_2.c'; else $(CYGPATH_W) '$(srcdir)/frecnt_2.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/frecnt_2-frecnt_2.Tpo $(DEPDIR)/frecnt_2-frecnt_2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='frecnt_2.c' object='frecnt_2-frecnt_2.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(frecnt_2_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o frecnt_2-frecnt_2.obj `if test -f 'frecnt_2.c'; then $(CYGPATH_W) 'frecnt_2.c'; else $(CYGPATH_W) '$(srcdir)/frecnt_2.c'; fi`
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libsframe/testsuite/libsframe.decode/bigendian_data.c b/libsframe/testsuite/libsframe.decode/bigendian_data.c
new file mode 100644
index 00000000000..5d9271e6f90
--- /dev/null
+++ b/libsframe/testsuite/libsframe.decode/bigendian_data.c
@@ -0,0 +1,107 @@
+/* bigendian_data.c -- Test for handling different endianness in libsframe.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "sframe-api.h"
+
+/* DejaGnu should not use gnulib's vsnprintf replacement here.  */
+#undef vsnprintf
+#include <dejagnu.h>
+
+/*
+ * SFrame info from the following source (1 fde 4 fres):
+ * static int cnt;
+ * int main() { cnt++; return (cnt); }
+ *
+ * Then its contents are flipped from little-endian to big-endian.
+ */
+#define DATA	"DATA_BIGE"
+
+int
+main ()
+{
+  sframe_decoder_ctx *dctx = NULL;
+  uint32_t nfres, fsize;
+  int32_t fstart;
+  unsigned char finfo;
+  int err = 0;
+  FILE *fp;
+  struct stat st;
+  char *sf_buf;
+  size_t sf_size;
+
+#define TEST(name, cond)                                                      \
+  do                                                                          \
+    {                                                                         \
+      if (cond)                                                               \
+	pass (name);                                                          \
+      else                                                                    \
+	fail (name);                                                          \
+    }                                                                         \
+    while (0)
+
+  /* Test setup.  */
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    goto setup_fail;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      goto setup_fail;
+    }
+  sf_buf = malloc (st.st_size);
+  if (sf_buf == NULL)
+    {
+      perror ("malloc");
+      goto setup_fail;
+    }
+  sf_size = fread (sf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  if (sf_size == 0)
+    {
+      fprintf (stderr, "Decode: Read buffer failed\n");
+      goto setup_fail;
+    }
+
+  /* Execute tests.  */
+
+  /* Call to sframe_decode will endian flip the input buffer and
+     keep the new copy of buffer internally.  */
+  dctx = sframe_decode (sf_buf, sf_size, &err);
+  TEST ("bigendian_data: Decoder setup", dctx != NULL);
+
+  unsigned int fde_cnt = sframe_decoder_get_num_fidx (dctx);
+  TEST ("bigendian_data: Decoder FDE count", fde_cnt == 1);
+
+  err = sframe_decoder_get_funcdesc (dctx, 0, &nfres, &fsize, &fstart, &finfo);
+  TEST ("bigendian_data: Decoder get FDE", err == 0);
+  TEST ("bigendian_data: Decoder FRE count", nfres == 4);
+      
+  sframe_decoder_free (&dctx);
+  return 0;
+
+setup_fail:
+  sframe_decoder_free (&dctx);
+  fail ("bigendian_data: Test setup");
+  return 1;
+}
diff --git a/libsframe/testsuite/libsframe.decode/decode.exp b/libsframe/testsuite/libsframe.decode/decode.exp
new file mode 100644
index 00000000000..2538a63e93c
--- /dev/null
+++ b/libsframe/testsuite/libsframe.decode/decode.exp
@@ -0,0 +1,41 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+load_lib dejagnu.exp
+
+catch "exec ln -s $srcdir/../testsuite/libsframe.decode/DATA1 ." status
+catch "exec ln -s $srcdir/../testsuite/libsframe.decode/DATA2 ." status
+catch "exec ln -s $srcdir/../testsuite/libsframe.decode/DATA_BIGE ." status
+
+if { [host_execute "libsframe.decode/bigendian_data"] ne "" } {
+    fail "bigendian_data"
+}
+
+if { [host_execute "libsframe.decode/frecnt_1"] ne "" } {
+    fail "frecnt_1"
+}
+
+if { [host_execute "libsframe.decode/frecnt_2"] ne "" } {
+    fail "frecnt_2"
+}
+
+catch "exec rm libsframe.decode/DATA1" status
+catch "exec rm libsframe.decode/DATA2" status
+catch "exec rm libsframe.decode/DATA_BIGE" status
diff --git a/libsframe/testsuite/libsframe.decode/frecnt_1.c b/libsframe/testsuite/libsframe.decode/frecnt_1.c
new file mode 100644
index 00000000000..613a47930dd
--- /dev/null
+++ b/libsframe/testsuite/libsframe.decode/frecnt_1.c
@@ -0,0 +1,99 @@
+/* frecnt_1.c -- Test for decoder in libsframe.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "sframe-api.h"
+
+/* DejaGnu should not use gnulib's vsnprintf replacement here.  */
+#undef vsnprintf
+#include <dejagnu.h>
+
+/*
+ * SFrame info from the following source (1 fde 4 fres):
+ * static int cnt;
+ * int main() { cnt++; return (cnt); }
+ */
+#define DATA	"DATA1"
+
+int
+main ()
+{
+  sframe_decoder_ctx *dctx = NULL;
+  uint32_t nfres, fsize;
+  int32_t fstart;
+  unsigned char finfo;
+  int err = 0;
+  FILE *fp;
+  struct stat st;
+  char *sf_buf;
+  size_t sf_size;
+
+#define TEST(name, cond)                                                      \
+  do                                                                          \
+    {                                                                         \
+      if (cond)                                                               \
+	pass (name);                                                          \
+      else                                                                    \
+	fail (name);                                                          \
+    }                                                                         \
+    while (0)
+
+  /* Test Setup.  */
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    goto setup_fail;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      goto setup_fail;
+    }
+  sf_buf = malloc (st.st_size);
+  if (sf_buf == NULL)
+    {
+      perror ("malloc");
+      goto setup_fail;
+    }
+
+  /* Execute tests.  */
+  sf_size = fread (sf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  TEST ("frecnt_1: Read section", sf_size != 0);
+
+  dctx = sframe_decode (sf_buf, sf_size, &err);
+  TEST ("frecnt_1: Decoder setup", dctx != NULL);
+
+  unsigned int fde_cnt = sframe_decoder_get_num_fidx (dctx);
+  TEST ("frecnt_1: Decoder FDE count", fde_cnt == 1);
+
+  err = sframe_decoder_get_funcdesc (dctx, 0, &nfres, &fsize, &fstart, &finfo);
+  TEST ("frecnt_1: Decoder get FDE", err == 0);
+  TEST ("frecnt_1: Decoder FRE count", nfres == 4);
+
+  sframe_decoder_free (&dctx);
+  return 0;
+
+setup_fail:
+  sframe_decoder_free (&dctx);
+  fail ("frecnt_1: Test setup");
+  return 1;
+}
diff --git a/libsframe/testsuite/libsframe.decode/frecnt_2.c b/libsframe/testsuite/libsframe.decode/frecnt_2.c
new file mode 100644
index 00000000000..930788665dd
--- /dev/null
+++ b/libsframe/testsuite/libsframe.decode/frecnt_2.c
@@ -0,0 +1,103 @@
+/* frecnt_2.c -- Test for decoder in libsframe.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "sframe-api.h"
+
+/* DejaGnu should not use gnulib's vsnprintf replacement here.  */
+#undef vsnprintf
+#include <dejagnu.h>
+
+/*
+ * SFrame info from the following source (2 fde 8 fres):
+ * static int cnt;
+ * int foo() { return ++cnt; }
+ * int main() { return foo(); }
+ */
+#define DATA	"DATA2"
+
+int
+main ()
+{
+  sframe_decoder_ctx *dctx = NULL;
+  uint32_t nfres, fsize;
+  int32_t fstart;
+  unsigned char finfo;
+  int i, err = 0;
+  FILE *fp;
+  struct stat st;
+  char *sf_buf;
+  size_t sf_size;
+
+#define TEST(name, cond)                                                      \
+  do                                                                          \
+    {                                                                         \
+      if (cond)                                                               \
+	pass (name);                                                          \
+      else                                                                    \
+	fail (name);                                                          \
+    }                                                                         \
+    while (0)
+
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    goto setup_fail;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      goto setup_fail;
+    }
+  sf_buf = malloc (st.st_size);
+  if (sf_buf == NULL)
+    {
+      perror ("malloc");
+      goto setup_fail;
+    }
+
+  /* Execute tests.  */
+  sf_size = fread (sf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  TEST ("frecnt_2: Read section", sf_size != 0);
+
+  dctx = sframe_decode (sf_buf, sf_size, &err);
+  TEST ("frecnt_2: Decode setup", dctx != NULL);
+
+  unsigned int fde_cnt = sframe_decoder_get_num_fidx (dctx);
+  TEST ("frecnt_2: Decode FDE count", fde_cnt == 2);
+
+  for (i = 0; i < fde_cnt; ++i)
+    {
+      err = sframe_decoder_get_funcdesc (dctx, i, &nfres, &fsize, &fstart,
+		 			    &finfo);
+      TEST ("frecnt_2: Decode get FDE", err == 0);
+      TEST ("frecnt_2: Decode get FRE", nfres == 4); 
+    }
+
+  sframe_decoder_free (&dctx);
+  return 0;
+
+setup_fail:
+  sframe_decoder_free (&dctx);
+  fail ("frecnt_2: Test setup");
+  return 1;
+}
diff --git a/libsframe/testsuite/libsframe.encode/Makefile.am b/libsframe/testsuite/libsframe.encode/Makefile.am
new file mode 100644
index 00000000000..47613485b13
--- /dev/null
+++ b/libsframe/testsuite/libsframe.encode/Makefile.am
@@ -0,0 +1,6 @@
+check_PROGRAMS = encode_1
+
+encode_1_SOURCES = encode_1.c
+encode_1_LDADD = ${top_builddir}/libsframe.la
+encode_1_CPPFLAGS = -I${top_srcdir}/../include -Wall
+
diff --git a/libsframe/testsuite/libsframe.encode/Makefile.in b/libsframe/testsuite/libsframe.encode/Makefile.in
new file mode 100644
index 00000000000..678a9ce9b43
--- /dev/null
+++ b/libsframe/testsuite/libsframe.encode/Makefile.in
@@ -0,0 +1,608 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = encode_1$(EXEEXT)
+subdir = testsuite/libsframe.encode
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
+	$(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/depstand.m4 \
+	$(top_srcdir)/../config/jobserver.m4 \
+	$(top_srcdir)/../config/lead-dot.m4 \
+	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/warnings.m4 \
+	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
+	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
+	$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_encode_1_OBJECTS = encode_1-encode_1.$(OBJEXT)
+encode_1_OBJECTS = $(am_encode_1_OBJECTS)
+encode_1_DEPENDENCIES = ${top_builddir}/libsframe.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(encode_1_SOURCES)
+DIST_SOURCES = $(encode_1_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../depcomp \
+	$(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_PEDANTIC = @WARN_PEDANTIC@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_libsframe_warn_cflags = @ac_libsframe_warn_cflags@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+c_warn = @c_warn@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_noncanonical = @host_noncanonical@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+target_noncanonical = @target_noncanonical@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+warn = @warn@
+encode_1_SOURCES = encode_1.c
+encode_1_LDADD = ${top_builddir}/libsframe.la
+encode_1_CPPFLAGS = -I${top_srcdir}/../include -Wall
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/libsframe.encode/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign testsuite/libsframe.encode/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+encode_1$(EXEEXT): $(encode_1_OBJECTS) $(encode_1_DEPENDENCIES) $(EXTRA_encode_1_DEPENDENCIES) 
+	@rm -f encode_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(encode_1_OBJECTS) $(encode_1_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encode_1-encode_1.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+encode_1-encode_1.o: encode_1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(encode_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT encode_1-encode_1.o -MD -MP -MF $(DEPDIR)/encode_1-encode_1.Tpo -c -o encode_1-encode_1.o `test -f 'encode_1.c' || echo '$(srcdir)/'`encode_1.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/encode_1-encode_1.Tpo $(DEPDIR)/encode_1-encode_1.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='encode_1.c' object='encode_1-encode_1.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(encode_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o encode_1-encode_1.o `test -f 'encode_1.c' || echo '$(srcdir)/'`encode_1.c
+
+encode_1-encode_1.obj: encode_1.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(encode_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT encode_1-encode_1.obj -MD -MP -MF $(DEPDIR)/encode_1-encode_1.Tpo -c -o encode_1-encode_1.obj `if test -f 'encode_1.c'; then $(CYGPATH_W) 'encode_1.c'; else $(CYGPATH_W) '$(srcdir)/encode_1.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/encode_1-encode_1.Tpo $(DEPDIR)/encode_1-encode_1.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='encode_1.c' object='encode_1-encode_1.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(encode_1_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o encode_1-encode_1.obj `if test -f 'encode_1.c'; then $(CYGPATH_W) 'encode_1.c'; else $(CYGPATH_W) '$(srcdir)/encode_1.c'; fi`
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libsframe/testsuite/libsframe.encode/encode.exp b/libsframe/testsuite/libsframe.encode/encode.exp
new file mode 100644
index 00000000000..cd4debcd884
--- /dev/null
+++ b/libsframe/testsuite/libsframe.encode/encode.exp
@@ -0,0 +1,25 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+load_lib dejagnu.exp
+
+if { [host_execute "libsframe.encode/encode_1"] ne "" } {
+    fail "encode_1"
+}
diff --git a/libsframe/testsuite/libsframe.encode/encode_1.c b/libsframe/testsuite/libsframe.encode/encode_1.c
new file mode 100644
index 00000000000..f584747cb0c
--- /dev/null
+++ b/libsframe/testsuite/libsframe.encode/encode_1.c
@@ -0,0 +1,182 @@
+/* encode_1.c -- Test for encoder in libsframe.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "sframe-api.h"
+
+/* DejaGnu should not use gnulib's vsnprintf replacement here.  */
+#undef vsnprintf
+#include <dejagnu.h>
+
+static int
+add_fde1 (sframe_encoder_ctx *encode, int idx)
+{
+  int i, err;
+  /* A contiguous block containing 4 FREs.  */
+  sframe_frame_row_entry fres[]
+    = { {0x0, 0x3, {0x8, 0, 0}},
+	{0x1, 0x5, {0x10, 0xf0, 0}},
+	{0x4, 0x4, {0x10, 0xf0, 0}},
+	{0x1a, 0x5, {0x8, 0xf0, 0}}
+      };
+
+  unsigned char finfo = sframe_fde_func_info (SFRAME_FRE_TYPE_ADDR1,
+					      SFRAME_FDE_TYPE_PCINC);
+  err = sframe_encoder_add_funcdesc (encode, 0xffffefd6, 0x1b, finfo, 4);
+  if (err == -1)
+    return err;
+
+  for (i = 0; i < 4; i++)
+    if (sframe_encoder_add_fre (encode, idx,fres+i) == SFRAME_ERR)
+      return -1;
+
+  return 0;
+}
+
+static int
+add_fde2 (sframe_encoder_ctx *encode, int idx)
+{
+  int i, err;
+  /* A contiguous block containing 4 FREs.  */
+  sframe_frame_row_entry fres[]
+    = { {0x0, 0x3, {0x8, 0, 0}},
+	{0x1, 0x5, {0x10, 0xf0, 0}},
+	{0x4, 0x4, {0x10, 0xf0, 0}},
+	{0xf, 0x5, {0x8, 0xf0, 0}}
+      };
+
+  unsigned char finfo = sframe_fde_func_info (SFRAME_FRE_TYPE_ADDR1,
+					      SFRAME_FDE_TYPE_PCINC);
+  err = sframe_encoder_add_funcdesc (encode, 0xffffeff1, 0x10, finfo, 4);
+  if (err == -1)
+    return err;
+
+  for (i = 0; i < 4; i++)
+    if (sframe_encoder_add_fre (encode, idx, fres+i) == SFRAME_ERR)
+      return -1;
+
+  return 0;
+}
+
+/*
+ * SFrame info from the following source (2 fdes, 4 fres in each fde):
+ * static int cnt;
+ * int foo() { return ++cnt; }
+ * int main() { return foo(); }
+ */
+#define DATA    "DATA2"
+
+static int
+data_match (char *sframe_buf, size_t sz)
+{
+  FILE *fp;
+  struct stat st;
+  char *sf_buf;
+  size_t sf_size;
+  int diffs;
+
+  fp = fopen (DATA, "r");
+  if (fp == NULL)
+    return 0;
+  if (fstat (fileno (fp), &st) < 0)
+    {
+      perror ("fstat");
+      fclose (fp);
+      return 0;
+    }
+  sf_buf = malloc (st.st_size);
+  if (sf_buf == NULL)
+    {
+      perror ("malloc");
+      return 0;
+    }
+  sf_size = fread (sf_buf, 1, st.st_size, fp);
+  fclose (fp);
+  if (sf_size == 0 || sf_buf == NULL)
+    {
+      fprintf (stderr, "Encode: Read section failed\n");
+      return 0;
+    }
+  if (sf_size != sz)
+    return 0;
+
+  diffs = memcmp (sf_buf, sframe_buf, sz);
+
+  free (sf_buf);
+  return diffs == 0;
+}
+
+int main ()
+{
+  sframe_encoder_ctx *encode;
+  sframe_frame_row_entry frep;
+  char *sframe_buf;
+  size_t sf_size;
+  int err = 0;
+
+  encode = sframe_encode (SFRAME_VERSION, 0,
+			  SFRAME_ABI_AMD64_ENDIAN_LITTLE, &err);
+
+  if (sframe_encoder_get_num_fidx (encode) != 0)
+    {
+      fprintf (stderr, "Encode: incorrect FDEs count\n");
+      goto fail;
+    }
+
+  /* Error test.  */
+  if (sframe_encoder_add_fre (encode, 1, &frep) != SFRAME_ERR)
+    {
+      fprintf (stderr, "Encode: Adding FRE befoer FDE does\n");
+      goto fail;
+    }
+
+  if (add_fde1 (encode, 0) == -1)
+    {
+      fprintf (stderr, "Encode: Adding FDE1\n");
+      goto fail;
+    }
+  if (add_fde2 (encode, 1) == -1)
+    {
+      fprintf (stderr, "Encode: Adding FDE2\n");
+      goto fail;
+    }
+
+  if (sframe_encoder_get_num_fidx (encode) != 2)
+    {
+      fprintf (stderr, "Encode: Wrong FDE count\n");
+      goto fail;
+    }
+
+  sframe_buf = sframe_write_encoder (encode, &sf_size, &err);
+  if (err)
+    return 1;
+  if (data_match (sframe_buf, sf_size))
+    {
+      sframe_encoder_free (&encode);
+      pass ("encode test");
+    }
+
+fail:
+  sframe_encoder_free (&encode);
+  return 1;
+}
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 06/14] bfd: linker: merge .sframe sections
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (4 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 05/14] libsframe: add the SFrame library Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30 10:51       ` Nick Clifton
  2022-09-30  0:04     ` [PATCH,V1 07/14] readelf/objdump: support for SFrame section Indu Bhagat
                       ` (10 subsequent siblings)
  16 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

The linker merges all the input .sframe sections.  When merging, the
linker verifies that all the input .sframe sections have the same
abi/arch.

The linker uses libsframe library to perform key actions on the
.sframe sections - decode, read, and create output data.  This
implies buildsystem changes to make and install libsframe before
libbfd.

The linker places the output .sframe section in a new segment of its
own: PT_GNU_SFRAME.  A new segment is not added, however, if the
generated .sframe section is empty.

When a section is discarded from the final link, the corresponding
entries in the .sframe section for those functions are also deleted.

The linker sorts the SFrame FDEs on start address by default and sets
the SFRAME_F_FDE_SORTED flag in the .sframe section.

This patch also adds support for generation of SFrame unwind
information for the .plt* sections on x86_64.  SFrame unwind info is
generated for IBT enabled PLT, lazy/non-lazy PLT.

The existing linker option --no-ld-generated-unwind-info has been
adapted to include the control of whether .sframe unwind information
will be generated for the linker generated sections like PLT.

Changes to the linker script have been made as necessary.

ChangeLog:

	* Makefile.def: Add install dependency on libsframe for libbfd.
	* Makefile.in: Regenerated.
	* bfd/Makefile.am: Add elf-sframe.c
	* bfd/Makefile.in: Regenerated.
	* bfd/bfd-in2.h (SEC_INFO_TYPE_SFRAME): Regenerated.
	* bfd/configure: Regenerate.
	* bfd/configure.ac: Add elf-sframe.lo.
	* bfd/elf-bfd.h (struct sframe_func_bfdinfo): New struct.
	(struct sframe_dec_info): Likewise.
	(struct sframe_enc_info): Likewise.
	(struct elf_link_hash_table): New member for encoded .sframe
	object.
	(struct output_elf_obj_tdata): New member.
	(elf_sframe): New access macro.
	(_bfd_elf_set_section_sframe): New declaration.
	* bfd/elf.c (get_segment_type): Handle new segment
	PT_GNU_SFRAME.
	(bfd_section_from_phdr): Likewise.
	(get_program_header_size): Likewise.
	(_bfd_elf_map_sections_to_segments): Likewise.
	* bfd/elf64-x86-64.c (elf_x86_64_link_setup_gnu_properties): Add
	contents to the .sframe sections or .plt* entries.
	* bfd/elflink.c (elf_section_ignore_discarded_relocs): Handle
	SEC_INFO_TYPE_SFRAME.
	(_bfd_elf_default_action_discarded): Handle .sframe section.
	(elf_link_input_bfd): Merge .sframe section.
	(bfd_elf_final_link): Write the output .sframe section.
	(bfd_elf_discard_info): Handle discarding .sframe section.
	* bfd/elfxx-x86.c (_bfd_x86_elf_size_dynamic_sections): Create
	.sframe section for .plt and .plt.sec.
	(_bfd_x86_elf_finish_dynamic_sections): Handle .sframe from
	.plt* sections.
	* bfd/elfxx-x86.h (PLT_SFRAME_FDE_START_OFFSET): New
	definition.
	(SFRAME_PLT0_MAX_NUM_FRES): Likewise.
	(SFRAME_PLTN_MAX_NUM_FRES): Likewise.
	(struct elf_x86_sframe_plt): New structure.
	(struct elf_x86_link_hash_table): New member.
	(struct elf_x86_init_table): New members for .sframe
	creation.
	* bfd/section.c: Add new definition SEC_INFO_TYPE_SFRAME.
	* binutils/readelf.c (get_segment_type): Handle new segment
	PT_GNU_SFRAME.
	* ld/ld.texi: Update documentation for
	--no-ld-generated-unwind-info.
	* ld/scripttempl/elf.sc: Support .sframe sections.
	* Makefile.am (TESTSFRAMELIB): Use it.
	(check-DEJAGNU): Likewise.
	* configure.ac (TESTSFRAMELIB): Set to the .so or .a like TESTBFDLIB.
	* testsuite/ld-bootstrap/bootstrap.exp: Add SFRAMELIB.
	* bfd/elf-sframe.c: New file.

include/ChangeLog:

	* elf/common.h (PT_GNU_SFRAME): New definition.
	* elf/internal.h (struct elf_segment_map): Handle new segment
	type PT_GNU_SFRAME.

ld/testsuite/ChangeLog:

	* ld/testsuite/ld-aarch64/aarch64-elf.exp: Add new test
	  sframe-simple-1.
	* ld/testsuite/ld-aarch64/sframe-bar.s: New file.
	* ld/testsuite/ld-aarch64/sframe-foo.s: Likewise.
	* ld/testsuite/ld-aarch64/sframe-simple-1.d: Likewise.
	* ld/testsuite/ld-sframe/sframe-empty.d: New test.
	* ld/testsuite/ld-sframe/sframe-empty.s: New file.
	* ld/testsuite/ld-sframe/sframe.exp: New testsuite.
	* ld/testsuite/ld-x86-64/sframe-bar.s: New file.
	* ld/testsuite/ld-x86-64/sframe-foo.s: Likewise.
	* ld/testsuite/ld-x86-64/sframe-simple-1.d: Likewise.
	* ld/testsuite/ld-x86-64/sframe-plt-1.d: Likewise.
	* ld/testsuite/ld-x86-64/sframe-simple-1.d: Likewise.
	* ld/testsuite/ld-x86-64/x86-64.exp: Add new tests -
	  sframe-simple-1, sframe-plt-1.
	* ld/testsuite/lib/ld-lib.exp: Add new proc to check if
	  assembler supports SFrame section.
	* ld/testsuite/ld-sframe/discard.d: New file.
	* ld/testsuite/ld-sframe/discard.ld: Likewise.
	* ld/testsuite/ld-sframe/discard.s: Likewise.
---
 Makefile.def                              |   4 +
 Makefile.in                               |  11 +
 bfd/Makefile.am                           |   6 +-
 bfd/Makefile.in                           |   7 +-
 bfd/bfd-in2.h                             |   1 +
 bfd/configure                             |   2 +-
 bfd/configure.ac                          |   2 +-
 bfd/elf-bfd.h                             |  54 +++
 bfd/elf-sframe.c                          | 533 ++++++++++++++++++++++
 bfd/elf.c                                 |  32 ++
 bfd/elf64-x86-64.c                        |  97 +++-
 bfd/elflink.c                             |  52 +++
 bfd/elfxx-x86.c                           | 377 ++++++++++++++-
 bfd/elfxx-x86.h                           |  46 ++
 bfd/section.c                             |   1 +
 binutils/readelf.c                        |   1 +
 include/elf/common.h                      |   1 +
 include/elf/internal.h                    |   1 +
 include/sframe-api.h                      |   2 +-
 ld/Makefile.am                            |   2 +
 ld/Makefile.in                            |   2 +
 ld/configure                              |   8 +-
 ld/configure.ac                           |   3 +
 ld/ld.texi                                |   4 +-
 ld/scripttempl/elf.sc                     |   2 +
 ld/testsuite/ld-aarch64/aarch64-elf.exp   |   2 +
 ld/testsuite/ld-aarch64/sframe-bar.s      |   7 +
 ld/testsuite/ld-aarch64/sframe-foo.s      |  10 +
 ld/testsuite/ld-aarch64/sframe-simple-1.d |  26 ++
 ld/testsuite/ld-bootstrap/bootstrap.exp   |   8 +-
 ld/testsuite/ld-sframe/discard.d          |  10 +
 ld/testsuite/ld-sframe/discard.ld         |   9 +
 ld/testsuite/ld-sframe/discard.s          |  13 +
 ld/testsuite/ld-sframe/sframe-empty.d     |  10 +
 ld/testsuite/ld-sframe/sframe-empty.s     |   2 +
 ld/testsuite/ld-sframe/sframe.exp         |  47 ++
 ld/testsuite/ld-x86-64/sframe-bar.s       |  31 ++
 ld/testsuite/ld-x86-64/sframe-foo.s       |  37 ++
 ld/testsuite/ld-x86-64/sframe-plt-1.d     |  29 ++
 ld/testsuite/ld-x86-64/sframe-simple-1.d  |  35 ++
 ld/testsuite/ld-x86-64/x86-64.exp         |   2 +
 ld/testsuite/lib/ld-lib.exp               |  45 ++
 libsframe/sframe.c                        |  28 +-
 43 files changed, 1578 insertions(+), 24 deletions(-)
 create mode 100644 bfd/elf-sframe.c
 create mode 100644 ld/testsuite/ld-aarch64/sframe-bar.s
 create mode 100644 ld/testsuite/ld-aarch64/sframe-foo.s
 create mode 100644 ld/testsuite/ld-aarch64/sframe-simple-1.d
 create mode 100644 ld/testsuite/ld-sframe/discard.d
 create mode 100644 ld/testsuite/ld-sframe/discard.ld
 create mode 100644 ld/testsuite/ld-sframe/discard.s
 create mode 100644 ld/testsuite/ld-sframe/sframe-empty.d
 create mode 100644 ld/testsuite/ld-sframe/sframe-empty.s
 create mode 100644 ld/testsuite/ld-sframe/sframe.exp
 create mode 100644 ld/testsuite/ld-x86-64/sframe-bar.s
 create mode 100644 ld/testsuite/ld-x86-64/sframe-foo.s
 create mode 100644 ld/testsuite/ld-x86-64/sframe-plt-1.d
 create mode 100644 ld/testsuite/ld-x86-64/sframe-simple-1.d

diff --git a/Makefile.def b/Makefile.def
index 1b39c910447..f974565d8ca 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -458,11 +458,14 @@ dependencies = { module=all-gdbsupport; on=all-gnulib; };
 dependencies = { module=all-gdbsupport; on=all-intl; };
 
 // Host modules specific to binutils.
+// build libsframe before bfd for encoder/decoder support for linking
+// SFrame sections
 dependencies = { module=configure-bfd; on=configure-libiberty; hard=true; };
 dependencies = { module=configure-bfd; on=configure-intl; };
 dependencies = { module=all-bfd; on=all-libiberty; };
 dependencies = { module=all-bfd; on=all-intl; };
 dependencies = { module=all-bfd; on=all-zlib; };
+dependencies = { module=all-bfd; on=all-libsframe; };
 dependencies = { module=configure-opcodes; on=configure-libiberty; hard=true; };
 dependencies = { module=all-opcodes; on=all-libiberty; };
 
@@ -488,6 +491,7 @@ dependencies = { module=install-binutils; on=install-opcodes; };
 dependencies = { module=install-strip-binutils; on=install-strip-opcodes; };
 
 // Likewise for ld, libctf, and bfd.
+dependencies = { module=install-bfd; on=install-libsframe; };
 dependencies = { module=install-libctf; on=install-bfd; };
 dependencies = { module=install-ld; on=install-bfd; };
 dependencies = { module=install-ld; on=install-libctf; };
diff --git a/Makefile.in b/Makefile.in
index b26f778a94a..a425b54e094 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -64407,6 +64407,16 @@ all-stagetrain-bfd: maybe-all-stagetrain-zlib
 all-stagefeedback-bfd: maybe-all-stagefeedback-zlib
 all-stageautoprofile-bfd: maybe-all-stageautoprofile-zlib
 all-stageautofeedback-bfd: maybe-all-stageautofeedback-zlib
+all-bfd: maybe-all-libsframe
+all-stage1-bfd: maybe-all-stage1-libsframe
+all-stage2-bfd: maybe-all-stage2-libsframe
+all-stage3-bfd: maybe-all-stage3-libsframe
+all-stage4-bfd: maybe-all-stage4-libsframe
+all-stageprofile-bfd: maybe-all-stageprofile-libsframe
+all-stagetrain-bfd: maybe-all-stagetrain-libsframe
+all-stagefeedback-bfd: maybe-all-stagefeedback-libsframe
+all-stageautoprofile-bfd: maybe-all-stageautoprofile-libsframe
+all-stageautofeedback-bfd: maybe-all-stageautofeedback-libsframe
 configure-opcodes: configure-libiberty
 configure-stage1-opcodes: configure-stage1-libiberty
 configure-stage2-opcodes: configure-stage2-libiberty
@@ -64539,6 +64549,7 @@ all-stageautoprofile-binutils: maybe-all-stageautoprofile-libsframe
 all-stageautofeedback-binutils: maybe-all-stageautofeedback-libsframe
 install-binutils: maybe-install-opcodes
 install-strip-binutils: maybe-install-strip-opcodes
+install-bfd: maybe-install-libsframe
 install-libctf: maybe-install-bfd
 install-ld: maybe-install-bfd
 install-ld: maybe-install-libctf
diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 98a487b7fcd..51240acd4f0 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -286,6 +286,7 @@ BFD32_BACKENDS = \
 	ecofflink.lo \
 	elf-attrs.lo \
 	elf-eh-frame.lo \
+	elf-sframe.lo \
 	elf-ifunc.lo \
 	elf-m10200.lo \
 	elf-m10300.lo \
@@ -419,6 +420,7 @@ BFD32_BACKENDS_CFILES = \
 	ecofflink.c \
 	elf-attrs.c \
 	elf-eh-frame.c \
+	elf-sframe.c \
 	elf-ifunc.c \
 	elf-m10200.c \
 	elf-m10300.c \
@@ -775,8 +777,8 @@ ofiles: stamp-ofiles ; @true
 # dependency tracking fragments are picked up in the Makefile.
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
-libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
+libbfd_la_DEPENDENCIES = $(OFILES) ofiles ../libsframe/libsframe.la
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS) ../libsframe/libsframe.la
 libbfd_la_LDFLAGS += -release `cat libtool-soversion` @SHARED_LDFLAGS@
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 3c9ebf38f83..11aad5ac5cf 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -755,6 +755,7 @@ BFD32_BACKENDS = \
 	ecofflink.lo \
 	elf-attrs.lo \
 	elf-eh-frame.lo \
+	elf-sframe.lo \
 	elf-ifunc.lo \
 	elf-m10200.lo \
 	elf-m10300.lo \
@@ -888,6 +889,7 @@ BFD32_BACKENDS_CFILES = \
 	ecofflink.c \
 	elf-attrs.c \
 	elf-eh-frame.c \
+	elf-sframe.c \
 	elf-ifunc.c \
 	elf-m10200.c \
 	elf-m10300.c \
@@ -1205,8 +1207,8 @@ OFILES = $(BFD_BACKENDS) $(BFD_MACHINES) @COREFILE@ @bfd64_libs@
 # dependency tracking fragments are picked up in the Makefile.
 libbfd_la_SOURCES = $(BFD32_LIBS_CFILES)
 EXTRA_libbfd_la_SOURCES = $(CFILES)
-libbfd_la_DEPENDENCIES = $(OFILES) ofiles
-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS)
+libbfd_la_DEPENDENCIES = $(OFILES) ofiles ../libsframe/libsframe.la
+libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS) ../libsframe/libsframe.la
 
 # libtool will build .libs/libbfd.a.  We create libbfd.a in the build
 # directory so that we don't have to convert all the programs that use
@@ -1572,6 +1574,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-m10300.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-nacl.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-properties.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-sframe.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-strtab.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-vxworks.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf.Plo@am__quote@
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 5c80956c79c..5012fc2e055 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -980,6 +980,7 @@ typedef struct bfd_section
 #define SEC_INFO_TYPE_JUST_SYMS 4
 #define SEC_INFO_TYPE_TARGET    5
 #define SEC_INFO_TYPE_EH_FRAME_ENTRY 6
+#define SEC_INFO_TYPE_SFRAME  7
 
   /* Nonzero if this section uses RELA relocations, rather than REL.  */
   unsigned int use_rela_p:1;
diff --git a/bfd/configure b/bfd/configure
index d905a7bf7a8..9307563f9ab 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -13581,7 +13581,7 @@ selarchs="$f"
 tb=
 
 elf="elf.lo elflink.lo elf-attrs.lo elf-strtab.lo elf-eh-frame.lo
-     dwarf1.lo dwarf2.lo"
+     elf-sframe.lo dwarf1.lo dwarf2.lo"
 coffgen="coffgen.lo dwarf2.lo"
 coff="cofflink.lo $coffgen"
 ecoff="ecofflink.lo $coffgen"
diff --git a/bfd/configure.ac b/bfd/configure.ac
index 7a0ad0ffe33..ce4d3eb12d2 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -383,7 +383,7 @@ selarchs="$f"
 tb=
 
 elf="elf.lo elflink.lo elf-attrs.lo elf-strtab.lo elf-eh-frame.lo
-     dwarf1.lo dwarf2.lo"
+     elf-sframe.lo dwarf1.lo dwarf2.lo"
 coffgen="coffgen.lo dwarf2.lo"
 coff="cofflink.lo $coffgen"
 ecoff="ecofflink.lo $coffgen"
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index f00f87b2779..70595a97638 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -490,6 +490,40 @@ struct eh_frame_hdr_info
   u;
 };
 
+/* Additional information for each function (used at link time).  */
+struct sframe_func_bfdinfo
+{
+  /* Whether the function has been discarded from the final output.  */
+  bool func_deleted_p;
+  /* Relocation offset.  */
+  unsigned int func_r_offset;
+  /* Relocation index.  */
+  unsigned int func_reloc_index;
+};
+
+/* SFrame decoder info.
+   Contains all information for a decoded .sframe section.  */
+struct sframe_dec_info
+{
+  /* Decoder context.  */
+  struct sframe_decoder_ctx *sfd_ctx;
+  /* Number of function descriptor entries in this .sframe.  */
+  unsigned int sfd_fde_count;
+  /* Additional information for linking.  */
+  struct sframe_func_bfdinfo *sfd_func_bfdinfo;
+};
+
+/* SFrame encoder info.
+   Contains all information for an encoded .sframe section to be
+   written out.  */
+struct sframe_enc_info
+{
+  /* Encoder context.  */
+  struct sframe_encoder_ctx *sfe_ctx;
+  /* Output section.  */
+  asection *sframe_section;
+};
+
 /* Enum used to identify target specific extensions to the elf_obj_tdata
    and elf_link_hash_table structures.  Note the enums deliberately start
    from 1 so that we can detect an uninitialized field.  The generic value
@@ -668,6 +702,9 @@ struct elf_link_hash_table
   /* Used by eh_frame code when editing .eh_frame.  */
   struct eh_frame_hdr_info eh_info;
 
+  /* Used to link unwind data in .sframe sections.  */
+  struct sframe_enc_info sfe_info;
+
   /* A linked list of local symbols to be added to .dynsym.  */
   struct elf_link_local_dynamic_entry *dynlocal;
 
@@ -1941,6 +1978,10 @@ struct output_elf_obj_tdata
   /* Segment flags for the PT_GNU_STACK segment.  */
   unsigned int stack_flags;
 
+  /* Used to determine if PT_GNU_SFRAME segment header should be
+     created.  */
+  asection *sframe;
+
   /* Used to determine if the e_flags field has been initialized */
   bool flags_init;
 };
@@ -2122,6 +2163,7 @@ struct elf_obj_tdata
 #define elf_link_info(bfd)	(elf_tdata(bfd) -> o->link_info)
 #define elf_next_file_pos(bfd)	(elf_tdata(bfd) -> o->next_file_pos)
 #define elf_stack_flags(bfd)	(elf_tdata(bfd) -> o->stack_flags)
+#define elf_sframe(bfd)		(elf_tdata(bfd) -> o->sframe)
 #define elf_shstrtab(bfd)	(elf_tdata(bfd) -> o->strtab_ptr)
 #define elf_onesymtab(bfd)	(elf_tdata(bfd) -> symtab_section)
 #define elf_symtab_shndx_list(bfd)	(elf_tdata(bfd) -> symtab_shndx_list)
@@ -2436,6 +2478,18 @@ extern bool _bfd_elf_eh_frame_entry_present
 extern bool _bfd_elf_maybe_strip_eh_frame_hdr
   (struct bfd_link_info *);
 
+extern bool _bfd_elf_sframe_present
+  (struct bfd_link_info *);
+extern bool _bfd_elf_parse_sframe
+  (bfd *, struct bfd_link_info *, asection *, struct elf_reloc_cookie *);
+extern bool _bfd_elf_discard_section_sframe
+  (asection *, bool (*) (bfd_vma, void *), struct elf_reloc_cookie *);
+extern bool _bfd_elf_merge_section_sframe
+  (bfd *, struct bfd_link_info *, asection *, bfd_byte *);
+extern bool _bfd_elf_write_section_sframe
+  (bfd *, struct bfd_link_info *);
+extern bool _bfd_elf_set_section_sframe (bfd *, struct bfd_link_info *);
+
 extern bool _bfd_elf_hash_symbol (struct elf_link_hash_entry *);
 
 extern long _bfd_elf_link_lookup_local_dynindx
diff --git a/bfd/elf-sframe.c b/bfd/elf-sframe.c
new file mode 100644
index 00000000000..84aeb5aadea
--- /dev/null
+++ b/bfd/elf-sframe.c
@@ -0,0 +1,533 @@
+/* .sframe section processing.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "sframe-api.h"
+
+/* Return TRUE if the function has been marked for deletion during the linking
+   process.  */
+
+static bool
+sframe_decoder_func_deleted_p (struct sframe_dec_info *sfd_info,
+			       unsigned int func_idx)
+{
+  if (func_idx < sfd_info->sfd_fde_count)
+    return sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p;
+
+  return false;
+}
+
+/* Mark the function in the decoder info for deletion.  */
+
+static void
+sframe_decoder_mark_func_deleted (struct sframe_dec_info *sfd_info,
+				  unsigned int func_idx)
+{
+  if (func_idx < sfd_info->sfd_fde_count)
+    sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p = true;
+}
+
+/* Get the relocation offset from the decoder info for the given function.  */
+
+static unsigned int
+sframe_decoder_get_func_r_offset (struct sframe_dec_info *sfd_info,
+				  unsigned int func_idx)
+{
+  BFD_ASSERT (func_idx < sfd_info->sfd_fde_count);
+  unsigned int func_r_offset
+    = sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset;
+  /* There must have been a reloc.  */
+  BFD_ASSERT (func_r_offset);
+  return func_r_offset;
+}
+
+/* Bookkeep the function relocation offset in the decoder info.  */
+
+static void
+sframe_decoder_set_func_r_offset (struct sframe_dec_info *sfd_info,
+				  unsigned int func_idx,
+				  unsigned int r_offset)
+{
+  if (func_idx < sfd_info->sfd_fde_count)
+    sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset = r_offset;
+}
+
+/* Get the relocation index in the elf_reloc_cookie for the function.  */
+
+static unsigned int
+sframe_decoder_get_func_reloc_index (struct sframe_dec_info *sfd_info,
+				     unsigned int func_idx)
+{
+  BFD_ASSERT (func_idx < sfd_info->sfd_fde_count);
+  return sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index;
+}
+
+/* Bookkeep the relocation index in the elf_reloc_cookie for the function.  */
+
+static void
+sframe_decoder_set_func_reloc_index (struct sframe_dec_info *sfd_info,
+				     unsigned int func_idx,
+				     unsigned int reloc_index)
+{
+  if (func_idx < sfd_info->sfd_fde_count)
+    sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index = reloc_index;
+}
+
+/* Initialize the set of additional information in CFD_INFO,
+   needed for linking SEC.  Returns TRUE if setup is done successfully.  */
+
+static bool
+sframe_decoder_init_func_bfdinfo (asection *sec,
+				  struct sframe_dec_info *sfd_info,
+				  struct elf_reloc_cookie *cookie)
+{
+  unsigned int fde_count;
+  unsigned int func_bfdinfo_size, i;
+
+  fde_count = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx);
+  sfd_info->sfd_fde_count = fde_count;
+
+  /* Allocate and clear the memory.  */
+  func_bfdinfo_size = (sizeof (struct sframe_func_bfdinfo)) * fde_count;
+  sfd_info->sfd_func_bfdinfo
+    = (struct sframe_func_bfdinfo*) bfd_malloc (func_bfdinfo_size);
+  if (sfd_info->sfd_func_bfdinfo == NULL)
+    return false;
+  memset (sfd_info->sfd_func_bfdinfo, 0, func_bfdinfo_size);
+
+  /* For linker generated .sframe sections, we have no relocs.  Skip.  */
+  if ((sec->flags & SEC_LINKER_CREATED) && cookie->rels == NULL)
+    return true;
+
+  for (i = 0; i < fde_count; i++)
+    {
+      cookie->rel = cookie->rels + i;
+      BFD_ASSERT (cookie->rel < cookie->relend);
+      /* Bookkeep the relocation offset and relocation index of each function
+	 for later use.  */
+      sframe_decoder_set_func_r_offset (sfd_info, i, cookie->rel->r_offset);
+      sframe_decoder_set_func_reloc_index (sfd_info, i,
+					   (cookie->rel - cookie->rels));
+
+      cookie->rel++;
+    }
+  BFD_ASSERT (cookie->rel == cookie->relend);
+
+  return true;
+}
+
+/* Read the value from CONTENTS at the specified OFFSET for the given ABFD.  */
+
+static bfd_vma
+sframe_read_value (bfd *abfd, bfd_byte *contents, unsigned int offset,
+		   unsigned int width)
+{
+  BFD_ASSERT (contents && offset);
+  /* Supporting the usecase of reading only the 4-byte relocated
+     value (signed offset for func start addr) for now.  */
+  BFD_ASSERT (width == 4);
+  /* FIXME endianness ?? */
+  unsigned char *buf = contents + offset;
+  bfd_vma value = bfd_get_signed_32 (abfd, buf);
+  return value;
+}
+
+/* Return true if there is at least one non-empty .sframe section in
+   input files.  Can only be called after ld has mapped input to
+   output sections, and before sections are stripped.  */
+
+bool
+_bfd_elf_sframe_present (struct bfd_link_info *info)
+{
+  asection *sframe = bfd_get_section_by_name (info->output_bfd, ".sframe");
+
+  if (sframe == NULL)
+    return false;
+
+  /* Count only sections which have at least a single FDE.  */
+  for (sframe = sframe->map_head.s; sframe != NULL; sframe = sframe->map_head.s)
+    if (sframe->size > sizeof (sframe_header))
+      return true;
+  return false;
+}
+
+/* Try to parse .sframe section SEC, which belongs to ABFD.  Store the
+   information in the section's sec_info field on success.  COOKIE
+   describes the relocations in SEC.
+
+   Returns TRUE if success, FALSE if any error or failure.  */
+
+bool
+_bfd_elf_parse_sframe (bfd *abfd,
+		       struct bfd_link_info *info ATTRIBUTE_UNUSED,
+		       asection *sec, struct elf_reloc_cookie *cookie)
+{
+  bfd_byte *sfbuf = NULL;
+  struct sframe_dec_info *sfd_info;
+  sframe_decoder_ctx *sfd_ctx;
+  bfd_size_type sf_size;
+  int decerr = 0;
+
+  if (sec->size == 0
+      || sec->sec_info_type != SEC_INFO_TYPE_NONE)
+    {
+      /* This file does not contain .sframe information.  */
+      return false;
+    }
+
+  if (bfd_is_abs_section (sec->output_section))
+    {
+      /* At least one of the sections is being discarded from the
+	 link, so we should just ignore them.  */
+      return false;
+    }
+
+  /* Read the SFrame unwind information from abfd.  */
+  if (!bfd_malloc_and_get_section (abfd, sec, &sfbuf))
+    goto fail_no_free;
+
+  /* Decode the buffer and keep decoded contents for later use.
+     Relocations are performed later, but are such that the section's
+     size is unaffected.  */
+  sfd_info = bfd_malloc (sizeof (struct sframe_dec_info));
+  sf_size = sec->size;
+
+  sfd_info->sfd_ctx = sframe_decode ((const char*)sfbuf, sf_size, &decerr);
+  sfd_ctx = sfd_info->sfd_ctx;
+  if (!sfd_ctx)
+    /* Free'ing up any memory held by decoder context is done by
+       sframe_decode in case of error.  */
+    goto fail_no_free;
+
+  if (!sframe_decoder_init_func_bfdinfo (sec, sfd_info, cookie))
+    {
+      sframe_decoder_free (&sfd_ctx);
+      goto fail_no_free;
+    }
+
+  elf_section_data (sec)->sec_info = sfd_info;
+  sec->sec_info_type = SEC_INFO_TYPE_SFRAME;
+
+  goto success;
+
+fail_no_free:
+  _bfd_error_handler
+   (_("error in %pB(%pA); no .sframe will be created"),
+    abfd, sec);
+  return false;
+success:
+  free (sfbuf);
+  return true;
+}
+
+/* This function is called for each input file before the .sframe section
+   is relocated.  It marks the SFrame FDE for the discarded functions for
+   deletion.
+
+   The function returns TRUE iff any entries have been deleted.  */
+
+bool
+_bfd_elf_discard_section_sframe
+   (asection *sec,
+    bool (*reloc_symbol_deleted_p) (bfd_vma, void *),
+    struct elf_reloc_cookie *cookie)
+{
+  bool changed;
+  bool keep;
+  unsigned int i;
+  unsigned int func_desc_offset;
+  unsigned int num_fidx;
+  struct sframe_dec_info *sfd_info;
+
+  changed = false;
+  /* FIXME - if relocatable link and changed = true, how does the final
+     .rela.sframe get updated ?.  */
+  keep = false;
+
+  sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info;
+
+  /* Skip checking for the linker created .sframe sections
+     (for PLT sections).  */
+  if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL)
+    {
+      num_fidx = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx);
+      for (i = 0; i < num_fidx; i++)
+	{
+	  func_desc_offset = sframe_decoder_get_func_r_offset (sfd_info, i);
+
+	  cookie->rel = cookie->rels
+	    + sframe_decoder_get_func_reloc_index (sfd_info, i);
+	  keep = !(*reloc_symbol_deleted_p) (func_desc_offset, cookie);
+
+	  if (!keep)
+	    {
+	      sframe_decoder_mark_func_deleted (sfd_info, i);
+	      changed = true;
+	    }
+	}
+    }
+  return changed;
+}
+
+/* Update the reference to the output .sframe section in the output ELF
+   BFD ABFD.  Returns true if no error.  */
+
+bool
+_bfd_elf_set_section_sframe (bfd *abfd,
+				struct bfd_link_info *info)
+{
+  asection *cfsec;
+
+  cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe");
+  if (!cfsec)
+    return false;
+
+  elf_sframe (abfd) = cfsec;
+
+  return true;
+}
+
+/* Merge .sframe section SEC.  This is called with the relocated
+   CONTENTS.  */
+
+bool
+_bfd_elf_merge_section_sframe (bfd *abfd,
+			       struct bfd_link_info *info,
+			       asection *sec,
+			       bfd_byte *contents)
+{
+  struct sframe_dec_info *sfd_info;
+  struct sframe_enc_info *sfe_info;
+  sframe_decoder_ctx *sfd_ctx;
+  sframe_encoder_ctx *sfe_ctx;
+  unsigned char sfd_ctx_abi_arch;
+  int encerr = 0;
+
+  struct elf_link_hash_table *htab;
+  asection *cfsec;
+
+  /* Sanity check - handle SFrame sections only.  */
+  if (sec->sec_info_type != SEC_INFO_TYPE_SFRAME)
+    return false;
+
+  sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info;
+  sfd_ctx = sfd_info->sfd_ctx;
+
+  htab = elf_hash_table (info);
+  sfe_info = &(htab->sfe_info);
+  sfe_ctx = sfe_info->sfe_ctx;
+
+  /* All input bfds are expected to have a valid SFrame section.  Even if
+     the SFrame section is empty with only a header, there must be a valid
+     SFrame decoder context by now.  The SFrame encoder context, however,
+     will get set later here, if this is the first call to the function.  */
+  if (sfd_ctx == NULL || sfe_info == NULL)
+    return false;
+
+  if (htab->sfe_info.sfe_ctx == NULL)
+    {
+      sfd_ctx_abi_arch = sframe_decoder_get_abi_arch (sfd_ctx);
+      /* Valid values are non-zero.  */
+      if (!sfd_ctx_abi_arch)
+	return false;
+
+      htab->sfe_info.sfe_ctx = sframe_encode (SFRAME_VERSION_1,
+					      0, /* SFrame flags.  */
+					      sfd_ctx_abi_arch,
+					      &encerr);
+      /* Handle errors from sframe_encode.  */
+      if (htab->sfe_info.sfe_ctx == NULL)
+	return false;
+    }
+  sfe_ctx = sfe_info->sfe_ctx;
+
+  if (sfe_info->sframe_section == NULL)
+    {
+      /* Make sure things are set for an eventual write.
+	 Size of the output section is not known until
+	 _bfd_elf_write_section_sframe is ready with the buffer
+	 to write out.  */
+      cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe");
+      if (cfsec)
+	{
+	  sfe_info->sframe_section = cfsec;
+	  // elf_sframe (abfd) = cfsec;
+	}
+      else
+	return false;
+    }
+
+  /* Check that all .sframe sections being linked have the same
+     ABI/arch.  */
+  if (sframe_decoder_get_abi_arch (sfd_ctx)
+      != sframe_encoder_get_abi_arch (sfe_ctx))
+    {
+      _bfd_error_handler
+	(_("input SFrame sections with different abi prevent .sframe"
+	  " generation"));
+      return false;
+    }
+
+  /* Iterate over the function descriptor entries and the FREs of the
+     function from the decoder context.  Add each of them to the encoder
+     context, if suitable.  */
+  unsigned int i = 0, j = 0, cur_fidx = 0;
+
+  unsigned int num_fidx = sframe_decoder_get_num_fidx (sfd_ctx);
+  unsigned int num_enc_fidx = sframe_encoder_get_num_fidx (sfe_ctx);
+
+  for (i = 0; i < num_fidx; i++)
+    {
+      unsigned int num_fres = 0;
+      int32_t func_start_address;
+      bfd_vma address;
+      uint32_t func_size = 0;
+      unsigned char func_info = 0;
+      unsigned int r_offset = 0;
+      bool pltn_reloc_by_hand = false;
+      unsigned int pltn_r_offset = 0;
+
+      if (!sframe_decoder_get_funcdesc (sfd_ctx, i, &num_fres, &func_size,
+					&func_start_address, &func_info))
+	{
+	  /* If function belongs to a deleted section, skip editing the
+	     function descriptor entry.  */
+	  if (sframe_decoder_func_deleted_p(sfd_info, i))
+	    continue;
+
+	  /* Don't edit function descriptor entries for relocatable link.  */
+	  if (!bfd_link_relocatable (info))
+	    {
+	      if (!(sec->flags & SEC_LINKER_CREATED))
+		{
+		  /* Get relocated contents by reading the value of the
+		     relocated function start address at the beginning of the
+		     function descriptor entry.  */
+		  r_offset = sframe_decoder_get_func_r_offset (sfd_info, i);
+		}
+	      else
+		{
+		  /* Expected to land here for SFrame unwind info as created
+		     for the .plt* sections.  These sections can have upto two
+		     FDE entries.  Although the code should work for > 2,
+		     leaving this assert here for safety.  */
+		  BFD_ASSERT (num_fidx <= 2);
+		  /* For the first entry, we know the offset of the SFrame FDE's
+		     sfde_func_start_address.  Side note: see how the value
+		     of PLT_SFRAME_FDE_START_OFFSET is also set to the
+		     same.  */
+		  r_offset = sizeof (sframe_header);
+		  /* For any further SFrame FDEs, the generator has already put
+		     in an offset in place of sfde_func_start_address of the
+		     corresponding FDE.  We will use it by hand to relocate.  */
+		  if (i > 0)
+		    {
+		      pltn_r_offset
+			= r_offset + (i * sizeof (sframe_func_desc_entry));
+		      pltn_reloc_by_hand = true;
+		    }
+		}
+
+	      /* Get the SFrame FDE function start address after relocation.  */
+	      address = sframe_read_value (abfd, contents, r_offset, 4);
+	      if (pltn_reloc_by_hand)
+		address += sframe_read_value (abfd, contents,
+					      pltn_r_offset, 4);
+	      address += (sec->output_offset + r_offset);
+
+	      /* FIXME For testing only. Cleanup later.  */
+	      // address += (sec->output_section->vma);
+
+	      func_start_address = address;
+	    }
+
+	  /* Update the encoder context with updated content.  */
+	  int err = sframe_encoder_add_funcdesc (sfe_ctx, func_start_address,
+						 func_size, func_info,
+						 num_fres);
+	  cur_fidx++;
+	  BFD_ASSERT (!err);
+	}
+
+      for (j = 0; j < num_fres; j++)
+	{
+	  sframe_frame_row_entry fre;
+	  if (!sframe_decoder_get_fre (sfd_ctx, i, j, &fre))
+	    {
+	      int err = sframe_encoder_add_fre (sfe_ctx,
+						cur_fidx-1+num_enc_fidx,
+						&fre);
+	      BFD_ASSERT (!err);
+	    }
+	}
+    }
+  /* Free the SFrame decoder context.  */
+  sframe_decoder_free (&sfd_ctx);
+
+  return true;
+}
+
+/* Write out the .sframe section.  This must be called after
+   _bfd_elf_merge_section_sframe has been called on all input
+   .sframe sections.  */
+
+bool
+_bfd_elf_write_section_sframe (bfd *abfd, struct bfd_link_info *info)
+{
+  bool retval = true;
+
+  struct elf_link_hash_table *htab;
+  struct sframe_enc_info *sfe_info;
+  sframe_encoder_ctx *sfe_ctx;
+  asection *sec;
+  void *contents;
+  size_t sec_size;
+  int err = 0;
+
+  htab = elf_hash_table (info);
+  sfe_info = &htab->sfe_info;
+  sec = sfe_info->sframe_section;
+  sfe_ctx = sfe_info->sfe_ctx;
+
+  if (sec == NULL)
+    return true;
+
+  contents = sframe_write_encoder (sfe_ctx, &sec_size, &err);
+  sec->size = (bfd_size_type) sec_size;
+
+  if (!bfd_set_section_contents (abfd, sec->output_section, contents,
+				 (file_ptr) sec->output_offset,
+				 sec->size))
+    retval = false;
+  else if (!bfd_link_relocatable (info))
+    {
+      Elf_Internal_Shdr *hdr = &elf_section_data (sec)->this_hdr;
+      hdr->sh_size = sec->size;
+    }
+  /* For relocatable links, do not update the section size as the section
+     contents have not been relocated.  */
+
+  sframe_encoder_free (&sfe_ctx);
+
+  return retval;
+}
diff --git a/bfd/elf.c b/bfd/elf.c
index d496c1b2983..d6c1fc2488e 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1671,6 +1671,7 @@ get_segment_type (unsigned int p_type)
     case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
     case PT_GNU_STACK: pt = "STACK"; break;
     case PT_GNU_RELRO: pt = "RELRO"; break;
+    case PT_GNU_SFRAME: pt = "SFRAME"; break;
     default: pt = NULL; break;
     }
   return pt;
@@ -3079,6 +3080,10 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index)
     case PT_GNU_RELRO:
       return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "relro");
 
+    case PT_GNU_SFRAME:
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index,
+					      "sframe");
+
     default:
       /* Check for any processor-specific program segment types.  */
       bed = get_elf_backend_data (abfd);
@@ -4448,6 +4453,12 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
       ++segs;
     }
 
+  if (elf_sframe (abfd))
+    {
+      /* We need a PT_GNU_SFRAME segment.  */
+      ++segs;
+    }
+
   s = bfd_get_section_by_name (abfd,
 			       NOTE_GNU_PROPERTY_SECTION_NAME);
   if (s != NULL && s->size != 0)
@@ -4713,6 +4724,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd,
       asection *first_tls = NULL;
       asection *first_mbind = NULL;
       asection *dynsec, *eh_frame_hdr;
+      asection *sframe;
       size_t amt;
       bfd_vma addr_mask, wrap_to = 0;  /* Bytes.  */
       bfd_size_type phdr_size;  /* Octets/bytes.  */
@@ -5208,6 +5220,26 @@ _bfd_elf_map_sections_to_segments (bfd *abfd,
 	  pm = &m->next;
 	}
 
+      /* If there is a .sframe section, throw in a PT_GNU_SFRAME
+	 segment.  */
+      sframe = elf_sframe (abfd);
+      if (sframe != NULL
+	  && (sframe->output_section->flags & SEC_LOAD) != 0
+	  && sframe->size != 0)
+	{
+	  amt = sizeof (struct elf_segment_map);
+	  m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+	  if (m == NULL)
+	    goto error_return;
+	  m->next = NULL;
+	  m->p_type = PT_GNU_SFRAME;
+	  m->count = 1;
+	  m->sections[0] = sframe->output_section;
+
+	  *pm = m;
+	  pm = &m->next;
+	}
+
       if (elf_stack_flags (abfd))
 	{
 	  amt = sizeof (struct elf_segment_map);
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index f3b54400013..14d88ad0afa 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -22,6 +22,7 @@
 #include "elfxx-x86.h"
 #include "dwarf2.h"
 #include "libiberty.h"
+#include "sframe.h"
 
 #include "opcode/i386.h"
 
@@ -818,6 +819,87 @@ static const bfd_byte elf_x86_64_eh_frame_non_lazy_plt[] =
   DW_CFA_nop, DW_CFA_nop, DW_CFA_nop
 };
 
+static const sframe_frame_row_entry elf_x86_64_sframe_null_fre =
+{
+  0,
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .sframe FRE covering the .plt section entry.  */
+static const sframe_frame_row_entry elf_x86_64_sframe_plt0_fre1 =
+{
+  0, /* SFrame FRE start address.  */
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .sframe FRE covering the .plt section entry.  */
+static const sframe_frame_row_entry elf_x86_64_sframe_plt0_fre2 =
+{
+  6, /* SFrame FRE start address.  */
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .sframe FRE covering the .plt section entry.  */
+static const sframe_frame_row_entry elf_x86_64_sframe_pltn_fre1 =
+{
+  0, /* SFrame FRE start address.  */
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .sframe FRE covering the .plt section entry.  */
+static const sframe_frame_row_entry elf_x86_64_sframe_pltn_fre2 =
+{
+  11, /* SFrame FRE start address.  */
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* .sframe FRE covering the second .plt section entry.  */
+static const sframe_frame_row_entry elf_x86_64_sframe_sec_pltn_fre1 =
+{
+  0, /* SFrame FRE start address.  */
+  SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_1B), /* FRE info.  */
+  {8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* 12 bytes.  */
+};
+
+/* SFrame helper object for non-lazy PLT.  Also used for IBT enabled PLT.  */
+static const struct elf_x86_sframe_plt elf_x86_64_sframe_non_lazy_plt =
+{
+  LAZY_PLT_ENTRY_SIZE,
+  2, /* Number of FREs for PLT0.  */
+  /* Array of SFrame FREs for plt0.  */
+  { &elf_x86_64_sframe_plt0_fre1, &elf_x86_64_sframe_plt0_fre2 },
+  LAZY_PLT_ENTRY_SIZE,
+  1, /* Number of FREs for PLTn.  */
+  /* Array of SFrame FREs for plt.  */
+  { &elf_x86_64_sframe_sec_pltn_fre1, &elf_x86_64_sframe_null_fre },
+  0,
+  0, /* There is no second PLT necessary.  */
+  { &elf_x86_64_sframe_null_fre }
+};
+
+/* SFrame helper object for lazy PLT.  Also used for IBT enabled PLT.  */
+static const struct elf_x86_sframe_plt elf_x86_64_sframe_plt =
+{
+  LAZY_PLT_ENTRY_SIZE,
+  2, /* Number of FREs for PLT0.  */
+  /* Array of SFrame FREs for plt0.  */
+  { &elf_x86_64_sframe_plt0_fre1, &elf_x86_64_sframe_plt0_fre2 },
+  LAZY_PLT_ENTRY_SIZE,
+  2, /* Number of FREs for PLTn.  */
+  /* Array of SFrame FREs for plt.  */
+  { &elf_x86_64_sframe_pltn_fre1, &elf_x86_64_sframe_pltn_fre2 },
+  NON_LAZY_PLT_ENTRY_SIZE,
+  1, /* Number of FREs for PLTn for second PLT.  */
+  /* FREs for second plt ( unwind info for .plt.got is
+     identical).  Used when IBT or non-lazy PLT is in effect.  */
+  { &elf_x86_64_sframe_sec_pltn_fre1 }
+};
+
 /* These are the standard parameters.  */
 static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_plt =
   {
@@ -971,7 +1053,6 @@ static const struct elf_x86_non_lazy_plt_layout elf_x32_non_lazy_ibt_plt =
     sizeof (elf_x86_64_eh_frame_non_lazy_plt) /* eh_frame_plt_size */
   };
 
-
 static bool
 elf64_x86_64_elf_object_p (bfd *abfd)
 {
@@ -5228,6 +5309,20 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info)
       init_table.non_lazy_ibt_plt = &elf_x32_non_lazy_ibt_plt;
     }
 
+  if (ABI_64_P (info->output_bfd))
+    {
+      init_table.sframe_lazy_plt = &elf_x86_64_sframe_plt;
+      init_table.sframe_non_lazy_plt = &elf_x86_64_sframe_non_lazy_plt;
+      init_table.sframe_lazy_ibt_plt = &elf_x86_64_sframe_plt;
+      init_table.sframe_non_lazy_ibt_plt = &elf_x86_64_sframe_non_lazy_plt;
+    }
+  else
+    {
+      /* SFrame is not supported for non AMD64.  */
+      init_table.sframe_lazy_plt = NULL;
+      init_table.sframe_non_lazy_plt = NULL;
+    }
+
   if (ABI_64_P (info->output_bfd))
     {
       init_table.r_info = elf64_r_info;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 89dcf26108c..4ee8c9e5b17 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -10899,6 +10899,7 @@ elf_section_ignore_discarded_relocs (asection *sec)
     case SEC_INFO_TYPE_STABS:
     case SEC_INFO_TYPE_EH_FRAME:
     case SEC_INFO_TYPE_EH_FRAME_ENTRY:
+    case SEC_INFO_TYPE_SFRAME:
       return true;
     default:
       break;
@@ -10930,6 +10931,9 @@ _bfd_elf_default_action_discarded (asection *sec)
   if (strcmp (".eh_frame", sec->name) == 0)
     return 0;
 
+  if (strcmp (".sframe", sec->name) == 0)
+    return 0;
+
   if (strcmp (".gcc_except_table", sec->name) == 0)
     return 0;
 
@@ -11863,6 +11867,16 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 	      return false;
 	  }
 	  break;
+	case SEC_INFO_TYPE_SFRAME:
+	    {
+	      /* Merge .sframe sections into the ctf frame encoder
+		 context of the output_bfd's section.  The final .sframe
+		 output section will be written out later.  */
+	      if (!_bfd_elf_merge_section_sframe (output_bfd, flinfo->info,
+						  o, contents))
+		return false;
+	    }
+	    break;
 	default:
 	  {
 	    if (! (o->flags & SEC_EXCLUDE))
@@ -13446,6 +13460,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info))
     goto error_return;
 
+  if (! _bfd_elf_write_section_sframe (abfd, info))
+    goto error_return;
+
   if (info->callbacks->emit_ctf)
       info->callbacks->emit_ctf ();
 
@@ -14901,6 +14918,41 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
 				_bfd_elf_adjust_eh_frame_global_symbol, NULL);
     }
 
+  o = bfd_get_section_by_name (output_bfd, ".sframe");
+  if (o != NULL)
+    {
+      asection *i;
+
+      for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+	{
+	  if (i->size == 0)
+	    continue;
+
+	  abfd = i->owner;
+	  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+	    continue;
+
+	  if (!init_reloc_cookie_for_section (&cookie, info, i))
+	    return -1;
+
+	  _bfd_elf_parse_sframe (abfd, info, i, &cookie);
+
+	  if (_bfd_elf_discard_section_sframe (i,
+					       bfd_elf_reloc_symbol_deleted_p,
+					       &cookie))
+	    {
+	      if (i->size != i->rawsize)
+		changed = 1;
+	    }
+
+	  fini_reloc_cookie_for_section (&cookie, i);
+	}
+      /* Update the reference to the output .sframe section.  Used to
+	 determine later if PT_GNU_SFRAME segment is to be generated.  */
+      if (!_bfd_elf_set_section_sframe (output_bfd, info))
+	return -1;
+    }
+
   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
     {
       const struct elf_backend_data *bed;
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 7fb972752b3..54dc95a0335 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -1777,6 +1777,189 @@ elf_x86_relative_reloc_compare (const void *pa, const void *pb)
   return 0;
 }
 
+enum dynobj_sframe_plt_type
+{
+  SFRAME_PLT = 1,
+  SFRAME_PLT_SEC = 2
+};
+
+/* Create SFrame unwind info for the plt entries in the .plt section
+   of type PLT_SEC_TYPE.  */
+
+static bool
+_bfd_x86_elf_create_sframe_plt (bfd *output_bfd,
+				struct bfd_link_info *info,
+				unsigned int plt_sec_type)
+{
+  struct elf_x86_link_hash_table *htab;
+  const struct elf_backend_data *bed;
+
+  bool plt0_generated_p;
+  unsigned int plt0_entry_size;
+  unsigned char func_info;
+  unsigned int fre_type;
+  /* The dynamic plt section for which .sframe unwind information is being
+     created.  */
+  asection *dpltsec;
+
+  int err = 0;
+
+  sframe_encoder_ctx **ectx = NULL;
+  unsigned plt_entry_size = 0;
+  unsigned int num_pltn_fres = 0;
+  unsigned int num_pltn_entries = 0;
+
+  bed = get_elf_backend_data (output_bfd);
+  htab = elf_x86_hash_table (info, bed->target_id);
+  /* Whether SFrame unwind info for plt0 is to be generated.  */
+  plt0_generated_p = htab->plt.has_plt0;
+  plt0_entry_size
+    = (plt0_generated_p) ? htab->sframe_plt->plt0_entry_size : 0;
+
+  switch (plt_sec_type)
+    {
+    case SFRAME_PLT:
+	{
+	  ectx = &htab->plt_cfe_ctx;
+	  dpltsec = htab->elf.splt;
+
+	  plt_entry_size = htab->plt.plt_entry_size;
+	  num_pltn_fres = htab->sframe_plt->pltn_num_fres;
+	  num_pltn_entries
+	    = (htab->elf.splt->size - plt0_entry_size) / plt_entry_size;
+
+	  break;
+	}
+    case SFRAME_PLT_SEC:
+	{
+	  ectx = &htab->plt_second_cfe_ctx;
+	  /* FIXME - this or htab->plt_second_sframe ?  */
+	  dpltsec = htab->plt_second_eh_frame;
+
+	  plt_entry_size = htab->sframe_plt->sec_pltn_entry_size;
+	  num_pltn_fres = htab->sframe_plt->sec_pltn_num_fres;
+	  num_pltn_entries
+		= htab->plt_second_eh_frame->size / plt_entry_size;
+	  break;
+	}
+    default:
+      /* No other value is possible.  */
+      return false;
+      break;
+    }
+
+  *ectx = sframe_encode (SFRAME_VERSION_1,
+			 0,
+			 SFRAME_ABI_AMD64_ENDIAN_LITTLE,
+			 &err);
+
+  /* FRE type is dependent on the size of the function.  */
+  fre_type = sframe_calc_fre_type (dpltsec->size);
+  func_info = sframe_fde_func_info (fre_type,
+				    SFRAME_FDE_TYPE_PCINC);
+
+  /* Add SFrame FDE and the associated FREs for plt0 if plt0 has been
+     generated.  */
+  if (plt0_generated_p)
+    {
+      /* Add SFrame FDE for plt0, the function start address is updated later
+	 at _bfd_elf_merge_section_sframe time.  */
+      sframe_encoder_add_funcdesc (*ectx,
+				      0, /* func start addr.  */
+				      plt0_entry_size,
+				      func_info,
+				      0 /* Num FREs.  */);
+      sframe_frame_row_entry plt0_fre;
+      unsigned int num_plt0_fres = htab->sframe_plt->plt0_num_fres;
+      for (unsigned int j = 0; j < num_plt0_fres; j++)
+	{
+	  plt0_fre = *(htab->sframe_plt->plt0_fres[j]);
+	  sframe_encoder_add_fre (*ectx, 0, &plt0_fre);
+	}
+    }
+
+
+  if (num_pltn_entries)
+    {
+      /* pltn entries use an SFrame FDE of type
+	 SFRAME_FDE_TYPE_PCMASK to exploit the repetitive
+	 pattern of the instructions in these entries.  Using this SFrame FDE
+	 type helps in keeping the unwind information for pltn entries
+	 compact.  */
+      func_info	= sframe_fde_func_info (fre_type, SFRAME_FDE_TYPE_PCMASK);
+      /* Add the SFrame FDE for all PCs starting at the first pltn entry (hence,
+	 function start address = plt0_entry_size.  As usual, this will be
+	 updated later at _bfd_elf_merge_section_sframe, by when the
+	 sections are relocated.  */
+      sframe_encoder_add_funcdesc (*ectx,
+				   plt0_entry_size, /* func start addr.  */
+				   dpltsec->size - plt0_entry_size,
+				   func_info,
+				   0 /* Num FREs.  */);
+
+      sframe_frame_row_entry pltn_fre;
+      /* Now add the FREs for pltn.  Simply adding the two FREs suffices due
+	 to the usage of SFRAME_FDE_TYPE_PCMASK above.  */
+      for (unsigned int j = 0; j < num_pltn_fres; j++)
+	{
+	  pltn_fre = *(htab->sframe_plt->pltn_fres[j]);
+	  sframe_encoder_add_fre (*ectx, 1, &pltn_fre);
+	}
+    }
+
+  return true;
+}
+
+/* Put contents of the .sframe section corresponding to the specified
+   PLT_SEC_TYPE.  */
+
+static bool
+_bfd_x86_elf_write_sframe_plt (bfd *output_bfd,
+			       struct bfd_link_info *info,
+			       unsigned int plt_sec_type)
+{
+  struct elf_x86_link_hash_table *htab;
+  const struct elf_backend_data *bed;
+  sframe_encoder_ctx *ectx;
+  size_t sec_size;
+  asection *sec;
+  bfd *dynobj;
+
+  int err = 0;
+
+  bed = get_elf_backend_data (output_bfd);
+  htab = elf_x86_hash_table (info, bed->target_id);
+  dynobj = htab->elf.dynobj;
+
+  switch (plt_sec_type)
+    {
+    case SFRAME_PLT:
+      ectx = htab->plt_cfe_ctx;
+      sec = htab->plt_sframe;
+      break;
+    case SFRAME_PLT_SEC:
+      ectx = htab->plt_second_cfe_ctx;
+      sec = htab->plt_second_sframe;
+      break;
+    default:
+      /* No other value is possible.  */
+      return false;
+      break;
+    }
+
+  BFD_ASSERT (ectx);
+
+  void *contents = sframe_write_encoder (ectx, &sec_size, &err);
+
+  sec->size = (bfd_size_type) sec_size;
+  sec->contents = (unsigned char *) bfd_zalloc (dynobj, sec->size);
+  memcpy (sec->contents, contents, sec_size);
+
+  sframe_encoder_free (&ectx);
+
+  return true;
+}
+
 bool
 _bfd_elf_x86_size_relative_relocs (struct bfd_link_info *info,
 				   bool *need_layout)
@@ -2267,6 +2450,42 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
 	  = htab->non_lazy_plt->eh_frame_plt_size;
     }
 
+  /* No need to size the .sframe section explicitly because the write-out
+     mechanism is different.  Simply prep up the FDE/FRE for the
+     .plt section.  */
+  if (_bfd_elf_sframe_present (info))
+    {
+      if (htab->plt_sframe != NULL
+	  && htab->elf.splt != NULL
+	  && htab->elf.splt->size != 0
+	  && !bfd_is_abs_section (htab->elf.splt->output_section))
+	{
+	  _bfd_x86_elf_create_sframe_plt (output_bfd, info, SFRAME_PLT);
+	  /* FIXME - Dirty Hack.  Set the size to something non-zero for now,
+	     so that the section does not get stripped out below.  The precise
+	     size of this section is known only when the contents are
+	     serialized in _bfd_x86_elf_write_sframe_plt.  */
+	  htab->plt_sframe->size = sizeof (sframe_header) + 1;
+	}
+
+      /* FIXME - generate for .got.plt ?  */
+
+      /* Unwind info for the second PLT.  */
+      if (htab->plt_second_sframe != NULL
+	  && htab->plt_second != NULL
+	  && htab->plt_second->size != 0
+	  && !bfd_is_abs_section (htab->plt_second->output_section))
+	{
+	  _bfd_x86_elf_create_sframe_plt (output_bfd, info,
+					     SFRAME_PLT_SEC);
+	  /* FIXME - Dirty Hack.  Set the size to something non-zero for now,
+	     so that the section does not get stripped out below.  The precise
+	     size of this section is known only when the contents are
+	     serialized in _bfd_x86_elf_write_sframe_plt.  */
+	  htab->plt_second_sframe->size = sizeof (sframe_header) + 1;
+	}
+    }
+
   /* We now have determined the sizes of the various dynamic sections.
      Allocate memory for them.  */
   relocs = false;
@@ -2302,6 +2521,8 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
 	       || s == htab->plt_eh_frame
 	       || s == htab->plt_got_eh_frame
 	       || s == htab->plt_second_eh_frame
+	       || s == htab->plt_sframe
+	       || s == htab->plt_second_sframe
 	       || s == htab->elf.sdynbss
 	       || s == htab->elf.sdynrelro)
 	{
@@ -2344,6 +2565,11 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
       if ((s->flags & SEC_HAS_CONTENTS) == 0)
 	continue;
 
+      /* Skip allocating contents for .sframe section as it is written
+	 out differently.  See below.  */
+      if ((s == htab->plt_sframe) || (s == htab->plt_second_sframe))
+	continue;
+
       /* NB: Initially, the iplt section has minimal alignment to
 	 avoid moving dot of the following section backwards when
 	 it is empty.  Update its section alignment now since it
@@ -2393,6 +2619,21 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
 		   + PLT_FDE_LEN_OFFSET));
     }
 
+  if (_bfd_elf_sframe_present (info))
+    {
+      if (htab->plt_sframe != NULL
+	  && htab->elf.splt != NULL
+	  && htab->elf.splt->size != 0
+	  && htab->plt_sframe->contents == NULL)
+	_bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT);
+
+      if (htab->plt_second_sframe != NULL
+	  && htab->elf.splt != NULL
+	  && htab->elf.splt->size != 0
+	  && htab->plt_second_sframe->contents == NULL)
+	_bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT_SEC);
+    }
+
   return _bfd_elf_maybe_vxworks_add_dynamic_tags (output_bfd, info,
 						  relocs);
 }
@@ -2607,6 +2848,78 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd,
 	}
     }
 
+  /* Make any adjustment if necessary and merge .sframe section to
+     create the final .sframe section for output_bfd.  */
+  if (htab->plt_sframe != NULL
+      && htab->plt_sframe->contents != NULL)
+    {
+      if (htab->elf.splt != NULL
+	  && htab->elf.splt->size != 0
+	  && (htab->elf.splt->flags & SEC_EXCLUDE) == 0
+	  && htab->elf.splt->output_section != NULL
+	  && htab->plt_sframe->output_section != NULL)
+	{
+	  bfd_vma plt_start = htab->elf.splt->output_section->vma;
+	  bfd_vma sframe_start = htab->plt_sframe->output_section->vma
+				   + htab->plt_sframe->output_offset
+				   + PLT_SFRAME_FDE_START_OFFSET;
+#if 0 /* FIXME Testing only. Remove before review.  */
+	  bfd_vma test_value = (plt_start - sframe_start)
+	    + htab->plt_sframe->output_section->vma
+	    + htab->plt_sframe->output_offset
+	    + PLT_SFRAME_FDE_START_OFFSET;
+	  bfd_put_signed_32 (dynobj, test_value,
+#endif
+	  bfd_put_signed_32 (dynobj, plt_start - sframe_start,
+			     htab->plt_sframe->contents
+			     + PLT_SFRAME_FDE_START_OFFSET);
+	}
+      if (htab->plt_sframe->sec_info_type == SEC_INFO_TYPE_SFRAME)
+	{
+	  /* FIXME - contents need to be relocated for this call.  Need to
+	     reflect the relocated contents manually ?  */
+	  if (! _bfd_elf_merge_section_sframe (output_bfd, info,
+					       htab->plt_sframe,
+					       htab->plt_sframe->contents))
+	    return NULL;
+	}
+    }
+
+  if (htab->plt_second_sframe != NULL
+      && htab->plt_second_sframe->contents != NULL)
+    {
+      if (htab->plt_second != NULL
+	  && htab->plt_second->size != 0
+	  && (htab->plt_second->flags & SEC_EXCLUDE) == 0
+	  && htab->plt_second->output_section != NULL
+	  && htab->plt_second_sframe->output_section != NULL)
+	{
+	  bfd_vma plt_start = htab->plt_second->output_section->vma;
+	  bfd_vma sframe_start
+	    = (htab->plt_second_sframe->output_section->vma
+	       + htab->plt_second_sframe->output_offset
+	       + PLT_SFRAME_FDE_START_OFFSET);
+#if 0 /* FIXME Testing only. Remove before review.  */
+	  bfd_vma test_value = (plt_start - sframe_start)
+	    + htab->plt_second_sframe->output_section->vma
+	    + htab->plt_second_sframe->output_offset
+	    + PLT_SFRAME_FDE_START_OFFSET;
+	  bfd_put_signed_32 (dynobj, test_value,
+#endif
+	  bfd_put_signed_32 (dynobj, plt_start - sframe_start,
+			     htab->plt_second_sframe->contents
+			     + PLT_SFRAME_FDE_START_OFFSET);
+	}
+      if (htab->plt_second_sframe->sec_info_type == SEC_INFO_TYPE_SFRAME)
+	{
+	  /* FIXME - contents need to be relocated for this call.  Need to
+	     reflect the relocated contents manually ?  */
+	  if (! _bfd_elf_merge_section_sframe (output_bfd, info,
+					       htab->plt_second_sframe,
+					       htab->plt_second_sframe->contents))
+	    return NULL;
+	}
+    }
   if (htab->elf.sgot && htab->elf.sgot->size > 0)
     elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize
       = htab->got_entry_size;
@@ -3949,12 +4262,36 @@ _bfd_x86_elf_link_setup_gnu_properties
 
   pltsec = htab->elf.splt;
 
-  /* If the non-lazy PLT is available, use it for all PLT entries if
-     there are no PLT0 or no .plt section.  */
   if (htab->non_lazy_plt != NULL
       && (!htab->plt.has_plt0 || pltsec == NULL))
+    lazy_plt = false;
+  else
+    lazy_plt = true;
+
+  if (normal_target)
+    {
+      if (use_ibt_plt)
+	{
+	  if (lazy_plt)
+	    htab->sframe_plt = init_table->sframe_lazy_ibt_plt;
+	  else
+	    htab->sframe_plt = init_table->sframe_non_lazy_ibt_plt;
+	}
+      else
+	{
+	  if (lazy_plt)
+	    htab->sframe_plt = init_table->sframe_lazy_plt;
+	  else
+	    htab->sframe_plt = init_table->sframe_non_lazy_plt;
+	}
+    }
+  else
+    htab->sframe_plt = NULL;
+
+  /* If the non-lazy PLT is available, use it for all PLT entries if
+     there are no PLT0 or no .plt section.  */
+  if (!lazy_plt)
     {
-      lazy_plt = false;
       if (bfd_link_pic (info))
 	htab->plt.plt_entry = htab->non_lazy_plt->pic_plt_entry;
       else
@@ -3969,7 +4306,6 @@ _bfd_x86_elf_link_setup_gnu_properties
     }
   else
     {
-      lazy_plt = true;
       if (bfd_link_pic (info))
 	{
 	  htab->plt.plt0_entry = htab->lazy_plt->pic_plt0_entry;
@@ -4145,6 +4481,39 @@ _bfd_x86_elf_link_setup_gnu_properties
 	      htab->plt_second_eh_frame = sec;
 	    }
 	}
+
+      /* .sframe sections are emitted for AMD64 ABI only.  */
+      if (ABI_64_P (info->output_bfd) && !info->no_ld_generated_unwind_info)
+	{
+	  flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+			    | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+			    | SEC_LINKER_CREATED);
+
+	  sec = bfd_make_section_anyway_with_flags (dynobj,
+						    ".sframe",
+						    flags);
+	  if (sec == NULL)
+	    info->callbacks->einfo (_("%F%P: failed to create PLT .sframe section\n"));
+
+	  // FIXME check this
+	  // if (!bfd_set_section_alignment (sec, class_align))
+	  //  goto error_alignment;
+
+	  htab->plt_sframe = sec;
+
+	  /* Second PLT is generated for Intel IBT / MPX Support + lazy plt.  */
+	  if (htab->plt_second != NULL)
+	    {
+	      sec = bfd_make_section_anyway_with_flags (dynobj,
+							".sframe",
+							flags);
+	      if (sec == NULL)
+		info->callbacks->einfo (_("%F%P: failed to create second PLT .sframe section\n"));
+
+	      htab->plt_second_sframe = sec;
+	    }
+	  /* FIXME - add later for plt_got. */
+	}
     }
 
   /* The .iplt section is used for IFUNC symbols in static
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 7d23893938c..f24ed72596b 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -30,6 +30,7 @@
 #include "elf-linker-x86.h"
 #include "elf/i386.h"
 #include "elf/x86-64.h"
+#include "sframe-api.h"
 
 #define X86_64_PCREL_TYPE_P(TYPE) \
   ((TYPE) == R_X86_64_PC8 \
@@ -105,6 +106,8 @@
    || (TYPE) == R_X86_64_PC32_BND \
    || (TYPE) == R_X86_64_PC64)
 
+#define PLT_SFRAME_FDE_START_OFFSET	sizeof (sframe_header)
+
 #define ABI_64_P(abfd) \
   (get_elf_backend_data (abfd)->s->elfclass == ELFCLASS64)
 
@@ -388,6 +391,24 @@ struct elf_x86_link_hash_entry
   bfd_vma tlsdesc_got;
 };
 
+#define SFRAME_PLT0_MAX_NUM_FRES 2
+#define SFRAME_PLTN_MAX_NUM_FRES 2
+
+struct elf_x86_sframe_plt
+{
+  unsigned int plt0_entry_size;
+  unsigned int plt0_num_fres;
+  const sframe_frame_row_entry *plt0_fres[SFRAME_PLT0_MAX_NUM_FRES];
+
+  unsigned int pltn_entry_size;
+  unsigned int pltn_num_fres;
+  const sframe_frame_row_entry *pltn_fres[SFRAME_PLTN_MAX_NUM_FRES];
+
+  unsigned int sec_pltn_entry_size;
+  unsigned int sec_pltn_num_fres;
+  const sframe_frame_row_entry *sec_pltn_fres[SFRAME_PLTN_MAX_NUM_FRES];
+};
+
 struct elf_x86_lazy_plt_layout
 {
   /* The first entry in a lazy procedure linkage table looks like this.  */
@@ -584,6 +605,11 @@ struct elf_x86_link_hash_table
   asection *plt_got;
   asection *plt_got_eh_frame;
 
+  sframe_encoder_ctx *plt_cfe_ctx;
+  asection *plt_sframe;
+  sframe_encoder_ctx *plt_second_cfe_ctx;
+  asection *plt_second_sframe;
+
   /* Parameters describing PLT generation, lazy or non-lazy.  */
   struct elf_x86_plt_layout plt;
 
@@ -593,6 +619,10 @@ struct elf_x86_link_hash_table
   /* Parameters describing non-lazy PLT generation.  */
   const struct elf_x86_non_lazy_plt_layout *non_lazy_plt;
 
+  /* The .sframe helper object for .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_sframe_plt *sframe_plt;
+
   union
   {
     bfd_signed_vma refcount;
@@ -682,6 +712,22 @@ struct elf_x86_init_table
   /* The non-lazy PLT layout for IBT.  */
   const struct elf_x86_non_lazy_plt_layout *non_lazy_ibt_plt;
 
+  /* The .sframe helper object for lazy .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_sframe_plt *sframe_lazy_plt;
+
+  /* The .sframe helper object for non-lazy .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_sframe_plt *sframe_non_lazy_plt;
+
+  /* The .sframe helper object for lazy IBT .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_sframe_plt *sframe_lazy_ibt_plt;
+
+  /* The .sframe helper object for non-lazy IBT .plt section.
+     This is used for x86-64 only.  */
+  const struct elf_x86_sframe_plt *sframe_non_lazy_ibt_plt;
+
   bfd_byte plt0_pad_byte;
 
   bfd_vma (*r_info) (bfd_vma, bfd_vma);
diff --git a/bfd/section.c b/bfd/section.c
index 614570e976e..ba8904d228e 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -409,6 +409,7 @@ CODE_FRAGMENT
 .#define SEC_INFO_TYPE_JUST_SYMS 4
 .#define SEC_INFO_TYPE_TARGET    5
 .#define SEC_INFO_TYPE_EH_FRAME_ENTRY 6
+.#define SEC_INFO_TYPE_SFRAME  7
 .
 .  {* Nonzero if this section uses RELA relocations, rather than REL.  *}
 .  unsigned int use_rela_p:1;
diff --git a/binutils/readelf.c b/binutils/readelf.c
index b1dbcad06f5..241c44ecfa1 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -4601,6 +4601,7 @@ get_segment_type (Filedata * filedata, unsigned long p_type)
     case PT_GNU_STACK:	return "GNU_STACK";
     case PT_GNU_RELRO:  return "GNU_RELRO";
     case PT_GNU_PROPERTY: return "GNU_PROPERTY";
+    case PT_GNU_SFRAME: return "GNU_SFRAME";
 
     case PT_OPENBSD_RANDOMIZE: return "OPENBSD_RANDOMIZE";
     case PT_OPENBSD_WXNEEDED: return "OPENBSD_WXNEEDED";
diff --git a/include/elf/common.h b/include/elf/common.h
index 287526d74ed..16587f6fb06 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -489,6 +489,7 @@
 #define PT_GNU_STACK	(PT_LOOS + 0x474e551) /* Stack flags */
 #define PT_GNU_RELRO	(PT_LOOS + 0x474e552) /* Read-only after relocation */
 #define PT_GNU_PROPERTY	(PT_LOOS + 0x474e553) /* GNU property */
+#define PT_GNU_SFRAME	(PT_LOOS + 0x474e554) /* SFrame unwind information */
 
 /* OpenBSD segment types.  */
 #define PT_OPENBSD_RANDOMIZE (PT_LOOS + 0x5a3dbe6)  /* Fill with random data.  */
diff --git a/include/elf/internal.h b/include/elf/internal.h
index 8affb3d9b2e..de9f67809b3 100644
--- a/include/elf/internal.h
+++ b/include/elf/internal.h
@@ -339,6 +339,7 @@ struct elf_segment_map
 	    || (segment)->p_type == PT_GNU_EH_FRAME			\
 	    || (segment)->p_type == PT_GNU_STACK			\
 	    || (segment)->p_type == PT_GNU_RELRO			\
+	    || (segment)->p_type == PT_GNU_SFRAME			\
 	    || ((segment)->p_type >= PT_GNU_MBIND_LO			\
 		&& (segment)->p_type <= PT_GNU_MBIND_HI)))		\
    /* Any section besides one of type SHT_NOBITS must have file		\
diff --git a/include/sframe-api.h b/include/sframe-api.h
index 0c77cd4284a..351cf1f7398 100644
--- a/include/sframe-api.h
+++ b/include/sframe-api.h
@@ -171,7 +171,7 @@ sframe_encode (unsigned char ver, unsigned char flags, int abi, int *errp);
 
 /* Free the encoder context.  */
 extern void
-sframe_free_encoder (sframe_encoder_ctx *encoder);
+sframe_encoder_free (sframe_encoder_ctx **encoder);
 
 /* Get the abi/arch info from the SFrame encoder context CTX.  */
 extern unsigned char
diff --git a/ld/Makefile.am b/ld/Makefile.am
index bbe25f3aca2..3be467cb03f 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -968,6 +968,7 @@ EXTRA_ld_new_SOURCES += $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES)
 # This is the real libbfd.a and libctf.a created by libtool.
 TESTBFDLIB = @TESTBFDLIB@
 TESTCTFLIB = @TESTCTFLIB@
+TESTSFRAMELIB = @TESTSFRAMELIB@
 
 check-DEJAGNU: site.exp
 	(cd .libs; test -e ldscripts || test ! -e ld-new || $(LN_S) ../ldscripts .)
@@ -985,6 +986,7 @@ check-DEJAGNU: site.exp
 		CXX_FOR_TARGET="$(CXX_FOR_TARGET)" \
 		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
 		OFILES="$(OFILES)" BFDLIB="$(TESTBFDLIB)" CTFLIB="$(TESTCTFLIB) $(ZLIB)" \
+		SFRAMELIB="$(TESTSFRAMELIB)" \
 		LIBIBERTY="$(LIBIBERTY) $(LIBINTL)" LIBS="$(LIBS)" \
 		DO_COMPARE="`echo '$(do_compare)' | sed -e 's,\\$$,,g'`" \
 		$(RUNTESTFLAGS); \
diff --git a/ld/Makefile.in b/ld/Makefile.in
index 400eed2717e..e7fb0dc2504 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -470,6 +470,7 @@ TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@
 # This is the real libbfd.a and libctf.a created by libtool.
 TESTBFDLIB = @TESTBFDLIB@
 TESTCTFLIB = @TESTCTFLIB@
+TESTSFRAMELIB = @TESTSFRAMELIB@
 USE_NLS = @USE_NLS@
 VERSION = @VERSION@
 WARN_CFLAGS = @WARN_CFLAGS@
@@ -2636,6 +2637,7 @@ check-DEJAGNU: site.exp
 		CXX_FOR_TARGET="$(CXX_FOR_TARGET)" \
 		CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \
 		OFILES="$(OFILES)" BFDLIB="$(TESTBFDLIB)" CTFLIB="$(TESTCTFLIB) $(ZLIB)" \
+		SFRAMELIB="$(TESTSFRAMELIB)" \
 		LIBIBERTY="$(LIBIBERTY) $(LIBINTL)" LIBS="$(LIBS)" \
 		DO_COMPARE="`echo '$(do_compare)' | sed -e 's,\\$$,,g'`" \
 		$(RUNTESTFLAGS); \
diff --git a/ld/configure b/ld/configure
index 9dd3ed5f1e7..79ffcc4ac60 100755
--- a/ld/configure
+++ b/ld/configure
@@ -634,6 +634,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+TESTSFRAMELIB
 TESTCTFLIB
 TESTBFDLIB
 EMULATION_LIBPATH
@@ -11620,7 +11621,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11623 "configure"
+#line 11624 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11726,7 +11727,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11729 "configure"
+#line 11730 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -17468,9 +17469,11 @@ EMULATION_LIBPATH=$all_libpath
 if test x${enable_static} = xno; then
   TESTBFDLIB="-Wl,--rpath,../bfd/.libs ../bfd/.libs/libbfd.so"
   TESTCTFLIB="-Wl,--rpath,../libctf/.libs ../libctf/.libs/libctf.so"
+  TESTSFRAMELIB="-Wl,--rpath,../libsframe/.libs ../libsframe/.libs/libsframe.so"
 else
   TESTBFDLIB="../bfd/.libs/libbfd.a"
   TESTCTFLIB="../libctf/.libs/libctf.a"
+  TESTSFRAMELIB="../libsframe/.libs/libsframe.a"
 fi
 if test "${enable_libctf}" = no; then
     TESTCTFLIB=
@@ -17478,6 +17481,7 @@ fi
 
 
 
+
 target_vendor=${target_vendor=$host_vendor}
 case "$target_vendor" in
   hp) EXTRA_SHLIB_EXTENSION=".sl" ;;
diff --git a/ld/configure.ac b/ld/configure.ac
index f1b2f9897f8..1b92b32874b 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -616,15 +616,18 @@ AC_SUBST(EMULATION_LIBPATH)
 if test x${enable_static} = xno; then
   TESTBFDLIB="-Wl,--rpath,../bfd/.libs ../bfd/.libs/libbfd.so"
   TESTCTFLIB="-Wl,--rpath,../libctf/.libs ../libctf/.libs/libctf.so"
+  TESTSFRAMELIB="-Wl,--rpath,../libsframe/.libs ../libsframe/.libs/libsframe.so"
 else
   TESTBFDLIB="../bfd/.libs/libbfd.a"
   TESTCTFLIB="../libctf/.libs/libctf.a"
+  TESTSFRAMELIB="../libsframe/.libs/libsframe.a"
 fi
 if test "${enable_libctf}" = no; then
     TESTCTFLIB=
 fi
 AC_SUBST(TESTBFDLIB)
 AC_SUBST(TESTCTFLIB)
+AC_SUBST(TESTSFRAMELIB)
 
 target_vendor=${target_vendor=$host_vendor}
 case "$target_vendor" in
diff --git a/ld/ld.texi b/ld/ld.texi
index 9daed2e7e9f..909407551f3 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -2828,7 +2828,9 @@ section and ELF @code{PT_GNU_EH_FRAME} segment header.
 @item --no-ld-generated-unwind-info
 Request creation of @code{.eh_frame} unwind info for linker
 generated code sections like PLT.  This option is on by default
-if linker generated unwind info is supported.
+if linker generated unwind info is supported.  This option also
+controls the generation of @code{.sframe} unwind info for linker
+generated code sections like PLT.
 
 @kindex --enable-new-dtags
 @kindex --disable-new-dtags
diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
index bf2268bb0ad..5cc364b0c2a 100644
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -601,6 +601,7 @@ cat <<EOF
   ${OTHER_READONLY_SECTIONS}
   .eh_frame_hdr ${RELOCATING-0} : { *(.eh_frame_hdr)${RELOCATING+ *(.eh_frame_entry .eh_frame_entry.*)} }
   .eh_frame     ${RELOCATING-0} : ONLY_IF_RO { KEEP (*(.eh_frame))${RELOCATING+ *(.eh_frame.*)} }
+  .sframe       ${RELOCATING-0} : ONLY_IF_RO { *(.sframe)${RELOCATING+ *(.sframe.*)} }
   .gcc_except_table ${RELOCATING-0} : ONLY_IF_RO { *(.gcc_except_table${RELOCATING+ .gcc_except_table.*}) }
   .gnu_extab ${RELOCATING-0} : ONLY_IF_RO { *(.gnu_extab*) }
   /* These sections are generated by the Sun/Oracle C++ compiler.  */
@@ -619,6 +620,7 @@ cat <<EOF
 
   /* Exception handling  */
   .eh_frame     ${RELOCATING-0} : ONLY_IF_RW { KEEP (*(.eh_frame))${RELOCATING+ *(.eh_frame.*)} }
+  .sframe       ${RELOCATING-0} : ONLY_IF_RW { *(.sframe)${RELOCATING+ *(.sframe.*)} }
   .gnu_extab    ${RELOCATING-0} : ONLY_IF_RW { *(.gnu_extab) }
   .gcc_except_table ${RELOCATING-0} : ONLY_IF_RW { *(.gcc_except_table${RELOCATING+ .gcc_except_table.*}) }
   .exception_ranges ${RELOCATING-0} : ONLY_IF_RW { *(.exception_ranges${RELOCATING+*}) }
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 337beadcbfe..9f2eb3cf775 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -457,3 +457,5 @@ run_dump_test "bti-pac-plt-2"
 run_dump_test "bti-warn"
 run_dump_test "weak-tls"
 run_dump_test "undef-tls"
+
+run_dump_test "sframe-simple-1"
diff --git a/ld/testsuite/ld-aarch64/sframe-bar.s b/ld/testsuite/ld-aarch64/sframe-bar.s
new file mode 100644
index 00000000000..8dd50bfaa38
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/sframe-bar.s
@@ -0,0 +1,7 @@
+	.cfi_startproc
+	cmp	w0, 1000
+	bgt	.L4
+	ret
+.L4:
+	b	foo
+	.cfi_endproc
diff --git a/ld/testsuite/ld-aarch64/sframe-foo.s b/ld/testsuite/ld-aarch64/sframe-foo.s
new file mode 100644
index 00000000000..a2780a645d6
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/sframe-foo.s
@@ -0,0 +1,10 @@
+	.cfi_startproc
+	mov	w1, 26215
+	movk	w1, 0x6666, lsl 16
+	smull	x1, w0, w1
+	asr	x1, x1, 34
+	sub	w1, w1, w0, asr 31
+	add	w1, w1, w1, lsl 2
+	sub	w0, w0, w1, lsl 1
+	ret
+	.cfi_endproc
diff --git a/ld/testsuite/ld-aarch64/sframe-simple-1.d b/ld/testsuite/ld-aarch64/sframe-simple-1.d
new file mode 100644
index 00000000000..2ebf2d65961
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/sframe-simple-1.d
@@ -0,0 +1,26 @@
+#as: --gsframe
+#source: sframe-foo.s
+#source: sframe-bar.s
+#objdump: --sframe=.sframe
+#ld: -shared
+#name: Simple link
+
+.*:     file format .*
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: SFRAME_F_FDE_SORTED
+    Num FDEs: 2
+    Num FREs: 2
+
+  Function Index :
+
+#...
+    STARTPC +CFA +FP +RA +
+    0+[0-9a-f]+ +sp\+0 +u +u +
+
+#...
+    STARTPC +CFA +FP +RA +
+    0+[0-9a-f]+ +sp\+0 +u +u +
diff --git a/ld/testsuite/ld-bootstrap/bootstrap.exp b/ld/testsuite/ld-bootstrap/bootstrap.exp
index 99a11090ee7..de82a2bfbff 100644
--- a/ld/testsuite/ld-bootstrap/bootstrap.exp
+++ b/ld/testsuite/ld-bootstrap/bootstrap.exp
@@ -184,7 +184,7 @@ foreach flags $test_flags {
 	setup_xfail "mips*-*-irix5*"
     }
 
-    if ![ld_link $CC tmpdir/ld1 "$CFLAGS $flags tmpdir/ld-partial.o $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+    if ![ld_link $CC tmpdir/ld1 "$CFLAGS $flags tmpdir/ld-partial.o $CTFLIB $BFDLIB $LIBIBERTY $SFRAMELIB $extralibs"] {
 	fail $testname
 	continue
     }
@@ -201,13 +201,13 @@ foreach flags $test_flags {
     }
 
     regsub /tmpdir/ld/ $gcc_B_opt_save /tmpdir/gccld1/ gcc_B_opt
-    if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+    if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $SFRAMELIB $extralibs"] {
 	fail $testname
 	continue
     }
 
     regsub /tmpdir/ld/ $gcc_B_opt_save /tmpdir/gccld2/ gcc_B_opt
-    if ![ld_link $CC tmpdir/ld3 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+    if ![ld_link $CC tmpdir/ld3 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $SFRAMELIB $extralibs"] {
 	fail $testname
 	continue
     }
@@ -220,7 +220,7 @@ foreach flags $test_flags {
 	# generated by different linkers, tmpdir/ld1 and tmpdir/ld2.
 	# So we rebuild tmpdir/ld2 with tmpdir/ld3.
 	regsub /tmpdir/ld/ $gcc_B_opt_save /tmpdir/gccld3/ gcc_B_opt
-	if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $extralibs"] {
+	if ![ld_link $CC tmpdir/ld2 "$CFLAGS $flags $OFILES $CTFLIB $BFDLIB $LIBIBERTY $SFRAMELIB $extralibs"] {
 	    fail $testname
 	    continue
 	}
diff --git a/ld/testsuite/ld-sframe/discard.d b/ld/testsuite/ld-sframe/discard.d
new file mode 100644
index 00000000000..cb0371e34a2
--- /dev/null
+++ b/ld/testsuite/ld-sframe/discard.d
@@ -0,0 +1,10 @@
+#as:
+#source: discard.s
+#ld: -T discard.ld
+#objdump: -hw
+#name: Check that SFrame section can be discarded
+
+#failif
+#...
+  [0-9] .sframe .*
+#...
diff --git a/ld/testsuite/ld-sframe/discard.ld b/ld/testsuite/ld-sframe/discard.ld
new file mode 100644
index 00000000000..5745ccefc3b
--- /dev/null
+++ b/ld/testsuite/ld-sframe/discard.ld
@@ -0,0 +1,9 @@
+ENTRY(_start)
+SECTIONS
+{
+  . = SIZEOF_HEADERS;
+  /* Sections to be discarded */
+  /DISCARD/ : {
+	*(.sframe)
+	}
+}
diff --git a/ld/testsuite/ld-sframe/discard.s b/ld/testsuite/ld-sframe/discard.s
new file mode 100644
index 00000000000..a438b42bffa
--- /dev/null
+++ b/ld/testsuite/ld-sframe/discard.s
@@ -0,0 +1,13 @@
+	.text
+	.cfi_sections .sframe
+	.globl	foo
+	.type	foo, @function
+foo:
+	.cfi_startproc
+	.cfi_def_cfa_offset 16
+	.cfi_def_cfa 7, 8
+	.cfi_endproc
+
+	.globl _start
+_start:
+	.long   foo
diff --git a/ld/testsuite/ld-sframe/sframe-empty.d b/ld/testsuite/ld-sframe/sframe-empty.d
new file mode 100644
index 00000000000..bad08c563d1
--- /dev/null
+++ b/ld/testsuite/ld-sframe/sframe-empty.d
@@ -0,0 +1,10 @@
+#as:
+#source: sframe-empty.s
+#objdump: -hw
+#ld: -shared
+#name: Empty SFrame section
+
+#failif
+#...
+  [0-9] .sframe .*
+#...
diff --git a/ld/testsuite/ld-sframe/sframe-empty.s b/ld/testsuite/ld-sframe/sframe-empty.s
new file mode 100644
index 00000000000..659b3b9d99b
--- /dev/null
+++ b/ld/testsuite/ld-sframe/sframe-empty.s
@@ -0,0 +1,2 @@
+	.cfi_startproc
+	.cfi_endproc
diff --git a/ld/testsuite/ld-sframe/sframe.exp b/ld/testsuite/ld-sframe/sframe.exp
new file mode 100644
index 00000000000..392dfbd44c4
--- /dev/null
+++ b/ld/testsuite/ld-sframe/sframe.exp
@@ -0,0 +1,47 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+if [skip_sframe_tests] {
+    unsupported "no SFrame format support in the assembler, or SFrame disabled"
+    return 0
+}
+
+if ![is_elf_format] {
+    unsupported "SFrame not supported"
+    return 0
+}
+
+if {[info exists env(LC_ALL)]} {
+    set old_lc_all $env(LC_ALL)
+}
+set env(LC_ALL) "C"
+
+set sframe_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
+
+foreach sframe_test $sframe_test_list {
+    verbose [file rootname $sframe_test]
+    run_dump_test [file rootname $sframe_test]
+}
+
+if {[info exists old_lc_all]} {
+    set env(LC_ALL) $old_lc_all
+} else {
+    unset env(LC_ALL)
+}
diff --git a/ld/testsuite/ld-x86-64/sframe-bar.s b/ld/testsuite/ld-x86-64/sframe-bar.s
new file mode 100644
index 00000000000..4d032130f9b
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/sframe-bar.s
@@ -0,0 +1,31 @@
+	.file	"sframe-bar.c"
+	.text
+	.globl	bar
+	.type	bar, @function
+bar:
+.LFB0:
+	.cfi_startproc
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset 6, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register 6
+	subq	$16, %rsp
+	movl	%edi, -4(%rbp)
+	cmpl	$1000, -4(%rbp)
+	jle	.L2
+	movl	-4(%rbp), %eax
+	movl	%eax, %edi
+	call	foo
+	jmp	.L3
+.L2:
+	movl	-4(%rbp), %eax
+.L3:
+	leave
+	.cfi_def_cfa 7, 8
+	ret
+	.cfi_endproc
+.LFE0:
+	.size	bar, .-bar
+	.ident	"GCC: (GNU) 13.0.0 20220519 (experimental)"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/sframe-foo.s b/ld/testsuite/ld-x86-64/sframe-foo.s
new file mode 100644
index 00000000000..a871908b76c
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/sframe-foo.s
@@ -0,0 +1,37 @@
+	.file	"sframe-foo.c"
+	.text
+	.globl	foo
+	.type	foo, @function
+foo:
+.LFB0:
+	.cfi_startproc
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset 6, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register 6
+	movl	%edi, -4(%rbp)
+	movl	-4(%rbp), %ecx
+	movslq	%ecx, %rax
+	imulq	$1717986919, %rax, %rax
+	shrq	$32, %rax
+	movl	%eax, %edx
+	sarl	$2, %edx
+	movl	%ecx, %eax
+	sarl	$31, %eax
+	subl	%eax, %edx
+	movl	%edx, %eax
+	sall	$2, %eax
+	addl	%edx, %eax
+	addl	%eax, %eax
+	subl	%eax, %ecx
+	movl	%ecx, %edx
+	movl	%edx, %eax
+	popq	%rbp
+	.cfi_def_cfa 7, 8
+	ret
+	.cfi_endproc
+.LFE0:
+	.size	foo, .-foo
+	.ident	"GCC: (GNU) 13.0.0 20220519 (experimental)"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/sframe-plt-1.d b/ld/testsuite/ld-x86-64/sframe-plt-1.d
new file mode 100644
index 00000000000..06bb16bd482
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/sframe-plt-1.d
@@ -0,0 +1,29 @@
+#as: --gsframe
+#source: sframe-foo.s
+#source: sframe-bar.s
+#objdump: --sframe=.sframe
+#ld: -shared
+#name: SFrame for plt0 and pltN
+
+.*: +file format .*
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: SFRAME_F_FDE_SORTED
+#...
+
+  Function Index :
+
+    func idx \[0\]: pc = 0x1000, size = 16 bytes
+    STARTPC +CFA +FP +RA +
+    0+1000 +sp\+16 +u +u +
+    0+1006 +sp\+24 +u +u +
+
+    func idx \[1\]: pc = 0x1010, size = 16 bytes
+    STARTPC\[m\] +CFA +FP +RA +
+    0+0000 +sp\+8 +u +u +
+    0+000b +sp\+16 +u +u +
+
+#...
diff --git a/ld/testsuite/ld-x86-64/sframe-simple-1.d b/ld/testsuite/ld-x86-64/sframe-simple-1.d
new file mode 100644
index 00000000000..7274bef160a
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/sframe-simple-1.d
@@ -0,0 +1,35 @@
+#as: --gsframe
+#source: sframe-foo.s
+#source: sframe-bar.s
+#objdump: --sframe=.sframe
+#ld: -shared
+#name: Simple link
+
+.*: +file format .*
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_1
+    Flags: SFRAME_F_FDE_SORTED
+#...
+
+  Function Index :
+
+#...
+
+#...
+
+    func idx \[2\]: pc = 0x1020, size = 53 bytes
+    STARTPC +CFA +FP +RA +
+    0+1020 +sp\+8 +u +u +
+    0+1021 +sp\+16 +c-16 +u +
+    0+1024 +fp\+16 +c-16 +u +
+    0+1054 +sp\+8 +c-16 +u +
+
+    func idx \[3\]: pc = 0x1055, size = 37 bytes
+    STARTPC +CFA +FP +RA +
+    0+1055 +sp\+8 +u +u +
+    0+1056 +sp\+16 +c-16 +u +
+    0+1059 +fp\+16 +c-16 +u +
+    0+1079 +sp\+8 +c-16 +u +
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index e6a834a2a61..2cb53e5f6ab 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -505,6 +505,8 @@ run_dump_test "dt-relr-1a"
 run_dump_test "dt-relr-1a-x32"
 run_dump_test "dt-relr-1b"
 run_dump_test "dt-relr-1b-x32"
+run_dump_test "sframe-simple-1"
+run_dump_test "sframe-plt-1"
 
 if ![istarget "x86_64-*-linux*"] {
     return
diff --git a/ld/testsuite/lib/ld-lib.exp b/ld/testsuite/lib/ld-lib.exp
index ec27388a72e..1241ac0a10a 100644
--- a/ld/testsuite/lib/ld-lib.exp
+++ b/ld/testsuite/lib/ld-lib.exp
@@ -1676,3 +1676,48 @@ proc skip_ctf_tests { } {
 
     return 1
 }
+
+# Check if the assembler supports SFrame.
+
+proc check_as_sframe { } {
+    global check_as_sframe_result
+    global as
+    if [info exists check_as_sframe_result] {
+	return $check_as_sframe_result
+    }
+
+    # SFrame generation needs CFI support
+    if { ![check_as_cfi] } {
+	set check_as_sframe_result 0;
+	return 0
+    }
+
+    set as_file "tmpdir/check_as_sframe.s"
+    set as_fh [open $as_file w 0666]
+    puts $as_fh "# Generated file. DO NOT EDIT"
+    puts $as_fh "\t.cfi_sections \".sframe\""
+    puts $as_fh "\t.cfi_startproc"
+    puts $as_fh "\t.cfi_endproc"
+    close $as_fh
+    remote_download host $as_file
+    verbose -log "Checking SFrame:"
+    set success [ld_assemble $as $as_file "/dev/null"]
+    #remote_file host delete $as_file
+    set check_as_sframe_result $success
+    return $success
+}
+
+proc skip_sframe_tests { } {
+# FIXME TODO
+#    global enable_libsframe
+#
+#    if {$enable_libsframe eq "no"} {
+#	return 1
+#    }
+
+    if [check_as_sframe] {
+	return 0
+    }
+
+    return 1
+}
diff --git a/libsframe/sframe.c b/libsframe/sframe.c
index 13cf5686f30..41b7ef411c8 100644
--- a/libsframe/sframe.c
+++ b/libsframe/sframe.c
@@ -1119,14 +1119,32 @@ sframe_encode (unsigned char ver, unsigned char flags, int abi_arch,
 /* Free the encoder context.  */
 
 void
-sframe_free_encoder (sframe_encoder_ctx *encoder)
+sframe_encoder_free (sframe_encoder_ctx **encoder)
 {
   if (encoder != NULL)
     {
-      free (encoder->sfe_funcdesc);
-      free (encoder->sfe_fres);
-      free (encoder->sfe_data);
-      free (encoder);
+      sframe_encoder_ctx *ectx = *encoder;
+      if (ectx == NULL)
+	return;
+
+      if (ectx->sfe_funcdesc != NULL)
+	{
+	  free (ectx->sfe_funcdesc);
+	  ectx->sfe_funcdesc = NULL;
+	}
+      if (ectx->sfe_fres != NULL)
+	{
+	  free (ectx->sfe_fres);
+	  ectx->sfe_fres = NULL;
+	}
+      if (ectx->sfe_data != NULL)
+	{
+	  free (ectx->sfe_data);
+	  ectx->sfe_data = NULL;
+	}
+
+      free (*encoder);
+      *encoder = NULL;
     }
 }
 
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 07/14] readelf/objdump: support for SFrame section
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (5 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 06/14] bfd: linker: merge .sframe sections Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30 11:08       ` Nick Clifton
  2022-09-30  0:04     ` [PATCH,V1 08/14] unwinder: generate backtrace using SFrame format Indu Bhagat
                       ` (9 subsequent siblings)
  16 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

This patch adds support for SFrame in readelf and objdump.

include/ChangeLog:

	* sframe-api.h (dump_sframe): New function declaration.

ChangeLog:

	* binutils/Makefile.am: Add dependency on libsframe for
	readelf and objdump.
	* binutils/Makefile.in: Regenerate.
	* binutils/doc/binutils.texi: Document --sframe=[section].
	* binutils/doc/sframe.options.texi: New file.
	* binutils/objdump.c: Add support for SFrame format.
	* binutils/readelf.c: Likewise.
	* include/sframe-api.h: Add new API for dumping .sframe
	section.
	* libsframe/Makefile.am: Add sframe-dump.c.
	* libsframe/Makefile.in: Regenerate.
	* libsframe/sframe-dump.c: New file.
---
 binutils/Makefile.am             |   8 +-
 binutils/Makefile.in             |   8 +-
 binutils/doc/binutils.texi       |   4 +
 binutils/doc/sframe.options.texi |  10 ++
 binutils/objdump.c               |  76 +++++++++++++
 binutils/readelf.c               |  46 ++++++++
 include/sframe-api.h             |   3 +
 libsframe/Makefile.am            |   3 +-
 libsframe/Makefile.in            |  12 +-
 libsframe/sframe-dump.c          | 181 +++++++++++++++++++++++++++++++
 10 files changed, 339 insertions(+), 12 deletions(-)
 create mode 100644 binutils/doc/sframe.options.texi
 create mode 100644 libsframe/sframe-dump.c

diff --git a/binutils/Makefile.am b/binutils/Makefile.am
index b93684d9a65..3343e390276 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) $(LIBSFRAME)
 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) $(LIBSFRAME)
 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) $(LIBSFRAME)
 
 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) $(LIBSFRAME)
 
 objdump.@OBJEXT@:objdump.c
 if am__fastdepCC
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index 6cbdba1da26..f07cd871d93 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -766,7 +766,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) $(LIBSFRAME)
 nm_new_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 ar_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 strings_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
@@ -781,7 +781,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) $(LIBSFRAME)
 elfedit_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
 dllwrap_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
 bfdtest1_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
@@ -791,14 +791,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) $(LIBSFRAME)
 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) $(LIBSFRAME)
 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 34a4164eb94..979f93e7e3f 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -2262,6 +2262,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{--sframe=}@var{section}]
         [@option{-G}|@option{--stabs}]
         [@option{-t}|@option{--syms}]
         [@option{-T}|@option{--dynamic-syms}]
@@ -2842,6 +2843,8 @@ Enable additional checks for consistency of Dwarf information.
 
 @include ctf.options.texi
 
+@include sframe.options.texi
+
 @item -G
 @itemx --stabs
 @cindex stab
@@ -4929,6 +4932,7 @@ readelf [@option{-a}|@option{--all}]
         [@option{--ctf-parent=}@var{section}]
         [@option{--ctf-symbols=}@var{section}]
         [@option{--ctf-strings=}@var{section}]
+        [@option{--sframe=}@var{section}]
         [@option{-I}|@option{--histogram}]
         [@option{-v}|@option{--version}]
         [@option{-W}|@option{--wide}]
diff --git a/binutils/doc/sframe.options.texi b/binutils/doc/sframe.options.texi
new file mode 100644
index 00000000000..9e23679a3da
--- /dev/null
+++ b/binutils/doc/sframe.options.texi
@@ -0,0 +1,10 @@
+@c This file contains the entry for the --sframe option that is
+@c common to both readelf and objdump.
+
+@item --sframe[=@var{section}]
+@cindex SFrame
+
+Display the contents of the specified SFrame section.
+
+By default, display the name of the section named @var{.sframe}, which is the
+name emitted by @command{ld}.
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 6610906f83e..a97dc6f935a 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -58,6 +58,7 @@
 #include "demanguse.h"
 #include "dwarf.h"
 #include "ctf-api.h"
+#include "sframe-api.h"
 #include "getopt.h"
 #include "safe-ctype.h"
 #include "dis-asm.h"
@@ -108,6 +109,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_sframe_section_info;	/* --sframe */
+static char *dump_sframe_section_name;
 static int do_demangle;			/* -C, --demangle */
 static bool disassemble;		/* -d */
 static bool disassemble_all;		/* -D */
@@ -316,6 +319,9 @@ usage (FILE *stream, int status)
   fprintf (stream, _("\
       --ctf[=SECTION]      Display CTF info from SECTION, (default `.ctf')\n"));
 #endif
+  fprintf (stream, _("\
+      --sframe[=SECTION]\n\
+                           Display SFrame info from SECTION, (default '.sframe')\n"));
   fprintf (stream, _("\
   -t, --syms               Display the contents of the symbol table(s)\n"));
   fprintf (stream, _("\
@@ -462,6 +468,7 @@ enum option_values
     OPTION_CTF,
     OPTION_CTF_PARENT,
 #endif
+    OPTION_SFRAME,
     OPTION_VISUALIZE_JUMPS,
     OPTION_DISASSEMBLER_COLOR
   };
@@ -516,6 +523,7 @@ static struct option long_options[]=
   {"reloc", no_argument, NULL, 'r'},
   {"section", required_argument, NULL, 'j'},
   {"section-headers", no_argument, NULL, 'h'},
+  {"sframe", optional_argument, NULL, OPTION_SFRAME},
   {"show-raw-insn", no_argument, &show_raw_insn, 1},
   {"source", no_argument, NULL, 'S'},
   {"source-comment", optional_argument, NULL, OPTION_SOURCE_COMMENT},
@@ -4798,6 +4806,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_sframe (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr,
+		     bfd_vma *sframe_vma)
+{
+  asection *sframe_sect;
+  bfd_byte *contents;
+
+  sframe_sect = bfd_get_section_by_name (abfd, sect_name);
+  if (sframe_sect == NULL)
+    {
+      printf (_("No %s section present\n\n"),
+	      sanitize_string (sect_name));
+      return NULL;
+    }
+
+  if (!bfd_malloc_and_get_section (abfd, sframe_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 (sframe_sect);
+  *sframe_vma = bfd_section_vma (sframe_sect);
+
+  return contents;
+}
+
+static void
+dump_section_sframe (bfd *abfd ATTRIBUTE_UNUSED,
+		     const char * sect_name)
+{
+  sframe_decoder_ctx *sfd_ctx = NULL;
+  size_t sf_size;
+  bfd_byte *sframe_data = NULL;
+  bfd_vma sf_vma;
+  int err = 0;
+
+  if (sect_name == NULL)
+    sect_name = ".sframe";
+
+  sframe_data = read_section_sframe (abfd, sect_name, &sf_size, &sf_vma);
+
+  if (sframe_data == NULL)
+    bfd_fatal (bfd_get_filename (abfd));
+
+  /* Decode the contents of the section.  */
+  sfd_ctx = sframe_decode ((const char*)sframe_data, sf_size, &err);
+  if (!sfd_ctx)
+    bfd_fatal (bfd_get_filename (abfd));
+
+  printf (_("Contents of the SFrame section %s:"),
+	  sanitize_string (sect_name));
+  /* Dump the contents as text.  */
+  dump_sframe (sfd_ctx, sf_vma);
+}
+
 \f
 static void
 dump_bfd_private_header (bfd *abfd)
@@ -5551,6 +5619,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_sframe_section_info)
+	dump_section_sframe (abfd, dump_sframe_section_name);
       if (dump_stab_section_info)
 	dump_stabs (abfd);
       if (dump_reloc_info && ! disassemble)
@@ -6048,6 +6118,12 @@ main (int argc, char **argv)
 	  dump_ctf_parent_name = xstrdup (optarg);
 	  break;
 #endif
+	case OPTION_SFRAME:
+	  dump_sframe_section_info = true;
+	  if (optarg)
+	    dump_sframe_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 241c44ecfa1..ff223e48cee 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -60,6 +60,7 @@
 #include "demanguse.h"
 #include "dwarf.h"
 #include "ctf-api.h"
+#include "sframe-api.h"
 #include "demangle.h"
 
 #include "elf/common.h"
@@ -187,6 +188,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 SFRAME_DUMP	(1 << 6)	/* The --sframe command line switch.  */
 
 typedef unsigned char dump_type;
 
@@ -230,6 +232,7 @@ static bool do_version = false;
 static bool do_histogram = false;
 static bool do_debugging = false;
 static bool do_ctf = false;
+static bool do_sframe = false;
 static bool do_arch = false;
 static bool do_notes = false;
 static bool do_archive_index = false;
@@ -5068,6 +5071,7 @@ enum long_option_values
   OPTION_CTF_PARENT,
   OPTION_CTF_SYMBOLS,
   OPTION_CTF_STRINGS,
+  OPTION_SFRAME_DUMP,
   OPTION_WITH_SYMBOL_VERSIONS,
   OPTION_RECURSE_LIMIT,
   OPTION_NO_RECURSE_LIMIT,
@@ -5130,6 +5134,7 @@ static struct option options[] =
   {"ctf-strings",      required_argument, 0, OPTION_CTF_STRINGS},
   {"ctf-parent",       required_argument, 0, OPTION_CTF_PARENT},
 #endif
+  {"sframe",	       required_argument, 0, OPTION_SFRAME_DUMP},
   {"sym-base",	       optional_argument, 0, OPTION_SYM_BASE},
 
   {0,		       no_argument, 0, 0}
@@ -5270,6 +5275,8 @@ usage (FILE * stream)
   --ctf-strings=<number|name>\n\
                          Use section <number|name> as the CTF external strtab\n"));
 #endif
+  fprintf (stream, _("\
+  --sframe=<name>        Display SFrame info from section name\n"));
 
 #ifdef SUPPORT_DISASSEMBLY
   fprintf (stream, _("\
@@ -5543,6 +5550,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_SFRAME_DUMP:
+	  do_sframe = true;
+	  request_dump (dumpdata, SFRAME_DUMP);
+	  break;
 	case OPTION_DYN_SYMS:
 	  do_dyn_syms = true;
 	  break;
@@ -15819,6 +15830,36 @@ dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
 }
 #endif
 
+static bool
+dump_section_as_sframe (Elf_Internal_Shdr * section, Filedata * filedata)
+{
+  void *		  data = NULL;
+  sframe_decoder_ctx	  *sfd_ctx = NULL;
+  const char *print_name = printable_section_name (filedata, section);
+
+  bool ret = true;
+  size_t sf_size;
+  int err = 0;
+
+  data = get_section_contents (section, filedata);
+  sf_size = section->sh_size;
+  /* Decode the contents of the section.  */
+  sfd_ctx = sframe_decode ((const char*)data, sf_size, &err);
+  if (!sfd_ctx)
+    {
+      ret = false;
+      goto fail;
+    }
+
+  printf (_("Contents of the SFrame section %s:"), print_name);
+  /* Dump the contents as text.  */
+  dump_sframe (sfd_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,
@@ -16318,6 +16359,11 @@ process_section_contents (Filedata * filedata)
 	    res = false;
 	}
 #endif
+      if (dump & SFRAME_DUMP)
+	{
+	  if (! dump_section_as_sframe (section, filedata))
+	    res = false;
+	}
     }
 
   if (! filedata->is_separate)
diff --git a/include/sframe-api.h b/include/sframe-api.h
index 351cf1f7398..7712bbf4b53 100644
--- a/include/sframe-api.h
+++ b/include/sframe-api.h
@@ -145,6 +145,9 @@ sframe_decoder_get_funcdesc (sframe_decoder_ctx *ctx,
 				int32_t *func_start_address,
 				unsigned char *func_info);
 
+/* SFrame textual dump.  */
+extern void
+dump_sframe (sframe_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/libsframe/Makefile.am b/libsframe/Makefile.am
index 3a2218f1e5e..31576429816 100644
--- a/libsframe/Makefile.am
+++ b/libsframe/Makefile.am
@@ -37,7 +37,6 @@ include_HEADERS =
 noinst_LTLIBRARIES = libsframe.la
 endif
 
-libsframe_la_SOURCES = sframe.c sframe-error.c
+libsframe_la_SOURCES = sframe.c sframe-dump.c sframe-error.c
 libsframe_la_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include \
 			-I$(srcdir)/../libctf
-
diff --git a/libsframe/Makefile.in b/libsframe/Makefile.in
index 79ea3a9209d..0db5ff954b9 100644
--- a/libsframe/Makefile.in
+++ b/libsframe/Makefile.in
@@ -161,7 +161,7 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
 LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
 libsframe_la_LIBADD =
 am_libsframe_la_OBJECTS = libsframe_la-sframe.lo \
-	libsframe_la-sframe-error.lo
+	libsframe_la-sframe-dump.lo libsframe_la-sframe-error.lo
 libsframe_la_OBJECTS = $(am_libsframe_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -430,7 +430,7 @@ AM_CFLAGS = -std=gnu99 @ac_libsframe_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC
 @INSTALL_LIBBFD_FALSE@include_HEADERS = 
 @INSTALL_LIBBFD_TRUE@include_HEADERS = $(INCDIR)/sframe.h $(INCDIR)/sframe-api.h
 @INSTALL_LIBBFD_FALSE@noinst_LTLIBRARIES = libsframe.la
-libsframe_la_SOURCES = sframe.c sframe-error.c
+libsframe_la_SOURCES = sframe.c sframe-dump.c sframe-error.c
 libsframe_la_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include \
 			-I$(srcdir)/../libctf
 
@@ -543,6 +543,7 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframe_la-sframe-dump.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframe_la-sframe-error.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframe_la-sframe.Plo@am__quote@
 
@@ -574,6 +575,13 @@ libsframe_la-sframe.lo: sframe.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) $(libsframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsframe_la-sframe.lo `test -f 'sframe.c' || echo '$(srcdir)/'`sframe.c
 
+libsframe_la-sframe-dump.lo: sframe-dump.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsframe_la-sframe-dump.lo -MD -MP -MF $(DEPDIR)/libsframe_la-sframe-dump.Tpo -c -o libsframe_la-sframe-dump.lo `test -f 'sframe-dump.c' || echo '$(srcdir)/'`sframe-dump.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libsframe_la-sframe-dump.Tpo $(DEPDIR)/libsframe_la-sframe-dump.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sframe-dump.c' object='libsframe_la-sframe-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) $(libsframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsframe_la-sframe-dump.lo `test -f 'sframe-dump.c' || echo '$(srcdir)/'`sframe-dump.c
+
 libsframe_la-sframe-error.lo: sframe-error.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsframe_la-sframe-error.lo -MD -MP -MF $(DEPDIR)/libsframe_la-sframe-error.Tpo -c -o libsframe_la-sframe-error.lo `test -f 'sframe-error.c' || echo '$(srcdir)/'`sframe-error.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libsframe_la-sframe-error.Tpo $(DEPDIR)/libsframe_la-sframe-error.Plo
diff --git a/libsframe/sframe-dump.c b/libsframe/sframe-dump.c
new file mode 100644
index 00000000000..8ad1580afcf
--- /dev/null
+++ b/libsframe/sframe-dump.c
@@ -0,0 +1,181 @@
+/* sframe-dump.c - Textual dump of .sframe.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   his file is part of libsframe.
+
+   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 "sframe-impl.h"
+
+#define SFRAME_HEADER_FLAGS_STR_MAX_LEN 50
+
+static void
+dump_sframe_header (sframe_decoder_ctx *sfd_ctx)
+{
+  const char *verstr = NULL;
+  const sframe_header *header = &(sfd_ctx->sfd_header);
+
+  /* Prepare SFrame section version string.  */
+  const char *version_names[]
+    = { "NULL",
+	"SFRAME_VERSION_1" };
+  unsigned char ver = header->sfh_preamble.sfp_version;
+  if (ver <= SFRAME_VERSION)
+    verstr = version_names[ver];
+
+  /* Prepare SFrame section flags string.  */
+  unsigned char flags = header->sfh_preamble.sfp_flags;
+  char *flags_str
+    = (char*) calloc (sizeof (char), SFRAME_HEADER_FLAGS_STR_MAX_LEN);
+  if (flags)
+    {
+      const char *flag_names[]
+	= { "SFRAME_F_FDE_SORTED",
+	    "SFRAME_F_FRAME_POINTER" };
+      unsigned char flags = header->sfh_preamble.sfp_flags;
+      if (flags & SFRAME_F_FDE_SORTED)
+	strcpy (flags_str, flag_names[0]);
+      if (flags & SFRAME_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->sfh_num_fdes);
+  printf ("    Num FREs: %d\n", header->sfh_num_fres);
+
+  free (flags_str);
+}
+
+static void
+dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_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};
+
+  sframe_frame_row_entry fre;
+
+  /* Get the SFrame function descriptor.  */
+  sframe_decoder_get_funcdesc (sfd_ctx, funcidx, &num_fres,
+			       &func_size, &func_start_address, &func_info);
+  sframe_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 = (SFRAME_V1_FUNC_FDE_TYPE (func_info)
+			     == SFRAME_FDE_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++)
+    {
+      sframe_decoder_get_fre (sfd_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 = sframe_fre_get_base_reg_id (&fre, &err[0]);
+      cfa_offset = sframe_fre_get_cfa_offset (&fre, &err[0]);
+      fp_offset = sframe_fre_get_fp_offset (&fre, &err[1]);
+      ra_offset = sframe_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_sframe_functions (sframe_decoder_ctx *sfd_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 = sframe_decoder_get_num_fidx (sfd_ctx);
+  for (i = 0; i < num_fdes; i++)
+    {
+      dump_sframe_func_with_fres (sfd_ctx, i, sec_addr);
+      printf ("\n");
+    }
+}
+
+void
+dump_sframe (sframe_decoder_ctx *sfd_ctx, uint64_t sec_addr)
+{
+  dump_sframe_header (sfd_ctx);
+  dump_sframe_functions (sfd_ctx, sec_addr);
+}
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 08/14] unwinder: generate backtrace using SFrame format
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (6 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 07/14] readelf/objdump: support for SFrame section Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 09/14] unwinder: Add SFrame unwinder tests Indu Bhagat
                       ` (8 subsequent siblings)
  16 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan

From: Weimin Pan <weimin.pan@oracle.com>

A simple unwinder based on SFrame format.

The unwinder is made available via libsframebt library.

Buildsystem changes have been made to build libsframebt only when
--gsframe support is available in the assembler. These buildsystem
changes are necessary because the SFrame based unwinder the SFrame
unwind info for itself to work.

PS: libsframe/configure has NOT been included in the patch.  Please
regenerate.

config/ChangeLog:

	* sframe.m4: New file.

include/ChangeLog:

	* sframe-backtrace-api.h: New file.

ChangeLog:

	* libsframe/Makefile.am: Build backtrace functionality in its
	own library.  Install libsframebt conditionally.
	* libsframe/Makefile.in: Regenerate.
	* libsframe/aclocal.m4: Regenerate.
	* libsframe/configure: Regenerate.  <-- [REMOVED FROM THE PATCH.
	PLEASE REGENERATE.]
	* libsframe/configure.ac: Check if gas supports --gsframe
	command line option.
	* libsframe/sframe-backtrace-err.c: New file.
	* libsframe/sframe-backtrace.c: New file.
---
 config/sframe.m4                              |  16 +
 include/sframe-backtrace-api.h                |  57 ++
 libsframe/Makefile.am                         |  12 +
 libsframe/Makefile.in                         |  58 +-
 libsframe/aclocal.m4                          |   1 +
 libsframe/configure.ac                        |   7 +
 libsframe/sframe-backtrace-err.c              |  46 ++
 libsframe/sframe-backtrace.c                  | 619 ++++++++++++++++++
 libsframe/testsuite/Makefile.in               |   1 +
 .../testsuite/libsframe.decode/Makefile.in    |   1 +
 .../testsuite/libsframe.encode/Makefile.in    |   1 +
 11 files changed, 812 insertions(+), 7 deletions(-)
 create mode 100644 config/sframe.m4
 create mode 100644 include/sframe-backtrace-api.h
 create mode 100644 libsframe/sframe-backtrace-err.c
 create mode 100644 libsframe/sframe-backtrace.c

diff --git a/config/sframe.m4 b/config/sframe.m4
new file mode 100644
index 00000000000..9f149fda9ef
--- /dev/null
+++ b/config/sframe.m4
@@ -0,0 +1,16 @@
+# SFRAME_CHECK_AS_SFRAME
+# ----------------------
+# Check whether the assembler supports generation of SFrame
+# unwind information.
+#
+# Defines:
+# ac_cv_have_sframe
+
+AC_DEFUN([SFRAME_CHECK_AS_SFRAME],[
+  ac_save_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -Wa,--gsframe"
+  AC_MSG_CHECKING([for as that supports --gsframe])
+  AC_TRY_COMPILE([], [return 0;], [ac_cv_have_sframe=yes], [ac_cv_have_sframe=no])
+  AC_MSG_RESULT($ac_cv_have_sframe)
+  CFLAGS="$ac_save_CFLAGS"
+])
diff --git a/include/sframe-backtrace-api.h b/include/sframe-backtrace-api.h
new file mode 100644
index 00000000000..ad8f6bed024
--- /dev/null
+++ b/include/sframe-backtrace-api.h
@@ -0,0 +1,57 @@
+/* Public API to SFrame backtrace.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of libsframebt.
+
+   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/>.  */
+
+#ifndef	_SFRAME_BACKTRACE_API_H
+#define	_SFRAME_BACKTRACE_API_H
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+enum sframe_bt_errcode
+{
+  SFRAME_BT_OK,
+  SFRAME_BT_ERR_NOTPRESENT,
+  SFRAME_BT_ERR_PHDR,
+  SFRAME_BT_ERR_ARG,
+  SFRAME_BT_ERR_MALLOC,
+  SFRAME_BT_ERR_REALLOC,
+  SFRAME_BT_ERR_OPEN,
+  SFRAME_BT_ERR_READLINK,
+  SFRAME_BT_ERR_LSEEK,
+  SFRAME_BT_ERR_READ,
+  SFRAME_BT_ERR_GETCONTEXT,
+  SFRAME_BT_ERR_DECODE,
+  SFRAME_BT_ERR_CFA_OFFSET,
+};
+
+/* Get the backtrace of the calling program by storing return addresses
+   in BUFFER. The SIZE argument specifies the maximum number of addresses
+   that can be stored in the buffer. Return the number of return addresses
+   collected or -1 if there is any error.  */
+extern int sframe_backtrace (void **buffer, int size, int *errp);
+
+extern const char *sframe_bt_errmsg (enum sframe_bt_errcode ecode);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _SFRAME_BACKTRACE_API_H */
diff --git a/libsframe/Makefile.am b/libsframe/Makefile.am
index 31576429816..1b8a1081975 100644
--- a/libsframe/Makefile.am
+++ b/libsframe/Makefile.am
@@ -40,3 +40,15 @@ endif
 libsframe_la_SOURCES = sframe.c sframe-dump.c sframe-error.c
 libsframe_la_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include \
 			-I$(srcdir)/../libctf
+
+if HAVE_SFRAME_AS
+  libsframebt_la_SOURCES = sframe-backtrace.c sframe-backtrace-err.c
+  libsframebt_la_CPPFLAGS = -I$(srcdir) -I$(srcdir)/../include
+  libsframebt_la_CFLAGS = -Wa,--gsframe
+if INSTALL_LIBBFD
+  lib_LTLIBRARIES += libsframebt.la
+  include_HEADERS += $(INCDIR)/sframe-backtrace-api.h
+else
+  noinst_LTLIBRARIES += libsframebt.la
+endif
+endif
diff --git a/libsframe/Makefile.in b/libsframe/Makefile.in
index 0db5ff954b9..f5c32b7c9b9 100644
--- a/libsframe/Makefile.in
+++ b/libsframe/Makefile.in
@@ -107,6 +107,9 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@am__append_1 = libsframebt.la
+@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@am__append_2 = $(INCDIR)/sframe-backtrace-api.h
+@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_FALSE@am__append_3 = libsframebt.la
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
@@ -115,6 +118,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/jobserver.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/sframe.m4 \
 	$(top_srcdir)/../config/warnings.m4 \
 	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
 	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
@@ -169,6 +173,20 @@ am__v_lt_0 = --silent
 am__v_lt_1 = 
 @INSTALL_LIBBFD_FALSE@am_libsframe_la_rpath =
 @INSTALL_LIBBFD_TRUE@am_libsframe_la_rpath = -rpath $(libdir)
+libsframebt_la_LIBADD =
+am__libsframebt_la_SOURCES_DIST = sframe-backtrace.c \
+	sframe-backtrace-err.c
+@HAVE_SFRAME_AS_TRUE@am_libsframebt_la_OBJECTS =  \
+@HAVE_SFRAME_AS_TRUE@	libsframebt_la-sframe-backtrace.lo \
+@HAVE_SFRAME_AS_TRUE@	libsframebt_la-sframe-backtrace-err.lo
+libsframebt_la_OBJECTS = $(am_libsframebt_la_OBJECTS)
+libsframebt_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(libsframebt_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o \
+	$@
+@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_FALSE@am_libsframebt_la_rpath =
+@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@am_libsframebt_la_rpath =  \
+@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@	-rpath $(libdir)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -203,8 +221,9 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(libsframe_la_SOURCES)
-DIST_SOURCES = $(libsframe_la_SOURCES)
+SOURCES = $(libsframe_la_SOURCES) $(libsframebt_la_SOURCES)
+DIST_SOURCES = $(libsframe_la_SOURCES) \
+	$(am__libsframebt_la_SOURCES_DIST)
 RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
 	ctags-recursive dvi-recursive html-recursive info-recursive \
 	install-data-recursive install-dvi-recursive \
@@ -218,7 +237,8 @@ am__can_run_installinfo = \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
-am__include_HEADERS_DIST = $(INCDIR)/sframe.h $(INCDIR)/sframe-api.h
+am__include_HEADERS_DIST = $(INCDIR)/sframe-backtrace-api.h \
+	$(INCDIR)/sframe.h $(INCDIR)/sframe-api.h
 HEADERS = $(include_HEADERS)
 RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
   distclean-recursive maintainer-clean-recursive
@@ -426,14 +446,19 @@ INCDIR = $(srcdir)/../include
 # include libctf for swap.h
 AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../libctf
 AM_CFLAGS = -std=gnu99 @ac_libsframe_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@
-@INSTALL_LIBBFD_TRUE@lib_LTLIBRARIES = libsframe.la
-@INSTALL_LIBBFD_FALSE@include_HEADERS = 
-@INSTALL_LIBBFD_TRUE@include_HEADERS = $(INCDIR)/sframe.h $(INCDIR)/sframe-api.h
-@INSTALL_LIBBFD_FALSE@noinst_LTLIBRARIES = libsframe.la
+@INSTALL_LIBBFD_TRUE@lib_LTLIBRARIES = libsframe.la $(am__append_1)
+@INSTALL_LIBBFD_FALSE@include_HEADERS = $(am__append_2)
+@INSTALL_LIBBFD_TRUE@include_HEADERS = $(INCDIR)/sframe.h \
+@INSTALL_LIBBFD_TRUE@	$(INCDIR)/sframe-api.h $(am__append_2)
+@INSTALL_LIBBFD_FALSE@noinst_LTLIBRARIES = libsframe.la \
+@INSTALL_LIBBFD_FALSE@	$(am__append_3)
 libsframe_la_SOURCES = sframe.c sframe-dump.c sframe-error.c
 libsframe_la_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include \
 			-I$(srcdir)/../libctf
 
+@HAVE_SFRAME_AS_TRUE@libsframebt_la_SOURCES = sframe-backtrace.c sframe-backtrace-err.c
+@HAVE_SFRAME_AS_TRUE@libsframebt_la_CPPFLAGS = -I$(srcdir) -I$(srcdir)/../include
+@HAVE_SFRAME_AS_TRUE@libsframebt_la_CFLAGS = -Wa,--gsframe
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-recursive
 
@@ -537,6 +562,9 @@ clean-noinstLTLIBRARIES:
 libsframe.la: $(libsframe_la_OBJECTS) $(libsframe_la_DEPENDENCIES) $(EXTRA_libsframe_la_DEPENDENCIES) 
 	$(AM_V_CCLD)$(LINK) $(am_libsframe_la_rpath) $(libsframe_la_OBJECTS) $(libsframe_la_LIBADD) $(LIBS)
 
+libsframebt.la: $(libsframebt_la_OBJECTS) $(libsframebt_la_DEPENDENCIES) $(EXTRA_libsframebt_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libsframebt_la_LINK) $(am_libsframebt_la_rpath) $(libsframebt_la_OBJECTS) $(libsframebt_la_LIBADD) $(LIBS)
+
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
 
@@ -546,6 +574,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframe_la-sframe-dump.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframe_la-sframe-error.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframe_la-sframe.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframebt_la-sframe-backtrace-err.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframebt_la-sframe-backtrace.Plo@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -589,6 +619,20 @@ libsframe_la-sframe-error.lo: sframe-error.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) $(libsframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsframe_la-sframe-error.lo `test -f 'sframe-error.c' || echo '$(srcdir)/'`sframe-error.c
 
+libsframebt_la-sframe-backtrace.lo: sframe-backtrace.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsframebt_la_CPPFLAGS) $(CPPFLAGS) $(libsframebt_la_CFLAGS) $(CFLAGS) -MT libsframebt_la-sframe-backtrace.lo -MD -MP -MF $(DEPDIR)/libsframebt_la-sframe-backtrace.Tpo -c -o libsframebt_la-sframe-backtrace.lo `test -f 'sframe-backtrace.c' || echo '$(srcdir)/'`sframe-backtrace.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libsframebt_la-sframe-backtrace.Tpo $(DEPDIR)/libsframebt_la-sframe-backtrace.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sframe-backtrace.c' object='libsframebt_la-sframe-backtrace.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) $(libsframebt_la_CPPFLAGS) $(CPPFLAGS) $(libsframebt_la_CFLAGS) $(CFLAGS) -c -o libsframebt_la-sframe-backtrace.lo `test -f 'sframe-backtrace.c' || echo '$(srcdir)/'`sframe-backtrace.c
+
+libsframebt_la-sframe-backtrace-err.lo: sframe-backtrace-err.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsframebt_la_CPPFLAGS) $(CPPFLAGS) $(libsframebt_la_CFLAGS) $(CFLAGS) -MT libsframebt_la-sframe-backtrace-err.lo -MD -MP -MF $(DEPDIR)/libsframebt_la-sframe-backtrace-err.Tpo -c -o libsframebt_la-sframe-backtrace-err.lo `test -f 'sframe-backtrace-err.c' || echo '$(srcdir)/'`sframe-backtrace-err.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libsframebt_la-sframe-backtrace-err.Tpo $(DEPDIR)/libsframebt_la-sframe-backtrace-err.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sframe-backtrace-err.c' object='libsframebt_la-sframe-backtrace-err.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) $(libsframebt_la_CPPFLAGS) $(CPPFLAGS) $(libsframebt_la_CFLAGS) $(CFLAGS) -c -o libsframebt_la-sframe-backtrace-err.lo `test -f 'sframe-backtrace-err.c' || echo '$(srcdir)/'`sframe-backtrace-err.c
+
 mostlyclean-libtool:
 	-rm -f *.lo
 
diff --git a/libsframe/aclocal.m4 b/libsframe/aclocal.m4
index 3a0b3426ebc..d2f540bb073 100644
--- a/libsframe/aclocal.m4
+++ b/libsframe/aclocal.m4
@@ -1233,6 +1233,7 @@ m4_include([../config/depstand.m4])
 m4_include([../config/jobserver.m4])
 m4_include([../config/lead-dot.m4])
 m4_include([../config/override.m4])
+m4_include([../config/sframe.m4])
 m4_include([../config/warnings.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
diff --git a/libsframe/configure.ac b/libsframe/configure.ac
index d2f32ae2ebd..82fafee5068 100644
--- a/libsframe/configure.ac
+++ b/libsframe/configure.ac
@@ -57,6 +57,13 @@ ACX_PROG_CC_WARNING_ALMOST_PEDANTIC([-Wno-long-long])
 # corrected.
 ACX_PROG_CC_WARNINGS_ARE_ERRORS([manual])
 
+dnl The libsframebt library needs to be built with SFrame info.
+dnl If the build assembler is not capable of generate SFrame then
+dnl the library is not built.
+
+SFRAME_CHECK_AS_SFRAME
+AM_CONDITIONAL([HAVE_SFRAME_AS], [test "x$ac_cv_have_sframe" = "xyes"])
+
 AM_MAINTAINER_MODE
 AM_INSTALL_LIBBFD
 ACX_PROG_CC_WARNING_OPTS([-Wall], [ac_libsframe_warn_cflags])
diff --git a/libsframe/sframe-backtrace-err.c b/libsframe/sframe-backtrace-err.c
new file mode 100644
index 00000000000..70bd55ccf35
--- /dev/null
+++ b/libsframe/sframe-backtrace-err.c
@@ -0,0 +1,46 @@
+/* sframe-backtrace-err.c - SFrame Backtrace Error table.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of libsframebt.
+
+   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 "config.h"
+#include "sframe-backtrace-api.h"
+
+/* SFrame backtrace error messages.  */
+static const char *const sframe_bt_errlist[] =
+{
+  "",
+  "File does not contain SFrame data",
+  "Iterating shared object reading error",
+  "Failed to malloc memory space",
+  "Failed to realloc memory space",
+  "Failed to open file",
+  "Failed on resolve canonical file name",
+  "Failed to reposition file offset",
+  "Failed to read from a file descriptor",
+  "Failed to get the user context",
+  "Failed to set up decode data",
+  "Illegal CFA offset"
+};
+
+/* Return the error message associated with the error code.  */
+
+const char *
+sframe_bt_errmsg (enum sframe_bt_errcode ecode)
+{
+  return sframe_bt_errlist[ecode];
+}
diff --git a/libsframe/sframe-backtrace.c b/libsframe/sframe-backtrace.c
new file mode 100644
index 00000000000..dcee7c486b5
--- /dev/null
+++ b/libsframe/sframe-backtrace.c
@@ -0,0 +1,619 @@
+/* sframe-backtrace.c - The SFrame backtracer.
+
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of libsframebt.
+
+   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/>.  */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "config.h"
+#include <elf.h>
+#include <link.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <execinfo.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ucontext.h>
+#include <stdarg.h>
+#include "ansidecl.h"
+#include "sframe-api.h"
+#include "sframe-backtrace-api.h"
+
+#ifndef PT_SFRAME
+#define PT_SFRAME 0x6474e554		/* FIXME.  */
+#endif
+
+#define _sf_printflike_(string_index,first_to_check) \
+    __attribute__ ((__format__ (__printf__, (string_index), (first_to_check))))
+
+static int _sframe_unwind_debug;	/* Control for printing out debug info.  */
+static int no_of_entries = 32;
+
+/* SFrame decode data for the main module or a DSO.  */
+struct sframe_decode_data
+{
+  char *sfdd_data;			/* SFrame decode data.  */
+  int sfdd_data_size;			/* SFrame decode data size.  */
+  uint64_t sfdd_text_vma;		/* Text segment's virtual address.  */
+  int sfdd_text_size;			/* Text segment's size.  */
+  uint64_t sfdd_sframe_vma;		/* SFrame segment's virtual address.  */	
+  sframe_decoder_ctx *sfdd_sframe_ctx;	/* SFrame decoder context.  */
+};
+
+/* List that holds SFrame info for the shared libraries.  */
+struct dso_cfi_list
+{
+  int alloced;				/* Entries allocated.  */
+  int used;				/* Entries used.  */
+  struct sframe_decode_data *entry;	/* DSO's decode data.  */
+};
+
+/* Data that's passed through sframe_callback.  */
+struct sframe_unwind_info
+{
+  int sui_fd;				/* File descriptor.  */
+  struct sframe_decode_data sui_ctx;	/* The decode data.  */
+  struct dso_cfi_list sui_dsos;		/* The DSO list.  */
+};
+
+static void
+sframe_unwind_init_debug (void)
+{
+  static int inited;
+
+  if (!inited)
+    {
+      _sframe_unwind_debug = getenv ("SFRAME_UNWIND_DEBUG") != NULL;
+      inited = 1;
+    }
+}
+
+_sf_printflike_ (1, 2)
+static void
+debug_printf (const char *format, ...)
+{
+  if (_sframe_unwind_debug)
+    {
+      va_list args;
+
+      va_start (args, format);
+      __builtin_vprintf (format, args);
+      va_end (args);
+    }
+}
+
+/* sframe_bt_errno - Check if there is error code in ERRP.  */
+
+static int
+sframe_bt_errno (int *errp)
+{
+  if (errp == NULL)
+    return 0;
+
+  return (*errp != SFRAME_BT_OK);
+}
+
+/* sframe_bt_set_errno - Store the specified error code ERROR into ERRP if
+   it is non-NULL.  */
+
+static void
+sframe_bt_set_errno (int *errp, int error)
+{
+  if (errp != NULL)
+    *errp = error;
+}
+
+/* sframe_add_dso - Add .sframe info in D_DATA, which is associated with
+   a dynamic shared object, to D_LIST.  */
+
+static void
+sframe_add_dso (struct dso_cfi_list *d_list,
+	     struct sframe_decode_data d_data,
+	     int *errp)
+{
+  if (d_list->alloced == 0)
+    {
+      d_list->entry = malloc (no_of_entries * sizeof (struct sframe_decode_data));
+      if (d_list->entry == NULL)
+	{
+	  sframe_bt_set_errno (errp, SFRAME_BT_ERR_MALLOC);
+	  return;
+	}
+      memset (d_list->entry, 0,
+	      no_of_entries * sizeof (struct sframe_decode_data));
+      d_list->alloced = no_of_entries;
+    }
+  else if (d_list->used == d_list->alloced)
+    {
+      d_list->entry = realloc (d_list->entry,
+			(d_list->alloced + no_of_entries) *
+			sizeof (struct sframe_decode_data));
+      if (d_list->entry == NULL)
+	{
+	  sframe_bt_set_errno (errp, SFRAME_BT_ERR_REALLOC);
+	  return;
+	}
+
+      memset (&d_list->entry[d_list->alloced], 0,
+	      no_of_entries * sizeof (struct sframe_decode_data));
+      d_list->alloced += no_of_entries;
+    }
+
+  sframe_bt_set_errno (errp, SFRAME_BT_OK);
+  d_list->entry[d_list->used++] = d_data;
+}
+
+/* sframe_free_cfi - Free up space allocated for .sframe info for CF.  */
+
+static void
+sframe_free_cfi (struct sframe_unwind_info *sf)
+{
+  struct dso_cfi_list *d_list;
+  int i;
+
+  if (sf == NULL)
+    return;
+
+  free (sf->sui_ctx.sfdd_data);
+  sframe_decoder_free (&sf->sui_ctx.sfdd_sframe_ctx);
+  close (sf->sui_fd);
+
+  d_list = &sf-> sui_dsos;
+  if (d_list == NULL)
+    return;
+
+  for (i = 0; i < d_list->used; ++i)
+    {
+      free (d_list->entry[i].sfdd_data);
+      sframe_decoder_free (&d_list->entry[i].sfdd_sframe_ctx);
+    }
+
+  free (d_list->entry);
+}
+
+/* sframe_find_context - Find the decode data that contains ADDR from CF.
+   Return the pointer to the decode data or NULL.  */
+
+static struct sframe_decode_data *
+sframe_find_context (struct sframe_unwind_info *sf, uint64_t addr)
+{
+  struct dso_cfi_list *d_list;
+  int i;
+
+  if (sf == NULL)
+    return NULL;
+
+  if (sf->sui_ctx.sfdd_text_vma < addr
+      && sf->sui_ctx.sfdd_text_vma + sf->sui_ctx.sfdd_text_size > addr)
+    return &sf->sui_ctx;
+
+  d_list = &sf->sui_dsos;
+  for (i = 0; i < sf->sui_dsos.used; ++i)
+    {
+      if (d_list->entry[i].sfdd_text_vma <= addr &&
+	  d_list->entry[i].sfdd_text_vma
+	  + d_list->entry[i].sfdd_text_size >= addr)
+	return &d_list->entry[i];
+    }
+
+  return NULL;
+}
+
+/* sframe_valid_addr - Check if ADDR is valid in CF. The address is considered
+   invalid, with regards to SFrame, if it's not in any address range of the
+   main module or any of its DSO's. Return 1 if valid, 0 otherwise.  */
+
+static int
+sframe_valid_addr (struct sframe_unwind_info *sf, uint64_t addr)
+{
+  struct sframe_decode_data *cdp;
+
+  if (sf == NULL)
+    return 0;
+
+  cdp = sframe_find_context (sf, addr);
+  return cdp ? 1 : 0;
+}
+
+/* sframe_load_ctx - Call decoder to create and set up the SFrame info for
+   either the main module or one of the DSOs from CF, based on the input
+   RADDR argument.  Return the newly created decode context or NULL.  */
+
+static sframe_decoder_ctx *
+sframe_load_ctx (struct sframe_unwind_info *sf, uint64_t raddr)
+{
+  sframe_decoder_ctx *nctx;
+  struct sframe_decode_data *cdp;
+
+  if (sf == NULL)
+    return NULL;
+
+  cdp = sframe_find_context (sf, raddr);
+  if (cdp == NULL)
+    return NULL;
+
+  if (cdp->sfdd_sframe_ctx == NULL)
+    {
+      int err; 
+      nctx = sframe_decode (cdp->sfdd_data, cdp->sfdd_data_size, &err);
+      if (nctx == NULL)
+	return NULL;
+      cdp->sfdd_sframe_ctx = nctx;
+      return nctx;
+    }
+
+  return NULL;
+}
+
+/* sframe_update_ctx - Check if need to do a decode context switch, based on
+   the input RADDR argument, from CF. A new decode context will be created
+   and set up if it isn't already done so. Return the new decode context in
+   CTX and vma in CFI_VMA.  */
+
+static void
+sframe_update_ctx (struct sframe_unwind_info *sf, uint64_t raddr,
+		sframe_decoder_ctx **ctx, uint64_t *cfi_vma)
+{
+  sframe_decoder_ctx *nctx;
+  struct sframe_decode_data *cdp;
+
+  cdp = sframe_find_context (sf, raddr);
+  if (cdp != NULL)
+    {
+      if (cdp->sfdd_sframe_ctx == NULL)
+	{
+	  int err; 
+	  nctx = sframe_decode (cdp->sfdd_data, cdp->sfdd_data_size, &err);
+	  if (nctx == NULL)
+	    {
+	      *ctx = NULL;
+	      return;
+	    }
+	  cdp->sfdd_sframe_ctx = nctx;
+	}
+	*ctx = cdp->sfdd_sframe_ctx;
+	*cfi_vma = cdp->sfdd_sframe_vma;
+    }
+}
+
+/* get_contents - Return contents at ADDR from file descriptor FD.  */
+
+static uint64_t
+get_contents (int fd, uint64_t addr, int *errp)
+{
+  uint64_t data;
+  size_t sz;
+
+  sframe_bt_set_errno (errp, SFRAME_BT_OK);
+  if (lseek (fd, addr, SEEK_SET) == -1)
+    {
+      sframe_bt_set_errno (errp, SFRAME_BT_ERR_LSEEK);
+      return 0;
+    }
+  sz = read (fd, &data, sizeof (uint64_t));
+  if (sz != sizeof (uint64_t))
+    {
+      sframe_bt_set_errno (errp, SFRAME_BT_ERR_READ);
+      return 0;
+    }
+
+  return data;
+}
+
+/* sframe_fd_open - Open /proc image associated with the process id and return
+   the file descriptor.  */
+
+static int
+sframe_fd_open (int *errp)
+{
+  char filename[PATH_MAX];
+  pid_t pid;
+  int fd;
+
+  pid = getpid ();
+  snprintf (filename, sizeof filename, "/proc/%d/task/%d/mem", pid, pid);
+  if ((fd = open (filename, O_RDONLY)) == -1)
+    {
+      sframe_bt_set_errno (errp, SFRAME_BT_ERR_OPEN);
+      return -1;
+    }
+
+  return fd;
+}
+
+/* sframe_callback - The callback from dl_iterate_phdr with header info
+   in INFO.
+   Return SFrame info for either the main module or a DSO in DATA.  */
+
+static int
+sframe_callback (struct dl_phdr_info *info,
+		    size_t size ATTRIBUTE_UNUSED,
+		    void *data)
+{
+  struct sframe_unwind_info *sf = (struct sframe_unwind_info *) data;
+  int p_type, i, fd, sframe_err;
+  ssize_t len;
+  uint64_t text_vma = 0;
+  int text_size = 0;
+
+  if (data == NULL || info == NULL)
+    return 1;
+
+  debug_printf ("-- name: %s %14p\n", info->dlpi_name, (void *)info->dlpi_addr);
+
+  for (i = 0; i < info->dlpi_phnum; i++)
+    {
+      debug_printf("    %2d: [%14p; memsz:%7lx] flags: 0x%x; \n", i,
+		   (void *) info->dlpi_phdr[i].p_vaddr,
+		   info->dlpi_phdr[i].p_memsz,
+		   info->dlpi_phdr[i].p_flags);
+
+      p_type = info->dlpi_phdr[i].p_type;
+      if (p_type == PT_LOAD && info->dlpi_phdr[i].p_flags & PF_X)
+	{
+	  text_vma = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
+	  text_size = info->dlpi_phdr[i].p_memsz;
+	  continue;
+	}
+      if (p_type != PT_SFRAME)
+	continue;
+
+      if (info->dlpi_name[0] == '\0')		/* the main module.  */
+	{
+	  fd = sframe_fd_open (&sframe_err);
+	  if (fd == -1)
+	    return 1;
+	  if (lseek (fd, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr,
+		     SEEK_SET) == -1)
+	    {
+	      sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_LSEEK);
+	      return 1;
+	    }
+
+	  sf->sui_ctx.sfdd_data = (char *) malloc (info->dlpi_phdr[i].p_memsz);
+	  if (sf->sui_ctx.sfdd_data == NULL)
+	    {
+	      sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_MALLOC);
+	      return 1;
+	    }
+
+	  len = read (fd, sf->sui_ctx.sfdd_data, info->dlpi_phdr[i].p_memsz);
+	  if (len == -1 || len != (ssize_t) info->dlpi_phdr[i].p_memsz)
+	    {
+	      sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_READ);
+	      return 1;
+	    }
+
+	  assert (text_vma);
+	  sf->sui_ctx.sfdd_data_size = len;
+	  sf->sui_ctx.sfdd_sframe_vma = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
+	  sf->sui_fd = fd;
+	  sf->sui_ctx.sfdd_text_vma = text_vma;
+	  sf->sui_ctx.sfdd_text_size = text_size;
+	  text_vma = 0;
+	  return 0;
+	}
+      else
+	{					/* a dynamic shared object.  */
+	  struct sframe_decode_data dt;
+	  memset (&dt, 0, sizeof (struct sframe_decode_data));
+	  assert (sf->sui_fd);
+	  if (lseek (sf->sui_fd, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr,
+		     SEEK_SET) == -1)
+	    {
+	      sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_LSEEK);
+	      return 1;
+	    }
+
+	  dt.sfdd_data = (char *) malloc (info->dlpi_phdr[i].p_memsz);
+	  if (dt.sfdd_data == NULL)
+	    {
+	      sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_MALLOC);
+	      return 1;
+	    }
+
+	  len = read (sf->sui_fd, dt.sfdd_data, info->dlpi_phdr[i].p_memsz);
+	  if (len == -1 || len != (ssize_t) info->dlpi_phdr[i].p_memsz)
+	    {
+	      sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_READ);
+	      return 1;
+	    }
+
+	  assert (text_vma);
+	  dt.sfdd_data_size = len;
+	  dt.sfdd_sframe_vma = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
+	  dt.sfdd_text_vma = text_vma;
+	  dt.sfdd_text_size = text_size;
+	  text_vma = 0;
+	  sframe_add_dso (&sf->sui_dsos, dt, &sframe_err);
+	  if (sframe_err != SFRAME_BT_OK)
+	    return 1;
+	  return 0;
+	}
+    }
+
+    return 0;
+}
+
+/* sframe_unwind - Unwind the stack backtrace for CF. If successful,
+   store the return addresses in RA_LST. The RA_SIZE argument specifies
+   the maximum number of return addresses that can be stored in RA_LST
+   and contains the number of the addresses collected.  */
+
+static void
+sframe_unwind (struct sframe_unwind_info *sf, void **ra_lst,
+	       int *ra_size, int *errp)
+{
+  uint64_t cfa, return_addr, ra_stack_loc, rfp_stack_loc;
+  sframe_decoder_ctx *ctx;
+  int cfa_offset, rfp_offset, errnum, i, count;
+  sframe_frame_row_entry fred, *frep = &fred;
+  uint64_t pc, rfp, rsp, cfi_vma;
+  ucontext_t context, *cp = &context;
+
+  if (sf == NULL || ra_lst == NULL || ra_size == NULL)
+    {
+      sframe_bt_set_errno (errp, SFRAME_BT_ERR_ARG);
+      return;
+    }
+
+  /* Get the user context for its registers.  */
+  if (getcontext (cp) != 0)
+    {
+      sframe_bt_set_errno (errp, SFRAME_BT_ERR_GETCONTEXT);
+      return;
+    }
+  sframe_bt_set_errno (errp, SFRAME_BT_OK);
+
+#ifdef __x86_64__
+  pc = cp->uc_mcontext.gregs[REG_RIP];
+  rsp = cp->uc_mcontext.gregs[REG_RSP];
+  rfp = cp->uc_mcontext.gregs[REG_RBP];
+#else
+#ifdef __aarch64__
+#define UNWIND_AARCH64_X29		29	/* 64-bit frame pointer.  */
+#define UNWIND_AARCH64_X30		30	/* 64-bit link pointer.  */
+  pc = cp->uc_mcontext.pc;
+  rsp = cp->uc_mcontext.sp;
+  rfp = cp->uc_mcontext.regs[UNWIND_AARCH64_X29];
+  uint64_t ra = cp->uc_mcontext.regs[UNWIND_AARCH64_X30];
+#endif
+#endif
+
+  /* Load and set up the decoder.  */
+  ctx = sframe_load_ctx (sf, pc);
+  if (ctx == NULL)
+    {
+      sframe_bt_set_errno (errp, SFRAME_BT_ERR_DECODE);
+      return;
+    }
+  cfi_vma = sf->sui_ctx.sfdd_sframe_vma;
+  count = *ra_size;
+
+  for (i = 0; i < count; ++i)
+    {
+      pc -= cfi_vma;
+      errnum = sframe_find_fre (ctx, pc, frep);
+      if (errnum == 0)
+	{
+	  cfa_offset = sframe_fre_get_cfa_offset (frep, &errnum);
+	  if (errnum == ESFRAME_FREOFFSET_NOPRESENT)
+	    {
+	      sframe_bt_set_errno (errp, SFRAME_BT_ERR_CFA_OFFSET);
+	      return;
+	    }
+
+	  cfa = ((frep->fre_info & 0x1) == SFRAME_BASE_REG_SP
+	    ? rsp : rfp) + cfa_offset;
+
+#ifdef __x86_64__
+	  /* For x86, read the return address from cfa - 8.  */
+	  ra_stack_loc = cfa - 8;
+	  return_addr = get_contents (sf->sui_fd, ra_stack_loc, errp);
+	  if (sframe_bt_errno (errp))
+	    return;
+#else
+#ifdef __aarch64__
+	  int ra_offset = sframe_fre_get_ra_offset (frep, &errnum);
+	  if (errnum == 0)
+	    {
+	      ra_stack_loc = cfa + ra_offset;
+	      return_addr = get_contents (sf->sui_fd, ra_stack_loc, errp);
+	      if (sframe_bt_errno (errp))
+		return;
+	    }
+	  else
+	    return_addr = ra;
+#endif
+#endif
+
+	  /* Validate and add return address to the list.  */
+	  if (sframe_valid_addr (sf, return_addr) == 0)
+	    {
+	      i -= 1;
+	      goto find_fre_ra_err;
+	    }
+	  if (i != 0)		/* exclude self.  */
+	    ra_lst[i-1] = (void *)return_addr;
+
+	  /* Set up for the next frame.  */
+	  rfp_offset = sframe_fre_get_fp_offset (frep, &errnum);
+	  if (errnum == 0)
+	    {
+	      rfp_stack_loc = cfa + rfp_offset;
+	      rfp = get_contents (sf->sui_fd, rfp_stack_loc, errp);
+	      if (sframe_bt_errno (errp))
+		return;
+	    }
+	  rsp = cfa;
+	  pc = return_addr;
+
+	  /* Check if need to update the decoder context and vma.  */
+	  sframe_update_ctx (sf, return_addr, &ctx, &cfi_vma);
+	  if (ctx == NULL)
+	    {
+	      sframe_bt_set_errno (errp, SFRAME_BT_ERR_DECODE);
+	      return;
+	    }
+	}
+      else
+	{
+	  i -= 1;
+	  goto find_fre_ra_err;
+	}
+    }
+
+find_fre_ra_err:
+  *ra_size = i;
+}
+
+/* sframe_backtrace - Main API that user program calls to get a backtrace.
+   The BUFFER argument provides space for the list of the return addresses
+   and the SIZE argument specifies the maximum number of addresses that
+   can be stored in the buffer.  Return the number of return addresses
+   collected or -1 if there is any error.  */
+
+int
+sframe_backtrace (void **buffer, int size, int *errp)
+{
+  struct sframe_unwind_info sframeinfo;
+
+  sframe_unwind_init_debug ();
+
+  memset (&sframeinfo, 0, sizeof (struct sframe_unwind_info));
+
+  /* find and set up the .sframe sections.  */
+  (void) dl_iterate_phdr (sframe_callback, (void *)&sframeinfo);
+  if (sframeinfo.sui_fd == 0)
+    {
+      sframe_bt_set_errno (errp, SFRAME_BT_ERR_NOTPRESENT);
+      return -1;
+    }
+
+  /* Do the stack unwinding.  */
+  sframe_unwind (&sframeinfo, buffer, &size, errp);
+  if (sframe_bt_errno (errp))
+    return -1;
+
+  sframe_free_cfi (&sframeinfo);
+
+  return size;
+}
diff --git a/libsframe/testsuite/Makefile.in b/libsframe/testsuite/Makefile.in
index f97c4330eb7..b89a4a4d052 100644
--- a/libsframe/testsuite/Makefile.in
+++ b/libsframe/testsuite/Makefile.in
@@ -95,6 +95,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/jobserver.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/sframe.m4 \
 	$(top_srcdir)/../config/warnings.m4 \
 	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
 	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
diff --git a/libsframe/testsuite/libsframe.decode/Makefile.in b/libsframe/testsuite/libsframe.decode/Makefile.in
index f4a1e43c374..210d9ae6856 100644
--- a/libsframe/testsuite/libsframe.decode/Makefile.in
+++ b/libsframe/testsuite/libsframe.decode/Makefile.in
@@ -97,6 +97,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/jobserver.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/sframe.m4 \
 	$(top_srcdir)/../config/warnings.m4 \
 	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
 	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
diff --git a/libsframe/testsuite/libsframe.encode/Makefile.in b/libsframe/testsuite/libsframe.encode/Makefile.in
index 678a9ce9b43..f72a378263d 100644
--- a/libsframe/testsuite/libsframe.encode/Makefile.in
+++ b/libsframe/testsuite/libsframe.encode/Makefile.in
@@ -96,6 +96,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \
 	$(top_srcdir)/../config/jobserver.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/sframe.m4 \
 	$(top_srcdir)/../config/warnings.m4 \
 	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
 	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 09/14] unwinder: Add SFrame unwinder tests
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (7 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 08/14] unwinder: generate backtrace using SFrame format Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 10/14] gdb: sim: buildsystem changes to accommodate libsframe Indu Bhagat
                       ` (7 subsequent siblings)
  16 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan

From: Weimin Pan <weimin.pan@oracle.com>

Add tests for backtracing using SFrame section.

PS: libsframe/configure has NOT been included in the patch.  Please
regenerate.

ChangeLog:

	* libsframe/Makefile.in: Regenerated.
	* libsframe/configure: Regenerated.  <-- [REMOVED FROM THE
	PATCH.  PLEASE REGENERATE]
	* libsframe/configure.ac: Check for cross compilation.
	* libsframe/testsuite/Makefile.in: Regenerated.
	* libsframe/testsuite/config/default.exp: Load
	  sframe-lib.exp.
	* libsframe/testsuite/libsframe.decode/Makefile.in:
	  Regenerated.
	* libsframe/testsuite/libsframe.encode/Makefile.in:
	  Regenerated.
	* libsframe/testsuite/lib/sframe-lib.exp: New file.  Add
	  procedures for handling unwinder tests.
	* libsframe/testsuite/libsframe.unwind/backtrace.c: New test.
	* libsframe/testsuite/libsframe.unwind/backtrace.lk: New test.
	* libsframe/testsuite/libsframe.unwind/inline-cmds.c: New test.
	* libsframe/testsuite/libsframe.unwind/inline-cmds.lk: New test.
	* libsframe/testsuite/libsframe.unwind/inline.c: New test.
	* libsframe/testsuite/libsframe.unwind/inline.lk: New test.
	* libsframe/testsuite/libsframe.unwind/solib-lib1.c: New test.
	* libsframe/testsuite/libsframe.unwind/solib-lib2.c: New test.
	* libsframe/testsuite/libsframe.unwind/solib-main.c: New test.
	* libsframe/testsuite/libsframe.unwind/solib-main.d: New test.
	* libsframe/testsuite/libsframe.unwind/solib.exp: New file.
	* libsframe/testsuite/libsframe.unwind/solib_lib1.h: New test.
	* libsframe/testsuite/libsframe.unwind/solib_lib2.h: New test.
	* libsframe/testsuite/libsframe.unwind/tailcall.c: New test.
	* libsframe/testsuite/libsframe.unwind/tailcall.lk: New test.
	* libsframe/testsuite/libsframe.unwind/ttest.c: New test.
	* libsframe/testsuite/libsframe.unwind/ttest.lk: New test.
	* libsframe/testsuite/libsframe.unwind/unwind.exp: New file.
---
 libsframe/Makefile.in                         |   1 +
 libsframe/configure.ac                        |  12 ++
 libsframe/testsuite/Makefile.in               |   1 +
 libsframe/testsuite/config/default.exp        |   3 +
 libsframe/testsuite/lib/sframe-lib.exp        | 180 ++++++++++++++++
 .../testsuite/libsframe.decode/Makefile.in    |   1 +
 .../testsuite/libsframe.encode/Makefile.in    |   1 +
 .../testsuite/libsframe.unwind/backtrace.c    | 145 +++++++++++++
 .../testsuite/libsframe.unwind/backtrace.lk   |   3 +
 .../testsuite/libsframe.unwind/inline-cmds.c  | 136 ++++++++++++
 .../testsuite/libsframe.unwind/inline-cmds.lk |   3 +
 libsframe/testsuite/libsframe.unwind/inline.c |  97 +++++++++
 .../testsuite/libsframe.unwind/inline.lk      |   3 +
 .../testsuite/libsframe.unwind/solib-lib1.c   |   8 +
 .../testsuite/libsframe.unwind/solib-lib2.c   |  51 +++++
 .../testsuite/libsframe.unwind/solib-main.c   |  47 ++++
 .../testsuite/libsframe.unwind/solib-main.d   |   3 +
 .../testsuite/libsframe.unwind/solib.exp      |  75 +++++++
 .../testsuite/libsframe.unwind/solib_lib1.h   |   3 +
 .../testsuite/libsframe.unwind/solib_lib2.h   |   3 +
 .../testsuite/libsframe.unwind/tailcall.c     | 103 +++++++++
 .../testsuite/libsframe.unwind/tailcall.lk    |   3 +
 libsframe/testsuite/libsframe.unwind/ttest.c  | 127 +++++++++++
 libsframe/testsuite/libsframe.unwind/ttest.lk |   3 +
 .../testsuite/libsframe.unwind/unwind.exp     | 200 ++++++++++++++++++
 25 files changed, 1212 insertions(+)
 create mode 100644 libsframe/testsuite/lib/sframe-lib.exp
 create mode 100644 libsframe/testsuite/libsframe.unwind/backtrace.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/backtrace.lk
 create mode 100644 libsframe/testsuite/libsframe.unwind/inline-cmds.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/inline-cmds.lk
 create mode 100644 libsframe/testsuite/libsframe.unwind/inline.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/inline.lk
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib-lib1.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib-lib2.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib-main.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib-main.d
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib.exp
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib_lib1.h
 create mode 100644 libsframe/testsuite/libsframe.unwind/solib_lib2.h
 create mode 100644 libsframe/testsuite/libsframe.unwind/tailcall.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/tailcall.lk
 create mode 100644 libsframe/testsuite/libsframe.unwind/ttest.c
 create mode 100644 libsframe/testsuite/libsframe.unwind/ttest.lk
 create mode 100644 libsframe/testsuite/libsframe.unwind/unwind.exp

diff --git a/libsframe/Makefile.in b/libsframe/Makefile.in
index f5c32b7c9b9..c803340ca7b 100644
--- a/libsframe/Makefile.in
+++ b/libsframe/Makefile.in
@@ -331,6 +331,7 @@ CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CROSS_COMPILE = @CROSS_COMPILE@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
diff --git a/libsframe/configure.ac b/libsframe/configure.ac
index 82fafee5068..9f54b9a4cf3 100644
--- a/libsframe/configure.ac
+++ b/libsframe/configure.ac
@@ -57,6 +57,18 @@ ACX_PROG_CC_WARNING_ALMOST_PEDANTIC([-Wno-long-long])
 # corrected.
 ACX_PROG_CC_WARNINGS_ARE_ERRORS([manual])
 
+# Determine if we are cross compiling
+AC_CANONICAL_HOST
+is_cross_compiler=
+if test x"${host}" = x"${target}" ; then
+  is_cross_compiler=no
+else
+  is_cross_compiler=yes
+fi
+CROSS_COMPILE=$is_cross_compiler
+AC_SUBST([CROSS_COMPILE])
+
+
 dnl The libsframebt library needs to be built with SFrame info.
 dnl If the build assembler is not capable of generate SFrame then
 dnl the library is not built.
diff --git a/libsframe/testsuite/Makefile.in b/libsframe/testsuite/Makefile.in
index b89a4a4d052..376f39db38a 100644
--- a/libsframe/testsuite/Makefile.in
+++ b/libsframe/testsuite/Makefile.in
@@ -204,6 +204,7 @@ CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CROSS_COMPILE = @CROSS_COMPILE@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
diff --git a/libsframe/testsuite/config/default.exp b/libsframe/testsuite/config/default.exp
index c45e25d3357..29dacbc2917 100644
--- a/libsframe/testsuite/config/default.exp
+++ b/libsframe/testsuite/config/default.exp
@@ -52,3 +52,6 @@ if {![info exists CFLAGS]} {
 if {![info exists CFLAGS_FOR_TARGET]} {
     set CFLAGS_FOR_TARGET $CFLAGS
 }
+
+# load the utility procedures
+load_lib sframe-lib.exp
diff --git a/libsframe/testsuite/lib/sframe-lib.exp b/libsframe/testsuite/lib/sframe-lib.exp
new file mode 100644
index 00000000000..1f29afa7735
--- /dev/null
+++ b/libsframe/testsuite/lib/sframe-lib.exp
@@ -0,0 +1,180 @@
+# Support routines for libsframe testsuite.
+#   Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This file 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+load_file $srcdir/../../ld/testsuite/lib/ld-lib.exp
+
+set unwind_test_file_name ""
+
+proc run_native_host_cmd { command } {
+    global link_output
+    global ld
+
+    verbose -log "$command"
+    set run_output ""
+    try {
+	set run_output [exec "sh" "-c" "$command" "2>@1"]
+	set status 0
+    } trap CHILDSTATUS {results options} {
+	set status [lindex [dict get $options -errorcode] 2]
+	set run_output $results
+    }
+    regsub "\n$" $run_output "" run_output
+    if { [lindex $status 0] != 0 && [string match "" $run_output] } then {
+	append run_output "child process exited abnormally"
+    }
+
+    if [string match "" $run_output] then {
+	return ""
+    }
+
+    verbose -log "$run_output"
+    return "$run_output"
+}
+
+# Compile and link a C source file for execution on the host.
+proc compile_link_one_host_cc { src output additional_args } {
+    global CC
+    global CFLAGS
+
+    return [run_native_host_cmd "../libtool --quiet --tag=CC --mode=link $CC $CFLAGS $src -o $output $additional_args" ]
+}
+
+proc make_unwind_parallel_path { args } {
+    global objdir
+    set joiner [list "file" "join" $objdir]
+    set joiner [concat $joiner $args]
+    return [eval $joiner]
+}
+
+proc standard_output_file {basename} {
+    global objdir subdir unwind_test_file_name
+
+    set dir [make_unwind_parallel_path outputs $subdir $unwind_test_file_name]
+    file mkdir $dir
+    return [file join $dir $basename]
+}
+
+proc standard_testfile {args} {
+    global unwind_test_file_name
+    global subdir
+    global unwind_test_file_last_vars
+
+    # Outputs.
+    global testfile binfile
+
+    set testfile $unwind_test_file_name
+    set binfile [standard_output_file ${testfile}]
+
+    if {[llength $args] == 0} {
+	set args .c
+    }
+
+    # Unset our previous output variables.
+    # This can help catch hidden bugs.
+    if {[info exists unwind_test_file_last_vars]} {
+	foreach varname $unwind_test_file_last_vars {
+	    global $varname
+	    catch {unset $varname}
+	}
+    }
+    # 'executable' is often set by tests.
+    set unwind_test_file_last_vars {executable}
+
+    set suffix ""
+    foreach arg $args {
+	set varname srcfile$suffix
+	global $varname
+
+	# Handle an extension.
+	if {$arg == ""} {
+	    set arg $testfile.c
+	} else {
+	    set first [string range $arg 0 0]
+	    if { $first == "." || $first == "-" } {
+		set arg $testfile$arg
+	    }
+	}
+
+	set $varname $arg
+	lappend unwind_test_file_last_vars $varname
+
+	if {$suffix == ""} {
+	    set suffix 2
+	} else {
+	    incr suffix
+	}
+    }
+}
+
+# Build a shared object DEST from SOURCES.
+proc unwind_compile_so {sources dest} {
+    global CFLAGS
+    set obj_options $CFLAGS
+    lappend obj_options "additional_flags=-fPIC -Wa,--gsframe"
+
+    set outdir [file dirname $dest]
+    set objects ""
+    foreach source $sources {
+	set sourcebase [file tail $source]
+	set object ${outdir}/${sourcebase}.o
+
+	if {[target_compile $source $object object \
+		  $obj_options] != ""} {
+	    return -1
+	}
+
+	lappend objects $object
+    }
+
+    set link_options "additional_flags=-shared"
+
+    set destbase [file tail $dest]
+    lappend link_options "additional_flags=-Wl,-soname,$destbase"
+
+    if {[target_compile "${objects}" "${dest}" executable $link_options] != ""} {
+	catch "exec rm ${objects}" status
+	return -1
+    }
+    catch "exec rm ${objects}" status
+    return ""
+}
+
+# Build a binary of TYPE from SOURCE at path DEST.
+proc unwind_compile {source dest type options} {
+    set new_options ""
+
+    foreach opt $options {
+	if {[regexp {^shlib=(.*)} $opt dummy_var shlib_name]
+	    && $type == "executable"} {
+	    lappend source "-Wl,$shlib_name"
+	} else {
+	    lappend new_options $opt
+	}
+    }
+    set options $new_options
+
+    verbose "options are $options"
+    verbose "source is $source $dest $type $options"
+
+    lappend options "additional_flags=-rdynamic -Wa,--gsframe ./../.libs/libsframebt.a ./../.libs/libsframe.a"
+    set result [target_compile $source $dest $type $options]
+
+    return $result
+}
diff --git a/libsframe/testsuite/libsframe.decode/Makefile.in b/libsframe/testsuite/libsframe.decode/Makefile.in
index 210d9ae6856..fa3b558eb91 100644
--- a/libsframe/testsuite/libsframe.decode/Makefile.in
+++ b/libsframe/testsuite/libsframe.decode/Makefile.in
@@ -200,6 +200,7 @@ CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CROSS_COMPILE = @CROSS_COMPILE@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
diff --git a/libsframe/testsuite/libsframe.encode/Makefile.in b/libsframe/testsuite/libsframe.encode/Makefile.in
index f72a378263d..f51045e2ecc 100644
--- a/libsframe/testsuite/libsframe.encode/Makefile.in
+++ b/libsframe/testsuite/libsframe.encode/Makefile.in
@@ -191,6 +191,7 @@ CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CROSS_COMPILE = @CROSS_COMPILE@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
diff --git a/libsframe/testsuite/libsframe.unwind/backtrace.c b/libsframe/testsuite/libsframe.unwind/backtrace.c
new file mode 100644
index 00000000000..072cb2f8f08
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/backtrace.c
@@ -0,0 +1,145 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* This is a revised version of gdb/testsuite/gdb.base/backtrace.c.  */
+
+#ifdef __has_attribute
+# if !__has_attribute (noclone)
+#  define ATTRIBUTE_NOCLONE
+# endif
+#endif
+#ifndef ATTRIBUTE_NOCLONE
+# define ATTRIBUTE_NOCLONE __attribute__((noclone))
+#endif
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "sframe-backtrace-api.h"
+
+#define BT_BUF_SIZE 100
+
+/* Expected funclist.  */
+static const char *const func_list[] =
+{
+  "show_bt",
+  "baz",
+  "bar",
+  "foo",
+  "main"
+};
+
+void __attribute__((__noinline__,__noclone__))
+show_bt ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int j, nptrs, err;
+  char **strings;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs != 5)
+    {
+      printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  /* Get these addresses symbolically.  */
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL) {
+      perror("backtrace_symbols");
+      exit(EXIT_FAILURE);
+  }
+
+  /* Verify the results.  */
+  for (j = 0; j < nptrs; j++)
+    if (!strstr (strings[j], func_list[j]))
+      break;
+
+  free(strings);
+
+  printf ("%s: backtrace test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+int __attribute__((__noinline__,__noclone__))
+baz ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+      return -1;
+    }
+
+  show_bt ();
+  return 0;
+}
+
+int __attribute__((__noinline__,__noclone__))
+bar ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+      return -1;
+    }
+
+  return baz ();
+}
+
+int __attribute__((__noinline__,__noclone__))
+foo ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+      return -1;
+    }
+
+  return bar ();
+}
+
+int __attribute__((__noinline__,__noclone__))
+main ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+      return -1;
+    }
+
+  return foo ();
+}
diff --git a/libsframe/testsuite/libsframe.unwind/backtrace.lk b/libsframe/testsuite/libsframe.unwind/backtrace.lk
new file mode 100644
index 00000000000..fdc78ebe34d
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/backtrace.lk
@@ -0,0 +1,3 @@
+# source: backtrace.c
+# link: on
+PASS: backtrace test
diff --git a/libsframe/testsuite/libsframe.unwind/inline-cmds.c b/libsframe/testsuite/libsframe.unwind/inline-cmds.c
new file mode 100644
index 00000000000..a6ceb50a956
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/inline-cmds.c
@@ -0,0 +1,136 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* This is only ever run if it is compiled with a new-enough GCC, but
+   we don't want the compilation to fail if compiled by some other
+   compiler.  */
+
+/* This is a revised version of gdb/testsuite/gdb.opt/inline-cmds.c.  */
+
+#ifdef __GNUC__
+#define ATTR __attribute__((always_inline))
+#else
+#define ATTR
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <execinfo.h>
+#include "sframe-backtrace-api.h"
+
+#define BT_BUF_SIZE 10
+
+int x, y;
+volatile int z = 0;
+volatile int result;
+
+void bar(void);
+void marker(void);
+void noinline(void);
+
+inline ATTR int func1(void)
+{
+  bar ();
+  return x * y;
+}
+
+inline ATTR int func2(void)
+{
+  return x * func1 ();
+}
+
+inline ATTR void func3(void)
+{
+  bar ();
+}
+
+inline ATTR void outer_inline1(void)
+{
+  noinline ();
+}
+
+inline ATTR void outer_inline2(void)
+{
+  outer_inline1 ();
+}
+
+int main (void)
+{ /* start of main */
+  int val;
+
+  x = 7;
+  y = 8;
+
+  outer_inline2 ();
+
+  return 0;
+}
+
+
+/* funclist for inline-cmds.  */
+const char *const func_list[] =
+{
+  "noinline",
+  "main"
+};
+
+void bar(void)
+{
+  x += y;
+}
+
+void marker(void)
+{
+  x += y - z;
+}
+
+inline ATTR void inlined_fn(void)
+{
+  x += y + z;
+
+  void *buffer[BT_BUF_SIZE];
+  char **strings;
+  /* Call the unwinder to get an array of return addresses.  */
+  int j, err;
+  int nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1 || nptrs != 2)
+    {
+      printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  /* Get these addresses symbolically.  */
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL)
+    {
+      perror("backtrace_symbols");
+      exit(EXIT_FAILURE);
+    }
+
+  /* Verify the results.  */
+  for (j = 0; j < nptrs; j++)
+    if (!strstr (strings[j], func_list[j]))
+      break;
+
+    free(strings);
+    printf ("%s: inline-cmds test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+void noinline(void)
+{
+  inlined_fn (); /* inlined */
+}
diff --git a/libsframe/testsuite/libsframe.unwind/inline-cmds.lk b/libsframe/testsuite/libsframe.unwind/inline-cmds.lk
new file mode 100644
index 00000000000..053b66bd683
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/inline-cmds.lk
@@ -0,0 +1,3 @@
+# source: inline-cmds.c
+# link: on
+PASS: inline-cmds test
diff --git a/libsframe/testsuite/libsframe.unwind/inline.c b/libsframe/testsuite/libsframe.unwind/inline.c
new file mode 100644
index 00000000000..86c93136b9a
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/inline.c
@@ -0,0 +1,97 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* This is a revised version of gdb/testsuite/gdb.opt/inline-bt.c.  */
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "sframe-backtrace-api.h"
+
+#define ATTR __attribute__((always_inline))
+
+#define BT_BUF_SIZE 32
+
+int x, y;
+volatile int z = 0;
+volatile int result;
+
+/* funclist.  */
+const char *const flist[] =
+{
+  "main"
+};
+
+void bar(void)
+{
+  x += y;
+}
+
+inline ATTR int func1(void)
+{
+  bar ();
+  return x * y;
+}
+
+inline ATTR int func2(void)
+{
+  void *buffer[BT_BUF_SIZE];
+  int ok = 0, nptrs, err;
+  char **strings;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("SFrame error: %s\n", sframe_bt_errmsg (err));
+      return -1;
+    }
+
+  /* Get these addresses symbolically.  */
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL) {
+      perror("backtrace_symbols");
+      exit(EXIT_FAILURE);
+  }
+
+  /* Verify the results.  */
+  if (nptrs == 1 && strstr (strings[0], flist[0]))
+    ok = 1;
+
+  free(strings);
+
+  printf ("%s: unwind test\n", ok == 1 ? "PASS" : "FAIL");
+
+  return x * func1 ();
+}
+
+int main (void)
+{
+  int val;
+
+  x = 7;
+  y = 8;
+  bar ();
+
+  val = func1 ();
+  result = val;
+
+  val = func2 ();
+  result = val;
+
+  return 0;
+}
diff --git a/libsframe/testsuite/libsframe.unwind/inline.lk b/libsframe/testsuite/libsframe.unwind/inline.lk
new file mode 100644
index 00000000000..88f846b0fce
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/inline.lk
@@ -0,0 +1,3 @@
+# source: inline.c
+# link: on
+PASS: unwind test
diff --git a/libsframe/testsuite/libsframe.unwind/solib-lib1.c b/libsframe/testsuite/libsframe.unwind/solib-lib1.c
new file mode 100644
index 00000000000..f4eebf927d9
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib-lib1.c
@@ -0,0 +1,8 @@
+#include "solib_lib1.h"
+
+unsigned int
+adder(unsigned int a, unsigned int b, int (*call)(int))
+{
+  (void)(*call)(a+b);
+  return (a+b);
+}
diff --git a/libsframe/testsuite/libsframe.unwind/solib-lib2.c b/libsframe/testsuite/libsframe.unwind/solib-lib2.c
new file mode 100644
index 00000000000..aea949c0d08
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib-lib2.c
@@ -0,0 +1,51 @@
+#include <execinfo.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sframe-backtrace-api.h"
+#include "solib_lib2.h"
+
+#define BT_BUF_SIZE 100
+
+/* funclist for running "ttest.x 3".  */
+static const char *const bt_list[] =
+{
+  "adder2",
+  "bar",
+  "adder",
+  "main"
+};
+
+unsigned int
+adder2 (unsigned int a, unsigned int b, int (*call)(int))
+{
+  void *buffer[BT_BUF_SIZE];
+  int i, nptrs, err;
+  char **strings;
+
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1 || nptrs != 4)
+    {
+/* printf ("bcktrace failed: %d %d\n", nptrs, err); */
+      printf ("SFrame error: %s\n", sframe_bt_errmsg (err));
+      return(-1);
+    }
+
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL)
+    {
+       perror("backtrace_symbols");
+       return(-1);
+    }
+
+  /* Verify the results.  */
+  for (i = 0; i < nptrs; i++)
+    if (!strstr (strings[i], bt_list[i]))
+      break;
+
+  free (strings);
+
+  printf ("%s: unwind solib test\n", i == nptrs ? "PASS" : "FAIL");
+
+  (void)(*call) (a+b);
+  return (a+b);
+}
diff --git a/libsframe/testsuite/libsframe.unwind/solib-main.c b/libsframe/testsuite/libsframe.unwind/solib-main.c
new file mode 100644
index 00000000000..4161f13d652
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib-main.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "sframe-backtrace-api.h"
+#include "solib_lib1.h"
+#include "solib_lib2.h"
+
+#define BT_BUF_SIZE 100
+
+int foo (int x)
+{
+  return ++x;
+}
+
+int bar (int x)
+{
+  x = adder2 (x, x+1, foo);
+
+  return ++x;
+}
+
+int main (void)
+{
+  unsigned int a = 1;
+  unsigned int b = 2;
+  unsigned int result = 0;
+
+  result = adder (a,b, bar);
+
+  return 0;
+}
diff --git a/libsframe/testsuite/libsframe.unwind/solib-main.d b/libsframe/testsuite/libsframe.unwind/solib-main.d
new file mode 100644
index 00000000000..483ded5a1e5
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib-main.d
@@ -0,0 +1,3 @@
+# source: solib-main.c
+# link: on
+PASS: unwind solib test
diff --git a/libsframe/testsuite/libsframe.unwind/solib.exp b/libsframe/testsuite/libsframe.unwind/solib.exp
new file mode 100644
index 00000000000..267452c58ad
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib.exp
@@ -0,0 +1,75 @@
+# Copyright 2022 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Run the test only if sframebt library exists.
+if [catch "exec ls $objdir/../.libs/libsframebt.la" status] then {
+  return;
+}
+
+# Run the tests only if we are not cross compiling.
+if [string equal $CROSS_COMPILE "yes"] {
+    return;
+}
+
+set experimental ""
+
+# Shared object files.
+set libname1 "solib-lib1"
+set srcfile_lib1 ${srcdir}/${subdir}/${libname1}.c
+set binfile_lib1 ${objdir}/${libname1}.so
+set libname2 "solib-lib2"
+set srcfile_lib2 ${srcdir}/${subdir}/${libname2}.c
+set binfile_lib2 ${objdir}/${libname2}.so
+
+# Binary file.
+set testfile "solib-main"
+set srcfile ${srcdir}/${subdir}/${testfile}.c
+set binfile [standard_output_file ${testfile}]
+set bin_flags [list debug shlib=${binfile_lib1} shlib=${binfile_lib2}]
+
+if { [unwind_compile_so ${srcfile_lib1} ${binfile_lib1}] != ""
+     || [unwind_compile_so ${srcfile_lib2} ${binfile_lib2}] != ""
+     || [unwind_compile ${srcfile} ${binfile} executable $bin_flags] != "" } {
+    untested "failed to compile"
+    return -1
+}
+
+if {[info exists env(LD_LIBRARY_PATH)]} {
+    set old_ld_lib $env(LD_LIBRARY_PATH)
+}
+set env(LD_LIBRARY_PATH) "${objdir}"
+
+set solib_output "${binfile} ${binfile_lib1} ${binfile_lib2}"
+set results [run_host_cmd ${binfile} $solib_output]
+
+set f [open "tmpdir/solib.out" "w"]
+puts $f $results
+close $f
+
+if { [regexp_diff "tmpdir/solib.out" "${srcdir}/${subdir}/${testfile}.d"] } then {
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
+
+catch "exec rm ${binfile_lib1}" status
+catch "exec rm ${binfile_lib2}" status
+catch "exec rm tmpdir/solib.out" status
+
+if {[info exists old_ld_lib]} {
+    set env(LD_LIBRARY_PATH) $old_ld_lib
+} else {
+    unset env(LD_LIBRARY_PATH)
+}
diff --git a/libsframe/testsuite/libsframe.unwind/solib_lib1.h b/libsframe/testsuite/libsframe.unwind/solib_lib1.h
new file mode 100644
index 00000000000..d40eac0769c
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib_lib1.h
@@ -0,0 +1,3 @@
+#include<stdio.h>
+
+extern unsigned int adder(unsigned int a, unsigned int b, int (*call)(int));
diff --git a/libsframe/testsuite/libsframe.unwind/solib_lib2.h b/libsframe/testsuite/libsframe.unwind/solib_lib2.h
new file mode 100644
index 00000000000..61b72122771
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib_lib2.h
@@ -0,0 +1,3 @@
+#include<stdio.h>
+
+extern unsigned int adder2(unsigned int a, unsigned int b, int (*call)(int));
diff --git a/libsframe/testsuite/libsframe.unwind/tailcall.c b/libsframe/testsuite/libsframe.unwind/tailcall.c
new file mode 100644
index 00000000000..7ffa728a27e
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/tailcall.c
@@ -0,0 +1,103 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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 <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "sframe-backtrace-api.h"
+
+#ifdef __has_attribute
+# if !__has_attribute (noclone)
+#  define ATTRIBUTE_NOCLONE
+# endif
+#endif
+#ifndef ATTRIBUTE_NOCLONE
+# define ATTRIBUTE_NOCLONE __attribute__((noclone))
+#endif
+
+#define BT_BUF_SIZE 16
+
+/* funclist for running tailcall.  */
+const char *const func_list[] =
+{
+  "show_bt",
+  "dec",
+  "dec",
+  "main"
+};
+
+void show_bt ()
+{
+  void *buffer[BT_BUF_SIZE];
+  int j, nptrs, err;
+  char **strings;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1 || nptrs != 4)
+    {
+      printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  /* Get these addresses symbolically.  */
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL) {
+      perror("backtrace_symbols");
+      exit(EXIT_FAILURE);
+  }
+
+  /* Verify the results.  */
+  for (j = 0; j < nptrs; j++)
+    if (!strstr (strings[j], func_list[j]))
+      break;
+
+  free(strings);
+
+  printf ("%s: tailcall test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+/* An example of tail recursive function.  */
+void __attribute__((__noinline__,__noclone__))
+dec (int n)
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  if (n < 0)
+     return;
+
+  if (n == 2)
+    show_bt ();
+
+  /* The last executed statement is recursive call.  */
+  dec (n-1);
+}
+
+int
+main (void)
+{
+  dec (3);
+}
diff --git a/libsframe/testsuite/libsframe.unwind/tailcall.lk b/libsframe/testsuite/libsframe.unwind/tailcall.lk
new file mode 100644
index 00000000000..3d7ab98ddba
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/tailcall.lk
@@ -0,0 +1,3 @@
+# source: tailcall.c
+# link: on
+PASS: tailcall test
diff --git a/libsframe/testsuite/libsframe.unwind/ttest.c b/libsframe/testsuite/libsframe.unwind/ttest.c
new file mode 100644
index 00000000000..5e245db93c9
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/ttest.c
@@ -0,0 +1,127 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* This is the revised version of the example in "man backtrace".  */
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "sframe-backtrace-api.h"
+
+#ifdef __has_attribute
+# if !__has_attribute (noclone)
+#  define ATTRIBUTE_NOCLONE
+# endif
+#endif
+#ifndef ATTRIBUTE_NOCLONE
+# define ATTRIBUTE_NOCLONE __attribute__((noclone))
+#endif
+
+#define BT_BUF_SIZE 100
+
+/* funclist  */
+static const char *const func_list[] =
+{
+  "myfunc3",
+  "()",
+  "myfunc",
+  "myfunc",
+  "myfunc",
+  "main"
+};
+
+void myfunc3 (void)
+{
+  void *buffer[BT_BUF_SIZE];
+  int j, nptrs, err;
+  char **strings;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1 || nptrs != 6)
+    {
+      printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  /* Get these addresses symbolically.  */
+  strings = backtrace_symbols (buffer, nptrs);
+  if (strings == NULL) {
+    perror("backtrace_symbols");
+    exit(EXIT_FAILURE);
+  }
+
+  /* Verify the results.  */
+  for (j = 0; j < nptrs; j++)
+    if (!strstr (strings[j], func_list[j]))
+      break;
+
+  free(strings);
+
+  printf ("%s: unwind test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+static void __attribute__((__noinline__,__noclone__))
+/* "static" means don't export the symbol.  */
+myfunc2 (void)
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  myfunc3 ();
+}
+
+void __attribute__((__noinline__,__noclone__))
+myfunc (int ncalls)
+{
+  void *buffer[BT_BUF_SIZE];
+  int nptrs, err;
+
+  /* Call the unwinder to get an array of return addresses.  */
+  nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+  if (nptrs == -1)
+    {
+      printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+      return;
+    }
+
+  if (ncalls > 1)
+    myfunc (ncalls - 1);
+  else
+    myfunc2 ();
+}
+
+int
+main (int argc, char *argv[])
+{
+  int cnt;
+  if (argc != 2) {
+    cnt = 3;
+  }
+  else
+    cnt = atoi(argv[1]);
+  myfunc (cnt);
+  exit (EXIT_SUCCESS);
+}
diff --git a/libsframe/testsuite/libsframe.unwind/ttest.lk b/libsframe/testsuite/libsframe.unwind/ttest.lk
new file mode 100644
index 00000000000..80aa2241402
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/ttest.lk
@@ -0,0 +1,3 @@
+# source: ttest.c
+# link: on
+PASS: unwind test
diff --git a/libsframe/testsuite/libsframe.unwind/unwind.exp b/libsframe/testsuite/libsframe.unwind/unwind.exp
new file mode 100644
index 00000000000..0c047fad06c
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/unwind.exp
@@ -0,0 +1,200 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+# Run the tests only if sframebt library exists.
+
+if [catch "exec ls $objdir/../.libs/libsframebt.la" status] then {
+  verbose -log "$objdir/../.libs/libsframebt.la not found.";
+  verbose -log "Skipping SFrame unwind tests";
+  return;
+}
+
+# Run the tests only if we are not cross compiling.
+if [string equal $CROSS_COMPILE "yes"] {
+    return;
+}
+
+if {[info exists env(LC_ALL)]} {
+    set old_lc_all $env(LC_ALL)
+}
+set env(LC_ALL) "C"
+
+proc run_unwind_test { name } {
+    global CC
+    global CFLAGS
+    global copyfile env runtests srcdir subdir verbose
+
+    # Append additional flags for unwinder to work properly
+    set unwind_cflags "-Wa,--gsframe -rdynamic"
+
+    if ![runtest_file_p $runtests $name] then {
+	return
+    }
+
+    if [string match "*/*" $name] {
+	set file $name
+	set name [file tail $name]
+    } else {
+	set file "$srcdir/$subdir/$name"
+    }
+
+    set opt_array [slurp_options "${file}.lk"]
+    if { $opt_array == -1 } {
+	perror "error reading options from $file.lk"
+	unresolved $subdir/$name
+	return
+    }
+    set run_ld 0
+    set shared "-shared"
+    set opts(link) {}
+    set opts(link_flags) {}
+    set opts(nonshared) {}
+    set opts(unwind) {}
+    set opts(name) {}
+    set opts(source) {}
+    set opts(xfail) {}
+
+    foreach i $opt_array {
+	set opt_name [lindex $i 0]
+	set opt_val [lindex $i 1]
+	if { $opt_name == "" } {
+	    set in_extra 1
+	    continue
+	}
+	if ![info exists opts($opt_name)] {
+	    perror "unknown option $opt_name in file $file.lk"
+	    unresolved $subdir/$name
+	    return
+	}
+
+	set opts($opt_name) [concat $opts($opt_name) $opt_val]
+    }
+
+    if { [llength $opts(unwind)] == 0 } {
+	set opts(unwind) "$file.c"
+    } else {
+	set opts(unwind) "[file dirname $file]/$opts(unwind)"
+    }
+
+    if { [llength $opts(name)] == 0 } {
+	set opts(name) $opts(unwind)
+    }
+
+    if { [llength $opts(link)] != 0
+	 || [llength $opts(source)] > 1 } {
+	set run_ld 1
+    }
+
+    if { [llength $opts(nonshared)] != 0 } {
+	set shared ""
+    }
+
+    set testname $opts(name)
+    if { $opts(name) == "" } {
+	set testname "$subdir/$name"
+    }
+
+    # Compile and link the unwind program.
+    set comp_output [compile_link_one_host_cc $opts(unwind) "tmpdir/test_x" "./../.libs/libsframebt.la ./../.libs/libsframe.la"]
+
+    if { $comp_output != ""} {
+	send_log "compilation of unwind program $opts(unwind) failed with <$comp_output>"
+	perror "compilation of unwind program $opts(unwind) failed"
+	fail $testname
+	return 0
+    }
+
+    # Compile the inputs and posibly link them together.
+
+    set unwind ""
+    if { [llength $opts(source)] > 0 } {
+	set unwind ""
+	if { $run_ld } {
+	    set unwind_output "tmpdir/test_x ./../.libs/libsframebt.a ./../.libs/libsframe.a"
+	    # set unwind_output "tmpdir/out.so"
+	    # set unwind_flags "-fPIC $shared $opts(link_flags)"
+	} else {
+	    set unwind_output "tmpdir/out.o"
+	    # set unwind_flags "-fPIC -c"
+	}
+	if [board_info [target_info name] exists cflags] {
+	    append unwind_flags " [board_info [target_info name] cflags]"
+	}
+	if [board_info [target_info name] exists ldflags] {
+	    append unwind_flags " [board_info [target_info name] ldflags]"
+	}
+	set src {}
+	foreach sfile $opts(source) {
+	    if [is_remote host] {
+		lappend src [remote_download host [file join [file dirname $file] $sfile]]
+	    } else {
+		lappend src [file join [file dirname $file] $sfile]
+	    }
+	}
+
+	set comp_output [run_host_cmd "$CC" "$CFLAGS $unwind_cflags [concat $src] -o $unwind_output"]
+
+	if { $comp_output != ""} {
+	    send_log "compilation of SFrame test program [concat $src] failed with <$comp_output>"
+	    fail $testname
+	    return 0
+	}
+    }
+
+    # Time to setup xfailures.
+    foreach targ $opts(xfail) {
+	if [match_target $targ] {
+	    setup_xfail "*-*-*"
+	    break
+	}
+    }
+
+    # Invoke the unwind program on the outputs.
+
+    verbose -log "$srcdir"
+    set results [run_host_cmd tmpdir/test_x $unwind_output]
+
+    set f [open "tmpdir/test_x.out" "w"]
+    puts $f $results
+    close $f
+
+    if { [regexp_diff "tmpdir/test_x.out" "${file}.lk"] } then {
+	fail $testname
+	if { $verbose == 2 } then { verbose "output is [file_contents tmpdir/test_x.out]" 2 }
+	return 0
+    }
+
+    pass $testname
+    return 0
+}
+
+set sframe_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.lk]]
+
+foreach sframe_test $sframe_test_list {
+    verbose [file rootname $sframe_test]
+    verbose running unwind test on $sframe_test
+    run_unwind_test [file rootname $sframe_test]
+}
+
+if {[info exists old_lc_all]} {
+    set env(LC_ALL) $old_lc_all
+} else {
+    unset env(LC_ALL)
+}
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 10/14] gdb: sim: buildsystem changes to accommodate libsframe
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (8 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 09/14] unwinder: Add SFrame unwinder tests Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-10-11 16:08       ` [PATCH, V1 " Tom Tromey
  2022-09-30  0:04     ` [PATCH,V1 11/14] libctf: add libsframe to LDFLAGS and LIBS Indu Bhagat
                       ` (6 subsequent siblings)
  16 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

Both gdb and sim need buildsystem fixes to now include libsframe for a
successful build.

gdb/ChangeLog:
	* acinclude.m4: Fix GDB_AC_CHECK_BFD to include libsframe.
	* Makefile.in: Bring in libsframe for linking.
	* configure.ac: Check for static or shared.
	* configure: Regenerated.

sim/common/ChangeLog:
	* sim/common/Make-common.in: Bring in libsframe.a for linking.
---
 gdb/Makefile.in           |  8 ++++++--
 gdb/acinclude.m4          |  4 ++--
 gdb/configure             | 35 +++++++++++++++++++++++++++++++----
 gdb/configure.ac          | 11 +++++++++++
 sim/common/Make-common.in |  7 +++++--
 5 files changed, 55 insertions(+), 10 deletions(-)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c528ee5aa80..492e08d6c63 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -161,6 +161,10 @@ LIBIBERTY = ../libiberty/libiberty.a
 LIBCTF = @LIBCTF@
 CTF_DEPS = @CTF_DEPS@
 
+# Where is the SFrame library?  Typically in ../libsframe.
+LIBSFRAME = @LIBSFRAME@
+SFRAME_DEPS = @SFRAME_DEPS@
+
 # Where is the BFD library?  Typically in ../bfd.
 BFD_DIR = ../bfd
 BFD = $(BFD_DIR)/libbfd.a
@@ -650,7 +654,7 @@ INTERNAL_LDFLAGS = \
 # Libraries and corresponding dependencies for compiling gdb.
 # XM_CLIBS, defined in *config files, have host-dependent libs.
 # LIBIBERTY appears twice on purpose.
-CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) $(ZSTD_LIBS) \
+CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(LIBSFRAME) $(ZLIB) $(ZSTD_LIBS) \
         $(LIBSUPPORT) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
 	$(XM_CLIBS) $(GDBTKLIBS)  $(LIBBACKTRACE_LIB) \
 	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
@@ -658,7 +662,7 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) $(ZSTD_LIBS) \
 	$(WIN32LIBS) $(LIBGNU) $(LIBGNU_EXTRA_LIBS) $(LIBICONV) \
 	$(LIBMPFR) $(LIBGMP) $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
 	$(DEBUGINFOD_LIBS) $(LIBBABELTRACE_LIB)
-CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(CTF_DEPS) \
+CDEPS = $(NAT_CDEPS) $(SIM) $(SFRAME_DEPS) $(BFD) $(READLINE_DEPS) $(CTF_DEPS) \
 	$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) \
 	$(LIBSUPPORT)
 
diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4
index 28846119dcb..a7205e90b0b 100644
--- a/gdb/acinclude.m4
+++ b/gdb/acinclude.m4
@@ -234,9 +234,9 @@ AC_DEFUN([GDB_AC_CHECK_BFD], [
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty -L../libsframe/.libs/ $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
-  LIBS="-lbfd -liberty -lz $intl $LIBS"
+  LIBS="-lbfd -liberty -lz -lsframe $intl $LIBS"
   AC_CACHE_CHECK(
     [$1],
     [$2],
diff --git a/gdb/configure b/gdb/configure
index 9c7a37a623e..ec1b3fd8bf4 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -631,6 +631,8 @@ GDB_NM_FILE
 LTLIBXXHASH
 LIBXXHASH
 HAVE_LIBXXHASH
+SFRAME_DEPS
+LIBSFRAME
 CTF_DEPS
 LIBCTF
 LTLIBBABELTRACE
@@ -939,6 +941,7 @@ with_libbabeltrace_prefix
 with_libbabeltrace_type
 with_xxhash
 enable_libctf
+enable_libsframe
 with_libxxhash_prefix
 with_libxxhash_type
 enable_unit_tests
@@ -1617,6 +1620,7 @@ Optional Features:
   --enable-libbacktrace   use libbacktrace to write a backtrace after a fatal
                           signal.
   --enable-libctf         Handle .ctf type-info sections [default=yes]
+  --enable-libsframe      Handle .sframe sections [default=yes]
   --enable-unit-tests     Enable the inclusion of unit tests when compiling
                           GDB
 
@@ -17412,9 +17416,9 @@ WIN32LIBS="$WIN32LIBS $WIN32APILIBS"
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty -L../libsframe/.libs/ $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
-  LIBS="-lbfd -liberty -lz $intl $LIBS"
+  LIBS="-lbfd -liberty -lz -lsframe $intl $LIBS"
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF support in BFD" >&5
 $as_echo_n "checking for ELF support in BFD... " >&6; }
 if ${gdb_cv_var_elf+:} false; then :
@@ -17527,9 +17531,9 @@ fi
   # always want our bfd.
   CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
   ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-  LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
+  LDFLAGS="-L../bfd -L../libiberty -L../libsframe/.libs/ $ZLIBDIR $ZSTD_LIBS $LDFLAGS"
   intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
-  LIBS="-lbfd -liberty -lz $intl $LIBS"
+  LIBS="-lbfd -liberty -lz -lsframe $intl $LIBS"
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Mach-O support in BFD" >&5
 $as_echo_n "checking for Mach-O support in BFD... " >&6; }
 if ${gdb_cv_var_macho+:} false; then :
@@ -19498,6 +19502,29 @@ fi
 
 
 
+ # Check whether --enable-libsframe was given.
+if test "${enable_libsframe+set}" = set; then :
+  enableval=$enable_libsframe;
+      case "$enableval" in
+       yes|no) ;;
+       *) as_fn_error $? "Argument to enable/disable libsframe must be yes or no" "$LINENO" 5 ;;
+      esac
+
+else
+  enable_libsframe=yes
+fi
+
+
+if test x${enable_static} = xno; then
+  LIBSFRAME="-Wl,--rpath,../libsframe/.libs ../libsframe/.libs/libsframe.so"
+  SFRAME_DEPS="../libsframe/.libs/libsframe.so"
+else
+  LIBSFRAME="../libsframe/.libs/libsframe.a"
+  SFRAME_DEPS="$LIBSFRAME"
+fi
+
+
+
 # If nativefile (NAT_FILE) is not set in configure.nat, we link to an
 # empty version.
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index fceb80e8c9d..c302e58b4bf 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2167,6 +2167,17 @@ fi
 AC_SUBST(LIBCTF)
 AC_SUBST(CTF_DEPS)
 
+GCC_ENABLE([libsframe], [yes], [], [Handle .sframe sections])
+if test x${enable_static} = xno; then
+  LIBSFRAME="-Wl,--rpath,../libsframe/.libs ../libsframe/.libs/libsframe.so"
+  SFRAME_DEPS="../libsframe/.libs/libsframe.so"
+else
+  LIBSFRAME="../libsframe/.libs/libsframe.a"
+  SFRAME_DEPS="$LIBSFRAME"
+fi
+AC_SUBST(LIBSFRAME)
+AC_SUBST(SFRAME_DEPS)
+
 # If nativefile (NAT_FILE) is not set in configure.nat, we link to an
 # empty version.
 
diff --git a/sim/common/Make-common.in b/sim/common/Make-common.in
index b07ec96e147..8a49e0b4ef2 100644
--- a/sim/common/Make-common.in
+++ b/sim/common/Make-common.in
@@ -222,11 +222,14 @@ SIM_HW_DEVICES = cfi core pal glue $(SIM_EXTRA_HW_DEVICES)
 ZLIB = $(zlibdir) -lz
 LIBIBERTY_LIB = ../../libiberty/libiberty.a
 BFD_LIB = ../../bfd/libbfd.a
+LIBSFRAME_LIB = ../../libsframe/.libs/libsframe.a
 OPCODES_LIB = ../../opcodes/libopcodes.a
 CONFIG_LIBS = $(COMMON_LIBS) @LIBS@ $(ZLIB) $(ZSTD_LIBS)
-LIBDEPS = $(BFD_LIB) $(OPCODES_LIB) $(LIBINTL_DEP) $(LIBIBERTY_LIB)
+LIBDEPS = $(BFD_LIB) $(OPCODES_LIB) $(LIBINTL_DEP) $(LIBIBERTY_LIB) \
+	  $(LIBSFRAME_LIB)
 EXTRA_LIBS = $(BFD_LIB) $(OPCODES_LIB) $(LIBINTL) $(LIBIBERTY_LIB) \
-	$(CONFIG_LIBS) $(SIM_EXTRA_LIBS) $(LIBDL) $(LIBGNU) $(LIBGNU_EXTRA_LIBS)
+	     $(LIBSFRAME_LIB) $(CONFIG_LIBS) $(SIM_EXTRA_LIBS) \
+	     $(LIBDL) $(LIBGNU) $(LIBGNU_EXTRA_LIBS)
 
 COMMON_OBJS_NAMES = \
 	callback.o \
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 11/14] libctf: add libsframe to LDFLAGS and LIBS
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (9 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 10/14] gdb: sim: buildsystem changes to accommodate libsframe Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 12/14] src-release.sh: Add libsframe Indu Bhagat
                       ` (5 subsequent siblings)
  16 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

bfd now depends on libsframe.

ChangeLog:

	* libctf/configure.ac:
	* libctf/configure: Regenerated
---
 libctf/configure    | 4 ++--
 libctf/configure.ac | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libctf/configure b/libctf/configure
index 176b3d6b918..abe4cfe1eff 100755
--- a/libctf/configure
+++ b/libctf/configure
@@ -13218,9 +13218,9 @@ OLD_LIBS=$LIBS
 # always want our bfd.
 CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
 ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+LDFLAGS="-L../bfd -L../libiberty -L../libsframe/.libs/ $ZLIBDIR $LDFLAGS"
 intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
-LIBS="-lbfd -liberty -lz $ZSTD_LIBS $intl $LIBS"
+LIBS="-lbfd -liberty -lz -lsframe $ZSTD_LIBS $intl $LIBS"
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF support in BFD" >&5
 $as_echo_n "checking for ELF support in BFD... " >&6; }
 if ${ac_cv_libctf_bfd_elf+:} false; then :
diff --git a/libctf/configure.ac b/libctf/configure.ac
index 2e2ccf4b624..72b2ed7ea31 100644
--- a/libctf/configure.ac
+++ b/libctf/configure.ac
@@ -88,9 +88,9 @@ OLD_LIBS=$LIBS
 # always want our bfd.
 CFLAGS="-I${srcdir}/../include -I../bfd -I${srcdir}/../bfd $CFLAGS"
 ZLIBDIR=`echo $zlibdir | sed 's,\$(top_builddir)/,,g'`
-LDFLAGS="-L../bfd -L../libiberty $ZLIBDIR $LDFLAGS"
+LDFLAGS="-L../bfd -L../libiberty -L../libsframe/.libs/ $ZLIBDIR $LDFLAGS"
 intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
-LIBS="-lbfd -liberty -lz $ZSTD_LIBS $intl $LIBS"
+LIBS="-lbfd -liberty -lz -lsframe $ZSTD_LIBS $intl $LIBS"
 AC_CACHE_CHECK([for ELF support in BFD], ac_cv_libctf_bfd_elf,
 [AC_TRY_LINK([#include <stdlib.h>
 	     #include <string.h>
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 12/14] src-release.sh: Add libsframe
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (10 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 11/14] libctf: add libsframe to LDFLAGS and LIBS Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 13/14] binutils/NEWS: add text for SFrame support Indu Bhagat
                       ` (4 subsequent siblings)
  16 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

Add libsframe to the list of top level directories that will be included
in a release.

ChangeLog:

	* src-release.sh: Add libsframe
---
 src-release.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src-release.sh b/src-release.sh
index 079b545ae7c..e42c485214f 100755
--- a/src-release.sh
+++ b/src-release.sh
@@ -93,7 +93,7 @@ do_proto_toplev()
     # built in the gold dir.  The disables speed the build a little.
     enables=
     disables=
-    for dir in binutils gas gdb gold gprof gprofng ld libctf libdecnumber readline sim; do
+    for dir in binutils gas gdb gold gprof gprofng libsframe ld libctf libdecnumber readline sim; do
 	case " $tool $support_files " in
 	    *" $dir "*) enables="$enables --enable-$dir" ;;
 	    *) disables="$disables --disable-$dir" ;;
@@ -295,7 +295,7 @@ gdb_tar_compress()
 }
 
 # The FSF "binutils" release includes gprof and ld.
-BINUTILS_SUPPORT_DIRS="bfd gas include libiberty libctf opcodes ld elfcpp gold gprof gprofng intl setup.com makefile.vms cpu zlib"
+BINUTILS_SUPPORT_DIRS="libsframe bfd gas include libiberty libctf opcodes ld elfcpp gold gprof gprofng intl setup.com makefile.vms cpu zlib"
 binutils_release()
 {
     compressors=$1
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 13/14] binutils/NEWS: add text for SFrame support
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (11 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 12/14] src-release.sh: Add libsframe Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30  0:04     ` [PATCH,V1 14/14] gas/NEWS: add text about new command line option and " Indu Bhagat
                       ` (3 subsequent siblings)
  16 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

ChangeLog:

	* binutils/NEWS: Add item for SFrame support.
---
 binutils/NEWS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/binutils/NEWS b/binutils/NEWS
index 83c73d0660a..924c98fb938 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -11,6 +11,8 @@
   not it generates deterministic output libraries.  If neither of these options
   are used the default is whatever was set when the binutils were configured.
   
+* Support for SFrame unwind information.
+
 Changes in 2.39:
 
 * Add --no-weak/-W option to nm to make it ignore weak symbols.
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH,V1 14/14] gas/NEWS: add text about new command line option and SFrame support
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (12 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 13/14] binutils/NEWS: add text for SFrame support Indu Bhagat
@ 2022-09-30  0:04     ` Indu Bhagat
  2022-09-30  8:09     ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Jan Beulich
                       ` (2 subsequent siblings)
  16 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-09-30  0:04 UTC (permalink / raw)
  To: binutils; +Cc: nickc, weimin.pan, Indu Bhagat

ChangeLog:

	* gas/NEWS: Add SFrame related news.
---
 gas/NEWS | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/gas/NEWS b/gas/NEWS
index 9a8b726b942..b51639a52e2 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -3,6 +3,9 @@
 * gas now supports --compress-debug-sections=zstd to compress
   debug sections with zstd.
 
+* New command line option --gsframe to generate SFrame unwind information
+  on x86_64 and aarch64 targets.
+
 Changes in 2.39:
 
 * Remove (rudimentary) support for the x86-64 sub-architectures Intel L1OM and
-- 
2.37.2


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V1 00/14] Definition and support for SFrame unwind format
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (13 preceding siblings ...)
  2022-09-30  0:04     ` [PATCH,V1 14/14] gas/NEWS: add text about new command line option and " Indu Bhagat
@ 2022-09-30  8:09     ` Jan Beulich
  2022-10-04  5:16       ` Indu Bhagat
  2022-09-30  8:24     ` Fangrui Song
  2022-09-30  9:12     ` Nick Clifton
  16 siblings, 1 reply; 51+ messages in thread
From: Jan Beulich @ 2022-09-30  8:09 UTC (permalink / raw)
  To: Indu Bhagat; +Cc: binutils

On 30.09.2022 02:04, Indu Bhagat via Binutils wrote:
> What is SFrame format and why do we need it
> -------------------------------------------
> SFrame format is the Simple Frame format.  It can be used to represent the
> minimal necessary information for backtracing.  As such, it only encodes how to
> recover the CFA (based on SP/FP) and the return address (RA) for all
> instructions of a program.
> 
> The format is supported on AMD64 and AARCH64 ABIs only.  The information stored
> in the .sframe section is a subset of what .eh_frame can convey: .eh_frame can
> convey how to resurrect all callee-saved registers, if need be; but .sframe
> does not.

I expect the question was asked before, but since the summary here doesn't
answer it: What about cases where the return address is stored in a
callee-saved register? You won't be able to determine its value if that
wasn't the leaf-most function in the active call chain and some inner
function saved and then modified that (presumably) GPR. The same would
likely apply if the return address was saved to some secondary stack.

Jan

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V1 00/14] Definition and support for SFrame unwind format
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (14 preceding siblings ...)
  2022-09-30  8:09     ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Jan Beulich
@ 2022-09-30  8:24     ` Fangrui Song
  2022-10-01  0:15       ` Indu Bhagat
  2022-09-30  9:12     ` Nick Clifton
  16 siblings, 1 reply; 51+ messages in thread
From: Fangrui Song @ 2022-09-30  8:24 UTC (permalink / raw)
  To: Indu Bhagat; +Cc: binutils

On 2022-09-29, Indu Bhagat via Binutils wrote:
>What is SFrame format and why do we need it
>-------------------------------------------
>SFrame format is the Simple Frame format.  It can be used to represent the
>minimal necessary information for backtracing.  As such, it only encodes how to
>recover the CFA (based on SP/FP) and the return address (RA) for all
>instructions of a program.
>
>The format is supported on AMD64 and AARCH64 ABIs only.  The information stored
>in the .sframe section is a subset of what .eh_frame can convey: .eh_frame can
>convey how to resurrect all callee-saved registers, if need be; but .sframe
>does not.
>
>SFrame format is intended for usecases where fast virtual stack unwind is
>needed, along with a need for a small simple unwinder. So, those applications
>which struggle with the following two complaints will want to consider SFrame
>format:
>  - EH Frame based unwinders are complex and slow to manage with
>  - EH Frame based unwinders are large as they need to deal with DWARF
>  opcodes via a stack machine implementation
>
>More details about the format are available in include/sframe.h, please see
>commit "sframe.h: Add SFrame format definition".
>
>Our not-so-exhaustive experiments (basically binutils programs built with
>-Wa,--gsframe) show that SFrame/EH Frame section ratio to be an average of 0.8x
>for x86_64 and 0.7x for aarch64.

For an executable with 1000KiB .eh_frame, .sframe takes 800KiB?
Does SFrame has something similar to .eh_frame_hdr and what is the size
comparison? The saving isn't apealing in my view.

Have you tried removing callee-saved register information from
.eh_frame?

Has SFrame be compared with macOS compact unwind descriptors, Windows
ARM64 exception handling, MIPS compact exception tables (their .eh_frame
counterpart, not the .gcc_except_table counterpart)?

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V1 00/14] Definition and support for SFrame unwind format
  2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
                       ` (15 preceding siblings ...)
  2022-09-30  8:24     ` Fangrui Song
@ 2022-09-30  9:12     ` Nick Clifton
  2022-10-01  0:29       ` Indu Bhagat
  2022-10-01  9:51       ` Jose E. Marchesi
  16 siblings, 2 replies; 51+ messages in thread
From: Nick Clifton @ 2022-09-30  9:12 UTC (permalink / raw)
  To: Indu Bhagat, binutils; +Cc: weimin.pan

Hi Indu,

> The format specification document still mains a TODO at this time. I plan to
> resume working on this after I have tackled the task of SFrame generation for
> PLT/veneers in aarch64.

I am concerned about this.  If you do not have a specification then it is going
to be hard to get the format adopted by third parties.  I assume that you would
like tools such as LLVM to support the format, as well as projects like the
Linux kernel.  Maybe other commercial interests or academic endeavours.  None of
them are going to take the format seriously if there isn't a specification.


> The format is supported on AMD64 and AARCH64 ABIs only.

This is sad and a little bit surprising.  I would have at least expected to see
the x86_64 architecture listed as well, and ideally I would like to see a whole
lot more.  I do hope that your plans including writing a "How to extended the
SFrame specification/implementation to support a new architecture" document.


> The information stored
> in the .sframe section is a subset of what .eh_frame can convey: .eh_frame can
> convey how to resurrect all callee-saved registers, if need be; but .sframe
> does not.

Is it possible to convert existing .eh_frame sections into equivalent .sframe
sections ?

Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V1 06/14] bfd: linker: merge .sframe sections
  2022-09-30  0:04     ` [PATCH,V1 06/14] bfd: linker: merge .sframe sections Indu Bhagat
@ 2022-09-30 10:51       ` Nick Clifton
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Clifton @ 2022-09-30 10:51 UTC (permalink / raw)
  To: Indu Bhagat, binutils; +Cc: weimin.pan

Hi Indu,
> ld/testsuite/ChangeLog:
> 
> 	* ld/testsuite/ld-aarch64/aarch64-elf.exp: Add new test
> 	  sframe-simple-1.
> 	* ld/testsuite/ld-aarch64/sframe-bar.s: New file.
> 	* ld/testsuite/ld-aarch64/sframe-foo.s: Likewise.
> 	* ld/testsuite/ld-aarch64/sframe-simple-1.d: Likewise.
> 	* ld/testsuite/ld-sframe/sframe-empty.d: New test.
> 	* ld/testsuite/ld-sframe/sframe-empty.s: New file.
> 	* ld/testsuite/ld-sframe/sframe.exp: New testsuite.
  Unfortunately I have found one way to make this new test fail:

   Executing on host: sh -c {./ld-new -z norelro  -L/work/sources/binutils/upstream/current/ld/testsuite/ld-aarch64  -shared -o tmpdir/dump tmpdir/sframe-foo.o 
tmpdir/sframe-bar.o  2>&1}  /dev/null dump.tmp (timeout = 300)
   spawn [open ...]

   succeeded with: </work/sources/binutils/upstream/current/ld/testsuite/ld-aarch64/sframe-bar.s: Assembler messages:
   /work/sources/binutils/upstream/current/ld/testsuite/ld-aarch64/sframe-bar.s: Warning: .sframe not supported for target>, no expected output
   FAIL: Simple link

The cause was the fact that I was using a big-endian, 32-bit AArch64 toolchain.
Ie one configured as --target=aarch64_be-linux-gnu_ilp32  Not your typical
configuration, but a valid one nonetheless.

Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V1 07/14] readelf/objdump: support for SFrame section
  2022-09-30  0:04     ` [PATCH,V1 07/14] readelf/objdump: support for SFrame section Indu Bhagat
@ 2022-09-30 11:08       ` Nick Clifton
  0 siblings, 0 replies; 51+ messages in thread
From: Nick Clifton @ 2022-09-30 11:08 UTC (permalink / raw)
  To: Indu Bhagat, binutils; +Cc: weimin.pan

Hi Indu,

> This patch adds support for SFrame in readelf and objdump.
There appear to be a couple of problems with the readelf implementation of this feature:

   1. Just using the --sframe option on its own results in readelf saying that there is
      nothing to do:

       % ./readelf --sframe ../ld/tmpdir/sframe-bar.o
       readelf: Warning: Nothing to do.
       [...whole list of accepted command line options....]

   2. Not providing a section name gives a slightly off error message:

        % ./readelf --sframe= ../ld/tmpdir/sframe-bar.o
        Section '' has no data to dump.

      I would have expected something along the lines of "section name must be provided".

   3. Providing an incorrect section name does not result in any kind of error message,
      although the exit code is set to 1:

         % ./readelf --sframe=.eh_frame ../ld/tmpdir/sframe-bar.o
         % echo $?
         1

One other minor point - it would be good to mention support for this new feature in
the binutils/NEWS file.  (I know that you have a patch for gas/NEWS, I just think
that it should be mentioned here as well).

Cheers
   Nick


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V1 00/14] Definition and support for SFrame unwind format
  2022-09-30  8:24     ` Fangrui Song
@ 2022-10-01  0:15       ` Indu Bhagat
  0 siblings, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-10-01  0:15 UTC (permalink / raw)
  To: Fangrui Song; +Cc: binutils

On 9/30/22 01:24, Fangrui Song wrote:
> On 2022-09-29, Indu Bhagat via Binutils wrote:
>> What is SFrame format and why do we need it
>> -------------------------------------------
>> SFrame format is the Simple Frame format.  It can be used to represent 
>> the
>> minimal necessary information for backtracing.  As such, it only 
>> encodes how to
>> recover the CFA (based on SP/FP) and the return address (RA) for all
>> instructions of a program.
>>
>> The format is supported on AMD64 and AARCH64 ABIs only.  The 
>> information stored
>> in the .sframe section is a subset of what .eh_frame can convey: 
>> .eh_frame can
>> convey how to resurrect all callee-saved registers, if need be; but 
>> .sframe
>> does not.
>>
>> SFrame format is intended for usecases where fast virtual stack unwind is
>> needed, along with a need for a small simple unwinder. So, those 
>> applications
>> which struggle with the following two complaints will want to consider 
>> SFrame
>> format:
>>  - EH Frame based unwinders are complex and slow to manage with
>>  - EH Frame based unwinders are large as they need to deal with DWARF
>>  opcodes via a stack machine implementation
>>
>> More details about the format are available in include/sframe.h, 
>> please see
>> commit "sframe.h: Add SFrame format definition".
>>
>> Our not-so-exhaustive experiments (basically binutils programs built with
>> -Wa,--gsframe) show that SFrame/EH Frame section ratio to be an 
>> average of 0.8x
>> for x86_64 and 0.7x for aarch64.
> 
> For an executable with 1000KiB .eh_frame, .sframe takes 800KiB?
> Does SFrame has something similar to .eh_frame_hdr and what is the size
> comparison? The saving isn't apealing in my view.
> 

Small correction - For an executable with 1000KiB of 
.eh_frame+.eh_frame_hdr sections, .sframe takes 800KiB.

Yes, SFrame has something similar to .eh_frame_hdr.  The SFrame FDE 
(Function Descriptor Entries) are sorted on start PC by the linker 
before writing out the .sframe section.

Re: size comparison of the index in SFrame vs .eh_frame_hdr - The size 
numbers I quote is the ratio of .sframe/(.eh_frame + .eh_frame_hdr) size 
for binutils programs. As SFrame FDEs contain more information than the 
individual entry in the .eh_frame_hdr, I don't know if this comparison 
will fetch us much insight.

Re : space saving appeal - SFrame's "reason for existence" is to allow 
fast unwinding while using a simple unwinder. The stack offsets, for 
example, are encoded directly rather than being calculated at the time 
of backtracing.  Such a representation will need more space when 
compared to the opcode-based encoding in EH Frame format in isolation. 
That said, there might be some more optimization opportunities to 
explore for reducing the size of SFrame further.

> Have you tried removing callee-saved register information from
> .eh_frame?
> 

I haven't tried this yet. BTW, other folks also were curious about this 
at Cauldron.

This keeps getting pushed lower on my task list, however, because the 
outcome of the experiment does not change the fact that there are 
applications where fast, plain vanilla backtracing is needed using a 
simple backtracer. Such a comparison can be informative though, I see that.

> Has SFrame be compared with macOS compact unwind descriptors, Windows
> ARM64 exception handling, MIPS compact exception tables (their .eh_frame
> counterpart, not the .gcc_except_table counterpart)?

I havent looked at them closely enough to offer a meaningful comparison 
at this time. I will take a second look.

Thanks

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V1 00/14] Definition and support for SFrame unwind format
  2022-09-30  9:12     ` Nick Clifton
@ 2022-10-01  0:29       ` Indu Bhagat
  2022-10-01  9:51       ` Jose E. Marchesi
  1 sibling, 0 replies; 51+ messages in thread
From: Indu Bhagat @ 2022-10-01  0:29 UTC (permalink / raw)
  To: Nick Clifton, binutils; +Cc: weimin.pan

On 9/30/22 02:12, Nick Clifton wrote:
> Hi Indu,
> 
>> The format specification document still mains a TODO at this time. I 
>> plan to
>> resume working on this after I have tackled the task of SFrame 
>> generation for
>> PLT/veneers in aarch64.
> 
> I am concerned about this.  If you do not have a specification then it 
> is going
> to be hard to get the format adopted by third parties.  I assume that 
> you would
> like tools such as LLVM to support the format, as well as projects like the
> Linux kernel.  Maybe other commercial interests or academic endeavours.  
> None of
> them are going to take the format seriously if there isn't a specification.
> 

Noted. Let me see how I can get this done sooner.

> 
>> The information stored
>> in the .sframe section is a subset of what .eh_frame can convey: 
>> .eh_frame can
>> convey how to resurrect all callee-saved registers, if need be; but 
>> .sframe
>> does not.
> 
> Is it possible to convert existing .eh_frame sections into equivalent 
> .sframe
> sections ?
> 

It should be possible with additional tooling, yes.

Thanks

> Cheers
>    Nick
> 



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V1 00/14] Definition and support for SFrame unwind format
  2022-09-30  9:12     ` Nick Clifton
  2022-10-01  0:29       ` Indu Bhagat
@ 2022-10-01  9:51       ` Jose E. Marchesi
  1 sibling, 0 replies; 51+ messages in thread
From: Jose E. Marchesi @ 2022-10-01  9:51 UTC (permalink / raw)
  To: Nick Clifton via Binutils; +Cc: Indu Bhagat, Nick Clifton


>> The format is supported on AMD64 and AARCH64 ABIs only.
>
> This is sad and a little bit surprising.  I would have at least expected to see
> the x86_64 architecture listed as well, and ideally I would like to see a whole
> lot more.  I do hope that your plans including writing a "How to extended the
> SFrame specification/implementation to support a new architecture" document.

I think the above was a typo.
SFrame is supported for both x86_64 and Aaarch64.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V1 00/14] Definition and support for SFrame unwind format
  2022-09-30  8:09     ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Jan Beulich
@ 2022-10-04  5:16       ` Indu Bhagat
  2022-10-04  6:53         ` Jan Beulich
  0 siblings, 1 reply; 51+ messages in thread
From: Indu Bhagat @ 2022-10-04  5:16 UTC (permalink / raw)
  To: Jan Beulich; +Cc: binutils

On 9/30/22 01:09, Jan Beulich wrote:
> On 30.09.2022 02:04, Indu Bhagat via Binutils wrote:
>> What is SFrame format and why do we need it
>> -------------------------------------------
>> SFrame format is the Simple Frame format.  It can be used to represent the
>> minimal necessary information for backtracing.  As such, it only encodes how to
>> recover the CFA (based on SP/FP) and the return address (RA) for all
>> instructions of a program.
>>
>> The format is supported on AMD64 and AARCH64 ABIs only.  The information stored
>> in the .sframe section is a subset of what .eh_frame can convey: .eh_frame can
>> convey how to resurrect all callee-saved registers, if need be; but .sframe
>> does not.
> 
> I expect the question was asked before, but since the summary here doesn't
> answer it: What about cases where the return address is stored in a
> callee-saved register? You won't be able to determine its value if that
> wasn't the leaf-most function in the active call chain and some inner
> function saved and then modified that (presumably) GPR. The same would
> likely apply if the return address was saved to some secondary stack.
> 
> Jan

Yes, this question was asked before. And thanks for asking this here.

(In the context of recovering return address) As far as x86_64 and 
aarch64 are concerned, I *believe* SFrame can represent most 
ABI-conforming cases with standard stack usage (except the #exceptions 
noted at the end of this message):
  - For x86_64, the return address is saved on stack with every call 
instruction
  - For aarch64, (from the ABI doc) all "Conforming code shall construct 
a linked list of stack-frames. Each frame shall link to the frame of its 
caller by means
of a frame record of two 64-bit values on the stack (independent of the 
data model).". So the return address is tracked as it flows from LR to 
stack and so on in the SFrame format.

So, IIUC, the case you mention will be "non ABI conforming code", 
correct ? In such a case, SFrame format cannot be used as is. It will 
need to be extended to support such cases:
  - first, encode the return register per SFrame FDE (so additional few 
bits per FDE).
  - second, recover all possible return registers (i.e., all 
callee-saved registers per FDE) via stack offsets in every FRE as 
applicable.

The second item will not fly in the SFrame format (atleast not in its 
current form); storing stack offsets explicitly like that (for a bunch 
of registers) will cause the unwind metadata to get quite large.  If 
there is a high usage of non-conforming code in applications, and SFrame 
is still desirable for those, something needs to be done.

My viewpoint here was to keep the format simple by targeting to support 
all ABI-conforming code. Is that reasonable ? (Posing this question to 
also the wider community).

Now a subset your question, I believe, also intends to ask - how do you 
plan to support architectures/ABIs where the return address can be in 
any register. The answer goes back to the above-mentioned two pieces of 
information (needed for non ABI conforming code in context of x86_64 and 
aarch64) and their high cost in SFrame format. Instead, an alternative 
strategy could be to take compiler's help to assign a "recommended 
register" for return register usage in such ABIs. The SFrame format will 
still need extensions (but these extensions are minimal) :
  - an additional field in the SFrame header to designate the 
"recommended return register" (the same register which was used at 
compile time).
  - the new ABI marker in the SFrame header.

Now if the compiler is not able to use the recommended return register 
for some functions, it will mean that SFrame-based backtracing will not 
work through those functions, hence affecting asynchronicity. I must 
admit that I haven't fully thought this one through, so not completely 
sure if such a solution work ? I think it might.

re: return address was saved to some secondary stack. I need some more 
understanding of the issue here. I was thinking an entity higher up, 
like the unwinder, will have enough context to pick the appropriate 
stack to which the stack offsets apply; because the decision as to when 
to switch to a secondary stack (or not) must be a application specific 
property ? If you have some resources to share here, it will be helpful. 
Alternatively, if usage of secondary stack is specified at an ABI level, 
can you please provide a reference so I can take a look ?

#exceptions (PS: I plan to work on these) :
  - .cfi_negate_ra_state handling in aarch64: if the code uses pointer 
signing for the return address, SFrame needs extensions to represent that.
  - .cfi_escape asm directives: these are also being skipped at this 
time. I may not be able to handle everything here, but even if we handle 
the most commonly occurring cases, I think we can get close.

Thanks

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH,V1 00/14] Definition and support for SFrame unwind format
  2022-10-04  5:16       ` Indu Bhagat
@ 2022-10-04  6:53         ` Jan Beulich
  0 siblings, 0 replies; 51+ messages in thread
From: Jan Beulich @ 2022-10-04  6:53 UTC (permalink / raw)
  To: Indu Bhagat; +Cc: binutils

On 04.10.2022 07:16, Indu Bhagat wrote:
> re: return address was saved to some secondary stack. I need some more 
> understanding of the issue here. I was thinking an entity higher up, 
> like the unwinder, will have enough context to pick the appropriate 
> stack to which the stack offsets apply; because the decision as to when 
> to switch to a secondary stack (or not) must be a application specific 
> property ? If you have some resources to share here, it will be helpful. 
> Alternatively, if usage of secondary stack is specified at an ABI level, 
> can you please provide a reference so I can take a look ?

That's not the kind of "secondary stack" I was referring to. IA-64, for
example, had a 2nd stack for its Register Stack Engine (for kind of
implicit spilling of a subset of GPRs). The return address of a function
therefore can, in principle, land on either the normal or the RSE stack.

x86 has now gained a secondary stack as well, for CET-SS. If that's in
use, in principle I think it would be preferable to unwind using that
one (as there's far less stuff there which isn't a return address, and
in the common case going from one function's slot to the next means
merely incrementing/decrementing the pointer used to point into that
stack).

Jan

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH, V1 10/14] gdb: sim: buildsystem changes to accommodate libsframe
  2022-09-30  0:04     ` [PATCH,V1 10/14] gdb: sim: buildsystem changes to accommodate libsframe Indu Bhagat
@ 2022-10-11 16:08       ` Tom Tromey
  0 siblings, 0 replies; 51+ messages in thread
From: Tom Tromey @ 2022-10-11 16:08 UTC (permalink / raw)
  To: Indu Bhagat via Binutils; +Cc: Indu Bhagat

>>>>> Indu Bhagat via Binutils <binutils@sourceware.org> writes:

> Both gdb and sim need buildsystem fixes to now include libsframe for a
> successful build.

> gdb/ChangeLog:
> 	* acinclude.m4: Fix GDB_AC_CHECK_BFD to include libsframe.
> 	* Makefile.in: Bring in libsframe for linking.
> 	* configure.ac: Check for static or shared.
> 	* configure: Regenerated.

gdb doesn't use ChangeLog entries.

> sim/common/ChangeLog:
> 	* sim/common/Make-common.in: Bring in libsframe.a for linking.

The sim and gdb parts are fine once the rest is approved.

Tom

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2022-10-11 16:27 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-02  8:04 [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Indu Bhagat
2022-08-02  8:04 ` [PATCH,V6 01/10] ctf-frame.h: Add CTF Frame format definition Indu Bhagat
2022-08-15 12:04   ` Nick Clifton
2022-08-02  8:04 ` [PATCH,V6 02/10] gas: add new command line option --gctf-frame Indu Bhagat
2022-08-15 12:07   ` Nick Clifton
2022-08-02  8:04 ` [PATCH,V6 03/10] gas: generate .ctf_frame Indu Bhagat
2022-08-15 12:22   ` Nick Clifton
2022-08-02  8:04 ` [PATCH,V6 04/10] libctfframe: add the CTF Frame library Indu Bhagat
2022-08-15 12:46   ` Nick Clifton
2022-08-02  8:04 ` [PATCH,V6 05/10] libctfframe: add GNU poke pickles for CTF Frame Indu Bhagat
2022-08-15 12:50   ` Nick Clifton
2022-08-02  8:04 ` [PATCH,V6 06/10] bfd: linker: merge .ctf_frame sections Indu Bhagat
2022-08-15 13:02   ` Nick Clifton
2022-08-18  2:11     ` Indu Bhagat
2022-08-02  8:04 ` [PATCH,V6 07/10] readelf/objdump: support for CTF Frame section Indu Bhagat
2022-08-15 13:11   ` Nick Clifton
2022-08-02  8:04 ` [PATCH,V6 08/10] unwinder: generate backtrace using CTF Frame format Indu Bhagat
2022-08-15 13:16   ` Nick Clifton
2022-08-02  8:04 ` [PATCH,V6 09/10] unwinder: Add CTF Frame unwinder tests Indu Bhagat
2022-08-15 13:27   ` Nick Clifton
2022-08-02  8:04 ` [PATCH, V6 10/10] gdb: sim: buildsystem changes to accommodate libctfframe Indu Bhagat
2022-08-05 14:43   ` Tom Tromey
2022-08-15 12:18 ` [PATCH,V6 00/10] Definition and Implementation of CTF Frame format Nick Clifton
2022-08-18  1:38   ` Indu Bhagat
2022-08-15 14:25 ` Nick Clifton
2022-09-30  0:04   ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Indu Bhagat
2022-09-30  0:04     ` [PATCH,V1 01/14] sframe.h: Add SFrame format definition Indu Bhagat
2022-09-30  0:04     ` [PATCH,V1 02/14] gas: add new command line option --gsframe Indu Bhagat
2022-09-30  0:04     ` [PATCH,V1 03/14] gas: generate .sframe from CFI directives Indu Bhagat
2022-09-30  0:04     ` [PATCH,V1 04/14] gas: testsuite: add new tests for SFrame unwind info Indu Bhagat
2022-09-30  0:04     ` [PATCH,V1 05/14] libsframe: add the SFrame library Indu Bhagat
2022-09-30  0:04     ` [PATCH,V1 06/14] bfd: linker: merge .sframe sections Indu Bhagat
2022-09-30 10:51       ` Nick Clifton
2022-09-30  0:04     ` [PATCH,V1 07/14] readelf/objdump: support for SFrame section Indu Bhagat
2022-09-30 11:08       ` Nick Clifton
2022-09-30  0:04     ` [PATCH,V1 08/14] unwinder: generate backtrace using SFrame format Indu Bhagat
2022-09-30  0:04     ` [PATCH,V1 09/14] unwinder: Add SFrame unwinder tests Indu Bhagat
2022-09-30  0:04     ` [PATCH,V1 10/14] gdb: sim: buildsystem changes to accommodate libsframe Indu Bhagat
2022-10-11 16:08       ` [PATCH, V1 " Tom Tromey
2022-09-30  0:04     ` [PATCH,V1 11/14] libctf: add libsframe to LDFLAGS and LIBS Indu Bhagat
2022-09-30  0:04     ` [PATCH,V1 12/14] src-release.sh: Add libsframe Indu Bhagat
2022-09-30  0:04     ` [PATCH,V1 13/14] binutils/NEWS: add text for SFrame support Indu Bhagat
2022-09-30  0:04     ` [PATCH,V1 14/14] gas/NEWS: add text about new command line option and " Indu Bhagat
2022-09-30  8:09     ` [PATCH,V1 00/14] Definition and support for SFrame unwind format Jan Beulich
2022-10-04  5:16       ` Indu Bhagat
2022-10-04  6:53         ` Jan Beulich
2022-09-30  8:24     ` Fangrui Song
2022-10-01  0:15       ` Indu Bhagat
2022-09-30  9:12     ` Nick Clifton
2022-10-01  0:29       ` Indu Bhagat
2022-10-01  9:51       ` Jose E. Marchesi

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).