From 1f1a10f4716e8d9b166f9c4741554fbbfa26fe66 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 23 May 2018 20:39:54 +1200 Subject: elftoolchain: Add libelftc. --- rtemstoolkit/elftoolchain/libelftc/Makefile | 60 + rtemstoolkit/elftoolchain/libelftc/_libelftc.h | 95 + rtemstoolkit/elftoolchain/libelftc/elftc.3 | 83 + .../elftoolchain/libelftc/elftc_bfd_find_target.3 | 200 + .../elftoolchain/libelftc/elftc_bfdtarget.c | 73 + .../elftoolchain/libelftc/elftc_copyfile.3 | 73 + .../elftoolchain/libelftc/elftc_copyfile.c | 113 + .../elftoolchain/libelftc/elftc_demangle.3 | 116 + .../elftoolchain/libelftc/elftc_demangle.c | 107 + .../elftoolchain/libelftc/elftc_reloc_type_str.3 | 72 + .../elftoolchain/libelftc/elftc_reloc_type_str.c | 832 ++++ .../elftoolchain/libelftc/elftc_set_timestamps.3 | 84 + .../elftoolchain/libelftc/elftc_set_timestamps.c | 85 + .../elftoolchain/libelftc/elftc_string_table.c | 392 ++ .../libelftc/elftc_string_table_create.3 | 227 ++ .../elftoolchain/libelftc/elftc_timestamp.3 | 79 + .../elftoolchain/libelftc/elftc_timestamp.c | 55 + rtemstoolkit/elftoolchain/libelftc/elftc_version.3 | 79 + rtemstoolkit/elftoolchain/libelftc/elftc_version.c | 10 + rtemstoolkit/elftoolchain/libelftc/libelftc.h | 100 + .../elftoolchain/libelftc/libelftc_bfdtarget.c | 463 +++ .../elftoolchain/libelftc/libelftc_dem_arm.c | 1216 ++++++ .../elftoolchain/libelftc/libelftc_dem_gnu2.c | 1365 +++++++ .../elftoolchain/libelftc/libelftc_dem_gnu3.c | 3991 ++++++++++++++++++++ rtemstoolkit/elftoolchain/libelftc/libelftc_hash.c | 70 + rtemstoolkit/elftoolchain/libelftc/libelftc_vstr.c | 359 ++ .../elftoolchain/libelftc/make-toolchain-version | 110 + rtemstoolkit/elftoolchain/libelftc/os.FreeBSD.mk | 7 + rtemstoolkit/elftoolchain/libelftc/os.Linux.mk | 3 + rtemstoolkit/elftoolchain/libelftc/os.NetBSD.mk | 2 + rtemstoolkit/wscript | 24 + 31 files changed, 10545 insertions(+) create mode 100644 rtemstoolkit/elftoolchain/libelftc/Makefile create mode 100644 rtemstoolkit/elftoolchain/libelftc/_libelftc.h create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc.3 create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_bfd_find_target.3 create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_bfdtarget.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.3 create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_demangle.3 create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_demangle.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.3 create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.3 create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_string_table.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_string_table_create.3 create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.3 create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_version.3 create mode 100644 rtemstoolkit/elftoolchain/libelftc/elftc_version.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/libelftc.h create mode 100644 rtemstoolkit/elftoolchain/libelftc/libelftc_bfdtarget.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/libelftc_dem_arm.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu2.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu3.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/libelftc_hash.c create mode 100644 rtemstoolkit/elftoolchain/libelftc/libelftc_vstr.c create mode 100755 rtemstoolkit/elftoolchain/libelftc/make-toolchain-version create mode 100644 rtemstoolkit/elftoolchain/libelftc/os.FreeBSD.mk create mode 100644 rtemstoolkit/elftoolchain/libelftc/os.Linux.mk create mode 100644 rtemstoolkit/elftoolchain/libelftc/os.NetBSD.mk diff --git a/rtemstoolkit/elftoolchain/libelftc/Makefile b/rtemstoolkit/elftoolchain/libelftc/Makefile new file mode 100644 index 0000000..cf4efc0 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/Makefile @@ -0,0 +1,60 @@ +# $Id: Makefile 3601 2018-04-12 16:58:53Z jkoshy $ + +TOP= .. + +LIB= elftc + +SRCS= elftc_bfdtarget.c \ + elftc_copyfile.c \ + elftc_demangle.c \ + elftc_reloc_type_str.c \ + elftc_set_timestamps.c \ + elftc_string_table.c \ + elftc_timestamp.c \ + elftc_version.c \ + libelftc_bfdtarget.c \ + libelftc_dem_arm.c \ + libelftc_dem_gnu2.c \ + libelftc_dem_gnu3.c \ + libelftc_hash.c \ + libelftc_vstr.c + +INCS= libelftc.h +INCSDIR= /usr/include + +RELEASE= HEAD # Change this on release branches. + +SHLIB_MAJOR= 1 + +WARNS?= 6 + +ELFTC_VERSION_FILE= ${.OBJDIR}/elftc_version.c +CLEANFILES+= ${ELFTC_VERSION_FILE} + +LDADD+= -lelf + +MAN= elftc.3 \ + elftc_bfd_find_target.3 \ + elftc_copyfile.3 \ + elftc_demangle.3 \ + elftc_reloc_type_str.3 \ + elftc_set_timestamps.3 \ + elftc_string_table_create.3 \ + elftc_version.3 + +MLINKS= elftc_bfd_find_target.3 elftc_bfd_target_byteorder.3 \ + elftc_bfd_find_target.3 elftc_bfd_target_class.3 \ + elftc_bfd_find_target.3 elftc_bfd_target_flavor.3 \ + elftc_string_table_create.3 elftc_string_table_from_section.3 \ + elftc_string_table_create.3 elftc_string_table_destroy.3 \ + elftc_string_table_create.3 elftc_string_table_image.3 \ + elftc_string_table_create.3 elftc_string_table_insert.3 \ + elftc_string_table_create.3 elftc_string_table_lookup.3 + +.if !make(clean) && !make(clobber) && !make(obj) +.BEGIN: .SILENT + ${.CURDIR}/make-toolchain-version -t ${.CURDIR}/${TOP} \ + -r ${RELEASE} -h ${OS_HOST} -o ${ELFTC_VERSION_FILE} +.endif + +.include "${TOP}/mk/elftoolchain.lib.mk" diff --git a/rtemstoolkit/elftoolchain/libelftc/_libelftc.h b/rtemstoolkit/elftoolchain/libelftc/_libelftc.h new file mode 100644 index 0000000..a56e29e --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/_libelftc.h @@ -0,0 +1,95 @@ +/*- + * Copyright (c) 2009 Kai Wang + * Copyright (c) 2007,2008 Hyogeol Lee + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: _libelftc.h 3531 2017-06-05 05:08:43Z kaiwang27 $ + */ + +#ifndef __LIBELFTC_H_ +#define __LIBELFTC_H_ + +#include + +#include "_elftc.h" + +struct _Elftc_Bfd_Target { + const char *bt_name; /* target name. */ + unsigned int bt_type; /* target type. */ + unsigned int bt_byteorder; /* elf target byteorder. */ + unsigned int bt_elfclass; /* elf target class (32/64bit). */ + unsigned int bt_machine; /* elf target arch. */ + unsigned int bt_osabi; /* elf target abi. */ +}; + +extern struct _Elftc_Bfd_Target _libelftc_targets[]; + +/** @brief Dynamic vector data for string. */ +struct vector_str { + /** Current size */ + size_t size; + /** Total capacity */ + size_t capacity; + /** String array */ + char **container; +}; + +#define BUFFER_GROWFACTOR 1.618 + +#define ELFTC_FAILURE 0 +#define ELFTC_ISDIGIT(C) (isdigit((C) & 0xFF)) +#define ELFTC_SUCCESS 1 + +#define VECTOR_DEF_CAPACITY 8 + + +#ifdef __cplusplus +extern "C" { +#endif +char *cpp_demangle_ARM(const char *_org); +char *cpp_demangle_gnu2(const char *_org); +char *cpp_demangle_gnu3(const char *_org); +bool is_cpp_mangled_ARM(const char *_org); +bool is_cpp_mangled_gnu2(const char *_org); +bool is_cpp_mangled_gnu3(const char *_org); +unsigned int libelftc_hash_string(const char *); +void vector_str_dest(struct vector_str *_vec); +int vector_str_find(const struct vector_str *_vs, const char *_str, + size_t _len); +char *vector_str_get_flat(const struct vector_str *_vs, size_t *_len); +bool vector_str_init(struct vector_str *_vs); +bool vector_str_pop(struct vector_str *_vs); +bool vector_str_push(struct vector_str *_vs, const char *_str, + size_t _len); +bool vector_str_push_vector(struct vector_str *_dst, + struct vector_str *_org); +bool vector_str_push_vector_head(struct vector_str *_dst, + struct vector_str *_org); +char *vector_str_substr(const struct vector_str *_vs, size_t _begin, + size_t _end, size_t *_rlen); +#ifdef __cplusplus +} +#endif + +#endif /* __LIBELFTC_H */ diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc.3 b/rtemstoolkit/elftoolchain/libelftc/elftc.3 new file mode 100644 index 0000000..bbf5173 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc.3 @@ -0,0 +1,83 @@ +.\" Copyright (c) 2012 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elftc.3 2818 2012-12-24 12:32:48Z jkoshy $ +.\" +.Dd December 24, 2012 +.Os +.Dt ELFTC 3 +.Sh NAME +.Nm elftc +.Nd support routines used in the Elftoolchain project +.Sh LIBRARY +.Lb libelftc +.Sh SYNOPSIS +.In libelftc.h +.Sh DESCRIPTION +The +.Lb libelftc +provides support routines used for developing the utilities in the +Elftoolchain source tree. +.Pp +This manual page serves as an overview of the functionality in this +library. +Additional reference information may be found in the individual +manual pages for the functions listed below. +.Ss Functional Grouping +.Bl -tag -width indent +.It "Binary Object Handling" +.Bl -tag -compact +.It Fn elftc_bfd_find_target +Locate a binary object descriptor. +.It Fn elftc_bfd_target_class +Query the ELF class for a binary object descriptor. +.It Fn elftc_bfd_target_byteorder +Query the byte order for a binary object descriptor. +.It Fn elftc_bfd_target_flavor +Query the object format for a binary object descriptor. +.It Fn elftc_bfd_target_machine +Query the target machine for a binary object descriptor. +.El +.It "C++ support" +.Bl -tag -compact +.It Fn elftc_demangle +Decodes a symbol name encoded according to the encoding rules for the +C++ language. +.El +.It "Programming conveniences" +.Bl -tag -compact +.It Fn elftc_copyfile +Copies the contents of a file to another. +.It Fn elftc_set_timestamp +Portably set the time stamps on a file. +.El +.It "Project Configuration" +.Bl -tag -compact +.It Fn elftc_version +Returns a project-wide identifier string that encodes the source +revision of the source tree. +.El +.El +.Sh SEE ALSO +.Xr dwarf 3 , +.Xr elf 3 diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_bfd_find_target.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_bfd_find_target.3 new file mode 100644 index 0000000..302c319 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_bfd_find_target.3 @@ -0,0 +1,200 @@ +.\" Copyright (c) 2010-2011 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elftc_bfd_find_target.3 3516 2017-02-10 02:33:08Z emaste $ +.\" +.Dd November 30, 2011 +.Os +.Dt ELFTC_BFD_FIND_TARGET +.Sh NAME +.Nm elftc_bfd_find_target , +.Nm elftc_bfd_target_byteorder , +.Nm elftc_bfd_target_class , +.Nm elftc_bfd_target_flavor , +.Nm elftc_bfd_target_machine +.Nd binary object descriptor handling +.Sh LIBRARY +.Lb libelftc +.Sh SYNOPSIS +.In libelftc.h +.Vt struct Elftc_Bfd_Target; +.Ft "Elftc_Bfd_Target *" +.Fn elftc_bfd_find_target "const char *target_name" +.Ft "unsigned int" +.Fn elftc_bfd_target_class "Elftc_Bfd_Target *target" +.Ft "unsigned int" +.Fn elftc_bfd_target_byteorder "Elftc_Bfd_Target *target" +.Ft Elftc_Bfd_Target_Flavor +.Fn elftc_bfd_target_flavor "Elftc_Bfd_Target *target" +.Ft "unsigned int" +.Fn elftc_bfd_target_machine "Elftc_Bfd_Target *target" +.Sh DESCRIPTION +Function +.Fn elftc_bfd_find_target +locates a binary object descriptor corresponding to the descriptor +name in argument +.Ar "target_name" . +Binary object descriptors encapsulate properties of an object format +such as its file representation, ELF class, and byte endianness. +.Pp +Known descriptor names and their properties include: +.Bl -column -offset "XXXX" ".Li elf32-x86-64-freebsd" "Object format" "Byte Order" "Bit Width" +.It Em Name Ta Em "Object Format" Ta Em "Byte Order" Ta Em "Bit Width" +.It Li binary Ta Binary Ta - Ta - +.It Li efi-app-ia32 Ta PE Ta LSB Ta 32 +.It Li efi-app-x86_64 Ta PE Ta LSB Ta 64 +.It Li elf32-avr Ta ELF Ta LSB Ta 32 +.It Li elf32-big Ta ELF Ta MSB Ta 32 +.It Li elf32-bigarm Ta ELF Ta MSB Ta 32 +.It Li elf32-bigmips Ta ELF Ta MSB Ta 32 +.It Li elf32-i386 Ta ELF Ta LSB Ta 32 +.It Li elf32-i386-freebsd Ta ELF Ta LSB Ta 32 +.It Li elf32-ia64-big Ta ELF Ta MSB Ta 32 +.It Li elf32-little Ta ELF Ta LSB Ta 32 +.It Li elf32-littlearm Ta ELF Ta LSB Ta 32 +.It Li elf32-littlemips Ta ELF Ta LSB Ta 32 +.It Li elf32-powerpc Ta ELF Ta MSB Ta 32 +.It Li elf32-powerpc-freebsd Ta ELF Ta MSB Ta 32 +.It Li elf32-powerpcle Ta ELF Ta LSB Ta 32 +.It Li elf32-sh Ta ELF Ta MSB Ta 32 +.It Li elf32-shl Ta ELF Ta LSB Ta 32 +.It Li elf32-sh-nbsd Ta ELF Ta MSB Ta 32 +.It Li elf32-shl-nbsd Ta ELF Ta LSB Ta 32 +.It Li elf32-shbig-linux Ta ELF Ta MSB Ta 32 +.It Li elf32-shl-linux Ta ELF Ta LSB Ta 32 +.It Li elf32-sparc Ta ELF Ta MSB Ta 32 +.It Li elf32-tradbigmips Ta ELF Ta MSB Ta 32 +.It Li elf32-tradlittlemips Ta ELF Ta LSB Ta 32 +.It Li elf64-alpha Ta ELF Ta LSB Ta 64 +.It Li elf64-alpha-freebsd Ta ELF Ta LSB Ta 64 +.It Li elf64-big Ta ELF Ta MSB Ta 64 +.It Li elf64-bigmips Ta ELF Ta MSB Ta 64 +.It Li elf64-ia64-big Ta ELF Ta MSB Ta 64 +.It Li elf64-ia64-little Ta ELF Ta LSB Ta 64 +.It Li elf64-little Ta ELF Ta LSB Ta 64 +.It Li elf64-littleaarch64 Ta ELF Ta LSB Ta 64 +.It Li elf64-littlemips Ta ELF Ta LSB Ta 64 +.It Li elf64-powerpc Ta ELF Ta MSB Ta 64 +.It Li elf64-powerpc-freebsd Ta ELF Ta MSB Ta 64 +.It Li elf64-powerpcle Ta ELF Ta LSB Ta 64 +.It Li elf64-sh64 Ta ELF Ta MSB Ta 64 +.It Li elf64-sh64l Ta ELF Ta LSB Ta 64 +.It Li elf64-sh64-nbsd Ta ELF Ta MSB Ta 64 +.It Li elf64-sh64l-nbsd Ta ELF Ta LSB Ta 64 +.It Li elf64-sh64big-linux Ta ELF Ta MSB Ta 64 +.It Li elf64-sh64-linux Ta ELF Ta LSB Ta 64 +.It Li elf64-sparc Ta ELF Ta MSB Ta 64 +.It Li elf64-sparc-freebsd Ta ELF Ta MSB Ta 64 +.It Li elf64-tradbigmips Ta ELF Ta MSB Ta 64 +.It Li elf64-tradlittlemips Ta ELF Ta LSB Ta 64 +.It Li elf64-x86-64 Ta ELF Ta LSB Ta 64 +.It Li elf64-x86-64-freebsd Ta ELF Ta LSB Ta 64 +.It Li ihex Ta IHEX Ta - Ta - +.It Li pei-i386 Ta PE Ta LSB Ta 32 +.It Li pei-x86-64 Ta PE Ta LSB Ta 64 +.It Li srec Ta SREC Ta - Ta - +.It Li symbolsrec Ta SREC Ta - Ta - +.El +.Pp +Function +.Fn elftc_bfd_target_byteorder +returns the ELF byte order associated with target descriptor +.Ar target . +.Pp +Function +.Fn elftc_bfd_target_class +returns the ELF class associated with target descriptor +.Ar target . +.Pp +Function +.Fn elftc_bfd_target_flavor +returns the object format associated with target descriptor +.Ar target . +The known object formats are: +.Bl -tag -offset "XXXX" -width ".Dv ETF_BINARY" -compact +.It Dv ETF_ELF +An ELF object. +.It Dv ETF_BINARY +Raw binary. +.It Dv ETF_IHEX +An object encoded in +.Tn Intel +hex format. +.It Dv ETF_NONE +An unknown object format. +.It Dv ETF_SREC +An object encoded as S-records. +.El +.Sh RETURN VALUES +Function +.Fn elftc_bfd_find_target +returns a valid pointer to an opaque binary target descriptor if +successful, or NULL in case of an error. +.Pp +Function +.Fn elftc_bfd_target_byteorder +returns the ELF byte order associated with the target descriptor; one of +.Dv ELFDATA2MSB +or +.Dv ELFDATA2LSB . +.Pp +Function +.Fn elftc_bfd_target_class +returns the ELF class associated with the target descriptor; one of +.Dv ELFCLASS32 +or +.Dv ELFCLASS64 . +.Pp +Function +.Fn elftc_bfd_target_machine +returns the ELF architecture associated with the target descriptor. +.Pp +Function +.Fn elftc_bfd_target_flavor +returns one of +.Dv ETF_BINARY , +.Dv ETF_ELF , +.Dv ETF_IHEX +or +.Dv ETF_SREC +if successful or +.Dv ETF_NONE +in case of error. +.Sh EXAMPLES +To return descriptor information associated with target name +.Dq elf64-big +use: +.Bd -literal -offset indent +struct Elftc_Bfd_Target *t; + +if ((t = elftc_bfd_find_target("elf64-big")) == NULL) + errx(EXIT_FAILURE, "Cannot find target descriptor"); + +printf("Class: %s\\n", elftc_bfd_target_class(t) == ELFCLASS32 ? + "ELFCLASS32" : "ELFCLASS64"); +printf("Byteorder: %s\\n", + elftc_bfd_target_byteorder(t) == ELFDATA2LSB ? "LSB" : "MSB"); +printf("Flavor: %d\\n", elftc_bfd_target_flavor(t)); +.Ed +.Sh SEE ALSO +.Xr elf 3 diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_bfdtarget.c b/rtemstoolkit/elftoolchain/libelftc/elftc_bfdtarget.c new file mode 100644 index 0000000..a5ae1a6 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_bfdtarget.c @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 2008,2009 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "_libelftc.h" + +ELFTC_VCSID("$Id: elftc_bfdtarget.c 3174 2015-03-27 17:13:41Z emaste $"); + +Elftc_Bfd_Target * +elftc_bfd_find_target(const char *tgt_name) +{ + Elftc_Bfd_Target *tgt; + + for (tgt = _libelftc_targets; tgt->bt_name; tgt++) + if (!strcmp(tgt_name, tgt->bt_name)) + return (tgt); + + return (NULL); /* not found */ +} + +Elftc_Bfd_Target_Flavor +elftc_bfd_target_flavor(Elftc_Bfd_Target *tgt) +{ + + return (tgt->bt_type); +} + +unsigned int +elftc_bfd_target_byteorder(Elftc_Bfd_Target *tgt) +{ + + return (tgt->bt_byteorder); +} + +unsigned int +elftc_bfd_target_class(Elftc_Bfd_Target *tgt) +{ + + return (tgt->bt_elfclass); +} + +unsigned int +elftc_bfd_target_machine(Elftc_Bfd_Target *tgt) +{ + + return (tgt->bt_machine); +} diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.3 new file mode 100644 index 0000000..4520433 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.3 @@ -0,0 +1,73 @@ +.\" Copyright (c) 2011 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elftc_copyfile.3 2315 2011-12-11 09:28:55Z jkoshy $ +.\" +.Dd December 11, 2011 +.Os +.Dt ELFTC_COPYFILE 3 +.Sh NAME +.Nm elftc_copyfile +.Nd convenience function to copy data +.Sh LIBRARY +.Lb libelftc +.Sh SYNOPSIS +.In libelftc.h +.Ft in +.Fn elftc_copyfile "int ifd" "int ofd" +.Sh DESCRIPTION +The function +.Fn elftc_copyfile +copies the contents of the file referenced by argument +.Ar ifd +to the file referenced by argument +.Ar ofd . +.Pp +The argument +.Ar ifd +should contain a file descriptor opened for reading, with its file +offset at the beginning of the file. +.Pp +The argument +.Ar ofd +should contain a file descriptor opened for writing. +.Sh RETURN VALUE +.Rv -std +.Sh ERRORS +The function +.Fn elftc_copyfile +may fail with any of the errors returned by +.Xr fstat 2 , +.Xr malloc 3 , +.Xr mmap 2 , +.Xr munmap 2 , +.Xr read 2 +or +.Xr write 2 . +.Sh SEE ALSO +.Xr fstat 2 , +.Xr malloc 3 , +.Xr mmap 2 , +.Xr munmap 2 , +.Xr read 2 , +.Xr write 2 diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.c b/rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.c new file mode 100644 index 0000000..dac9c14 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.c @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 2011, Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include + +#include "libelftc.h" +#include "_libelftc.h" + +#if ELFTC_HAVE_MMAP +#include +#endif + +ELFTC_VCSID("$Id: elftc_copyfile.c 3297 2016-01-09 15:26:34Z jkoshy $"); + +/* + * Copy the contents referenced by 'ifd' to 'ofd'. Returns 0 on + * success and -1 on error. + */ + +int +elftc_copyfile(int ifd, int ofd) +{ + size_t file_size, n; + int buf_mmapped; + struct stat sb; + char *b, *buf; + ssize_t nr, nw; + + /* Determine the input file's size. */ + if (fstat(ifd, &sb) < 0) + return (-1); + + /* Skip files without content. */ + if (sb.st_size == 0) + return (0); + + buf = NULL; + buf_mmapped = 0; + file_size = (size_t) sb.st_size; + +#if ELFTC_HAVE_MMAP + /* + * Prefer mmap() if it is available. + */ + buf = mmap(NULL, file_size, PROT_READ, MAP_SHARED, ifd, (off_t) 0); + if (buf != MAP_FAILED) + buf_mmapped = 1; + else + buf = NULL; +#endif + + /* + * If mmap() is not available, or if the mmap() operation + * failed, allocate a buffer, and read in input data. + */ + if (buf_mmapped == false) { + if ((buf = malloc(file_size)) == NULL) + return (-1); + b = buf; + for (n = file_size; n > 0; n -= (size_t) nr, b += nr) { + if ((nr = read(ifd, b, n)) < 0) { + free(buf); + return (-1); + } + } + } + + /* + * Write data to the output file descriptor. + */ + for (n = file_size, b = buf; n > 0; n -= (size_t) nw, b += nw) + if ((nw = write(ofd, b, n)) <= 0) + break; + + /* Release the input buffer. */ +#if ELFTC_HAVE_MMAP + if (buf_mmapped && munmap(buf, file_size) < 0) + return (-1); +#endif + + if (!buf_mmapped) + free(buf); + + return (n > 0 ? -1 : 0); +} + diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_demangle.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_demangle.3 new file mode 100644 index 0000000..44cf007 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_demangle.3 @@ -0,0 +1,116 @@ +.\" Copyright (c) 2009,2011 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elftc_demangle.3 3182 2015-04-10 16:08:10Z emaste $ +.\" +.Dd August 24, 2011 +.Os +.Dt ELFTC_DEMANGLE 3 +.Sh NAME +.Nm elftc_demangle +.Nd demangle a C++ name +.Sh LIBRARY +.Lb libelftc +.Sh SYNOPSIS +.In libelftc.h +.Ft int +.Fo elftc_demangle +.Fa "const char *encodedname" +.Fa "char *buffer" +.Fa "size_t bufsize" +.Fa "unsigned int flags" +.Fc +.Sh DESCRIPTION +Function +.Fn elftc_demangle +decodes a symbol name encoded according to the type encoding rules +for the C++ language and returns a string denoting an equivalent +C++ prototype. +.Pp +Argument +.Ar encodedname +specifies the encoded symbol name. +Argument +.Ar buffer +denotes a programmer-specified area to place the prototype string in. +Argument +.Ar bufsize +specifies the size of the programmer-specified area. +Argument +.Ar flags +specifies the encoding style in use for argument +.Ar encodedname . +Supported encoding styles are: +.Bl -tag -width ".Dv ELFTC_DEM_GNU3" +.It Dv ELFTC_DEM_ARM +The encoding style used by compilers adhering to the conventions of the +C++ Annotated Reference Manual. +.It Dv ELFTC_DEM_GNU2 +The encoding style by GNU C++ version 2. +.It Dv ELFTC_DEM_GNU3 +The encoding style by GNU C++ version 3 and later. +.El +.Pp +Argument +.Ar flags +may be zero, in which case the function will attempt to guess the +encoding scheme from the contents of +.Ar encodedname . +.Sh RETURN VALUE +Function +.Fn elftc_demangle +returns 0 on success. +In case of an error it returns -1 and sets the +.Va errno +variable. +.Sh EXAMPLES +To decode a name that uses an unknown encoding style use: +.Bd -literal -offset indent +char buffer[1024]; +const char *funcname; + +funcname = ...; /* points to string to be demangled */ +if (elftc_demangle(funcname, buffer, sizeof(buffer), 0) == 0) + printf("Demangled name: %\\n", buffer); +else + perror("Cannot demangle %s", funcname); +.Ed +.Sh ERRORS +Function +.Fn elftc_demangle +may fail with the following errors: +.Bl -tag -width ".Bq Er ENAMETOOLONG" +.It Bq Er EINVAL +Argument +.Ar encodedname +was not a valid encoded name. +.It Bq Er ENAMETOOLONG +The output buffer specified by arguments +.Ar buffer +and +.Ar bufsize +was too small to hold the decoded function prototype. +.El +.Sh SEE ALSO +.Xr elf 3 , +.Xr elf_strptr 3 diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_demangle.c b/rtemstoolkit/elftoolchain/libelftc/elftc_demangle.c new file mode 100644 index 0000000..945f777 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_demangle.c @@ -0,0 +1,107 @@ +/*- + * Copyright (c) 2009 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "_libelftc.h" + +ELFTC_VCSID("$Id: elftc_demangle.c 3296 2016-01-09 14:17:28Z jkoshy $"); + +static unsigned int +is_mangled(const char *s, unsigned int style) +{ + + switch (style) { + case ELFTC_DEM_ARM: return (is_cpp_mangled_ARM(s) ? style : 0); + case ELFTC_DEM_GNU2: return (is_cpp_mangled_gnu2(s) ? style : 0); + case ELFTC_DEM_GNU3: return (is_cpp_mangled_gnu3(s) ? style : 0); + } + + /* No style or invalid style spcified, try to guess. */ + if (is_cpp_mangled_gnu3(s)) + return (ELFTC_DEM_GNU3); + if (is_cpp_mangled_gnu2(s)) + return (ELFTC_DEM_GNU2); + if (is_cpp_mangled_ARM(s)) + return (ELFTC_DEM_ARM); + + /* Cannot be demangled. */ + return (0); +} + +static char * +demangle(const char *s, unsigned int style, unsigned int rc) +{ + + (void) rc; /* XXX */ + switch (style) { + case ELFTC_DEM_ARM: return (cpp_demangle_ARM(s)); + case ELFTC_DEM_GNU2: return (cpp_demangle_gnu2(s)); + case ELFTC_DEM_GNU3: return (cpp_demangle_gnu3(s)); + default: + assert(0); + return (NULL); + } +} + +int +elftc_demangle(const char *mangledname, char *buffer, size_t bufsize, + unsigned int flags) +{ + unsigned int style, rc; + char *rlt; + + style = flags & 0xFFFF; + rc = flags >> 16; + + if (mangledname == NULL || + ((style = is_mangled(mangledname, style)) == 0)) { + errno = EINVAL; + return (-1); + } + + if ((rlt = demangle(mangledname, style, rc)) == NULL) { + errno = EINVAL; + return (-1); + } + + if (buffer == NULL || bufsize < strlen(rlt) + 1) { + free(rlt); + errno = ENAMETOOLONG; + return (-1); + } + + strncpy(buffer, rlt, bufsize); + buffer[bufsize - 1] = '\0'; + free(rlt); + + return (0); +} diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.3 new file mode 100644 index 0000000..5cd08a6 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.3 @@ -0,0 +1,72 @@ +.\" Copyright (c) 2016 The FreeBSD Foundation. All rights reserved. +.\" +.\" This documentation was written by Ed Maste under sponsorship of +.\" the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by the author and contributors ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. In no event shall the author or contributors be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id$ +.\" +.Dd February 19, 2016 +.Os +.Dt ELFTC_RELOC_TYPE_STR 3 +.Sh NAME +.Nm elftc_reloc_type_str +.Nd return the type name for an ELF relocation +.Sh LIBRARY +.Lb libelftc +.Sh SYNOPSIS +.In libelftc.h +.Ft const char * +.Fo elftc_reloc_type_str +.Fa "unsigned int mach" +.Fa "unsigned int type" +.Fc +.Sh DESCRIPTION +Function +.Fn elftc_reloc_type_str +returns the name for specified relocation type. +.Pp +Argument +.Ar mach +specifies the machine (architecture) type. +Argument +.Ar type +specifies the relocation value. +.Sh RETURN VALUE +Function +.Fn elftc_program_version +returns a pointer to a string constant, or to an internal character buffer +if the relocation type is unknown. +.Sh EXAMPLES +To print ARM relocation type 7, use: +.Bd -literal -offset indent +#include +#include +#include + +(void) printf("%s\en", elftc_reloc_type_str(EM_ARM, 7)); +.Ed +.Sh ERRORS +Function +.Fn elftc_reloc_type_str +always succeeds. diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.c b/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.c new file mode 100644 index 0000000..fdad9a6 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.c @@ -0,0 +1,832 @@ +/*- + * Copyright (c) 2009-2015 Kai Wang + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Ed Maste under sponsorship + * of the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +const char * +elftc_reloc_type_str(unsigned int mach, unsigned int type) +{ + static char s_type[32]; + + switch(mach) { + case EM_386: + case EM_IAMCU: + switch(type) { + case 0: return "R_386_NONE"; + case 1: return "R_386_32"; + case 2: return "R_386_PC32"; + case 3: return "R_386_GOT32"; + case 4: return "R_386_PLT32"; + case 5: return "R_386_COPY"; + case 6: return "R_386_GLOB_DAT"; + case 7: return "R_386_JUMP_SLOT"; + case 8: return "R_386_RELATIVE"; + case 9: return "R_386_GOTOFF"; + case 10: return "R_386_GOTPC"; + case 11: return "R_386_32PLT"; /* Not in psabi */ + case 14: return "R_386_TLS_TPOFF"; + case 15: return "R_386_TLS_IE"; + case 16: return "R_386_TLS_GOTIE"; + case 17: return "R_386_TLS_LE"; + case 18: return "R_386_TLS_GD"; + case 19: return "R_386_TLS_LDM"; + case 20: return "R_386_16"; + case 21: return "R_386_PC16"; + case 22: return "R_386_8"; + case 23: return "R_386_PC8"; + case 24: return "R_386_TLS_GD_32"; + case 25: return "R_386_TLS_GD_PUSH"; + case 26: return "R_386_TLS_GD_CALL"; + case 27: return "R_386_TLS_GD_POP"; + case 28: return "R_386_TLS_LDM_32"; + case 29: return "R_386_TLS_LDM_PUSH"; + case 30: return "R_386_TLS_LDM_CALL"; + case 31: return "R_386_TLS_LDM_POP"; + case 32: return "R_386_TLS_LDO_32"; + case 33: return "R_386_TLS_IE_32"; + case 34: return "R_386_TLS_LE_32"; + case 35: return "R_386_TLS_DTPMOD32"; + case 36: return "R_386_TLS_DTPOFF32"; + case 37: return "R_386_TLS_TPOFF32"; + case 38: return "R_386_SIZE32"; + case 39: return "R_386_TLS_GOTDESC"; + case 40: return "R_386_TLS_DESC_CALL"; + case 41: return "R_386_TLS_DESC"; + case 42: return "R_386_IRELATIVE"; + case 43: return "R_386_GOT32X"; + } + break; + case EM_AARCH64: + switch(type) { + case 0: return "R_AARCH64_NONE"; + case 257: return "R_AARCH64_ABS64"; + case 258: return "R_AARCH64_ABS32"; + case 259: return "R_AARCH64_ABS16"; + case 260: return "R_AARCH64_PREL64"; + case 261: return "R_AARCH64_PREL32"; + case 262: return "R_AARCH64_PREL16"; + case 263: return "R_AARCH64_MOVW_UABS_G0"; + case 264: return "R_AARCH64_MOVW_UABS_G0_NC"; + case 265: return "R_AARCH64_MOVW_UABS_G1"; + case 266: return "R_AARCH64_MOVW_UABS_G1_NC"; + case 267: return "R_AARCH64_MOVW_UABS_G2"; + case 268: return "R_AARCH64_MOVW_UABS_G2_NC"; + case 269: return "R_AARCH64_MOVW_UABS_G3"; + case 270: return "R_AARCH64_MOVW_SABS_G0"; + case 271: return "R_AARCH64_MOVW_SABS_G1"; + case 272: return "R_AARCH64_MOVW_SABS_G2"; + case 273: return "R_AARCH64_LD_PREL_LO19"; + case 274: return "R_AARCH64_ADR_PREL_LO21"; + case 275: return "R_AARCH64_ADR_PREL_PG_HI21"; + case 276: return "R_AARCH64_ADR_PREL_PG_HI21_NC"; + case 277: return "R_AARCH64_ADD_ABS_LO12_NC"; + case 278: return "R_AARCH64_LDST8_ABS_LO12_NC"; + case 279: return "R_AARCH64_TSTBR14"; + case 280: return "R_AARCH64_CONDBR19"; + case 282: return "R_AARCH64_JUMP26"; + case 283: return "R_AARCH64_CALL26"; + case 284: return "R_AARCH64_LDST16_ABS_LO12_NC"; + case 285: return "R_AARCH64_LDST32_ABS_LO12_NC"; + case 286: return "R_AARCH64_LDST64_ABS_LO12_NC"; + case 287: return "R_AARCH64_MOVW_PREL_G0"; + case 288: return "R_AARCH64_MOVW_PREL_G0_NC"; + case 289: return "R_AARCH64_MOVW_PREL_G1"; + case 290: return "R_AARCH64_MOVW_PREL_G1_NC"; + case 291: return "R_AARCH64_MOVW_PREL_G2"; + case 292: return "R_AARCH64_MOVW_PREL_G2_NC"; + case 293: return "R_AARCH64_MOVW_PREL_G3"; + case 299: return "R_AARCH64_LDST128_ABS_LO12_NC"; + case 300: return "R_AARCH64_MOVW_GOTOFF_G0"; + case 301: return "R_AARCH64_MOVW_GOTOFF_G0_NC"; + case 302: return "R_AARCH64_MOVW_GOTOFF_G1"; + case 303: return "R_AARCH64_MOVW_GOTOFF_G1_NC"; + case 304: return "R_AARCH64_MOVW_GOTOFF_G2"; + case 305: return "R_AARCH64_MOVW_GOTOFF_G2_NC"; + case 306: return "R_AARCH64_MOVW_GOTOFF_G3"; + case 307: return "R_AARCH64_GOTREL64"; + case 308: return "R_AARCH64_GOTREL32"; + case 309: return "R_AARCH64_GOT_LD_PREL19"; + case 310: return "R_AARCH64_LD64_GOTOFF_LO15"; + case 311: return "R_AARCH64_ADR_GOT_PAGE"; + case 312: return "R_AARCH64_LD64_GOT_LO12_NC"; + case 313: return "R_AARCH64_LD64_GOTPAGE_LO15"; + case 560: return "R_AARCH64_TLSDESC_LD_PREL19"; + case 561: return "R_AARCH64_TLSDESC_ADR_PREL21"; + case 562: return "R_AARCH64_TLSDESC_ADR_PAGE21"; + case 563: return "R_AARCH64_TLSDESC_LD64_LO12"; + case 564: return "R_AARCH64_TLSDESC_ADD_LO12"; + case 565: return "R_AARCH64_TLSDESC_OFF_G1"; + case 566: return "R_AARCH64_TLSDESC_OFF_G0_NC"; + case 567: return "R_AARCH64_TLSDESC_LDR"; + case 568: return "R_AARCH64_TLSDESC_ADD"; + case 569: return "R_AARCH64_TLSDESC_CALL"; + case 1024: return "R_AARCH64_COPY"; + case 1025: return "R_AARCH64_GLOB_DAT"; + case 1026: return "R_AARCH64_JUMP_SLOT"; + case 1027: return "R_AARCH64_RELATIVE"; + case 1028: return "R_AARCH64_TLS_DTPREL64"; + case 1029: return "R_AARCH64_TLS_DTPMOD64"; + case 1030: return "R_AARCH64_TLS_TPREL64"; + case 1031: return "R_AARCH64_TLSDESC"; + case 1032: return "R_AARCH64_IRELATIVE"; + } + break; + case EM_ARM: + switch(type) { + case 0: return "R_ARM_NONE"; + case 1: return "R_ARM_PC24"; /* Deprecated */ + case 2: return "R_ARM_ABS32"; + case 3: return "R_ARM_REL32"; + case 4: return "R_ARM_LDR_PC_G0"; /* Also R_ARM_PC13 */ + case 5: return "R_ARM_ABS16"; + case 6: return "R_ARM_ABS12"; + case 7: return "R_ARM_THM_ABS5"; + case 8: return "R_ARM_ABS8"; + case 9: return "R_ARM_SBREL32"; + case 10: return "R_ARM_THM_CALL"; /* Also R_ARM_THM_PC22 */ + case 11: return "R_ARM_THM_PC8"; + case 12: return "R_ARM_BREL_ADJ"; /* Also R_ARM_AMP_VCALL9 */ + case 13: return "R_ARM_TLS_DESC"; /* Also R_ARM_SWI24 */ + case 14: return "R_ARM_THM_SWI8"; /* Obsolete */ + case 15: return "R_ARM_XPC25"; /* Obsolete */ + case 16: return "R_ARM_THM_XPC22"; /* Obsolete */ + case 17: return "R_ARM_TLS_DTPMOD32"; + case 18: return "R_ARM_TLS_DTPOFF32"; + case 19: return "R_ARM_TLS_TPOFF32"; + case 20: return "R_ARM_COPY"; + case 21: return "R_ARM_GLOB_DAT"; + case 22: return "R_ARM_JUMP_SLOT"; + case 23: return "R_ARM_RELATIVE"; + case 24: return "R_ARM_GOTOFF32"; /* Also R_ARM_GOTOFF */ + case 25: return "R_ARM_BASE_PREL"; /* GNU R_ARM_GOTPC */ + case 26: return "R_ARM_GOT_BREL"; /* GNU R_ARM_GOT32 */ + case 27: return "R_ARM_PLT32"; /* Deprecated */ + case 28: return "R_ARM_CALL"; + case 29: return "R_ARM_JUMP24"; + case 30: return "R_ARM_THM_JUMP24"; + case 31: return "R_ARM_BASE_ABS"; + case 32: return "R_ARM_ALU_PCREL_7_0"; /* Obsolete */ + case 33: return "R_ARM_ALU_PCREL_15_8"; /* Obsolete */ + case 34: return "R_ARM_ALU_PCREL_23_15"; /* Obsolete */ + case 35: return "R_ARM_LDR_SBREL_11_0_NC"; /* Deprecated */ + case 36: return "R_ARM_ALU_SBREL_19_12_NC"; /* Deprecated */ + case 37: return "R_ARM_ALU_SBREL_27_20_CK"; /* Deprecated */ + case 38: return "R_ARM_TARGET1"; + case 39: return "R_ARM_SBREL31"; /* Deprecated. */ + case 40: return "R_ARM_V4BX"; + case 41: return "R_ARM_TARGET2"; + case 42: return "R_ARM_PREL31"; + case 43: return "R_ARM_MOVW_ABS_NC"; + case 44: return "R_ARM_MOVT_ABS"; + case 45: return "R_ARM_MOVW_PREL_NC"; + case 46: return "R_ARM_MOVT_PREL"; + case 47: return "R_ARM_THM_MOVW_ABS_NC"; + case 48: return "R_ARM_THM_MOVT_ABS"; + case 49: return "R_ARM_THM_MOVW_PREL_NC"; + case 50: return "R_ARM_THM_MOVT_PREL"; + case 51: return "R_ARM_THM_JUMP19"; + case 52: return "R_ARM_THM_JUMP6"; + case 53: return "R_ARM_THM_ALU_PREL_11_0"; + case 54: return "R_ARM_THM_PC12"; + case 55: return "R_ARM_ABS32_NOI"; + case 56: return "R_ARM_REL32_NOI"; + case 57: return "R_ARM_ALU_PC_G0_NC"; + case 58: return "R_ARM_ALU_PC_G0"; + case 59: return "R_ARM_ALU_PC_G1_NC"; + case 60: return "R_ARM_ALU_PC_G1"; + case 61: return "R_ARM_ALU_PC_G2"; + case 62: return "R_ARM_LDR_PC_G1"; + case 63: return "R_ARM_LDR_PC_G2"; + case 64: return "R_ARM_LDRS_PC_G0"; + case 65: return "R_ARM_LDRS_PC_G1"; + case 66: return "R_ARM_LDRS_PC_G2"; + case 67: return "R_ARM_LDC_PC_G0"; + case 68: return "R_ARM_LDC_PC_G1"; + case 69: return "R_ARM_LDC_PC_G2"; + case 70: return "R_ARM_ALU_SB_G0_NC"; + case 71: return "R_ARM_ALU_SB_G0"; + case 72: return "R_ARM_ALU_SB_G1_NC"; + case 73: return "R_ARM_ALU_SB_G1"; + case 74: return "R_ARM_ALU_SB_G2"; + case 75: return "R_ARM_LDR_SB_G0"; + case 76: return "R_ARM_LDR_SB_G1"; + case 77: return "R_ARM_LDR_SB_G2"; + case 78: return "R_ARM_LDRS_SB_G0"; + case 79: return "R_ARM_LDRS_SB_G1"; + case 80: return "R_ARM_LDRS_SB_G2"; + case 81: return "R_ARM_LDC_SB_G0"; + case 82: return "R_ARM_LDC_SB_G1"; + case 83: return "R_ARM_LDC_SB_G2"; + case 84: return "R_ARM_MOVW_BREL_NC"; + case 85: return "R_ARM_MOVT_BREL"; + case 86: return "R_ARM_MOVW_BREL"; + case 87: return "R_ARM_THM_MOVW_BREL_NC"; + case 88: return "R_ARM_THM_MOVT_BREL"; + case 89: return "R_ARM_THM_MOVW_BREL"; + case 90: return "R_ARM_TLS_GOTDESC"; + case 91: return "R_ARM_TLS_CALL"; + case 92: return "R_ARM_TLS_DESCSEQ"; + case 93: return "R_ARM_THM_TLS_CALL"; + case 94: return "R_ARM_PLT32_ABS"; + case 95: return "R_ARM_GOT_ABS"; + case 96: return "R_ARM_GOT_PREL"; + case 97: return "R_ARM_GOT_BREL12"; + case 98: return "R_ARM_GOTOFF12"; + case 99: return "R_ARM_GOTRELAX"; + case 100: return "R_ARM_GNU_VTENTRY"; + case 101: return "R_ARM_GNU_VTINHERIT"; + case 102: return "R_ARM_THM_JUMP11"; /* Also R_ARM_THM_PC11 */ + case 103: return "R_ARM_THM_JUMP8"; /* Also R_ARM_THM_PC9 */ + case 104: return "R_ARM_TLS_GD32"; + case 105: return "R_ARM_TLS_LDM32"; + case 106: return "R_ARM_TLS_LDO32"; + case 107: return "R_ARM_TLS_IE32"; + case 108: return "R_ARM_TLS_LE32"; + case 109: return "R_ARM_TLS_LDO12"; + case 110: return "R_ARM_TLS_LE12"; + case 111: return "R_ARM_TLS_IE12GP"; + /* 112-127 R_ARM_PRIVATE_ */ + case 128: return "R_ARM_ME_TOO"; /* Obsolete */ + case 129: return "R_ARM_THM_TLS_DESCSEQ16"; + case 130: return "R_ARM_THM_TLS_DESCSEQ32"; + case 131: return "R_ARM_THM_GOT_BREL12"; + case 132: return "R_ARM_THM_ALU_ABS_G0_NC"; + case 133: return "R_ARM_THM_ALU_ABS_G1_NC"; + case 134: return "R_ARM_THM_ALU_ABS_G2_NC"; + case 135: return "R_ARM_THM_ALU_ABS_G3"; + /* 136-159 Reserved for future allocation. */ + case 160: return "R_ARM_IRELATIVE"; + /* 161-255 Reserved for future allocation. */ + case 249: return "R_ARM_RXPC25"; + case 250: return "R_ARM_RSBREL32"; + case 251: return "R_ARM_THM_RPC22"; + case 252: return "R_ARM_RREL32"; + case 253: return "R_ARM_RABS32"; + case 254: return "R_ARM_RPC24"; + case 255: return "R_ARM_RBASE"; + } + break; + case EM_IA_64: + switch(type) { + case 0: return "R_IA_64_NONE"; + case 33: return "R_IA_64_IMM14"; + case 34: return "R_IA_64_IMM22"; + case 35: return "R_IA_64_IMM64"; + case 36: return "R_IA_64_DIR32MSB"; + case 37: return "R_IA_64_DIR32LSB"; + case 38: return "R_IA_64_DIR64MSB"; + case 39: return "R_IA_64_DIR64LSB"; + case 42: return "R_IA_64_GPREL22"; + case 43: return "R_IA_64_GPREL64I"; + case 44: return "R_IA_64_GPREL32MSB"; + case 45: return "R_IA_64_GPREL32LSB"; + case 46: return "R_IA_64_GPREL64MSB"; + case 47: return "R_IA_64_GPREL64LSB"; + case 50: return "R_IA_64_LTOFF22"; + case 51: return "R_IA_64_LTOFF64I"; + case 58: return "R_IA_64_PLTOFF22"; + case 59: return "R_IA_64_PLTOFF64I"; + case 62: return "R_IA_64_PLTOFF64MSB"; + case 63: return "R_IA_64_PLTOFF64LSB"; + case 67: return "R_IA_64_FPTR64I"; + case 68: return "R_IA_64_FPTR32MSB"; + case 69: return "R_IA_64_FPTR32LSB"; + case 70: return "R_IA_64_FPTR64MSB"; + case 71: return "R_IA_64_FPTR64LSB"; + case 72: return "R_IA_64_PCREL60B"; + case 73: return "R_IA_64_PCREL21B"; + case 74: return "R_IA_64_PCREL21M"; + case 75: return "R_IA_64_PCREL21F"; + case 76: return "R_IA_64_PCREL32MSB"; + case 77: return "R_IA_64_PCREL32LSB"; + case 78: return "R_IA_64_PCREL64MSB"; + case 79: return "R_IA_64_PCREL64LSB"; + case 82: return "R_IA_64_LTOFF_FPTR22"; + case 83: return "R_IA_64_LTOFF_FPTR64I"; + case 84: return "R_IA_64_LTOFF_FPTR32MSB"; + case 85: return "R_IA_64_LTOFF_FPTR32LSB"; + case 86: return "R_IA_64_LTOFF_FPTR64MSB"; + case 87: return "R_IA_64_LTOFF_FPTR64LSB"; + case 92: return "R_IA_64_SEGREL32MSB"; + case 93: return "R_IA_64_SEGREL32LSB"; + case 94: return "R_IA_64_SEGREL64MSB"; + case 95: return "R_IA_64_SEGREL64LSB"; + case 100: return "R_IA_64_SECREL32MSB"; + case 101: return "R_IA_64_SECREL32LSB"; + case 102: return "R_IA_64_SECREL64MSB"; + case 103: return "R_IA_64_SECREL64LSB"; + case 108: return "R_IA_64_REL32MSB"; + case 109: return "R_IA_64_REL32LSB"; + case 110: return "R_IA_64_REL64MSB"; + case 111: return "R_IA_64_REL64LSB"; + case 116: return "R_IA_64_LTV32MSB"; + case 117: return "R_IA_64_LTV32LSB"; + case 118: return "R_IA_64_LTV64MSB"; + case 119: return "R_IA_64_LTV64LSB"; + case 121: return "R_IA_64_PCREL21BI"; + case 122: return "R_IA_64_PCREL22"; + case 123: return "R_IA_64_PCREL64I"; + case 128: return "R_IA_64_IPLTMSB"; + case 129: return "R_IA_64_IPLTLSB"; + case 133: return "R_IA_64_SUB"; + case 134: return "R_IA_64_LTOFF22X"; + case 135: return "R_IA_64_LDXMOV"; + case 145: return "R_IA_64_TPREL14"; + case 146: return "R_IA_64_TPREL22"; + case 147: return "R_IA_64_TPREL64I"; + case 150: return "R_IA_64_TPREL64MSB"; + case 151: return "R_IA_64_TPREL64LSB"; + case 154: return "R_IA_64_LTOFF_TPREL22"; + case 166: return "R_IA_64_DTPMOD64MSB"; + case 167: return "R_IA_64_DTPMOD64LSB"; + case 170: return "R_IA_64_LTOFF_DTPMOD22"; + case 177: return "R_IA_64_DTPREL14"; + case 178: return "R_IA_64_DTPREL22"; + case 179: return "R_IA_64_DTPREL64I"; + case 180: return "R_IA_64_DTPREL32MSB"; + case 181: return "R_IA_64_DTPREL32LSB"; + case 182: return "R_IA_64_DTPREL64MSB"; + case 183: return "R_IA_64_DTPREL64LSB"; + case 186: return "R_IA_64_LTOFF_DTPREL22"; + } + break; + case EM_MIPS: + switch(type) { + case 0: return "R_MIPS_NONE"; + case 1: return "R_MIPS_16"; + case 2: return "R_MIPS_32"; + case 3: return "R_MIPS_REL32"; + case 4: return "R_MIPS_26"; + case 5: return "R_MIPS_HI16"; + case 6: return "R_MIPS_LO16"; + case 7: return "R_MIPS_GPREL16"; + case 8: return "R_MIPS_LITERAL"; + case 9: return "R_MIPS_GOT16"; + case 10: return "R_MIPS_PC16"; + case 11: return "R_MIPS_CALL16"; + case 12: return "R_MIPS_GPREL32"; + case 16: return "R_MIPS_SHIFT5"; + case 17: return "R_MIPS_SHIFT6"; + case 18: return "R_MIPS_64"; + case 19: return "R_MIPS_GOT_DISP"; + case 20: return "R_MIPS_GOT_PAGE"; + case 21: return "R_MIPS_GOT_OFST"; + case 22: return "R_MIPS_GOT_HI16"; + case 23: return "R_MIPS_GOT_LO16"; + case 24: return "R_MIPS_SUB"; + case 30: return "R_MIPS_CALLHI16"; + case 31: return "R_MIPS_CALLLO16"; + case 37: return "R_MIPS_JALR"; + case 38: return "R_MIPS_TLS_DTPMOD32"; + case 39: return "R_MIPS_TLS_DTPREL32"; + case 40: return "R_MIPS_TLS_DTPMOD64"; + case 41: return "R_MIPS_TLS_DTPREL64"; + case 42: return "R_MIPS_TLS_GD"; + case 43: return "R_MIPS_TLS_LDM"; + case 44: return "R_MIPS_TLS_DTPREL_HI16"; + case 45: return "R_MIPS_TLS_DTPREL_LO16"; + case 46: return "R_MIPS_TLS_GOTTPREL"; + case 47: return "R_MIPS_TLS_TPREL32"; + case 48: return "R_MIPS_TLS_TPREL64"; + case 49: return "R_MIPS_TLS_TPREL_HI16"; + case 50: return "R_MIPS_TLS_TPREL_LO16"; + } + break; + case EM_PPC: + switch(type) { + case 0: return "R_PPC_NONE"; + case 1: return "R_PPC_ADDR32"; + case 2: return "R_PPC_ADDR24"; + case 3: return "R_PPC_ADDR16"; + case 4: return "R_PPC_ADDR16_LO"; + case 5: return "R_PPC_ADDR16_HI"; + case 6: return "R_PPC_ADDR16_HA"; + case 7: return "R_PPC_ADDR14"; + case 8: return "R_PPC_ADDR14_BRTAKEN"; + case 9: return "R_PPC_ADDR14_BRNTAKEN"; + case 10: return "R_PPC_REL24"; + case 11: return "R_PPC_REL14"; + case 12: return "R_PPC_REL14_BRTAKEN"; + case 13: return "R_PPC_REL14_BRNTAKEN"; + case 14: return "R_PPC_GOT16"; + case 15: return "R_PPC_GOT16_LO"; + case 16: return "R_PPC_GOT16_HI"; + case 17: return "R_PPC_GOT16_HA"; + case 18: return "R_PPC_PLTREL24"; + case 19: return "R_PPC_COPY"; + case 20: return "R_PPC_GLOB_DAT"; + case 21: return "R_PPC_JMP_SLOT"; + case 22: return "R_PPC_RELATIVE"; + case 23: return "R_PPC_LOCAL24PC"; + case 24: return "R_PPC_UADDR32"; + case 25: return "R_PPC_UADDR16"; + case 26: return "R_PPC_REL32"; + case 27: return "R_PPC_PLT32"; + case 28: return "R_PPC_PLTREL32"; + case 29: return "R_PPC_PLT16_LO"; + case 30: return "R_PPC_PLT16_HI"; + case 31: return "R_PPC_PLT16_HA"; + case 32: return "R_PPC_SDAREL16"; + case 33: return "R_PPC_SECTOFF"; + case 34: return "R_PPC_SECTOFF_LO"; + case 35: return "R_PPC_SECTOFF_HI"; + case 36: return "R_PPC_SECTOFF_HA"; + case 67: return "R_PPC_TLS"; + case 68: return "R_PPC_DTPMOD32"; + case 69: return "R_PPC_TPREL16"; + case 70: return "R_PPC_TPREL16_LO"; + case 71: return "R_PPC_TPREL16_HI"; + case 72: return "R_PPC_TPREL16_HA"; + case 73: return "R_PPC_TPREL32"; + case 74: return "R_PPC_DTPREL16"; + case 75: return "R_PPC_DTPREL16_LO"; + case 76: return "R_PPC_DTPREL16_HI"; + case 77: return "R_PPC_DTPREL16_HA"; + case 78: return "R_PPC_DTPREL32"; + case 79: return "R_PPC_GOT_TLSGD16"; + case 80: return "R_PPC_GOT_TLSGD16_LO"; + case 81: return "R_PPC_GOT_TLSGD16_HI"; + case 82: return "R_PPC_GOT_TLSGD16_HA"; + case 83: return "R_PPC_GOT_TLSLD16"; + case 84: return "R_PPC_GOT_TLSLD16_LO"; + case 85: return "R_PPC_GOT_TLSLD16_HI"; + case 86: return "R_PPC_GOT_TLSLD16_HA"; + case 87: return "R_PPC_GOT_TPREL16"; + case 88: return "R_PPC_GOT_TPREL16_LO"; + case 89: return "R_PPC_GOT_TPREL16_HI"; + case 90: return "R_PPC_GOT_TPREL16_HA"; + case 101: return "R_PPC_EMB_NADDR32"; + case 102: return "R_PPC_EMB_NADDR16"; + case 103: return "R_PPC_EMB_NADDR16_LO"; + case 104: return "R_PPC_EMB_NADDR16_HI"; + case 105: return "R_PPC_EMB_NADDR16_HA"; + case 106: return "R_PPC_EMB_SDAI16"; + case 107: return "R_PPC_EMB_SDA2I16"; + case 108: return "R_PPC_EMB_SDA2REL"; + case 109: return "R_PPC_EMB_SDA21"; + case 110: return "R_PPC_EMB_MRKREF"; + case 111: return "R_PPC_EMB_RELSEC16"; + case 112: return "R_PPC_EMB_RELST_LO"; + case 113: return "R_PPC_EMB_RELST_HI"; + case 114: return "R_PPC_EMB_RELST_HA"; + case 115: return "R_PPC_EMB_BIT_FLD"; + case 116: return "R_PPC_EMB_RELSDA"; + } + break; + case EM_PPC64: + switch(type) { + case 0: return "R_PPC64_NONE"; + case 1: return "R_PPC64_ADDR32"; + case 2: return "R_PPC64_ADDR24"; + case 3: return "R_PPC64_ADDR16"; + case 4: return "R_PPC64_ADDR16_LO"; + case 5: return "R_PPC64_ADDR16_HI"; + case 6: return "R_PPC64_ADDR16_HA"; + case 7: return "R_PPC64_ADDR14"; + case 8: return "R_PPC64_ADDR14_BRTAKEN"; + case 9: return "R_PPC64_ADDR14_BRNTAKEN"; + case 10: return "R_PPC64_REL24"; + case 11: return "R_PPC64_REL14"; + case 12: return "R_PPC64_REL14_BRTAKEN"; + case 13: return "R_PPC64_REL14_BRNTAKEN"; + case 14: return "R_PPC64_GOT16"; + case 15: return "R_PPC64_GOT16_LO"; + case 16: return "R_PPC64_GOT16_HI"; + case 17: return "R_PPC64_GOT16_HA"; + case 19: return "R_PPC64_COPY"; + case 20: return "R_PPC64_GLOB_DAT"; + case 21: return "R_PPC64_JMP_SLOT"; + case 22: return "R_PPC64_RELATIVE"; + case 24: return "R_PPC64_UADDR32"; + case 25: return "R_PPC64_UADDR16"; + case 26: return "R_PPC64_REL32"; + case 27: return "R_PPC64_PLT32"; + case 28: return "R_PPC64_PLTREL32"; + case 29: return "R_PPC64_PLT16_LO"; + case 30: return "R_PPC64_PLT16_HI"; + case 31: return "R_PPC64_PLT16_HA"; + case 33: return "R_PPC64_SECTOFF"; + case 34: return "R_PPC64_SECTOFF_LO"; + case 35: return "R_PPC64_SECTOFF_HI"; + case 36: return "R_PPC64_SECTOFF_HA"; + case 37: return "R_PPC64_ADDR30"; + case 38: return "R_PPC64_ADDR64"; + case 39: return "R_PPC64_ADDR16_HIGHER"; + case 40: return "R_PPC64_ADDR16_HIGHERA"; + case 41: return "R_PPC64_ADDR16_HIGHEST"; + case 42: return "R_PPC64_ADDR16_HIGHESTA"; + case 43: return "R_PPC64_UADDR64"; + case 44: return "R_PPC64_REL64"; + case 45: return "R_PPC64_PLT64"; + case 46: return "R_PPC64_PLTREL64"; + case 47: return "R_PPC64_TOC16"; + case 48: return "R_PPC64_TOC16_LO"; + case 49: return "R_PPC64_TOC16_HI"; + case 50: return "R_PPC64_TOC16_HA"; + case 51: return "R_PPC64_TOC"; + case 52: return "R_PPC64_PLTGOT16"; + case 53: return "R_PPC64_PLTGOT16_LO"; + case 54: return "R_PPC64_PLTGOT16_HI"; + case 55: return "R_PPC64_PLTGOT16_HA"; + case 56: return "R_PPC64_ADDR16_DS"; + case 57: return "R_PPC64_ADDR16_LO_DS"; + case 58: return "R_PPC64_GOT16_DS"; + case 59: return "R_PPC64_GOT16_LO_DS"; + case 60: return "R_PPC64_PLT16_LO_DS"; + case 61: return "R_PPC64_SECTOFF_DS"; + case 62: return "R_PPC64_SECTOFF_LO_DS"; + case 63: return "R_PPC64_TOC16_DS"; + case 64: return "R_PPC64_TOC16_LO_DS"; + case 65: return "R_PPC64_PLTGOT16_DS"; + case 66: return "R_PPC64_PLTGOT16_LO_DS"; + case 67: return "R_PPC64_TLS"; + case 68: return "R_PPC64_DTPMOD64"; + case 69: return "R_PPC64_TPREL16"; + case 70: return "R_PPC64_TPREL16_LO"; + case 71: return "R_PPC64_TPREL16_HI"; + case 72: return "R_PPC64_TPREL16_HA"; + case 73: return "R_PPC64_TPREL64"; + case 74: return "R_PPC64_DTPREL16"; + case 75: return "R_PPC64_DTPREL16_LO"; + case 76: return "R_PPC64_DTPREL16_HI"; + case 77: return "R_PPC64_DTPREL16_HA"; + case 78: return "R_PPC64_DTPREL64"; + case 79: return "R_PPC64_GOT_TLSGD16"; + case 80: return "R_PPC64_GOT_TLSGD16_LO"; + case 81: return "R_PPC64_GOT_TLSGD16_HI"; + case 82: return "R_PPC64_GOT_TLSGD16_HA"; + case 83: return "R_PPC64_GOT_TLSLD16"; + case 84: return "R_PPC64_GOT_TLSLD16_LO"; + case 85: return "R_PPC64_GOT_TLSLD16_HI"; + case 86: return "R_PPC64_GOT_TLSLD16_HA"; + case 87: return "R_PPC64_GOT_TPREL16_DS"; + case 88: return "R_PPC64_GOT_TPREL16_LO_DS"; + case 89: return "R_PPC64_GOT_TPREL16_HI"; + case 90: return "R_PPC64_GOT_TPREL16_HA"; + case 91: return "R_PPC64_GOT_DTPREL16_DS"; + case 92: return "R_PPC64_GOT_DTPREL16_LO_DS"; + case 93: return "R_PPC64_GOT_DTPREL16_HI"; + case 94: return "R_PPC64_GOT_DTPREL16_HA"; + case 95: return "R_PPC64_TPREL16_DS"; + case 96: return "R_PPC64_TPREL16_LO_DS"; + case 97: return "R_PPC64_TPREL16_HIGHER"; + case 98: return "R_PPC64_TPREL16_HIGHERA"; + case 99: return "R_PPC64_TPREL16_HIGHEST"; + case 100: return "R_PPC64_TPREL16_HIGHESTA"; + case 101: return "R_PPC64_DTPREL16_DS"; + case 102: return "R_PPC64_DTPREL16_LO_DS"; + case 103: return "R_PPC64_DTPREL16_HIGHER"; + case 104: return "R_PPC64_DTPREL16_HIGHERA"; + case 105: return "R_PPC64_DTPREL16_HIGHEST"; + case 106: return "R_PPC64_DTPREL16_HIGHESTA"; + case 107: return "R_PPC64_TLSGD"; + case 108: return "R_PPC64_TLSLD"; + case 249: return "R_PPC64_REL16"; + case 250: return "R_PPC64_REL16_LO"; + case 251: return "R_PPC64_REL16_HI"; + case 252: return "R_PPC64_REL16_HA"; + } + break; + case EM_RISCV: + switch(type) { + case 0: return "R_RISCV_NONE"; + case 1: return "R_RISCV_32"; + case 2: return "R_RISCV_64"; + case 3: return "R_RISCV_RELATIVE"; + case 4: return "R_RISCV_COPY"; + case 5: return "R_RISCV_JUMP_SLOT"; + case 6: return "R_RISCV_TLS_DTPMOD32"; + case 7: return "R_RISCV_TLS_DTPMOD64"; + case 8: return "R_RISCV_TLS_DTPREL32"; + case 9: return "R_RISCV_TLS_DTPREL64"; + case 10: return "R_RISCV_TLS_TPREL32"; + case 11: return "R_RISCV_TLS_TPREL64"; + case 16: return "R_RISCV_BRANCH"; + case 17: return "R_RISCV_JAL"; + case 18: return "R_RISCV_CALL"; + case 19: return "R_RISCV_CALL_PLT"; + case 20: return "R_RISCV_GOT_HI20"; + case 21: return "R_RISCV_TLS_GOT_HI20"; + case 22: return "R_RISCV_TLS_GD_HI20"; + case 23: return "R_RISCV_PCREL_HI20"; + case 24: return "R_RISCV_PCREL_LO12_I"; + case 25: return "R_RISCV_PCREL_LO12_S"; + case 26: return "R_RISCV_HI20"; + case 27: return "R_RISCV_LO12_I"; + case 28: return "R_RISCV_LO12_S"; + case 29: return "R_RISCV_TPREL_HI20"; + case 30: return "R_RISCV_TPREL_LO12_I"; + case 31: return "R_RISCV_TPREL_LO12_S"; + case 32: return "R_RISCV_TPREL_ADD"; + case 33: return "R_RISCV_ADD8"; + case 34: return "R_RISCV_ADD16"; + case 35: return "R_RISCV_ADD32"; + case 36: return "R_RISCV_ADD64"; + case 37: return "R_RISCV_SUB8"; + case 38: return "R_RISCV_SUB16"; + case 39: return "R_RISCV_SUB32"; + case 40: return "R_RISCV_SUB64"; + case 41: return "R_RISCV_GNU_VTINHERIT"; + case 42: return "R_RISCV_GNU_VTENTRY"; + case 43: return "R_RISCV_ALIGN"; + case 44: return "R_RISCV_RVC_BRANCH"; + case 45: return "R_RISCV_RVC_JUMP"; + case 46: return "R_RISCV_RVC_LUI"; + case 47: return "R_RISCV_GPREL_I"; + case 48: return "R_RISCV_GPREL_S"; + } + break; + case EM_S390: + switch (type) { + case 0: return "R_390_NONE"; + case 1: return "R_390_8"; + case 2: return "R_390_12"; + case 3: return "R_390_16"; + case 4: return "R_390_32"; + case 5: return "R_390_PC32"; + case 6: return "R_390_GOT12"; + case 7: return "R_390_GOT32"; + case 8: return "R_390_PLT32"; + case 9: return "R_390_COPY"; + case 10: return "R_390_GLOB_DAT"; + case 11: return "R_390_JMP_SLOT"; + case 12: return "R_390_RELATIVE"; + case 13: return "R_390_GOTOFF"; + case 14: return "R_390_GOTPC"; + case 15: return "R_390_GOT16"; + case 16: return "R_390_PC16"; + case 17: return "R_390_PC16DBL"; + case 18: return "R_390_PLT16DBL"; + case 19: return "R_390_PC32DBL"; + case 20: return "R_390_PLT32DBL"; + case 21: return "R_390_GOTPCDBL"; + case 22: return "R_390_64"; + case 23: return "R_390_PC64"; + case 24: return "R_390_GOT64"; + case 25: return "R_390_PLT64"; + case 26: return "R_390_GOTENT"; + } + break; + case EM_SPARC: + case EM_SPARCV9: + switch(type) { + case 0: return "R_SPARC_NONE"; + case 1: return "R_SPARC_8"; + case 2: return "R_SPARC_16"; + case 3: return "R_SPARC_32"; + case 4: return "R_SPARC_DISP8"; + case 5: return "R_SPARC_DISP16"; + case 6: return "R_SPARC_DISP32"; + case 7: return "R_SPARC_WDISP30"; + case 8: return "R_SPARC_WDISP22"; + case 9: return "R_SPARC_HI22"; + case 10: return "R_SPARC_22"; + case 11: return "R_SPARC_13"; + case 12: return "R_SPARC_LO10"; + case 13: return "R_SPARC_GOT10"; + case 14: return "R_SPARC_GOT13"; + case 15: return "R_SPARC_GOT22"; + case 16: return "R_SPARC_PC10"; + case 17: return "R_SPARC_PC22"; + case 18: return "R_SPARC_WPLT30"; + case 19: return "R_SPARC_COPY"; + case 20: return "R_SPARC_GLOB_DAT"; + case 21: return "R_SPARC_JMP_SLOT"; + case 22: return "R_SPARC_RELATIVE"; + case 23: return "R_SPARC_UA32"; + case 24: return "R_SPARC_PLT32"; + case 25: return "R_SPARC_HIPLT22"; + case 26: return "R_SPARC_LOPLT10"; + case 27: return "R_SPARC_PCPLT32"; + case 28: return "R_SPARC_PCPLT22"; + case 29: return "R_SPARC_PCPLT10"; + case 30: return "R_SPARC_10"; + case 31: return "R_SPARC_11"; + case 32: return "R_SPARC_64"; + case 33: return "R_SPARC_OLO10"; + case 34: return "R_SPARC_HH22"; + case 35: return "R_SPARC_HM10"; + case 36: return "R_SPARC_LM22"; + case 37: return "R_SPARC_PC_HH22"; + case 38: return "R_SPARC_PC_HM10"; + case 39: return "R_SPARC_PC_LM22"; + case 40: return "R_SPARC_WDISP16"; + case 41: return "R_SPARC_WDISP19"; + case 42: return "R_SPARC_GLOB_JMP"; + case 43: return "R_SPARC_7"; + case 44: return "R_SPARC_5"; + case 45: return "R_SPARC_6"; + case 46: return "R_SPARC_DISP64"; + case 47: return "R_SPARC_PLT64"; + case 48: return "R_SPARC_HIX22"; + case 49: return "R_SPARC_LOX10"; + case 50: return "R_SPARC_H44"; + case 51: return "R_SPARC_M44"; + case 52: return "R_SPARC_L44"; + case 53: return "R_SPARC_REGISTER"; + case 54: return "R_SPARC_UA64"; + case 55: return "R_SPARC_UA16"; + case 56: return "R_SPARC_TLS_GD_HI22"; + case 57: return "R_SPARC_TLS_GD_LO10"; + case 58: return "R_SPARC_TLS_GD_ADD"; + case 59: return "R_SPARC_TLS_GD_CALL"; + case 60: return "R_SPARC_TLS_LDM_HI22"; + case 61: return "R_SPARC_TLS_LDM_LO10"; + case 62: return "R_SPARC_TLS_LDM_ADD"; + case 63: return "R_SPARC_TLS_LDM_CALL"; + case 64: return "R_SPARC_TLS_LDO_HIX22"; + case 65: return "R_SPARC_TLS_LDO_LOX10"; + case 66: return "R_SPARC_TLS_LDO_ADD"; + case 67: return "R_SPARC_TLS_IE_HI22"; + case 68: return "R_SPARC_TLS_IE_LO10"; + case 69: return "R_SPARC_TLS_IE_LD"; + case 70: return "R_SPARC_TLS_IE_LDX"; + case 71: return "R_SPARC_TLS_IE_ADD"; + case 72: return "R_SPARC_TLS_LE_HIX22"; + case 73: return "R_SPARC_TLS_LE_LOX10"; + case 74: return "R_SPARC_TLS_DTPMOD32"; + case 75: return "R_SPARC_TLS_DTPMOD64"; + case 76: return "R_SPARC_TLS_DTPOFF32"; + case 77: return "R_SPARC_TLS_DTPOFF64"; + case 78: return "R_SPARC_TLS_TPOFF32"; + case 79: return "R_SPARC_TLS_TPOFF64"; + } + break; + case EM_X86_64: + switch(type) { + case 0: return "R_X86_64_NONE"; + case 1: return "R_X86_64_64"; + case 2: return "R_X86_64_PC32"; + case 3: return "R_X86_64_GOT32"; + case 4: return "R_X86_64_PLT32"; + case 5: return "R_X86_64_COPY"; + case 6: return "R_X86_64_GLOB_DAT"; + case 7: return "R_X86_64_JUMP_SLOT"; + case 8: return "R_X86_64_RELATIVE"; + case 9: return "R_X86_64_GOTPCREL"; + case 10: return "R_X86_64_32"; + case 11: return "R_X86_64_32S"; + case 12: return "R_X86_64_16"; + case 13: return "R_X86_64_PC16"; + case 14: return "R_X86_64_8"; + case 15: return "R_X86_64_PC8"; + case 16: return "R_X86_64_DTPMOD64"; + case 17: return "R_X86_64_DTPOFF64"; + case 18: return "R_X86_64_TPOFF64"; + case 19: return "R_X86_64_TLSGD"; + case 20: return "R_X86_64_TLSLD"; + case 21: return "R_X86_64_DTPOFF32"; + case 22: return "R_X86_64_GOTTPOFF"; + case 23: return "R_X86_64_TPOFF32"; + case 24: return "R_X86_64_PC64"; + case 25: return "R_X86_64_GOTOFF64"; + case 26: return "R_X86_64_GOTPC32"; + case 27: return "R_X86_64_GOT64"; + case 28: return "R_X86_64_GOTPCREL64"; + case 29: return "R_X86_64_GOTPC64"; + case 30: return "R_X86_64_GOTPLT64"; + case 31: return "R_X86_64_PLTOFF64"; + case 32: return "R_X86_64_SIZE32"; + case 33: return "R_X86_64_SIZE64"; + case 34: return "R_X86_64_GOTPC32_TLSDESC"; + case 35: return "R_X86_64_TLSDESC_CALL"; + case 36: return "R_X86_64_TLSDESC"; + case 37: return "R_X86_64_IRELATIVE"; + case 38: return "R_X86_64_RELATIVE64"; + case 41: return "R_X86_64_GOTPCRELX"; + case 42: return "R_X86_64_REX_GOTPCRELX"; + } + break; + } + + snprintf(s_type, sizeof(s_type), "", type); + return (s_type); +} diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.3 new file mode 100644 index 0000000..115fe92 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.3 @@ -0,0 +1,84 @@ +.\" Copyright (c) 2011 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id$ +.\" +.Dd December 15, 2011 +.Os +.Dt ELFTC_SET_TIMESTAMPS 3 +.Sh NAME +.Nm elftc_set_timestamps +.Nd set file timestamps +.Sh LIBRARY +.Lb libelftc +.Sh SYNOPSIS +.In libelftc.h +.Ft int +.Fn elftc_set_timestamps "const char *filename" "struct stat *sb" +.Sh DESCRIPTION +The +.Fn elftc_set_timestamps +function is used to set the access and modified time stamps on a file +based on the contents of a +.Vt "struct stat" +descriptor. +.Pp +Argument +.Ar filename +names an existing file in the file system. +.Pp +Argument +.Ar sb +points to structure of type +.Vt "struct stat" +populated by a prior call to +.Xr fstat 2 +or +.Xr stat 2 . +.Sh IMPLEMENTATION NOTES +This function will invoke the high-resolution +.Xr utimes 2 +system call if the underlying operating system supports it. +On operating systems lacking support for +.Xr utimes 2 , +the function will use lower resolution +.Xr utime 2 +system call. +.Sh EXAMPLES +To set the access and modified times for a new file to those of an +existing file, use: +.Bd -literal -offset indent +struct stat sb; +const char *existing_filename, *new_filename; + +if (stat(existing_filename, &sb) < 0) + err(EXIT_FAILURE, "stat failed"); + +if (elftc_set_timestamps(new_filename, &sb) < 0) + err(EXIT_FAILURE, "timestamps could not be set"); +.Ed +.Sh SEE ALSO +.Xr fstat 2 , +.Xr stat 2 , +.Xr utime 2 , +.Xr utimes 2 . diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.c b/rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.c new file mode 100644 index 0000000..cb28c35 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.c @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 2011 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "libelftc.h" + +#include "_libelftc.h" + +ELFTC_VCSID("$Id$"); + +/* + * Determine the field name for the timestamp fields inside a 'struct + * stat'. + */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) +#define ATIME st_atimespec +#define MTIME st_mtimespec +#define LIBELFTC_HAVE_UTIMES 1 +#endif + +#if defined(__DragonFly__) || defined(__linux__) || defined(__OpenBSD__) +#define ATIME st_atim +#define MTIME st_mtim +#define LIBELFTC_HAVE_UTIMES 1 +#endif + +#if LIBELFTC_HAVE_UTIMES +#include +#else +#include +#endif + +int +elftc_set_timestamps(const char *fn, struct stat *sb) +{ +#if LIBELFTC_HAVE_UTIMES + /* + * The BSD utimes() system call offers timestamps + * 1-microsecond granularity. + */ + struct timeval tv[2]; + + tv[0].tv_sec = sb->ATIME.tv_sec; + tv[0].tv_usec = sb->ATIME.tv_nsec / 1000; + tv[1].tv_sec = sb->MTIME.tv_sec; + tv[1].tv_usec = sb->MTIME.tv_nsec / 1000; + + return (utimes(fn, tv)); +#else + /* + * On OSes without utimes(), fall back to the POSIX utime() + * call, which offers 1-second granularity. + */ + struct utimbuf utb; + + utb.actime = sb->st_atime; + utb.modtime = sb->st_mtime; + return (utime(fn, &utb)); +#endif +} diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_string_table.c b/rtemstoolkit/elftoolchain/libelftc/elftc_string_table.c new file mode 100644 index 0000000..bba9ac6 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_string_table.c @@ -0,0 +1,392 @@ +/*- + * Copyright (c) 2013, Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "libelftc.h" +#include "_libelftc.h" + +ELFTC_VCSID("$Id: elftc_string_table.c 2869 2013-01-06 13:29:18Z jkoshy $"); + +#define ELFTC_STRING_TABLE_DEFAULT_SIZE (4*1024) +#define ELFTC_STRING_TABLE_EXPECTED_STRING_SIZE 16 +#define ELFTC_STRING_TABLE_EXPECTED_CHAIN_LENGTH 8 +#define ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT (4*1024) + +struct _Elftc_String_Table_Entry { + int ste_idx; + SLIST_ENTRY(_Elftc_String_Table_Entry) ste_next; +}; + +#define ELFTC_STRING_TABLE_COMPACTION_FLAG 0x1 +#define ELFTC_STRING_TABLE_LENGTH(st) ((st)->st_len >> 1) +#define ELFTC_STRING_TABLE_CLEAR_COMPACTION_FLAG(st) do { \ + (st)->st_len &= ~ELFTC_STRING_TABLE_COMPACTION_FLAG; \ + } while (0) +#define ELFTC_STRING_TABLE_SET_COMPACTION_FLAG(st) do { \ + (st)->st_len |= ELFTC_STRING_TABLE_COMPACTION_FLAG; \ + } while (0) +#define ELFTC_STRING_TABLE_UPDATE_LENGTH(st, len) do { \ + (st)->st_len = \ + ((st)->st_len & \ + ELFTC_STRING_TABLE_COMPACTION_FLAG) | \ + ((len) << 1); \ + } while (0) + +struct _Elftc_String_Table { + unsigned int st_len; /* length and flags */ + int st_nbuckets; + int st_string_pool_size; + char *st_string_pool; + SLIST_HEAD(_Elftc_String_Table_Bucket, + _Elftc_String_Table_Entry) st_buckets[]; +}; + +static struct _Elftc_String_Table_Entry * +elftc_string_table_find_hash_entry(Elftc_String_Table *st, const char *string, + int *rhashindex) +{ + struct _Elftc_String_Table_Entry *ste; + int hashindex; + char *s; + + hashindex = libelftc_hash_string(string) % st->st_nbuckets; + + if (rhashindex) + *rhashindex = hashindex; + + SLIST_FOREACH(ste, &st->st_buckets[hashindex], ste_next) { + s = st->st_string_pool + abs(ste->ste_idx); + + assert(s > st->st_string_pool && + s < st->st_string_pool + st->st_string_pool_size); + + if (strcmp(s, string) == 0) + return (ste); + } + + return (NULL); +} + +static int +elftc_string_table_add_to_pool(Elftc_String_Table *st, const char *string) +{ + char *newpool; + int len, newsize, stlen; + + len = strlen(string) + 1; /* length, including the trailing NUL */ + stlen = ELFTC_STRING_TABLE_LENGTH(st); + + /* Resize the pool, if needed. */ + if (stlen + len >= st->st_string_pool_size) { + newsize = roundup(st->st_string_pool_size + + ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT, + ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT); + if ((newpool = realloc(st->st_string_pool, newsize)) == + NULL) + return (0); + st->st_string_pool = newpool; + st->st_string_pool_size = newsize; + } + + strcpy(st->st_string_pool + stlen, string); + ELFTC_STRING_TABLE_UPDATE_LENGTH(st, stlen + len); + + return (stlen); +} + +Elftc_String_Table * +elftc_string_table_create(int sizehint) +{ + int n, nbuckets, tablesize; + struct _Elftc_String_Table *st; + + if (sizehint < ELFTC_STRING_TABLE_DEFAULT_SIZE) + sizehint = ELFTC_STRING_TABLE_DEFAULT_SIZE; + + nbuckets = sizehint / (ELFTC_STRING_TABLE_EXPECTED_CHAIN_LENGTH * + ELFTC_STRING_TABLE_EXPECTED_STRING_SIZE); + + tablesize = sizeof(struct _Elftc_String_Table) + + nbuckets * sizeof(struct _Elftc_String_Table_Bucket); + + if ((st = malloc(tablesize)) == NULL) + return (NULL); + if ((st->st_string_pool = malloc(sizehint)) == NULL) { + free(st); + return (NULL); + } + + for (n = 0; n < nbuckets; n++) + SLIST_INIT(&st->st_buckets[n]); + + st->st_len = 0; + st->st_nbuckets = nbuckets; + st->st_string_pool_size = sizehint; + *st->st_string_pool = '\0'; + ELFTC_STRING_TABLE_UPDATE_LENGTH(st, 1); + + return (st); +} + +void +elftc_string_table_destroy(Elftc_String_Table *st) +{ + int n; + struct _Elftc_String_Table_Entry *s, *t; + + for (n = 0; n < st->st_nbuckets; n++) + SLIST_FOREACH_SAFE(s, &st->st_buckets[n], ste_next, t) + free(s); + free(st->st_string_pool); + free(st); + + return; +} + +Elftc_String_Table * +elftc_string_table_from_section(Elf_Scn *scn, int sizehint) +{ + int len; + Elf_Data *d; + GElf_Shdr sh; + const char *s, *end; + Elftc_String_Table *st; + + /* Verify the type of the section passed in. */ + if (gelf_getshdr(scn, &sh) == NULL || + sh.sh_type != SHT_STRTAB) { + errno = EINVAL; + return (NULL); + } + + if ((d = elf_getdata(scn, NULL)) == NULL || + d->d_size == 0) { + errno = EINVAL; + return (NULL); + } + + if ((st = elftc_string_table_create(sizehint)) == NULL) + return (NULL); + + s = d->d_buf; + + /* + * Verify that the first byte of the data buffer is '\0'. + */ + if (*s != '\0') { + errno = EINVAL; + goto fail; + } + + end = s + d->d_size; + + /* + * Skip the first '\0' and insert the strings in the buffer, + * in order. + */ + for (s += 1; s < end; s += len) { + if (elftc_string_table_insert(st, s) == 0) + goto fail; + + len = strlen(s) + 1; /* Include space for the trailing NUL. */ + } + + return (st); + +fail: + if (st) + (void) elftc_string_table_destroy(st); + + return (NULL); +} + +const char * +elftc_string_table_image(Elftc_String_Table *st, size_t *size) +{ + char *r, *s, *end; + struct _Elftc_String_Table_Entry *ste; + struct _Elftc_String_Table_Bucket *head; + int copied, hashindex, offset, length, newsize; + + /* + * For the common case of a string table has not seen + * a string deletion, we can just export the current + * pool. + */ + if ((st->st_len & ELFTC_STRING_TABLE_COMPACTION_FLAG) == 0) { + if (size) + *size = ELFTC_STRING_TABLE_LENGTH(st); + return (st->st_string_pool); + } + + /* + * Otherwise, compact the string table in-place. + */ + assert(*st->st_string_pool == '\0'); + + newsize = 1; + end = st->st_string_pool + ELFTC_STRING_TABLE_LENGTH(st); + + for (r = s = st->st_string_pool + 1; + s < end; + s += length, r += copied) { + + copied = 0; + length = strlen(s) + 1; + + ste = elftc_string_table_find_hash_entry(st, s, + &hashindex); + head = &st->st_buckets[hashindex]; + + assert(ste != NULL); + + /* Ignore deleted strings. */ + if (ste->ste_idx < 0) { + SLIST_REMOVE(head, ste, _Elftc_String_Table_Entry, + ste_next); + free(ste); + continue; + } + + /* Move 'live' strings up. */ + offset = newsize; + newsize += length; + copied = length; + + if (r == s) /* Nothing removed yet. */ + continue; + + memmove(r, s, copied); + + /* Update the index for this entry. */ + ste->ste_idx = offset; + } + + ELFTC_STRING_TABLE_CLEAR_COMPACTION_FLAG(st); + ELFTC_STRING_TABLE_UPDATE_LENGTH(st, newsize); + + if (size) + *size = newsize; + + return (st->st_string_pool); +} + +size_t +elftc_string_table_insert(Elftc_String_Table *st, const char *string) +{ + int hashindex, idx; + struct _Elftc_String_Table_Entry *ste; + + hashindex = 0; + + ste = elftc_string_table_find_hash_entry(st, string, &hashindex); + + assert(hashindex >= 0 && hashindex < st->st_nbuckets); + + if (ste == NULL) { + if ((ste = malloc(sizeof(*ste))) == NULL) + return (0); + if ((ste->ste_idx = elftc_string_table_add_to_pool(st, + string)) == 0) { + free(ste); + return (0); + } + + SLIST_INSERT_HEAD(&st->st_buckets[hashindex], ste, ste_next); + } + + idx = ste->ste_idx; + if (idx < 0) /* Undelete. */ + ste->ste_idx = idx = (- idx); + + return (idx); +} + +size_t +elftc_string_table_lookup(Elftc_String_Table *st, const char *string) +{ + int hashindex, idx; + struct _Elftc_String_Table_Entry *ste; + + ste = elftc_string_table_find_hash_entry(st, string, &hashindex); + + assert(hashindex >= 0 && hashindex < st->st_nbuckets); + + if (ste == NULL || (idx = ste->ste_idx) < 0) + return (0); + + return (idx); +} + +int +elftc_string_table_remove(Elftc_String_Table *st, const char *string) +{ + int idx; + struct _Elftc_String_Table_Entry *ste; + + ste = elftc_string_table_find_hash_entry(st, string, NULL); + + if (ste == NULL || (idx = ste->ste_idx) < 0) + return (ELFTC_FAILURE); + + assert(idx > 0 && idx < (int) ELFTC_STRING_TABLE_LENGTH(st)); + + ste->ste_idx = (- idx); + + ELFTC_STRING_TABLE_SET_COMPACTION_FLAG(st); + + return (ELFTC_SUCCESS); +} + +const char * +elftc_string_table_to_string(Elftc_String_Table *st, size_t offset) +{ + const char *s; + + s = st->st_string_pool + offset; + + /* + * Check for: + * - An offset value within pool bounds. + * - A non-NUL byte at the specified offset. + * - The end of the prior string at offset - 1. + */ + if (offset == 0 || offset >= ELFTC_STRING_TABLE_LENGTH(st) || + *s == '\0' || *(s - 1) != '\0') { + errno = EINVAL; + return (NULL); + } + + return (s); +} diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_string_table_create.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_string_table_create.3 new file mode 100644 index 0000000..e11e73c --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_string_table_create.3 @@ -0,0 +1,227 @@ +.\" Copyright (c) 2012-2013 Joseph Koshy. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elftc_string_table_create.3 2866 2013-01-06 03:20:14Z jkoshy $ +.\" +.Dd January 5, 2013 +.Os +.Dt ELFTC_STRING_TABLE_CREATE 3 +.Sh NAME +.Nm elftc_string_table_create , +.Nm elftc_string_table_destroy , +.Nm elftc_string_table_from_section , +.Nm elftc_string_table_image , +.Nm elftc_string_table_insert , +.Nm elftc_string_table_lookup , +.Nm elftc_string_table_remove , +.Nm elftc_string_table_to_string +.Nd convenience routines for handling ELF string tables +.Sh SYNOPSIS +.In libelftc.h +.Ft "Elftc_String_Table *" +.Fn elftc_string_table_create "int sizehint" +.Ft int +.Fn elftc_string_table_destroy "Elftc_String_Table *table" +.Ft "Elftc_String_Table *" +.Fn elftc_string_table_from_section "Elf_Scn *scn" "int sizehint" +.Ft "const char *" +.Fo elftc_string_table_image +.Fa "Elftc_String_Table *table" +.Fa "size_t *size" +.Fc +.Ft size_t +.Fo elftc_string_table_insert +.Fa "Elftc_String_Table *table" +.Fa "const char *string" +.Fc +.Ft size_t +.Fo elftc_string_table_lookup +.Fa "Elftc_String_Table *table" +.Fa "const char *string" +.Fc +.Ft int +.Fo elftc_string_table_remove +.Fa "Elftc_String_Table *table" +.Fa "const char *string" +.Fc +.Ft "const char *" +.Fo elftc_string_table_to_string +.Fa "Elftc_String_Table *table" +.Fa "size_t offset" +.Fc +.Sh DESCRIPTION +This manual page documents convenience routines for handling ELF +string tables. +.Pp +Function +.Fn elftc_string_table_create +creates a new, empty string table. +The argument +.Ar sizehint +provides a hint about the expected number of bytes of string data in +the table. +If the argument +.Ar sizehint +is zero, an implementation-defined default will be used instead. +.Pp +Function +.Fn elftc_string_table_destroy +destroys the previously allocated string table specified by +argument +.Ar table , +and frees the internal resources allocated for it. +.Pp +Function +.Fn elftc_string_table_from_section +creates a new string table and initializes it based on the +contents of the section specified by argument +.Ar scn . +This section must be of type +.Dv SHT_STRTAB . +The argument +.Ar sizehint +provides a hint about expected number of bytes of string data in the +table. +If the value of +.Ar sizehint +is zero, an implementation-default will be used instead. +.Pp +Function +.Fn elftc_string_table_image +returns a pointer to the ELF representation of the contents of the +string table specified by argument +.Ar table . +If argument +.Ar size +is not NULL, the size of the ELF representation of the string table is +stored in the location pointed to by argument +.Ar size . +The function +.Fn elftc_string_table_image +will compact the string table if the table contains deleted strings. +The string offsets returned by prior calls to +.Fn elftc_string_table_insert +and +.Fn elftc_string_table_lookup +should be treated as invalid after a call to this function. +.Pp +Function +.Fn elftc_string_table_insert +inserts the NUL-terminated string pointed to by argument +.Ar string +into the string table specified by argument +.Ar table , +and returns an offset value usable in ELF data structures. +Multiple insertions of the same content will return the same offset. +The offset returned will remain valid until the next call to +.Fn elftc_string_table_image . +.Pp +Function +.Fn elftc_string_table_lookup +looks up the string referenced by argument +.Ar string +in the string table specified by argument +.Ar table , +and if found, returns the offset associated with the string. +The returned offset will be valid till the next call to function +.Fn elftc_string_table_image . +.Pp +Function +.Fn elftc_string_table_remove +removes the string pointed by argument +.Ar string +from the string table referenced by argument +.Ar table , +if it is present in the string table. +.Pp +Function +.Fn elftc_string_table_to_string +returns a pointer to the NUL-terminated string residing at argument +.Ar offset +in the string table specified by argument +.Ar table . +The value of argument +.Ar offset +should be one returned by a prior call to +.Fn elftc_string_table_insert +or +.Fn elftc_string_table_lookup . +The returned pointer will remain valid until the next call to +.Fn elftc_string_table_insert +or +.Fn elftc_string_table_image . +.Ss Memory Management +The +.Lb libelftc +library manages its own memory allocations. +The application should not free the pointers returned by the string +table functions. +.El +.Sh IMPLEMENTATION NOTES +The current implementation is optimized for the case where strings are +added to a string table, but rarely removed from it. +.Pp +The functions +.Fn elftc_string_table_insert , +.Fn elftc_string_table_lookup , +.Fn elftc_string_table_remove +and +.Fn elftc_string_table_to_string +have O(1) asymptotic behavior. +The function +.Fn elftc_string_table_image +can have O(size) asymptotic behavior, where +.Ar size +denotes the size of the string table. +.Sh RETURN VALUES +Functions +.Fn elftc_string_table_create +and +.Fn elftc_string_table_from_section +return a valid pointer to an opaque structure of type +.Vt Elftc_String_Table +on success, or NULL in case of an error. +.Pp +The function +.Fn elftc_string_table_image +returns a pointer to an in-memory representation of an ELF string +table on success, or NULL in case of an error. +.Pp +Functions +.Fn elftc_string_table_insert +and +.Fn elftc_string_table_lookup +return a non-zero offset on success, or zero in case of an error. +.Pp +Function +.Fn elftc_string_table_remove +returns a positive value on success, or zero in case of an error. +.Pp +Function +.Fn elftc_string_table_to_string +returns a valid pointer on success, or NULL in case of an error. +.Sh SEE ALSO +.Xr dwarf 3 , +.Xr elf 3 , +.Xr elftc 3 diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.3 new file mode 100644 index 0000000..3c56f2f --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.3 @@ -0,0 +1,79 @@ +.\" Copyright (c) 2016 The FreeBSD Foundation. All rights reserved. +.\" +.\" This documentation was written by Ed Maste under sponsorship of +.\" the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by the author and contributors ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. In no event shall the author or contributors be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id$ +.\" +.Dd August 24, 2016 +.Os +.Dt ELFTC_TIMESTAMP 3 +.Sh NAME +.Nm elftc_timestamp +.Nd return the current or environment-provided timestamp +.Sh LIBRARY +.Lb libelftc +.Sh SYNOPSIS +.In libelftc.h +.Ft int +.Fo elftc_timestamp +.Fa "time_t *timestamp" +.Fc +.Sh DESCRIPTION +The +.Fn elftc_timestamp +function returns a timestamp supplied by the +.Ev SOURCE_DATE_EPOCH +environment variable, or the current time provided by +.Xr time 3 +if the environment variable is not set. +.Pp +The +.Ar timestamp +argument specifies a pointer to the location where the timestamp will be +stored. +.Sh RETURN VALUE +Function +.Fn elftc_timestamp +returns 0 on success, and -1 in the event of an error. +.Sh ERRORS +The +.Fn elftc_timestamp +function may fail with the following errors: +.Bl -tag -width ".Bq Er ERANGE" +.It Bq Er EINVAL +.Ev SOURCE_DATE_EPOCH +contains invalid characters. +.It Bq Er ERANGE +.Ev SOURCE_DATE_EPOCH +specifies a negative value or a value that cannot be stored in a +time_t. +.El +The +.Fn elftc_timestamp +function may also fail for any of the reasons described in +.Xr strtoll 3 . +.Sh SEE ALSO +.Xr strtoll 3 , +.Xr time 3 diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.c b/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.c new file mode 100644 index 0000000..ccf482f --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.c @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Ed Maste under sponsorship + * of the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +int +elftc_timestamp(time_t *timestamp) +{ + long long source_date_epoch; + char *env, *eptr; + + if ((env = getenv("SOURCE_DATE_EPOCH")) != NULL) { + errno = 0; + source_date_epoch = strtoll(env, &eptr, 10); + if (*eptr != '\0') + errno = EINVAL; + if (source_date_epoch < 0) + errno = ERANGE; + if (errno != 0) + return (-1); + *timestamp = source_date_epoch; + return (0); + } + *timestamp = time(NULL); + return (0); +} diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_version.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_version.3 new file mode 100644 index 0000000..f7018a5 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_version.3 @@ -0,0 +1,79 @@ +.\" Copyright (c) 2011,2012 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: elftc_version.3 2828 2012-12-30 04:41:27Z jkoshy $ +.\" +.Dd December 30, 2012 +.Os +.Dt ELFTC_VERSION 3 +.Sh NAME +.Nm elftc_version +.Nd return a project-wide version identifier string +.Sh LIBRARY +.Lb libelftc +.Sh SYNOPSIS +.In libelftc.h +.Ft const char * +.Fn elftc_version void +.Sh DESCRIPTION +Function +.Fn elftc_version +returns a project-wide identifier string that encodes the source +revision of the project source tree. +.Pp +The returned identifier has four space-separated fields: +.Bl -tag -width ".Em Project Branch" +.It Em "Project-Name" +This is always +.Dq elftoolchain . +.It Em "Project-Branch" +The branch name for the project source tree. +.It Em "Build-OS" +The operating system that the tool chain was compiled for. +.It Em "Version-Number" +A tree-wide version number extracted from the version control +system in use. +.El +.Sh RETURN VALUE +Function +.Fn elftc_program_version +returns a pointer to an internal character buffer. +.Sh EXAMPLES +To retrieve and print the current toolchain version identifier, use: +.Bd -literal -offset indent +#include +#include + +(void) printf("%s\en", elftc_version()); +.Ed +.Pp +On the HEAD branch of the project's sources, when checked out using +Subversion and compiled on a NetBSD host, this would print: +.D1 Dq elftoolchain HEAD NetBSD svn: Ns Em REVINFO +where +.Em REVINFO +would be the current revision information for the project source tree. +.Sh ERRORS +Function +.Fn elftc_program_version +always succeeds. diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_version.c b/rtemstoolkit/elftoolchain/libelftc/elftc_version.c new file mode 100644 index 0000000..5c41c1b --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/elftc_version.c @@ -0,0 +1,10 @@ +/* WARNING: Generated by "make-toolchain-version". */ + +#include +#include + +const char * +elftc_version(void) +{ + return "elftoolchain HEAD RTEMS git:heads/covoar-dwarf-0-g9b49665-dirty"; +} diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc.h b/rtemstoolkit/elftoolchain/libelftc/libelftc.h new file mode 100644 index 0000000..a235097 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/libelftc.h @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 2009 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: users/kaiwang27/elftc/libelftc.h 392 2009-05-31 19:17:46Z kaiwang27 $ + * $Id: libelftc.h 3489 2016-08-31 00:12:15Z emaste $ + */ + +#ifndef _LIBELFTC_H_ +#define _LIBELFTC_H_ + +#include + +#include + +/* + * Types meant to be opaque to the consumers of these APIs. + */ +typedef struct _Elftc_Bfd_Target Elftc_Bfd_Target; +typedef struct _Elftc_String_Table Elftc_String_Table; + +/* Target types. */ +typedef enum { + ETF_NONE, + ETF_ELF, + ETF_BINARY, + ETF_SREC, + ETF_IHEX, + ETF_PE, + ETF_EFI, +} Elftc_Bfd_Target_Flavor; + +/* + * Demangler flags. + */ + +/* Name mangling style. */ +#define ELFTC_DEM_UNKNOWN 0x00000000U /* Not specified. */ +#define ELFTC_DEM_ARM 0x00000001U /* C++ Ann. Ref. Manual. */ +#define ELFTC_DEM_GNU2 0x00000002U /* GNU version 2. */ +#define ELFTC_DEM_GNU3 0x00000004U /* GNU version 3. */ + +/* Demangling behaviour control. */ +#define ELFTC_DEM_NOPARAM 0x00010000U + +#ifdef __cplusplus +extern "C" { +#endif +Elftc_Bfd_Target *elftc_bfd_find_target(const char *_tgt_name); +Elftc_Bfd_Target_Flavor elftc_bfd_target_flavor(Elftc_Bfd_Target *_tgt); +unsigned int elftc_bfd_target_byteorder(Elftc_Bfd_Target *_tgt); +unsigned int elftc_bfd_target_class(Elftc_Bfd_Target *_tgt); +unsigned int elftc_bfd_target_machine(Elftc_Bfd_Target *_tgt); +int elftc_copyfile(int _srcfd, int _dstfd); +int elftc_demangle(const char *_mangledname, char *_buffer, + size_t _bufsize, unsigned int _flags); +const char *elftc_reloc_type_str(unsigned int mach, unsigned int type); +int elftc_set_timestamps(const char *_filename, struct stat *_sb); +Elftc_String_Table *elftc_string_table_create(int _hint); +void elftc_string_table_destroy(Elftc_String_Table *_table); +Elftc_String_Table *elftc_string_table_from_section(Elf_Scn *_scn, + int _hint); +const char *elftc_string_table_image(Elftc_String_Table *_table, + size_t *_sz); +size_t elftc_string_table_insert(Elftc_String_Table *_table, + const char *_string); +size_t elftc_string_table_lookup(Elftc_String_Table *_table, + const char *_string); +int elftc_string_table_remove(Elftc_String_Table *_table, + const char *_string); +const char *elftc_string_table_to_string(Elftc_String_Table *_table, + size_t offset); +int elftc_timestamp(time_t *_timestamp); +const char *elftc_version(void); +#ifdef __cplusplus +} +#endif + +#endif /* _LIBELFTC_H_ */ diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc_bfdtarget.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_bfdtarget.c new file mode 100644 index 0000000..48b67a0 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/libelftc_bfdtarget.c @@ -0,0 +1,463 @@ +/*- + * Copyright (c) 2008,2009 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "_libelftc.h" + +ELFTC_VCSID("$Id: libelftc_bfdtarget.c 3516 2017-02-10 02:33:08Z emaste $"); + +struct _Elftc_Bfd_Target _libelftc_targets[] = { + + { + .bt_name = "binary", + .bt_type = ETF_BINARY, + }, + + { + .bt_name = "elf32-avr", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_AVR, + }, + + { + .bt_name = "elf32-big", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + }, + + { + .bt_name = "elf32-bigarm", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_ARM, + }, + + { + .bt_name = "elf32-bigmips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_MIPS, + }, + + { + .bt_name = "elf32-i386", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_386, + }, + + { + .bt_name = "elf32-i386-freebsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_386, + .bt_osabi = ELFOSABI_FREEBSD, + }, + + { + .bt_name = "elf32-ia64-big", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_IA_64, + }, + + { + .bt_name = "elf32-little", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + }, + + { + .bt_name = "elf32-littlearm", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_ARM, + }, + + { + .bt_name = "elf32-littlemips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_MIPS, + }, + + { + .bt_name = "elf32-powerpc", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_PPC, + }, + + { + .bt_name = "elf32-powerpc-freebsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_PPC, + .bt_osabi = ELFOSABI_FREEBSD, + }, + + { + .bt_name = "elf32-powerpcle", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_PPC, + }, + + { + .bt_name = "elf32-sh", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_SH, + }, + + { + .bt_name = "elf32-shl", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_SH, + }, + + { + .bt_name = "elf32-sh-nbsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_SH, + .bt_osabi = ELFOSABI_NETBSD, + }, + + { + .bt_name = "elf32-shl-nbsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_SH, + .bt_osabi = ELFOSABI_NETBSD, + }, + + { + .bt_name = "elf32-shbig-linux", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_SH, + .bt_osabi = ELFOSABI_LINUX, + }, + + { + .bt_name = "elf32-sh-linux", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_SH, + .bt_osabi = ELFOSABI_LINUX, + }, + + { + .bt_name = "elf32-sparc", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_SPARC, + }, + + { + .bt_name = "elf32-tradbigmips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_MIPS, + }, + + { + .bt_name = "elf32-tradlittlemips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS32, + .bt_machine = EM_MIPS, + }, + + { + .bt_name = "elf64-alpha", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_ALPHA, + }, + + { + .bt_name = "elf64-alpha-freebsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_ALPHA, + .bt_osabi = ELFOSABI_FREEBSD + }, + + { + .bt_name = "elf64-big", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + }, + + { + .bt_name = "elf64-bigmips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_MIPS, + }, + + { + .bt_name = "elf64-ia64-big", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_IA_64, + }, + + { + .bt_name = "elf64-ia64-little", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_IA_64, + }, + + { + .bt_name = "elf64-little", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + }, + + { + .bt_name = "elf64-littleaarch64", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_AARCH64, + }, + + { + .bt_name = "elf64-littlemips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_MIPS, + }, + + { + .bt_name = "elf64-powerpc", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_PPC64, + }, + + { + .bt_name = "elf64-powerpc-freebsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_PPC64, + .bt_osabi = ELFOSABI_FREEBSD, + }, + + { + .bt_name = "elf64-powerpcle", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_PPC64, + }, + + { + .bt_name = "elf64-sh64", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_SH, + }, + + { + .bt_name = "elf64-sh64l", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_SH, + }, + + { + .bt_name = "elf64-sh64-nbsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_SH, + .bt_osabi = ELFOSABI_NETBSD, + }, + + { + .bt_name = "elf64-sh64l-nbsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_SH, + .bt_osabi = ELFOSABI_NETBSD, + }, + + { + .bt_name = "elf64-sh64big-linux", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_SH, + .bt_osabi = ELFOSABI_LINUX, + }, + + { + .bt_name = "elf64-sh64-linux", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_SH, + .bt_osabi = ELFOSABI_LINUX, + }, + + { + .bt_name = "elf64-sparc", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_SPARCV9, + }, + + { + .bt_name = "elf64-sparc-freebsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_SPARCV9, + .bt_osabi = ELFOSABI_FREEBSD + }, + + { + .bt_name = "elf64-tradbigmips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2MSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_MIPS, + }, + + { + .bt_name = "elf64-tradlittlemips", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_MIPS, + }, + + { + .bt_name = "elf64-x86-64", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_X86_64, + }, + + { + .bt_name = "elf64-x86-64-freebsd", + .bt_type = ETF_ELF, + .bt_byteorder = ELFDATA2LSB, + .bt_elfclass = ELFCLASS64, + .bt_machine = EM_X86_64, + .bt_osabi = ELFOSABI_FREEBSD + }, + + { + .bt_name = "ihex", + .bt_type = ETF_IHEX, + }, + + { + .bt_name = "srec", + .bt_type = ETF_SREC, + }, + + { + .bt_name = "symbolsrec", + .bt_type = ETF_SREC, + }, + + { + .bt_name = "efi-app-ia32", + .bt_type = ETF_EFI, + .bt_machine = EM_386, + }, + + { + .bt_name = "efi-app-x86_64", + .bt_type = ETF_EFI, + .bt_machine = EM_X86_64, + }, + + { + .bt_name = "pei-i386", + .bt_type = ETF_PE, + .bt_machine = EM_386, + }, + + { + .bt_name = "pei-x86-64", + .bt_type = ETF_PE, + .bt_machine = EM_X86_64, + }, + + { + .bt_name = NULL, + .bt_type = ETF_NONE, + }, +}; diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_arm.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_arm.c new file mode 100644 index 0000000..5550505 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_arm.c @@ -0,0 +1,1216 @@ +/*- + * Copyright (c) 2008 Hyogeol Lee + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "_libelftc.h" + +ELFTC_VCSID("$Id: libelftc_dem_arm.c 3513 2016-12-29 07:04:22Z kaiwang27 $"); + +/** + * @file cpp_demangle_arm.c + * @brief Decode function name encoding in ARM. + * + * Function name encoding in "The Annotated C++ Reference Manual". + * + * Ref : "The Annotated C++ Reference Manual", Margaet A.Ellis, + * Bjarne Stroustrup, AT&T Bell Laboratories 1990, pp 122-126. + */ + +enum encode_type { + ENCODE_FUNC, ENCODE_OP, ENCODE_OP_CT, ENCODE_OP_DT, ENCODE_OP_USER +}; + +struct cstring { + char *buf; + size_t size; +}; + +struct demangle_data { + bool ptr, ref, cnst, array; + struct cstring array_str; + const char *p; + enum encode_type type; + struct vector_str vec; + struct vector_str arg; +}; + +#define SIMPLE_HASH(x,y) (64 * x + y) +#define VEC_PUSH_STR(d,s) vector_str_push((d), (s), strlen((s))) +#define CPP_DEMANGLE_ARM_TRY 128 + +static void dest_cstring(struct cstring *); +static void dest_demangle_data(struct demangle_data *); +static bool init_cstring(struct cstring *, size_t); +static bool init_demangle_data(struct demangle_data *); +static bool push_CTDT(const char *, size_t, struct vector_str *); +static bool read_array(struct demangle_data *); +static bool read_class(struct demangle_data *); +static bool read_func(struct demangle_data *); +static bool read_func_name(struct demangle_data *); +static bool read_func_ptr(struct demangle_data *); +static bool read_memptr(struct demangle_data *); +static bool read_op(struct demangle_data *); +static bool read_op_user(struct demangle_data *); +static bool read_qual_name(struct demangle_data *); +static int read_subst(struct demangle_data *); +static int read_subst_iter(struct demangle_data *); +static bool read_type(struct demangle_data *); + +/** + * @brief Decode the input string by the ARM style. + * + * @return New allocated demangled string or NULL if failed. + */ +char * +cpp_demangle_ARM(const char *org) +{ + struct demangle_data d; + size_t arg_begin, arg_len; + unsigned int try; + char *rtn, *arg; + + if (org == NULL) + return (NULL); + + if (init_demangle_data(&d) == false) + return (NULL); + + try = 0; + rtn = NULL; + + d.p = org; + if (read_func_name(&d) == false) + goto clean; + + if (d.type == ENCODE_OP_CT) { + if (push_CTDT("::", 2, &d.vec) == false) + goto clean; + + goto flat; + } + + if (d.type == ENCODE_OP_DT) { + if (push_CTDT("::~", 3, &d.vec) == false) + goto clean; + + goto flat; + } + + if (d.type == ENCODE_OP_USER) + goto flat; + + /* function type */ + if (*d.p != 'F') + goto clean; + ++d.p; + + /* start argument types */ + if (VEC_PUSH_STR(&d.vec, "(") == false) + goto clean; + + for (;;) { + if (*d.p == 'T') { + const int rtn_subst = read_subst(&d); + + if (rtn_subst == -1) + goto clean; + else if (rtn_subst == 1) + break; + + continue; + } + + if (*d.p == 'N') { + const int rtn_subst_iter = read_subst_iter(&d); + + if (rtn_subst_iter == -1) + goto clean; + else if(rtn_subst_iter == 1) + break; + + continue; + } + + arg_begin = d.vec.size; + + if (read_type(&d) == false) + goto clean; + + if (d.ptr == true) { + if (VEC_PUSH_STR(&d.vec, "*") == false) + goto clean; + + d.ptr = false; + } + + if (d.ref == true) { + if (VEC_PUSH_STR(&d.vec, "&") == false) + goto clean; + + d.ref = false; + } + + if (d.cnst == true) { + if (VEC_PUSH_STR(&d.vec, " const") == false) + goto clean; + + d.cnst = false; + } + + if (d.array == true) { + if (vector_str_push(&d.vec, d.array_str.buf, + d.array_str.size) == false) + goto clean; + + dest_cstring(&d.array_str); + d.array = false; + } + + if (*d.p == '\0') + break; + + if ((arg = vector_str_substr(&d.vec, arg_begin, d.vec.size - 1, + &arg_len)) == NULL) + goto clean; + + if (vector_str_push(&d.arg, arg, arg_len) == false) + goto clean; + + free(arg); + + if (VEC_PUSH_STR(&d.vec, ", ") == false) + goto clean; + + if (++try > CPP_DEMANGLE_ARM_TRY) + goto clean; + } + + /* end argument types */ + if (VEC_PUSH_STR(&d.vec, ")") == false) + goto clean; + +flat: + rtn = vector_str_get_flat(&d.vec, NULL); +clean: + dest_demangle_data(&d); + + return (rtn); +} + +/** + * @brief Test input string is encoded by the ARM style. + * + * @return True if input string is encoded by the ARM style. + */ +bool +is_cpp_mangled_ARM(const char *org) +{ + + if (org == NULL) + return (false); + + return (strstr(org, "__") != NULL); +} + +static void +dest_cstring(struct cstring *s) +{ + + if (s == NULL) + return; + + free(s->buf); + s->buf = NULL; + s->size = 0; +} + +static void +dest_demangle_data(struct demangle_data *d) +{ + + if (d != NULL) { + vector_str_dest(&d->arg); + vector_str_dest(&d->vec); + + dest_cstring(&d->array_str); + } +} + +static bool +init_cstring(struct cstring *s, size_t len) +{ + + if (s == NULL || len <= 1) + return (false); + + if ((s->buf = malloc(sizeof(char) * len)) == NULL) + return (false); + + s->size = len - 1; + + return (true); +} + +static bool +init_demangle_data(struct demangle_data *d) +{ + + if (d == NULL) + return (false); + + d->ptr = false; + d->ref = false; + d->cnst = false; + d->array = false; + + d->array_str.buf = NULL; + d->array_str.size = 0; + + d->type = ENCODE_FUNC; + + if (vector_str_init(&d->vec) == false) + return (false); + + if (vector_str_init(&d->arg) == false) { + vector_str_dest(&d->vec); + + return (false); + } + + return (true); +} + +static bool +push_CTDT(const char *s, size_t l, struct vector_str *v) +{ + + if (s == NULL || l == 0 || v == NULL) + return (false); + + if (vector_str_push(v, s, l) == false) + return (false); + + assert(v->size > 1); + if (VEC_PUSH_STR(v, v->container[v->size - 2]) == false) + return (false); + + if (VEC_PUSH_STR(v, "()") == false) + return (false); + + return (true); +} + +static bool +read_array(struct demangle_data *d) +{ + size_t len; + const char *end; + + if (d == NULL || d->p == NULL) + return (false); + + end = d->p; + assert(end != NULL); + + for (;;) { + if (*end == '\0') + return (false); + + if (ELFTC_ISDIGIT(*end) == 0) + break; + + ++end; + } + + if (*end != '_') + return (false); + + len = end - d->p; + assert(len > 0); + + dest_cstring(&d->array_str); + if (init_cstring(&d->array_str, len + 3) == false) + return (false); + + strncpy(d->array_str.buf + 1, d->p, len); + *d->array_str.buf = '['; + *(d->array_str.buf + len + 1) = ']'; + + d->array = true; + d->p = end + 1; + + return (true); +} + +static bool +read_class(struct demangle_data *d) +{ + size_t len; + char *str; + + if (d == NULL) + return (false); + + len = strtol(d->p, &str, 10); + if (len == 0 && (errno == EINVAL || errno == ERANGE)) + return (false); + + assert(len > 0); + assert(str != NULL); + + if (vector_str_push(&d->vec, str, len) == false) + return (false); + + d->p = str + len; + + return (true); +} + +static bool +read_func(struct demangle_data *d) +{ + size_t len; + const char *name; + char *delim; + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + if ((delim = strstr(d->p, "__")) == NULL) + return (false); + + len = delim - d->p; + assert(len != 0); + + name = d->p; + + d->p = delim + 2; + + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + if (read_qual_name(d) == false) + return (false); + } else if (ELFTC_ISDIGIT(*d->p)) { + if (read_class(d) == false) + return (false); + + if (VEC_PUSH_STR(&d->vec, "::") == false) + return (false); + } + + if (vector_str_push(&d->vec, name, len) == false) + return (false); + + return (true); +} + +static bool +read_func_name(struct demangle_data *d) +{ + size_t len; + bool rtn; + char *op_name; + + if (d == NULL) + return (false); + + rtn = false; + op_name = NULL; + + assert(d->p != NULL && "d->p (org str) is NULL"); + + if (*d->p == '_' && *(d->p + 1) == '_') { + d->p += 2; + + d->type = ENCODE_OP; + if (read_op(d) == false) + return (false); + + if (d->type == ENCODE_OP_CT || d->type == ENCODE_OP_DT || + d->type == ENCODE_OP_USER) + return (true); + + /* skip "__" */ + d->p += 2; + + /* assume delimiter is removed */ + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + assert(d->vec.size > 0); + + len = strlen(d->vec.container[d->vec.size - 1]); + if ((op_name = malloc(sizeof(char) * (len + 1))) + == NULL) + return (false); + + snprintf(op_name, len + 1, "%s", + d->vec.container[d->vec.size - 1]); + vector_str_pop(&d->vec); + + if (read_qual_name(d) == false) + goto clean; + + if (VEC_PUSH_STR(&d->vec, "::") == false) + goto clean; + + if (vector_str_push(&d->vec, op_name, len) == false) + goto clean; + + rtn = true; + } else if (ELFTC_ISDIGIT(*d->p)) { + assert(d->vec.size > 0); + + len = strlen(d->vec.container[d->vec.size - 1]); + if ((op_name = malloc(sizeof(char) * (len + 1))) + == NULL) + return (false); + + snprintf(op_name, len + 1, "%s", + d->vec.container[d->vec.size - 1]); + vector_str_pop(&d->vec); + + if (read_class(d) == false) + goto clean; + + if (VEC_PUSH_STR(&d->vec, "::") == false) + goto clean; + + if (vector_str_push(&d->vec, op_name, len) == false) + goto clean; + + rtn = true; + } + } else + return (read_func(d)); + +clean: + free(op_name); + + return (rtn); +} + +/* Read function ptr type */ +static bool +read_func_ptr(struct demangle_data *d) +{ + struct demangle_data fptr; + size_t arg_len, rtn_len; + char *arg_type, *rtn_type; + int lim; + + if (d == NULL) + return (false); + + if (init_demangle_data(&fptr) == false) + return (false); + + fptr.p = d->p + 1; + lim = 0; + arg_type = NULL; + rtn_type = NULL; + + for (;;) { + if (read_type(&fptr) == false) { + dest_demangle_data(&fptr); + + return (false); + } + + if (fptr.ptr == true) { + if (VEC_PUSH_STR(&fptr.vec, "*") == false) { + dest_demangle_data(&fptr); + + return (false); + } + + fptr.ptr = false; + } + + if (fptr.ref == true) { + if (VEC_PUSH_STR(&fptr.vec, "&") == false) { + dest_demangle_data(&fptr); + + return (false); + } + + fptr.ref = false; + } + + if (fptr.cnst == true) { + if (VEC_PUSH_STR(&fptr.vec, " const") == false) { + dest_demangle_data(&fptr); + + return (false); + } + + fptr.cnst = false; + } + + if (*fptr.p == '_') + break; + + if (VEC_PUSH_STR(&fptr.vec, ", ") == false) { + dest_demangle_data(&fptr); + + return (false); + } + + if (++lim > CPP_DEMANGLE_ARM_TRY) { + + dest_demangle_data(&fptr); + + return (false); + } + } + + arg_type = vector_str_get_flat(&fptr.vec, &arg_len); + /* skip '_' */ + d->p = fptr.p + 1; + + dest_demangle_data(&fptr); + + if (init_demangle_data(&fptr) == false) { + free(arg_type); + + return (false); + } + + fptr.p = d->p; + lim = 0; + + if (read_type(&fptr) == false) { + free(arg_type); + dest_demangle_data(&fptr); + + return (false); + } + + rtn_type = vector_str_get_flat(&fptr.vec, &rtn_len); + d->p = fptr.p; + + + dest_demangle_data(&fptr); + + if (vector_str_push(&d->vec, rtn_type, rtn_len) == false) { + free(rtn_type); + free(arg_type); + + return (false); + } + + free(rtn_type); + + if (VEC_PUSH_STR(&d->vec, " (*)(") == false) { + free(arg_type); + + return (false); + } + + if (vector_str_push(&d->vec, arg_type, arg_len) == false) { + free(arg_type); + + return (false); + } + + free(arg_type); + + return (VEC_PUSH_STR(&d->vec, ")")); +} + +static bool +read_memptr(struct demangle_data *d) +{ + struct demangle_data mptr; + size_t len; + bool rtn; + char *mptr_str; + + if (d == NULL || d->p == NULL) + return (false); + + if (init_demangle_data(&mptr) == false) + return (false); + + rtn = false; + mptr_str = NULL; + + mptr.p = d->p; + if (*mptr.p == 'Q') { + ++mptr.p; + + if (read_qual_name(&mptr) == false) + goto clean; + } else { + if (read_class(&mptr) == false) + goto clean; + } + + d->p = mptr.p; + + if ((mptr_str = vector_str_get_flat(&mptr.vec, &len)) == NULL) + goto clean; + + if (vector_str_push(&d->vec, mptr_str, len) == false) + goto clean; + + if (VEC_PUSH_STR(&d->vec, "::*") == false) + goto clean; + + rtn = true; +clean: + free(mptr_str); + dest_demangle_data(&mptr); + + return (rtn); +} + +static bool +read_op(struct demangle_data *d) +{ + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + + switch (SIMPLE_HASH(*(d->p), *(d->p+1))) { + case SIMPLE_HASH('m', 'l') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator*")); + case SIMPLE_HASH('d', 'v') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator/")); + case SIMPLE_HASH('m', 'd') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator%")); + case SIMPLE_HASH('p', 'l') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator+")); + case SIMPLE_HASH('m', 'i') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator-")); + case SIMPLE_HASH('l', 's') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator<<")); + case SIMPLE_HASH('r', 's') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator>>")); + case SIMPLE_HASH('e', 'q') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator==")); + case SIMPLE_HASH('n', 'e') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator!=")); + case SIMPLE_HASH('l', 't') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator<")); + case SIMPLE_HASH('g', 't') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator>")); + case SIMPLE_HASH('l', 'e') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator<=")); + case SIMPLE_HASH('g', 'e') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator>=")); + case SIMPLE_HASH('a', 'd') : + d->p += 2; + if (*d->p == 'v') { + ++d->p; + return (VEC_PUSH_STR(&d->vec, "operator/=")); + } else + return (VEC_PUSH_STR(&d->vec, "operator&")); + case SIMPLE_HASH('o', 'r') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator|")); + case SIMPLE_HASH('e', 'r') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator^")); + case SIMPLE_HASH('a', 'a') : + d->p += 2; + if (*d->p == 'd') { + ++d->p; + return (VEC_PUSH_STR(&d->vec, "operator&=")); + } else + return (VEC_PUSH_STR(&d->vec, "operator&&")); + case SIMPLE_HASH('o', 'o') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator||")); + case SIMPLE_HASH('n', 't') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator!")); + case SIMPLE_HASH('c', 'o') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator~")); + case SIMPLE_HASH('p', 'p') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator++")); + case SIMPLE_HASH('m', 'm') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator--")); + case SIMPLE_HASH('a', 's') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator=")); + case SIMPLE_HASH('r', 'f') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator->")); + case SIMPLE_HASH('a', 'p') : + /* apl */ + if (*(d->p + 2) != 'l') + return (false); + + d->p += 3; + return (VEC_PUSH_STR(&d->vec, "operator+=")); + case SIMPLE_HASH('a', 'm') : + d->p += 2; + if (*d->p == 'i') { + ++d->p; + return (VEC_PUSH_STR(&d->vec, "operator-=")); + } else if (*d->p == 'u') { + ++d->p; + return (VEC_PUSH_STR(&d->vec, "operator*=")); + } else if (*d->p == 'd') { + ++d->p; + return (VEC_PUSH_STR(&d->vec, "operator%=")); + } + + return (false); + case SIMPLE_HASH('a', 'l') : + /* als */ + if (*(d->p + 2) != 's') + return (false); + + d->p += 3; + return (VEC_PUSH_STR(&d->vec, "operator<<=")); + case SIMPLE_HASH('a', 'r') : + /* ars */ + if (*(d->p + 2) != 's') + return (false); + + d->p += 3; + return (VEC_PUSH_STR(&d->vec, "operator>>=")); + case SIMPLE_HASH('a', 'o') : + /* aor */ + if (*(d->p + 2) != 'r') + return (false); + + d->p += 3; + return (VEC_PUSH_STR(&d->vec, "operator|=")); + case SIMPLE_HASH('a', 'e') : + /* aer */ + if (*(d->p + 2) != 'r') + return (false); + + d->p += 3; + return (VEC_PUSH_STR(&d->vec, "operator^=")); + case SIMPLE_HASH('c', 'm') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator,")); + case SIMPLE_HASH('r', 'm') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator->*")); + case SIMPLE_HASH('c', 'l') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "()")); + case SIMPLE_HASH('v', 'c') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "[]")); + case SIMPLE_HASH('c', 't') : + d->p += 4; + d->type = ENCODE_OP_CT; + + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + return (read_qual_name(d)); + } else if (ELFTC_ISDIGIT(*d->p)) + return (read_class(d)); + + return (false); + case SIMPLE_HASH('d', 't') : + d->p += 4; + d->type = ENCODE_OP_DT; + + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + return (read_qual_name(d)); + } else if (ELFTC_ISDIGIT(*d->p)) + return (read_class(d)); + + return (false); + case SIMPLE_HASH('n', 'w') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator new()")); + case SIMPLE_HASH('d', 'l') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator delete()")); + case SIMPLE_HASH('o', 'p') : + /* __op__ */ + d->p += 2; + + d->type = ENCODE_OP_USER; + + return (read_op_user(d)); + default : + return (false); + }; +} + +static bool +read_op_user(struct demangle_data *d) +{ + struct demangle_data from, to; + size_t from_len, to_len; + bool rtn; + char *from_str, *to_str; + + if (d == NULL) + return (false); + + if (init_demangle_data(&from) == false) + return (false); + + rtn = false; + from_str = NULL; + to_str = NULL; + if (init_demangle_data(&to) == false) + goto clean; + + to.p = d->p; + if (*to.p == 'Q') { + ++to.p; + + if (read_qual_name(&to) == false) + goto clean; + + /* pop last '::' */ + if (vector_str_pop(&to.vec) == false) + goto clean; + } else { + if (read_class(&to) == false) + goto clean; + + /* skip '__' */ + to.p += 2; + } + + if ((to_str = vector_str_get_flat(&to.vec, &to_len)) == NULL) + goto clean; + + from.p = to.p; + if (*from.p == 'Q') { + ++from.p; + + if (read_qual_name(&from) == false) + goto clean; + + /* pop last '::' */ + if (vector_str_pop(&from.vec) == false) + goto clean; + } else { + if (read_class(&from) == false) + goto clean; + } + + if ((from_str = vector_str_get_flat(&from.vec, &from_len)) == NULL) + goto clean; + + if (vector_str_push(&d->vec, from_str, from_len) == false) + goto clean; + + if (VEC_PUSH_STR(&d->vec, "::operator ") == false) + return (false); + + if (vector_str_push(&d->vec, to_str, to_len) == false) + goto clean; + + rtn = VEC_PUSH_STR(&d->vec, "()"); +clean: + free(to_str); + free(from_str); + dest_demangle_data(&to); + dest_demangle_data(&from); + + return (rtn); +} + +/* single digit + class names */ +static bool +read_qual_name(struct demangle_data *d) +{ + int i; + char num; + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range"); + + num = *d->p - 48; + + assert(num > 0); + + ++d->p; + for (i = 0; i < num ; ++i) { + if (read_class(d) == false) + return (false); + + if (VEC_PUSH_STR(&d->vec, "::") == false) + return (false); + } + + if (*d->p != '\0') + d->p = d->p + 2; + + return (true); +} + +/* Return -1 at fail, 0 at success, and 1 at end */ +static int +read_subst(struct demangle_data *d) +{ + size_t idx; + char *str; + + if (d == NULL) + return (-1); + + idx = strtol(d->p + 1, &str, 10); + if (idx == 0 && (errno == EINVAL || errno == ERANGE)) + return (-1); + + assert(idx > 0); + assert(str != NULL); + + d->p = str; + + if (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false) + return (-1); + + if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false) + return (-1); + + if (*d->p == '\0') + return (1); + + return (0); +} + +static int +read_subst_iter(struct demangle_data *d) +{ + int i; + size_t idx; + char repeat; + char *str; + + if (d == NULL) + return (-1); + + ++d->p; + assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range"); + + repeat = *d->p - 48; + + assert(repeat > 1); + + ++d->p; + + idx = strtol(d->p, &str, 10); + if (idx == 0 && (errno == EINVAL || errno == ERANGE)) + return (-1); + + assert(idx > 0); + assert(str != NULL); + + d->p = str; + + for (i = 0; i < repeat ; ++i) { + if (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false) + return (-1); + + if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false) + return (-1); + + if (i != repeat - 1 && + VEC_PUSH_STR(&d->vec, ", ") == false) + return (-1); + } + + if (*d->p == '\0') + return (1); + + return (0); +} + +static bool +read_type(struct demangle_data *d) +{ + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + + while (*d->p == 'U' || *d->p == 'C' || *d->p == 'V' || *d->p == 'S' || + *d->p == 'P' || *d->p == 'R' || *d->p == 'A' || *d->p == 'F' || + *d->p == 'M') { + switch (*d->p) { + case 'U' : + ++d->p; + + if (VEC_PUSH_STR(&d->vec, "unsigned ") == false) + return (false); + + break; + case 'C' : + ++d->p; + + if (*d->p == 'P') + d->cnst = true; + else { + if (VEC_PUSH_STR(&d->vec, "const ") == + false) + return (false); + } + + break; + case 'V' : + ++d->p; + + if (VEC_PUSH_STR(&d->vec, "volatile ") == false) + return (false); + + break; + case 'S' : + ++d->p; + + if (VEC_PUSH_STR(&d->vec, "signed ") == false) + return (false); + + break; + case 'P' : + ++d->p; + + if (*d->p == 'F') + return (read_func_ptr(d)); + else + d->ptr = true; + + break; + case 'R' : + ++d->p; + + d->ref = true; + + break; + case 'F' : + break; + case 'A' : + ++d->p; + + if (read_array(d) == false) + return (false); + + break; + case 'M' : + ++d->p; + + if (read_memptr(d) == false) + return (false); + + break; + default : + break; + } + } + + if (ELFTC_ISDIGIT(*d->p)) + return (read_class(d)); + + switch (*d->p) { + case 'Q' : + ++d->p; + + return (read_qual_name(d)); + case 'v' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "void")); + case 'c' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "char")); + case 's' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "short")); + case 'i' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "int")); + case 'l' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "long")); + case 'f' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "float")); + case 'd': + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "double")); + case 'r': + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "long double")); + case 'e': + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "...")); + default: + return (false); + }; + + /* NOTREACHED */ + return (false); +} diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu2.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu2.c new file mode 100644 index 0000000..5c77b67 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu2.c @@ -0,0 +1,1365 @@ +/*- + * Copyright (c) 2008 Hyogeol Lee + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "_libelftc.h" + +ELFTC_VCSID("$Id: libelftc_dem_gnu2.c 3513 2016-12-29 07:04:22Z kaiwang27 $"); + +/** + * @file cpp_demangle_gnu2.c + * @brief Decode function name encoding in GNU 2. + * + * Function name encoding in GNU 2 based on ARM style. + */ + +enum encode_type { + ENCODE_FUNC, ENCODE_OP, ENCODE_OP_CT, ENCODE_OP_DT, ENCODE_OP_USER, + ENCODE_OP_TF, ENCODE_OP_TI, ENCODE_OP_VT +}; + +struct cstring { + char *buf; + size_t size; +}; + +struct demangle_data { + bool ptr, ref, cnst, array, cnst_fn, class_name; + struct cstring array_str; + const char *p; + enum encode_type type; + struct vector_str vec; + struct vector_str arg; +}; + +#define SIMPLE_HASH(x,y) (64 * x + y) +#define VEC_PUSH_STR(d,s) vector_str_push((d), (s), strlen((s))) +#define CPP_DEMANGLE_GNU2_TRY 128 + +static void dest_cstring(struct cstring *); +static void dest_demangle_data(struct demangle_data *); +static bool init_cstring(struct cstring *, size_t); +static bool init_demangle_data(struct demangle_data *); +static bool push_CTDT(const char *, size_t, struct vector_str *); +static bool read_array(struct demangle_data *); +static bool read_class(struct demangle_data *); +static bool read_func(struct demangle_data *); +static bool read_func_name(struct demangle_data *); +static bool read_func_ptr(struct demangle_data *); +static bool read_memptr(struct demangle_data *); +static bool read_op(struct demangle_data *); +static bool read_op_user(struct demangle_data *); +static bool read_qual_name(struct demangle_data *); +static int read_subst(struct demangle_data *); +static int read_subst_iter(struct demangle_data *); +static bool read_type(struct demangle_data *); + +/** + * @brief Decode the input string by the GNU 2 style. + * + * @return New allocated demangled string or NULL if failed. + */ +char * +cpp_demangle_gnu2(const char *org) +{ + struct demangle_data d; + size_t arg_begin, arg_len; + unsigned int try; + char *rtn, *arg; + + if (org == NULL) + return (NULL); + + if (init_demangle_data(&d) == false) + return (NULL); + + try = 0; + rtn = NULL; + + d.p = org; + if (read_func_name(&d) == false) + goto clean; + + switch (d.type) { + case ENCODE_FUNC : + case ENCODE_OP : + break; + + case ENCODE_OP_CT : + if (push_CTDT("::", 2, &d.vec) == false) + goto clean; + + break; + case ENCODE_OP_DT : + if (push_CTDT("::~", 3, &d.vec) == false) + goto clean; + + if (VEC_PUSH_STR(&d.vec, "(void)") == false) + goto clean; + + goto flat; + case ENCODE_OP_USER : + case ENCODE_OP_TF : + case ENCODE_OP_TI : + case ENCODE_OP_VT : + goto flat; + } + + if (*d.p == 'F') + ++d.p; + else if (*d.p == '\0') { + if (d.class_name == true) { + if (VEC_PUSH_STR(&d.vec, "(void)") == false) + goto clean; + + goto flat; + } else + goto clean; + } + + /* start argument types */ + if (VEC_PUSH_STR(&d.vec, "(") == false) + goto clean; + + for (;;) { + if (*d.p == 'T') { + const int rtn_subst = read_subst(&d); + + if (rtn_subst == -1) + goto clean; + else if (rtn_subst == 1) + break; + + continue; + } + + if (*d.p == 'N') { + const int rtn_subst_iter = read_subst_iter(&d); + + if (rtn_subst_iter == -1) + goto clean; + else if(rtn_subst_iter == 1) + break; + + continue; + } + + arg_begin = d.vec.size; + + if (read_type(&d) == false) + goto clean; + + if (d.ptr == true) { + if (VEC_PUSH_STR(&d.vec, "*") == false) + goto clean; + + d.ptr = false; + } + + if (d.ref == true) { + if (VEC_PUSH_STR(&d.vec, "&") == false) + goto clean; + + d.ref = false; + } + + if (d.cnst == true) { + if (VEC_PUSH_STR(&d.vec, " const") == false) + goto clean; + + d.cnst = false; + } + + if (d.array == true) { + if (vector_str_push(&d.vec, d.array_str.buf, + d.array_str.size) == false) + goto clean; + + dest_cstring(&d.array_str); + d.array = false; + } + + if (*d.p == '\0') + break; + + if ((arg = vector_str_substr(&d.vec, arg_begin, d.vec.size - 1, + &arg_len)) == NULL) + goto clean; + + if (vector_str_push(&d.arg, arg, arg_len) == false) + goto clean; + + free(arg); + + if (VEC_PUSH_STR(&d.vec, ", ") == false) + goto clean; + + if (++try > CPP_DEMANGLE_GNU2_TRY) + goto clean; + } + + /* end argument types */ + if (VEC_PUSH_STR(&d.vec, ")") == false) + goto clean; +flat: + if (d.cnst_fn == true && VEC_PUSH_STR(&d.vec, " const") == false) + goto clean; + + rtn = vector_str_get_flat(&d.vec, NULL); +clean: + dest_demangle_data(&d); + + return (rtn); +} + +/** + * @brief Test input string is encoded by the GNU 2 style. + * + * @return True if input string is encoded by the GNU 2 style. + */ +bool +is_cpp_mangled_gnu2(const char *org) +{ + char *str; + bool rtn = false; + + if (org == NULL) + return (false); + + /* search valid text to end */ + str = strstr(org, "__"); + while (str != NULL) { + if (*(str + 2) != '\0') { + if (*(str + 2) == 'C' || + *(str + 2) == 'F' || + *(str + 2) == 'Q' || + ELFTC_ISDIGIT(*(str + 2))) { + rtn |= true; + + break; + } + + if (*(str + 3) != '\0') { + switch (SIMPLE_HASH(*(str + 2), *(str + 3))) { + case SIMPLE_HASH('m', 'l') : + case SIMPLE_HASH('d', 'v') : + case SIMPLE_HASH('m', 'd') : + case SIMPLE_HASH('p', 'l') : + case SIMPLE_HASH('m', 'i') : + case SIMPLE_HASH('l', 's') : + case SIMPLE_HASH('r', 's') : + case SIMPLE_HASH('e', 'q') : + case SIMPLE_HASH('n', 'e') : + case SIMPLE_HASH('l', 't') : + case SIMPLE_HASH('g', 't') : + case SIMPLE_HASH('l', 'e') : + case SIMPLE_HASH('g', 'e') : + case SIMPLE_HASH('a', 'd') : + case SIMPLE_HASH('o', 'r') : + case SIMPLE_HASH('e', 'r') : + case SIMPLE_HASH('a', 'a') : + case SIMPLE_HASH('o', 'o') : + case SIMPLE_HASH('n', 't') : + case SIMPLE_HASH('c', 'o') : + case SIMPLE_HASH('p', 'p') : + case SIMPLE_HASH('m', 'm') : + case SIMPLE_HASH('a', 's') : + case SIMPLE_HASH('r', 'f') : + case SIMPLE_HASH('a', 'p') : + case SIMPLE_HASH('a', 'm') : + case SIMPLE_HASH('a', 'l') : + case SIMPLE_HASH('a', 'r') : + case SIMPLE_HASH('a', 'o') : + case SIMPLE_HASH('a', 'e') : + case SIMPLE_HASH('c', 'm') : + case SIMPLE_HASH('r', 'm') : + case SIMPLE_HASH('c', 'l') : + case SIMPLE_HASH('v', 'c') : + case SIMPLE_HASH('n', 'w') : + case SIMPLE_HASH('d', 'l') : + case SIMPLE_HASH('o', 'p') : + case SIMPLE_HASH('t', 'f') : + case SIMPLE_HASH('t', 'i') : + rtn |= true; + + break; + } + } + } + + str = strstr(str + 2, "__"); + } + + rtn |= strstr(org, "_$_") != NULL; + rtn |= strstr(org, "_vt$") != NULL; + + return (rtn); +} + +static void +dest_cstring(struct cstring *s) +{ + + if (s == NULL) + return; + + free(s->buf); + s->buf = NULL; + s->size = 0; +} + +static void +dest_demangle_data(struct demangle_data *d) +{ + + if (d != NULL) { + vector_str_dest(&d->arg); + vector_str_dest(&d->vec); + + dest_cstring(&d->array_str); + } +} + +static bool +init_cstring(struct cstring *s, size_t len) +{ + + if (s == NULL || len <= 1) + return (false); + + if ((s->buf = malloc(sizeof(char) * len)) == NULL) + return (false); + + s->size = len - 1; + + return (true); +} + +static bool +init_demangle_data(struct demangle_data *d) +{ + + if (d == NULL) + return (false); + + d->ptr = false; + d->ref = false; + d->cnst = false; + d->array = false; + d->cnst_fn = false; + d->class_name = false; + + d->array_str.buf = NULL; + d->array_str.size = 0; + + d->type = ENCODE_FUNC; + + if (vector_str_init(&d->vec) == false) + return (false); + + if (vector_str_init(&d->arg) == false) { + vector_str_dest(&d->vec); + + return (false); + } + + return (true); +} + +static bool +push_CTDT(const char *s, size_t l, struct vector_str *v) +{ + + if (s == NULL || l == 0 || v == NULL) + return (false); + + if (vector_str_push(v, s, l) == false) + return (false); + + assert(v->size > 1); + + return (VEC_PUSH_STR(v, v->container[v->size - 2])); +} + +static bool +read_array(struct demangle_data *d) +{ + size_t len; + const char *end; + + if (d == NULL || d->p == NULL) + return (false); + + end = d->p; + assert(end != NULL); + + for (;;) { + if (*end == '\0') + return (false); + + if (ELFTC_ISDIGIT(*end) == 0) + break; + + ++end; + } + + if (*end != '_') + return (false); + + len = end - d->p; + assert(len > 0); + + dest_cstring(&d->array_str); + if (init_cstring(&d->array_str, len + 3) == false) + return (false); + + strncpy(d->array_str.buf + 1, d->p, len); + *d->array_str.buf = '['; + *(d->array_str.buf + len + 1) = ']'; + + d->array = true; + d->p = end + 1; + + return (true); +} + +static bool +read_class(struct demangle_data *d) +{ + size_t len; + char *str; + + if (d == NULL) + return (false); + + len = strtol(d->p, &str, 10); + if (len == 0 && (errno == EINVAL || errno == ERANGE)) + return (false); + + assert(len > 0); + assert(str != NULL); + + if (vector_str_push(&d->vec, str, len) == false) + return (false); + + d->p = str + len; + + d->class_name = true; + + return (true); +} + +static bool +read_func(struct demangle_data *d) +{ + size_t len; + const char *name; + char *delim; + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + if ((delim = strstr(d->p, "__")) == NULL) + return (false); + + len = delim - d->p; + assert(len != 0); + + name = d->p; + + d->p = delim + 2; + + if (*d->p == 'C') { + ++d->p; + + d->cnst_fn = true; + } + + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + if (read_qual_name(d) == false) + return (false); + } else if (ELFTC_ISDIGIT(*d->p)) { + if (read_class(d) == false) + return (false); + + if (VEC_PUSH_STR(&d->vec, "::") == false) + return (false); + } + + return (vector_str_push(&d->vec, name, len)); +} + +static bool +read_func_name(struct demangle_data *d) +{ + size_t len; + bool rtn; + char *op_name; + + if (d == NULL) + return (false); + + rtn = false; + op_name = NULL; + + assert(d->p != NULL && "d->p (org str) is NULL"); + + if (*d->p == '_' && *(d->p + 1) == '_') { + d->p += 2; + + /* CTOR */ + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + d->type = ENCODE_OP_CT; + + if (read_qual_name(d) == false) + return (false); + + return (vector_str_pop(&d->vec)); + } else if (ELFTC_ISDIGIT(*d->p)) { + d->type = ENCODE_OP_CT; + + return (read_class(d)); + } + + d->type = ENCODE_OP; + if (read_op(d) == false) { + /* not good condition, start function name with '__' */ + d->type = ENCODE_FUNC; + + if (VEC_PUSH_STR(&d->vec, "__") == false) + return (false); + + return (read_func(d)); + } + + if (d->type == ENCODE_OP_USER || + d->type == ENCODE_OP_TF || + d->type == ENCODE_OP_TI) + return (true); + + /* skip "__" */ + d->p += 2; + + if (*d->p == 'C') { + ++d->p; + + d->cnst_fn = true; + } + + /* assume delimiter is removed */ + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + assert(d->vec.size > 0); + + len = strlen(d->vec.container[d->vec.size - 1]); + if ((op_name = malloc(sizeof(char) * (len + 1))) + == NULL) + return (false); + + snprintf(op_name, len + 1, "%s", + d->vec.container[d->vec.size - 1]); + vector_str_pop(&d->vec); + + if (read_qual_name(d) == false) + goto clean; + + if (VEC_PUSH_STR(&d->vec, "::") == false) + goto clean; + + if (vector_str_push(&d->vec, op_name, len) == false) + goto clean; + + rtn = true; + } else if (ELFTC_ISDIGIT(*d->p)) { + assert(d->vec.size > 0); + + len = strlen(d->vec.container[d->vec.size - 1]); + if ((op_name = malloc(sizeof(char) * (len + 1))) + == NULL) + return (false); + + snprintf(op_name, len + 1, "%s", + d->vec.container[d->vec.size - 1]); + vector_str_pop(&d->vec); + + if (read_class(d) == false) + goto clean; + + if (VEC_PUSH_STR(&d->vec, "::") == false) + goto clean; + + if (vector_str_push(&d->vec, op_name, len) == false) + goto clean; + + rtn = true; + } + } else if (memcmp(d->p, "_$_", 3) == 0) { + /* DTOR */ + d->p += 3; + d->type = ENCODE_OP_DT; + + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + if (read_qual_name(d) == false) + return (false); + + return (vector_str_pop(&d->vec)); + } else if (ELFTC_ISDIGIT(*d->p)) + return (read_class(d)); + + return (false); + } else if (memcmp(d->p, "_vt$", 4) == 0) { + /* vtable */ + d->p += 4; + d->type = ENCODE_OP_VT; + + if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) { + ++d->p; + + if (read_qual_name(d) == false) + return (false); + + if (vector_str_pop(&d->vec) == false) + return (false); + } else if (ELFTC_ISDIGIT(*d->p)) { + if (read_class(d) == false) + return (false); + } + + return (VEC_PUSH_STR(&d->vec, " virtual table")); + } else + return (read_func(d)); +clean: + free(op_name); + + return (rtn); +} + +/* Read function ptr type */ +static bool +read_func_ptr(struct demangle_data *d) +{ + struct demangle_data fptr; + size_t arg_len, rtn_len; + char *arg_type, *rtn_type; + int lim; + + if (d == NULL) + return (false); + + if (init_demangle_data(&fptr) == false) + return (false); + + fptr.p = d->p + 1; + lim = 0; + arg_type = NULL; + rtn_type = NULL; + + for (;;) { + if (read_type(&fptr) == false) { + dest_demangle_data(&fptr); + + return (false); + } + + if (fptr.ptr == true) { + if (VEC_PUSH_STR(&fptr.vec, "*") == false) { + dest_demangle_data(&fptr); + + return (false); + } + + fptr.ptr = false; + } + + if (fptr.ref == true) { + if (VEC_PUSH_STR(&fptr.vec, "&") == false) { + dest_demangle_data(&fptr); + + return (false); + } + + fptr.ref = false; + } + + if (fptr.cnst == true) { + if (VEC_PUSH_STR(&fptr.vec, " const") == false) { + dest_demangle_data(&fptr); + + return (false); + } + + fptr.cnst = false; + } + + if (*fptr.p == '_') + break; + + if (VEC_PUSH_STR(&fptr.vec, ", ") == false) { + dest_demangle_data(&fptr); + + return (false); + } + + if (++lim > CPP_DEMANGLE_GNU2_TRY) { + + dest_demangle_data(&fptr); + + return (false); + } + } + + arg_type = vector_str_get_flat(&fptr.vec, &arg_len); + /* skip '_' */ + d->p = fptr.p + 1; + + dest_demangle_data(&fptr); + + if (init_demangle_data(&fptr) == false) { + free(arg_type); + + return (false); + } + + fptr.p = d->p; + lim = 0; + + if (read_type(&fptr) == false) { + free(arg_type); + dest_demangle_data(&fptr); + + return (false); + } + + rtn_type = vector_str_get_flat(&fptr.vec, &rtn_len); + d->p = fptr.p; + + + dest_demangle_data(&fptr); + + if (vector_str_push(&d->vec, rtn_type, rtn_len) == false) { + free(rtn_type); + free(arg_type); + + return (false); + } + + free(rtn_type); + + if (VEC_PUSH_STR(&d->vec, " (*)(") == false) { + free(arg_type); + + return (false); + } + + if (vector_str_push(&d->vec, arg_type, arg_len) == false) { + free(arg_type); + + return (false); + } + + free(arg_type); + + return (VEC_PUSH_STR(&d->vec, ")")); +} + +static bool +read_memptr(struct demangle_data *d) +{ + struct demangle_data mptr; + size_t len; + bool rtn; + char *mptr_str; + + if (d == NULL || d->p == NULL) + return (false); + + if (init_demangle_data(&mptr) == false) + return (false); + + rtn = false; + mptr_str = NULL; + + mptr.p = d->p; + if (*mptr.p == 'Q') { + ++mptr.p; + + if (read_qual_name(&mptr) == false) + goto clean; + } else if (read_class(&mptr) == false) + goto clean; + + d->p = mptr.p; + + if ((mptr_str = vector_str_get_flat(&mptr.vec, &len)) == NULL) + goto clean; + + if (vector_str_push(&d->vec, mptr_str, len) == false) + goto clean; + + if (VEC_PUSH_STR(&d->vec, "::*") == false) + goto clean; + + rtn = true; +clean: + free(mptr_str); + dest_demangle_data(&mptr); + + return (rtn); +} + +static bool +read_op(struct demangle_data *d) +{ + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + + switch (SIMPLE_HASH(*(d->p), *(d->p+1))) { + case SIMPLE_HASH('m', 'l') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator*")); + case SIMPLE_HASH('d', 'v') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator/")); + case SIMPLE_HASH('m', 'd') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator%")); + case SIMPLE_HASH('p', 'l') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator+")); + case SIMPLE_HASH('m', 'i') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator-")); + case SIMPLE_HASH('l', 's') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator<<")); + case SIMPLE_HASH('r', 's') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator>>")); + case SIMPLE_HASH('e', 'q') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator==")); + case SIMPLE_HASH('n', 'e') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator!=")); + case SIMPLE_HASH('l', 't') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator<")); + case SIMPLE_HASH('g', 't') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator>")); + case SIMPLE_HASH('l', 'e') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator<=")); + case SIMPLE_HASH('g', 'e') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator>=")); + case SIMPLE_HASH('a', 'd') : + d->p += 2; + if (*d->p == 'v') { + ++d->p; + return (VEC_PUSH_STR(&d->vec, "operator/=")); + } else + return (VEC_PUSH_STR(&d->vec, "operator&")); + case SIMPLE_HASH('o', 'r') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator|")); + case SIMPLE_HASH('e', 'r') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator^")); + case SIMPLE_HASH('a', 'a') : + d->p += 2; + if (*d->p == 'd') { + ++d->p; + return (VEC_PUSH_STR(&d->vec, "operator&=")); + } else + return (VEC_PUSH_STR(&d->vec, "operator&&")); + case SIMPLE_HASH('o', 'o') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator||")); + case SIMPLE_HASH('n', 't') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator!")); + case SIMPLE_HASH('c', 'o') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator~")); + case SIMPLE_HASH('p', 'p') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator++")); + case SIMPLE_HASH('m', 'm') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator--")); + case SIMPLE_HASH('a', 's') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator=")); + case SIMPLE_HASH('r', 'f') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator->")); + case SIMPLE_HASH('a', 'p') : + /* apl */ + if (*(d->p + 2) != 'l') + return (false); + + d->p += 3; + return (VEC_PUSH_STR(&d->vec, "operator+=")); + case SIMPLE_HASH('a', 'm') : + d->p += 2; + if (*d->p == 'i') { + ++d->p; + return (VEC_PUSH_STR(&d->vec, "operator-=")); + } else if (*d->p == 'u') { + ++d->p; + return (VEC_PUSH_STR(&d->vec, "operator*=")); + } else if (*d->p == 'd') { + ++d->p; + return (VEC_PUSH_STR(&d->vec, "operator%=")); + } + + return (false); + case SIMPLE_HASH('a', 'l') : + /* als */ + if (*(d->p + 2) != 's') + return (false); + + d->p += 3; + return (VEC_PUSH_STR(&d->vec, "operator<<=")); + case SIMPLE_HASH('a', 'r') : + /* ars */ + if (*(d->p + 2) != 's') + return (false); + + d->p += 3; + return (VEC_PUSH_STR(&d->vec, "operator>>=")); + case SIMPLE_HASH('a', 'o') : + /* aor */ + if (*(d->p + 2) != 'r') + return (false); + + d->p += 3; + return (VEC_PUSH_STR(&d->vec, "operator|=")); + case SIMPLE_HASH('a', 'e') : + /* aer */ + if (*(d->p + 2) != 'r') + return (false); + + d->p += 3; + return (VEC_PUSH_STR(&d->vec, "operator^=")); + case SIMPLE_HASH('c', 'm') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator,")); + case SIMPLE_HASH('r', 'm') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator->*")); + case SIMPLE_HASH('c', 'l') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "()")); + case SIMPLE_HASH('v', 'c') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "[]")); + case SIMPLE_HASH('n', 'w') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator new()")); + case SIMPLE_HASH('d', 'l') : + d->p += 2; + return (VEC_PUSH_STR(&d->vec, "operator delete()")); + case SIMPLE_HASH('o', 'p') : + /* __op__ */ + d->p += 2; + + d->type = ENCODE_OP_USER; + + return (read_op_user(d)); + case SIMPLE_HASH('t', 'f') : + d->p += 2; + d->type = ENCODE_OP_TF; + + if (read_type(d) == false) + return (false); + + return (VEC_PUSH_STR(&d->vec, " type_info function")); + case SIMPLE_HASH('t', 'i') : + d->p += 2; + d->type = ENCODE_OP_TI; + + if (read_type(d) == false) + return (false); + + return (VEC_PUSH_STR(&d->vec, " type_info node")); + default : + return (false); + }; +} + +static bool +read_op_user(struct demangle_data *d) +{ + struct demangle_data from, to; + size_t from_len, to_len; + bool rtn; + char *from_str, *to_str; + + if (d == NULL) + return (false); + + if (init_demangle_data(&from) == false) + return (false); + + rtn = false; + from_str = NULL; + to_str = NULL; + if (init_demangle_data(&to) == false) + goto clean; + + to.p = d->p; + if (*to.p == 'Q') { + ++to.p; + + if (read_qual_name(&to) == false) + goto clean; + + /* pop last '::' */ + if (vector_str_pop(&to.vec) == false) + goto clean; + } else { + if (read_class(&to) == false) + goto clean; + + /* skip '__' */ + to.p += 2; + } + + if ((to_str = vector_str_get_flat(&to.vec, &to_len)) == NULL) + goto clean; + + from.p = to.p; + if (*from.p == 'Q') { + ++from.p; + + if (read_qual_name(&from) == false) + goto clean; + + /* pop last '::' */ + if (vector_str_pop(&from.vec) == false) + goto clean; + } else if (read_class(&from) == false) + goto clean; + + if ((from_str = vector_str_get_flat(&from.vec, &from_len)) == NULL) + goto clean; + + if (vector_str_push(&d->vec, from_str, from_len) == false) + goto clean; + + if (VEC_PUSH_STR(&d->vec, "::operator ") == false) + goto clean; + + if (vector_str_push(&d->vec, to_str, to_len) == false) + goto clean; + + rtn = VEC_PUSH_STR(&d->vec, "()"); +clean: + free(to_str); + free(from_str); + dest_demangle_data(&to); + dest_demangle_data(&from); + + return (rtn); +} + +/* single digit + class names */ +static bool +read_qual_name(struct demangle_data *d) +{ + int i; + char num; + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range"); + + num = *d->p - 48; + + assert(num > 0); + + ++d->p; + for (i = 0; i < num ; ++i) { + if (read_class(d) == false) + return (false); + + if (VEC_PUSH_STR(&d->vec, "::") == false) + return (false); + } + + if (*d->p != '\0') + d->p = d->p + 2; + + return (true); +} + +/* Return -1 at fail, 0 at success, and 1 at end */ +static int +read_subst(struct demangle_data *d) +{ + size_t idx; + char *str; + + if (d == NULL) + return (-1); + + idx = strtol(d->p + 1, &str, 10); + if (idx == 0 && (errno == EINVAL || errno == ERANGE)) + return (-1); + + assert(idx > 0); + assert(str != NULL); + + d->p = str; + + if (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false) + return (-1); + + if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false) + return (-1); + + if (*d->p == '\0') + return (1); + + return (0); +} + +static int +read_subst_iter(struct demangle_data *d) +{ + int i; + size_t idx; + char repeat; + char *str; + + if (d == NULL) + return (-1); + + ++d->p; + assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range"); + + repeat = *d->p - 48; + + assert(repeat > 1); + + ++d->p; + + idx = strtol(d->p, &str, 10); + if (idx == 0 && (errno == EINVAL || errno == ERANGE)) + return (-1); + + assert(idx > 0); + assert(str != NULL); + + d->p = str; + + for (i = 0; i < repeat ; ++i) { + if (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false) + return (-1); + + if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false) + return (-1); + + if (i != repeat - 1 && + VEC_PUSH_STR(&d->vec, ", ") == false) + return (-1); + } + + if (*d->p == '\0') + return (1); + + return (0); +} + +static bool +read_type(struct demangle_data *d) +{ + + if (d == NULL) + return (false); + + assert(d->p != NULL && "d->p (org str) is NULL"); + + while (*d->p == 'U' || *d->p == 'C' || *d->p == 'V' || *d->p == 'S' || + *d->p == 'P' || *d->p == 'R' || *d->p == 'A' || *d->p == 'F' || + *d->p == 'M') { + switch (*d->p) { + case 'U' : + ++d->p; + + if (VEC_PUSH_STR(&d->vec, "unsigned ") == false) + return (false); + + break; + case 'C' : + ++d->p; + + if (*d->p == 'P') + d->cnst = true; + else { + if (VEC_PUSH_STR(&d->vec, "const ") == + false) + return (false); + } + + break; + case 'V' : + ++d->p; + + if (VEC_PUSH_STR(&d->vec, "volatile ") == false) + return (false); + + break; + case 'S' : + ++d->p; + + if (VEC_PUSH_STR(&d->vec, "signed ") == false) + return (false); + + break; + case 'P' : + ++d->p; + + if (*d->p == 'F') + return (read_func_ptr(d)); + else + d->ptr = true; + + break; + case 'R' : + ++d->p; + + d->ref = true; + + break; + case 'F' : + break; + case 'A' : + ++d->p; + + if (read_array(d) == false) + return (false); + + break; + case 'M' : + ++d->p; + + if (read_memptr(d) == false) + return (false); + + break; + default : + break; + } + } + + if (ELFTC_ISDIGIT(*d->p)) + return (read_class(d)); + + switch (*d->p) { + case 'Q' : + ++d->p; + + return (read_qual_name(d)); + case 'v' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "void")); + case 'b': + ++d->p; + + return(VEC_PUSH_STR(&d->vec, "bool")); + case 'c' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "char")); + case 's' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "short")); + case 'i' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "int")); + case 'l' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "long")); + case 'f' : + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "float")); + case 'd': + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "double")); + case 'r': + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "long double")); + case 'e': + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "...")); + case 'w': + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "wchar_t")); + case 'x': + ++d->p; + + return (VEC_PUSH_STR(&d->vec, "long long")); + default: + return (false); + }; + + /* NOTREACHED */ + return (false); +} diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu3.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu3.c new file mode 100644 index 0000000..73ed371 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu3.c @@ -0,0 +1,3991 @@ +/*- + * Copyright (c) 2007 Hyogeol Lee + * Copyright (c) 2015-2017 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "_libelftc.h" + +ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 3583 2017-10-15 15:38:47Z emaste $"); + +/** + * @file cpp_demangle.c + * @brief Decode IA-64 C++ ABI style implementation. + * + * IA-64 standard ABI(Itanium C++ ABI) references. + * + * http://www.codesourcery.com/cxx-abi/abi.html#mangling \n + * http://www.codesourcery.com/cxx-abi/abi-mangling.html + */ + +enum type_qualifier { + TYPE_PTR, TYPE_REF, TYPE_CMX, TYPE_IMG, TYPE_EXT, TYPE_RST, TYPE_VAT, + TYPE_CST, TYPE_VEC, TYPE_RREF +}; + +struct vector_type_qualifier { + size_t size, capacity; + enum type_qualifier *q_container; + struct vector_str ext_name; +}; + +enum read_cmd { + READ_FAIL, READ_NEST, READ_TMPL, READ_EXPR, READ_EXPL, READ_LOCAL, + READ_TYPE, READ_FUNC, READ_PTRMEM +}; + +struct read_cmd_item { + enum read_cmd cmd; + void *data; +}; + +struct vector_read_cmd { + size_t size, capacity; + struct read_cmd_item *r_container; +}; + +enum push_qualifier { + PUSH_ALL_QUALIFIER, + PUSH_CV_QUALIFIER, + PUSH_NON_CV_QUALIFIER, +}; + +struct cpp_demangle_data { + struct vector_str output; /* output string vector */ + struct vector_str subst; /* substitution string vector */ + struct vector_str tmpl; + struct vector_str class_type; + struct vector_str *cur_output; /* ptr to current output vec */ + struct vector_read_cmd cmd; + bool mem_rst; /* restrict member function */ + bool mem_vat; /* volatile member function */ + bool mem_cst; /* const member function */ + bool mem_ref; /* lvalue-ref member func */ + bool mem_rref; /* rvalue-ref member func */ + bool is_tmpl; /* template args */ + bool is_functype; /* function type */ + bool ref_qualifier; /* ref qualifier */ + enum type_qualifier ref_qualifier_type; /* ref qualifier type */ + enum push_qualifier push_qualifier; /* which qualifiers to push */ + int func_type; + const char *cur; /* current mangled name ptr */ + const char *last_sname; /* last source name */ +}; + +struct type_delimit { + bool paren; + bool firstp; +}; + +#define CPP_DEMANGLE_TRY_LIMIT 128 +#define FLOAT_SPRINTF_TRY_LIMIT 5 +#define FLOAT_QUADRUPLE_BYTES 16 +#define FLOAT_EXTENED_BYTES 10 + +#define SIMPLE_HASH(x,y) (64 * x + y) +#define DEM_PUSH_STR(d,s) cpp_demangle_push_str((d), (s), strlen((s))) +#define VEC_PUSH_STR(d,s) vector_str_push((d), (s), strlen((s))) + +static void cpp_demangle_data_dest(struct cpp_demangle_data *); +static int cpp_demangle_data_init(struct cpp_demangle_data *, + const char *); +static int cpp_demangle_get_subst(struct cpp_demangle_data *, size_t); +static int cpp_demangle_get_tmpl_param(struct cpp_demangle_data *, size_t); +static int cpp_demangle_push_fp(struct cpp_demangle_data *, + char *(*)(const char *, size_t)); +static int cpp_demangle_push_str(struct cpp_demangle_data *, const char *, + size_t); +static int cpp_demangle_pop_str(struct cpp_demangle_data *); +static int cpp_demangle_push_subst(struct cpp_demangle_data *, + const char *, size_t); +static int cpp_demangle_push_subst_v(struct cpp_demangle_data *, + struct vector_str *); +static int cpp_demangle_push_type_qualifier(struct cpp_demangle_data *, + struct vector_type_qualifier *, const char *); +static int cpp_demangle_read_array(struct cpp_demangle_data *); +static int cpp_demangle_read_encoding(struct cpp_demangle_data *); +static int cpp_demangle_read_expr_primary(struct cpp_demangle_data *); +static int cpp_demangle_read_expression(struct cpp_demangle_data *); +static int cpp_demangle_read_expression_flat(struct cpp_demangle_data *, + char **); +static int cpp_demangle_read_expression_binary(struct cpp_demangle_data *, + const char *, size_t); +static int cpp_demangle_read_expression_unary(struct cpp_demangle_data *, + const char *, size_t); +static int cpp_demangle_read_expression_trinary(struct cpp_demangle_data *, + const char *, size_t, const char *, size_t); +static int cpp_demangle_read_function(struct cpp_demangle_data *, int *, + struct vector_type_qualifier *); +static int cpp_demangle_local_source_name(struct cpp_demangle_data *ddata); +static int cpp_demangle_read_local_name(struct cpp_demangle_data *); +static int cpp_demangle_read_name(struct cpp_demangle_data *); +static int cpp_demangle_read_name_flat(struct cpp_demangle_data *, + char**); +static int cpp_demangle_read_nested_name(struct cpp_demangle_data *); +static int cpp_demangle_read_number(struct cpp_demangle_data *, long *); +static int cpp_demangle_read_number_as_string(struct cpp_demangle_data *, + char **); +static int cpp_demangle_read_nv_offset(struct cpp_demangle_data *); +static int cpp_demangle_read_offset(struct cpp_demangle_data *); +static int cpp_demangle_read_offset_number(struct cpp_demangle_data *); +static int cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *, + struct vector_type_qualifier *); +static int cpp_demangle_read_sname(struct cpp_demangle_data *); +static int cpp_demangle_read_subst(struct cpp_demangle_data *); +static int cpp_demangle_read_subst_std(struct cpp_demangle_data *); +static int cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *, + const char *); +static int cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *); +static int cpp_demangle_read_tmpl_args(struct cpp_demangle_data *); +static int cpp_demangle_read_tmpl_param(struct cpp_demangle_data *); +static int cpp_demangle_read_type(struct cpp_demangle_data *, + struct type_delimit *); +static int cpp_demangle_read_type_flat(struct cpp_demangle_data *, + char **); +static int cpp_demangle_read_uqname(struct cpp_demangle_data *); +static int cpp_demangle_read_v_offset(struct cpp_demangle_data *); +static char *decode_fp_to_double(const char *, size_t); +static char *decode_fp_to_float(const char *, size_t); +static char *decode_fp_to_float128(const char *, size_t); +static char *decode_fp_to_float80(const char *, size_t); +static char *decode_fp_to_long_double(const char *, size_t); +static int hex_to_dec(char); +static void vector_read_cmd_dest(struct vector_read_cmd *); +static struct read_cmd_item *vector_read_cmd_find(struct vector_read_cmd *, + enum read_cmd); +static int vector_read_cmd_init(struct vector_read_cmd *); +static int vector_read_cmd_pop(struct vector_read_cmd *); +static int vector_read_cmd_push(struct vector_read_cmd *, enum read_cmd, + void *); +static void vector_type_qualifier_dest(struct vector_type_qualifier *); +static int vector_type_qualifier_init(struct vector_type_qualifier *); +static int vector_type_qualifier_push(struct vector_type_qualifier *, + enum type_qualifier); + +/** + * @brief Decode the input string by IA-64 C++ ABI style. + * + * GNU GCC v3 use IA-64 standard ABI. + * @return New allocated demangled string or NULL if failed. + * @todo 1. Testing and more test case. 2. Code cleaning. + */ +char * +cpp_demangle_gnu3(const char *org) +{ + struct cpp_demangle_data ddata; + struct vector_str ret_type; + struct type_delimit td; + ssize_t org_len; + unsigned int limit; + char *rtn; + bool has_ret, more_type; + + if (org == NULL || (org_len = strlen(org)) < 2) + return (NULL); + + if (org_len > 11 && !strncmp(org, "_GLOBAL__I_", 11)) { + if ((rtn = malloc(org_len + 19)) == NULL) + return (NULL); + snprintf(rtn, org_len + 19, + "global constructors keyed to %s", org + 11); + return (rtn); + } + + if (org[0] != '_' || org[1] != 'Z') + return (NULL); + + if (!cpp_demangle_data_init(&ddata, org + 2)) + return (NULL); + + rtn = NULL; + has_ret = more_type = false; + + if (!cpp_demangle_read_encoding(&ddata)) + goto clean; + + /* + * Pop function name from substitution candidate list. + */ + if (*ddata.cur != 0 && ddata.subst.size >= 1) { + if (!vector_str_pop(&ddata.subst)) + goto clean; + } + + td.paren = false; + td.firstp = true; + limit = 0; + + /* + * The first type is a return type if we just demangled template + * args. (the template args is right next to the function name, + * which means it's a template function) + */ + if (ddata.is_tmpl) { + ddata.is_tmpl = false; + if (!vector_str_init(&ret_type)) + goto clean; + ddata.cur_output = &ret_type; + has_ret = true; + } + + while (*ddata.cur != '\0') { + /* + * Breaking at some gcc info at tail. e.g) @@GLIBCXX_3.4 + */ + if (*ddata.cur == '@' && *(ddata.cur + 1) == '@') + break; + + if (has_ret) { + /* Read return type */ + if (!cpp_demangle_read_type(&ddata, NULL)) + goto clean; + } else { + /* Read function arg type */ + if (!cpp_demangle_read_type(&ddata, &td)) + goto clean; + } + + if (has_ret) { + /* Push return type to the beginning */ + if (!VEC_PUSH_STR(&ret_type, " ")) + goto clean; + if (!vector_str_push_vector_head(&ddata.output, + &ret_type)) + goto clean; + ddata.cur_output = &ddata.output; + vector_str_dest(&ret_type); + has_ret = false; + more_type = true; + } else if (more_type) + more_type = false; + if (limit++ > CPP_DEMANGLE_TRY_LIMIT) + goto clean; + } + if (more_type) + goto clean; + + if (ddata.output.size == 0) + goto clean; + if (td.paren && !VEC_PUSH_STR(&ddata.output, ")")) + goto clean; + if (ddata.mem_vat && !VEC_PUSH_STR(&ddata.output, " volatile")) + goto clean; + if (ddata.mem_cst && !VEC_PUSH_STR(&ddata.output, " const")) + goto clean; + if (ddata.mem_rst && !VEC_PUSH_STR(&ddata.output, " restrict")) + goto clean; + if (ddata.mem_ref && !VEC_PUSH_STR(&ddata.output, " &")) + goto clean; + if (ddata.mem_rref && !VEC_PUSH_STR(&ddata.output, " &&")) + goto clean; + + rtn = vector_str_get_flat(&ddata.output, (size_t *) NULL); + +clean: + if (has_ret) + vector_str_dest(&ret_type); + + cpp_demangle_data_dest(&ddata); + + return (rtn); +} + +static void +cpp_demangle_data_dest(struct cpp_demangle_data *d) +{ + + if (d == NULL) + return; + + vector_read_cmd_dest(&d->cmd); + vector_str_dest(&d->class_type); + vector_str_dest(&d->tmpl); + vector_str_dest(&d->subst); + vector_str_dest(&d->output); +} + +static int +cpp_demangle_data_init(struct cpp_demangle_data *d, const char *cur) +{ + + if (d == NULL || cur == NULL) + return (0); + + if (!vector_str_init(&d->output)) + return (0); + if (!vector_str_init(&d->subst)) + goto clean1; + if (!vector_str_init(&d->tmpl)) + goto clean2; + if (!vector_str_init(&d->class_type)) + goto clean3; + if (!vector_read_cmd_init(&d->cmd)) + goto clean4; + + assert(d->output.container != NULL); + assert(d->subst.container != NULL); + assert(d->tmpl.container != NULL); + assert(d->class_type.container != NULL); + + d->mem_rst = false; + d->mem_vat = false; + d->mem_cst = false; + d->mem_ref = false; + d->mem_rref = false; + d->is_tmpl = false; + d->is_functype = false; + d->ref_qualifier = false; + d->push_qualifier = PUSH_ALL_QUALIFIER; + d->func_type = 0; + d->cur = cur; + d->cur_output = &d->output; + d->last_sname = NULL; + + return (1); + +clean4: + vector_str_dest(&d->class_type); +clean3: + vector_str_dest(&d->tmpl); +clean2: + vector_str_dest(&d->subst); +clean1: + vector_str_dest(&d->output); + + return (0); +} + +static int +cpp_demangle_push_fp(struct cpp_demangle_data *ddata, + char *(*decoder)(const char *, size_t)) +{ + size_t len; + int rtn; + const char *fp; + char *f; + + if (ddata == NULL || decoder == NULL) + return (0); + + fp = ddata->cur; + while (*ddata->cur != 'E') + ++ddata->cur; + + if ((f = decoder(fp, ddata->cur - fp)) == NULL) + return (0); + + rtn = 0; + if ((len = strlen(f)) > 0) + rtn = cpp_demangle_push_str(ddata, f, len); + + free(f); + + ++ddata->cur; + + return (rtn); +} + +static int +cpp_demangle_push_str(struct cpp_demangle_data *ddata, const char *str, + size_t len) +{ + + if (ddata == NULL || str == NULL || len == 0) + return (0); + + /* + * is_tmpl is used to check if the type (function arg) is right next + * to template args, and should always be cleared whenever new string + * pushed. + */ + ddata->is_tmpl = false; + + return (vector_str_push(ddata->cur_output, str, len)); +} + +static int +cpp_demangle_pop_str(struct cpp_demangle_data *ddata) +{ + + if (ddata == NULL) + return (0); + + return (vector_str_pop(ddata->cur_output)); +} + +static int +cpp_demangle_push_subst(struct cpp_demangle_data *ddata, const char *str, + size_t len) +{ + + if (ddata == NULL || str == NULL || len == 0) + return (0); + + if (!vector_str_find(&ddata->subst, str, len)) + return (vector_str_push(&ddata->subst, str, len)); + + return (1); +} + +static int +cpp_demangle_push_subst_v(struct cpp_demangle_data *ddata, struct vector_str *v) +{ + size_t str_len; + int rtn; + char *str; + + if (ddata == NULL || v == NULL) + return (0); + + if ((str = vector_str_get_flat(v, &str_len)) == NULL) + return (0); + + rtn = cpp_demangle_push_subst(ddata, str, str_len); + + free(str); + + return (rtn); +} + +static int +cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata, + struct vector_type_qualifier *v, const char *type_str) +{ + struct vector_str subst_v; + enum type_qualifier t; + size_t idx, e_idx, e_len; + char *buf; + int rtn; + bool cv; + + if (ddata == NULL || v == NULL) + return (0); + + if ((idx = v->size) == 0) + return (1); + + rtn = 0; + if (type_str != NULL) { + if (!vector_str_init(&subst_v)) + return (0); + if (!VEC_PUSH_STR(&subst_v, type_str)) + goto clean; + } + + cv = true; + e_idx = 0; + while (idx > 0) { + switch (v->q_container[idx - 1]) { + case TYPE_PTR: + cv = false; + if (ddata->push_qualifier == PUSH_CV_QUALIFIER) + break; + if (!DEM_PUSH_STR(ddata, "*")) + goto clean; + if (type_str != NULL) { + if (!VEC_PUSH_STR(&subst_v, "*")) + goto clean; + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) + goto clean; + } + break; + + case TYPE_REF: + cv = false; + if (ddata->push_qualifier == PUSH_CV_QUALIFIER) + break; + if (!DEM_PUSH_STR(ddata, "&")) + goto clean; + if (type_str != NULL) { + if (!VEC_PUSH_STR(&subst_v, "&")) + goto clean; + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) + goto clean; + } + break; + + case TYPE_RREF: + cv = false; + if (ddata->push_qualifier == PUSH_CV_QUALIFIER) + break; + if (!DEM_PUSH_STR(ddata, "&&")) + goto clean; + if (type_str != NULL) { + if (!VEC_PUSH_STR(&subst_v, "&&")) + goto clean; + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) + goto clean; + } + break; + + case TYPE_CMX: + cv = false; + if (ddata->push_qualifier == PUSH_CV_QUALIFIER) + break; + if (!DEM_PUSH_STR(ddata, " complex")) + goto clean; + if (type_str != NULL) { + if (!VEC_PUSH_STR(&subst_v, " complex")) + goto clean; + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) + goto clean; + } + break; + + case TYPE_IMG: + cv = false; + if (ddata->push_qualifier == PUSH_CV_QUALIFIER) + break; + if (!DEM_PUSH_STR(ddata, " imaginary")) + goto clean; + if (type_str != NULL) { + if (!VEC_PUSH_STR(&subst_v, " imaginary")) + goto clean; + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) + goto clean; + } + break; + + case TYPE_EXT: + cv = false; + if (ddata->push_qualifier == PUSH_CV_QUALIFIER) + break; + if (v->ext_name.size == 0 || + e_idx > v->ext_name.size - 1) + goto clean; + if ((e_len = strlen(v->ext_name.container[e_idx])) == + 0) + goto clean; + if ((buf = malloc(e_len + 2)) == NULL) + goto clean; + snprintf(buf, e_len + 2, " %s", + v->ext_name.container[e_idx]); + + if (!DEM_PUSH_STR(ddata, buf)) { + free(buf); + goto clean; + } + + if (type_str != NULL) { + if (!VEC_PUSH_STR(&subst_v, buf)) { + free(buf); + goto clean; + } + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) { + free(buf); + goto clean; + } + } + free(buf); + ++e_idx; + break; + + case TYPE_RST: + if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER && + cv) + break; + if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv) + break; + if (!DEM_PUSH_STR(ddata, " restrict")) + goto clean; + if (type_str != NULL) { + if (!VEC_PUSH_STR(&subst_v, " restrict")) + goto clean; + if (idx - 1 > 0) { + t = v->q_container[idx - 2]; + if (t == TYPE_RST || t == TYPE_VAT || + t == TYPE_CST) + break; + } + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) + goto clean; + } + break; + + case TYPE_VAT: + if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER && + cv) + break; + if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv) + break; + if (!DEM_PUSH_STR(ddata, " volatile")) + goto clean; + if (type_str != NULL) { + if (!VEC_PUSH_STR(&subst_v, " volatile")) + goto clean; + if (idx - 1 > 0) { + t = v->q_container[idx - 2]; + if (t == TYPE_RST || t == TYPE_VAT || + t == TYPE_CST) + break; + } + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) + goto clean; + } + break; + + case TYPE_CST: + if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER && + cv) + break; + if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv) + break; + if (!DEM_PUSH_STR(ddata, " const")) + goto clean; + if (type_str != NULL) { + if (!VEC_PUSH_STR(&subst_v, " const")) + goto clean; + if (idx - 1 > 0) { + t = v->q_container[idx - 2]; + if (t == TYPE_RST || t == TYPE_VAT || + t == TYPE_CST) + break; + } + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) + goto clean; + } + break; + + case TYPE_VEC: + cv = false; + if (ddata->push_qualifier == PUSH_CV_QUALIFIER) + break; + if (v->ext_name.size == 0 || + e_idx > v->ext_name.size - 1) + goto clean; + if ((e_len = strlen(v->ext_name.container[e_idx])) == + 0) + goto clean; + if ((buf = malloc(e_len + 12)) == NULL) + goto clean; + snprintf(buf, e_len + 12, " __vector(%s)", + v->ext_name.container[e_idx]); + if (!DEM_PUSH_STR(ddata, buf)) { + free(buf); + goto clean; + } + if (type_str != NULL) { + if (!VEC_PUSH_STR(&subst_v, buf)) { + free(buf); + goto clean; + } + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) { + free(buf); + goto clean; + } + } + free(buf); + ++e_idx; + break; + } + --idx; + } + + rtn = 1; +clean: + if (type_str != NULL) + vector_str_dest(&subst_v); + + return (rtn); +} + +static int +cpp_demangle_get_subst(struct cpp_demangle_data *ddata, size_t idx) +{ + size_t len; + + if (ddata == NULL || ddata->subst.size <= idx) + return (0); + if ((len = strlen(ddata->subst.container[idx])) == 0) + return (0); + if (!cpp_demangle_push_str(ddata, ddata->subst.container[idx], len)) + return (0); + + /* skip '_' */ + ++ddata->cur; + + return (1); +} + +static int +cpp_demangle_get_tmpl_param(struct cpp_demangle_data *ddata, size_t idx) +{ + size_t len; + + if (ddata == NULL || ddata->tmpl.size <= idx) + return (0); + if ((len = strlen(ddata->tmpl.container[idx])) == 0) + return (0); + if (!cpp_demangle_push_str(ddata, ddata->tmpl.container[idx], len)) + return (0); + + ++ddata->cur; + + return (1); +} + +static int +cpp_demangle_read_array(struct cpp_demangle_data *ddata) +{ + size_t i, num_len, exp_len, p_idx, idx; + const char *num; + char *exp; + + if (ddata == NULL || *(++ddata->cur) == '\0') + return (0); + + if (*ddata->cur == '_') { + if (*(++ddata->cur) == '\0') + return (0); + + if (!cpp_demangle_read_type(ddata, NULL)) + return (0); + + if (!DEM_PUSH_STR(ddata, "[]")) + return (0); + } else { + if (ELFTC_ISDIGIT(*ddata->cur) != 0) { + num = ddata->cur; + while (ELFTC_ISDIGIT(*ddata->cur) != 0) + ++ddata->cur; + if (*ddata->cur != '_') + return (0); + num_len = ddata->cur - num; + assert(num_len > 0); + if (*(++ddata->cur) == '\0') + return (0); + if (!cpp_demangle_read_type(ddata, NULL)) + return (0); + if (!DEM_PUSH_STR(ddata, "[")) + return (0); + if (!cpp_demangle_push_str(ddata, num, num_len)) + return (0); + if (!DEM_PUSH_STR(ddata, "]")) + return (0); + } else { + p_idx = ddata->output.size; + if (!cpp_demangle_read_expression(ddata)) + return (0); + if ((exp = vector_str_substr(&ddata->output, p_idx, + ddata->output.size - 1, &exp_len)) == NULL) + return (0); + idx = ddata->output.size; + for (i = p_idx; i < idx; ++i) + if (!vector_str_pop(&ddata->output)) { + free(exp); + return (0); + } + if (*ddata->cur != '_') { + free(exp); + return (0); + } + ++ddata->cur; + if (*ddata->cur == '\0') { + free(exp); + return (0); + } + if (!cpp_demangle_read_type(ddata, NULL)) { + free(exp); + return (0); + } + if (!DEM_PUSH_STR(ddata, "[")) { + free(exp); + return (0); + } + if (!cpp_demangle_push_str(ddata, exp, exp_len)) { + free(exp); + return (0); + } + if (!DEM_PUSH_STR(ddata, "]")) { + free(exp); + return (0); + } + free(exp); + } + } + + return (1); +} + +static int +cpp_demangle_read_expr_primary(struct cpp_demangle_data *ddata) +{ + const char *num; + + if (ddata == NULL || *(++ddata->cur) == '\0') + return (0); + + if (*ddata->cur == '_' && *(ddata->cur + 1) == 'Z') { + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + if (!cpp_demangle_read_encoding(ddata)) + return (0); + ++ddata->cur; + return (1); + } + + switch (*ddata->cur) { + case 'b': + if (*(ddata->cur + 2) != 'E') + return (0); + switch (*(++ddata->cur)) { + case '0': + ddata->cur += 2; + return (DEM_PUSH_STR(ddata, "false")); + case '1': + ddata->cur += 2; + return (DEM_PUSH_STR(ddata, "true")); + default: + return (0); + } + + case 'd': + ++ddata->cur; + return (cpp_demangle_push_fp(ddata, decode_fp_to_double)); + + case 'e': + ++ddata->cur; + if (sizeof(long double) == 10) + return (cpp_demangle_push_fp(ddata, + decode_fp_to_double)); + return (cpp_demangle_push_fp(ddata, decode_fp_to_float80)); + + case 'f': + ++ddata->cur; + return (cpp_demangle_push_fp(ddata, decode_fp_to_float)); + + case 'g': + ++ddata->cur; + if (sizeof(long double) == 16) + return (cpp_demangle_push_fp(ddata, + decode_fp_to_double)); + return (cpp_demangle_push_fp(ddata, decode_fp_to_float128)); + + case 'i': + case 'j': + case 'l': + case 'm': + case 'n': + case 's': + case 't': + case 'x': + case 'y': + if (*(++ddata->cur) == 'n') { + if (!DEM_PUSH_STR(ddata, "-")) + return (0); + ++ddata->cur; + } + num = ddata->cur; + while (*ddata->cur != 'E') { + if (!ELFTC_ISDIGIT(*ddata->cur)) + return (0); + ++ddata->cur; + } + ++ddata->cur; + return (cpp_demangle_push_str(ddata, num, + ddata->cur - num - 1)); + + default: + return (0); + } +} + +static int +cpp_demangle_read_expression(struct cpp_demangle_data *ddata) +{ + + if (ddata == NULL || *ddata->cur == '\0') + return (0); + + switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { + case SIMPLE_HASH('s', 't'): + ddata->cur += 2; + return (cpp_demangle_read_type(ddata, NULL)); + + case SIMPLE_HASH('s', 'r'): + ddata->cur += 2; + if (!cpp_demangle_read_type(ddata, NULL)) + return (0); + if (!cpp_demangle_read_uqname(ddata)) + return (0); + if (*ddata->cur == 'I') + return (cpp_demangle_read_tmpl_args(ddata)); + return (1); + + case SIMPLE_HASH('a', 'a'): + /* operator && */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "&&", 2)); + + case SIMPLE_HASH('a', 'd'): + /* operator & (unary) */ + ddata->cur += 2; + return (cpp_demangle_read_expression_unary(ddata, "&", 1)); + + case SIMPLE_HASH('a', 'n'): + /* operator & */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "&", 1)); + + case SIMPLE_HASH('a', 'N'): + /* operator &= */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "&=", 2)); + + case SIMPLE_HASH('a', 'S'): + /* operator = */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "=", 1)); + + case SIMPLE_HASH('c', 'l'): + /* operator () */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "()", 2)); + + case SIMPLE_HASH('c', 'm'): + /* operator , */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, ",", 1)); + + case SIMPLE_HASH('c', 'o'): + /* operator ~ */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "~", 1)); + + case SIMPLE_HASH('c', 'v'): + /* operator (cast) */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "(cast)", 6)); + + case SIMPLE_HASH('d', 'a'): + /* operator delete [] */ + ddata->cur += 2; + return (cpp_demangle_read_expression_unary(ddata, "delete []", 9)); + + case SIMPLE_HASH('d', 'e'): + /* operator * (unary) */ + ddata->cur += 2; + return (cpp_demangle_read_expression_unary(ddata, "*", 1)); + + case SIMPLE_HASH('d', 'l'): + /* operator delete */ + ddata->cur += 2; + return (cpp_demangle_read_expression_unary(ddata, "delete", 6)); + + case SIMPLE_HASH('d', 'v'): + /* operator / */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "/", 1)); + + case SIMPLE_HASH('d', 'V'): + /* operator /= */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "/=", 2)); + + case SIMPLE_HASH('e', 'o'): + /* operator ^ */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "^", 1)); + + case SIMPLE_HASH('e', 'O'): + /* operator ^= */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "^=", 2)); + + case SIMPLE_HASH('e', 'q'): + /* operator == */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "==", 2)); + + case SIMPLE_HASH('g', 'e'): + /* operator >= */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, ">=", 2)); + + case SIMPLE_HASH('g', 't'): + /* operator > */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, ">", 1)); + + case SIMPLE_HASH('i', 'x'): + /* operator [] */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "[]", 2)); + + case SIMPLE_HASH('l', 'e'): + /* operator <= */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "<=", 2)); + + case SIMPLE_HASH('l', 's'): + /* operator << */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "<<", 2)); + + case SIMPLE_HASH('l', 'S'): + /* operator <<= */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "<<=", 3)); + + case SIMPLE_HASH('l', 't'): + /* operator < */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "<", 1)); + + case SIMPLE_HASH('m', 'i'): + /* operator - */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "-", 1)); + + case SIMPLE_HASH('m', 'I'): + /* operator -= */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "-=", 2)); + + case SIMPLE_HASH('m', 'l'): + /* operator * */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "*", 1)); + + case SIMPLE_HASH('m', 'L'): + /* operator *= */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "*=", 2)); + + case SIMPLE_HASH('m', 'm'): + /* operator -- */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "--", 2)); + + case SIMPLE_HASH('n', 'a'): + /* operator new[] */ + ddata->cur += 2; + return (cpp_demangle_read_expression_unary(ddata, "new []", 6)); + + case SIMPLE_HASH('n', 'e'): + /* operator != */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "!=", 2)); + + case SIMPLE_HASH('n', 'g'): + /* operator - (unary) */ + ddata->cur += 2; + return (cpp_demangle_read_expression_unary(ddata, "-", 1)); + + case SIMPLE_HASH('n', 't'): + /* operator ! */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "!", 1)); + + case SIMPLE_HASH('n', 'w'): + /* operator new */ + ddata->cur += 2; + return (cpp_demangle_read_expression_unary(ddata, "new", 3)); + + case SIMPLE_HASH('o', 'o'): + /* operator || */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "||", 2)); + + case SIMPLE_HASH('o', 'r'): + /* operator | */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "|", 1)); + + case SIMPLE_HASH('o', 'R'): + /* operator |= */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "|=", 2)); + + case SIMPLE_HASH('p', 'l'): + /* operator + */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "+", 1)); + + case SIMPLE_HASH('p', 'L'): + /* operator += */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "+=", 2)); + + case SIMPLE_HASH('p', 'm'): + /* operator ->* */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "->*", 3)); + + case SIMPLE_HASH('p', 'p'): + /* operator ++ */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "++", 2)); + + case SIMPLE_HASH('p', 's'): + /* operator + (unary) */ + ddata->cur += 2; + return (cpp_demangle_read_expression_unary(ddata, "+", 1)); + + case SIMPLE_HASH('p', 't'): + /* operator -> */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "->", 2)); + + case SIMPLE_HASH('q', 'u'): + /* operator ? */ + ddata->cur += 2; + return (cpp_demangle_read_expression_trinary(ddata, "?", 1, + ":", 1)); + + case SIMPLE_HASH('r', 'm'): + /* operator % */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "%", 1)); + + case SIMPLE_HASH('r', 'M'): + /* operator %= */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, "%=", 2)); + + case SIMPLE_HASH('r', 's'): + /* operator >> */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, ">>", 2)); + + case SIMPLE_HASH('r', 'S'): + /* operator >>= */ + ddata->cur += 2; + return (cpp_demangle_read_expression_binary(ddata, ">>=", 3)); + + case SIMPLE_HASH('r', 'z'): + /* operator sizeof */ + ddata->cur += 2; + return (cpp_demangle_read_expression_unary(ddata, "sizeof", 6)); + + case SIMPLE_HASH('s', 'v'): + /* operator sizeof */ + ddata->cur += 2; + return (cpp_demangle_read_expression_unary(ddata, "sizeof", 6)); + } + + switch (*ddata->cur) { + case 'L': + return (cpp_demangle_read_expr_primary(ddata)); + case 'T': + return (cpp_demangle_read_tmpl_param(ddata)); + } + + return (0); +} + +static int +cpp_demangle_read_expression_flat(struct cpp_demangle_data *ddata, char **str) +{ + struct vector_str *output; + size_t i, p_idx, idx, exp_len; + char *exp; + + output = &ddata->output; + + p_idx = output->size; + + if (!cpp_demangle_read_expression(ddata)) + return (0); + + if ((exp = vector_str_substr(output, p_idx, output->size - 1, + &exp_len)) == NULL) + return (0); + + idx = output->size; + for (i = p_idx; i < idx; ++i) { + if (!vector_str_pop(output)) { + free(exp); + return (0); + } + } + + *str = exp; + + return (1); +} + +static int +cpp_demangle_read_expression_binary(struct cpp_demangle_data *ddata, + const char *name, size_t len) +{ + + if (ddata == NULL || name == NULL || len == 0) + return (0); + if (!cpp_demangle_read_expression(ddata)) + return (0); + if (!cpp_demangle_push_str(ddata, name, len)) + return (0); + + return (cpp_demangle_read_expression(ddata)); +} + +static int +cpp_demangle_read_expression_unary(struct cpp_demangle_data *ddata, + const char *name, size_t len) +{ + + if (ddata == NULL || name == NULL || len == 0) + return (0); + if (!cpp_demangle_read_expression(ddata)) + return (0); + + return (cpp_demangle_push_str(ddata, name, len)); +} + +static int +cpp_demangle_read_expression_trinary(struct cpp_demangle_data *ddata, + const char *name1, size_t len1, const char *name2, size_t len2) +{ + + if (ddata == NULL || name1 == NULL || len1 == 0 || name2 == NULL || + len2 == 0) + return (0); + + if (!cpp_demangle_read_expression(ddata)) + return (0); + if (!cpp_demangle_push_str(ddata, name1, len1)) + return (0); + if (!cpp_demangle_read_expression(ddata)) + return (0); + if (!cpp_demangle_push_str(ddata, name2, len2)) + return (0); + + return (cpp_demangle_read_expression(ddata)); +} + +static int +cpp_demangle_read_function(struct cpp_demangle_data *ddata, int *ext_c, + struct vector_type_qualifier *v) +{ + struct type_delimit td; + struct read_cmd_item *rc; + size_t class_type_size, class_type_len, limit; + const char *class_type; + int i; + bool paren, non_cv_qualifier; + + if (ddata == NULL || *ddata->cur != 'F' || v == NULL) + return (0); + + ++ddata->cur; + if (*ddata->cur == 'Y') { + if (ext_c != NULL) + *ext_c = 1; + ++ddata->cur; + } + + /* Return type */ + if (!cpp_demangle_read_type(ddata, NULL)) + return (0); + + if (*ddata->cur != 'E') { + if (!DEM_PUSH_STR(ddata, " ")) + return (0); + + non_cv_qualifier = false; + if (v->size > 0) { + for (i = 0; (size_t) i < v->size; i++) { + if (v->q_container[i] != TYPE_RST && + v->q_container[i] != TYPE_VAT && + v->q_container[i] != TYPE_CST) { + non_cv_qualifier = true; + break; + } + } + } + + paren = false; + rc = vector_read_cmd_find(&ddata->cmd, READ_PTRMEM); + if (non_cv_qualifier || rc != NULL) { + if (!DEM_PUSH_STR(ddata, "(")) + return (0); + paren = true; + } + + /* Push non-cv qualifiers. */ + ddata->push_qualifier = PUSH_NON_CV_QUALIFIER; + if (!cpp_demangle_push_type_qualifier(ddata, v, NULL)) + return (0); + + if (rc) { + if (non_cv_qualifier && !DEM_PUSH_STR(ddata, " ")) + return (0); + if ((class_type_size = ddata->class_type.size) == 0) + return (0); + class_type = + ddata->class_type.container[class_type_size - 1]; + if (class_type == NULL) + return (0); + if ((class_type_len = strlen(class_type)) == 0) + return (0); + if (!cpp_demangle_push_str(ddata, class_type, + class_type_len)) + return (0); + if (!DEM_PUSH_STR(ddata, "::*")) + return (0); + /* Push pointer-to-member qualifiers. */ + ddata->push_qualifier = PUSH_ALL_QUALIFIER; + if (!cpp_demangle_push_type_qualifier(ddata, rc->data, + NULL)) + return (0); + ++ddata->func_type; + } + + if (paren) { + if (!DEM_PUSH_STR(ddata, ")")) + return (0); + paren = false; + } + + td.paren = false; + td.firstp = true; + limit = 0; + ddata->is_functype = true; + for (;;) { + if (!cpp_demangle_read_type(ddata, &td)) + return (0); + if (*ddata->cur == 'E') + break; + if (limit++ > CPP_DEMANGLE_TRY_LIMIT) + return (0); + } + ddata->is_functype = false; + if (td.paren) { + if (!DEM_PUSH_STR(ddata, ")")) + return (0); + td.paren = false; + } + + /* Push CV qualifiers. */ + ddata->push_qualifier = PUSH_CV_QUALIFIER; + if (!cpp_demangle_push_type_qualifier(ddata, v, NULL)) + return (0); + + ddata->push_qualifier = PUSH_ALL_QUALIFIER; + + /* Release type qualifier vector. */ + vector_type_qualifier_dest(v); + if (!vector_type_qualifier_init(v)) + return (0); + + /* Push ref-qualifiers. */ + if (ddata->ref_qualifier) { + switch (ddata->ref_qualifier_type) { + case TYPE_REF: + if (!DEM_PUSH_STR(ddata, " &")) + return (0); + break; + case TYPE_RREF: + if (!DEM_PUSH_STR(ddata, " &&")) + return (0); + break; + default: + return (0); + } + ddata->ref_qualifier = false; + } + } + + ++ddata->cur; + + return (1); +} + +/* read encoding, encoding are function name, data name, special-name */ +static int +cpp_demangle_read_encoding(struct cpp_demangle_data *ddata) +{ + char *name, *type, *num_str; + long offset; + int rtn; + + if (ddata == NULL || *ddata->cur == '\0') + return (0); + + /* special name */ + switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { + case SIMPLE_HASH('G', 'A'): + if (!DEM_PUSH_STR(ddata, "hidden alias for ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_encoding(ddata)); + + case SIMPLE_HASH('G', 'R'): + if (!DEM_PUSH_STR(ddata, "reference temporary #")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + if (!cpp_demangle_read_name_flat(ddata, &name)) + return (0); + rtn = 0; + if (!cpp_demangle_read_number_as_string(ddata, &num_str)) + goto clean1; + if (!DEM_PUSH_STR(ddata, num_str)) + goto clean2; + if (!DEM_PUSH_STR(ddata, " for ")) + goto clean2; + if (!DEM_PUSH_STR(ddata, name)) + goto clean2; + rtn = 1; + clean2: + free(num_str); + clean1: + free(name); + return (rtn); + + case SIMPLE_HASH('G', 'T'): + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + switch (*ddata->cur) { + case 'n': + if (!DEM_PUSH_STR(ddata, "non-transaction clone for ")) + return (0); + break; + case 't': + default: + if (!DEM_PUSH_STR(ddata, "transaction clone for ")) + return (0); + break; + } + ++ddata->cur; + return (cpp_demangle_read_encoding(ddata)); + + case SIMPLE_HASH('G', 'V'): + /* sentry object for 1 time init */ + if (!DEM_PUSH_STR(ddata, "guard variable for ")) + return (0); + ddata->cur += 2; + break; + + case SIMPLE_HASH('T', 'c'): + /* virtual function covariant override thunk */ + if (!DEM_PUSH_STR(ddata, + "virtual function covariant override ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + if (!cpp_demangle_read_offset(ddata)) + return (0); + if (!cpp_demangle_read_offset(ddata)) + return (0); + return (cpp_demangle_read_encoding(ddata)); + + case SIMPLE_HASH('T', 'C'): + /* construction vtable */ + if (!DEM_PUSH_STR(ddata, "construction vtable for ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + if (!cpp_demangle_read_type_flat(ddata, &type)) + return (0); + rtn = 0; + if (!cpp_demangle_read_number(ddata, &offset)) + goto clean3; + if (*ddata->cur++ != '_') + goto clean3; + if (!cpp_demangle_read_type(ddata, NULL)) + goto clean3; + if (!DEM_PUSH_STR(ddata, "-in-")) + goto clean3; + if (!DEM_PUSH_STR(ddata, type)) + goto clean3; + rtn = 1; + clean3: + free(type); + return (rtn); + + case SIMPLE_HASH('T', 'D'): + /* typeinfo common proxy */ + break; + + case SIMPLE_HASH('T', 'F'): + /* typeinfo fn */ + if (!DEM_PUSH_STR(ddata, "typeinfo fn for ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_type(ddata, NULL)); + + case SIMPLE_HASH('T', 'h'): + /* virtual function non-virtual override thunk */ + if (!DEM_PUSH_STR(ddata, + "virtual function non-virtual override ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + if (!cpp_demangle_read_nv_offset(ddata)) + return (0); + return (cpp_demangle_read_encoding(ddata)); + + case SIMPLE_HASH('T', 'H'): + /* TLS init function */ + if (!DEM_PUSH_STR(ddata, "TLS init function for ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + break; + + case SIMPLE_HASH('T', 'I'): + /* typeinfo structure */ + if (!DEM_PUSH_STR(ddata, "typeinfo for ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_type(ddata, NULL)); + + case SIMPLE_HASH('T', 'J'): + /* java class */ + if (!DEM_PUSH_STR(ddata, "java Class for ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_type(ddata, NULL)); + + case SIMPLE_HASH('T', 'S'): + /* RTTI name (NTBS) */ + if (!DEM_PUSH_STR(ddata, "typeinfo name for ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_type(ddata, NULL)); + + case SIMPLE_HASH('T', 'T'): + /* VTT table */ + if (!DEM_PUSH_STR(ddata, "VTT for ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_type(ddata, NULL)); + + case SIMPLE_HASH('T', 'v'): + /* virtual function virtual override thunk */ + if (!DEM_PUSH_STR(ddata, "virtual function virtual override ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + if (!cpp_demangle_read_v_offset(ddata)) + return (0); + return (cpp_demangle_read_encoding(ddata)); + + case SIMPLE_HASH('T', 'V'): + /* virtual table */ + if (!DEM_PUSH_STR(ddata, "vtable for ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_type(ddata, NULL)); + + case SIMPLE_HASH('T', 'W'): + /* TLS wrapper function */ + if (!DEM_PUSH_STR(ddata, "TLS wrapper function for ")) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + break; + } + + return (cpp_demangle_read_name(ddata)); +} + +static int +cpp_demangle_read_local_name(struct cpp_demangle_data *ddata) +{ + struct vector_str local_name; + struct type_delimit td; + size_t limit; + bool more_type; + + if (ddata == NULL) + return (0); + if (*(++ddata->cur) == '\0') + return (0); + + vector_str_init(&local_name); + ddata->cur_output = &local_name; + + if (!cpp_demangle_read_encoding(ddata)) { + vector_str_dest(&local_name); + return (0); + } + + ddata->cur_output = &ddata->output; + + td.paren = false; + td.firstp = true; + more_type = false; + limit = 0; + + /* + * The first type is a return type if we just demangled template + * args. (the template args is right next to the function name, + * which means it's a template function) + */ + if (ddata->is_tmpl) { + ddata->is_tmpl = false; + + /* Read return type */ + if (!cpp_demangle_read_type(ddata, NULL)) { + vector_str_dest(&local_name); + return (0); + } + + more_type = true; + } + + /* Now we can push the name after possible return type is handled. */ + if (!vector_str_push_vector(&ddata->output, &local_name)) { + vector_str_dest(&local_name); + return (0); + } + vector_str_dest(&local_name); + + while (*ddata->cur != '\0') { + if (!cpp_demangle_read_type(ddata, &td)) + return (0); + if (more_type) + more_type = false; + if (*ddata->cur == 'E') + break; + if (limit++ > CPP_DEMANGLE_TRY_LIMIT) + return (0); + } + if (more_type) + return (0); + + if (*(++ddata->cur) == '\0') + return (0); + if (td.paren == true) { + if (!DEM_PUSH_STR(ddata, ")")) + return (0); + td.paren = false; + } + if (*ddata->cur == 's') + ++ddata->cur; + else { + if (!DEM_PUSH_STR(ddata, "::")) + return (0); + if (!cpp_demangle_read_name(ddata)) + return (0); + } + if (*ddata->cur == '_') { + ++ddata->cur; + while (ELFTC_ISDIGIT(*ddata->cur) != 0) + ++ddata->cur; + } + + return (1); +} + +static int +cpp_demangle_read_name(struct cpp_demangle_data *ddata) +{ + struct vector_str *output, v; + size_t p_idx, subst_str_len; + int rtn; + char *subst_str; + + if (ddata == NULL || *ddata->cur == '\0') + return (0); + + output = ddata->cur_output; + + subst_str = NULL; + + switch (*ddata->cur) { + case 'S': + return (cpp_demangle_read_subst(ddata)); + case 'N': + return (cpp_demangle_read_nested_name(ddata)); + case 'Z': + return (cpp_demangle_read_local_name(ddata)); + } + + if (!vector_str_init(&v)) + return (0); + + p_idx = output->size; + rtn = 0; + if (!cpp_demangle_read_uqname(ddata)) + goto clean; + if ((subst_str = vector_str_substr(output, p_idx, output->size - 1, + &subst_str_len)) == NULL) + goto clean; + if (subst_str_len > 8 && strstr(subst_str, "operator") != NULL) { + rtn = 1; + goto clean; + } + if (!vector_str_push(&v, subst_str, subst_str_len)) + goto clean; + if (!cpp_demangle_push_subst_v(ddata, &v)) + goto clean; + + if (*ddata->cur == 'I') { + p_idx = output->size; + if (!cpp_demangle_read_tmpl_args(ddata)) + goto clean; + free(subst_str); + if ((subst_str = vector_str_substr(output, p_idx, + output->size - 1, &subst_str_len)) == NULL) + goto clean; + if (!vector_str_push(&v, subst_str, subst_str_len)) + goto clean; + if (!cpp_demangle_push_subst_v(ddata, &v)) + goto clean; + } + + rtn = 1; + +clean: + free(subst_str); + vector_str_dest(&v); + + return (rtn); +} + +static int +cpp_demangle_read_name_flat(struct cpp_demangle_data *ddata, char **str) +{ + struct vector_str *output; + size_t i, p_idx, idx, name_len; + char *name; + + output = ddata->cur_output; + + p_idx = output->size; + + if (!cpp_demangle_read_name(ddata)) + return (0); + + if ((name = vector_str_substr(output, p_idx, output->size - 1, + &name_len)) == NULL) + return (0); + + idx = output->size; + for (i = p_idx; i < idx; ++i) { + if (!vector_str_pop(output)) { + free(name); + return (0); + } + } + + *str = name; + + return (1); +} + +static int +cpp_demangle_read_nested_name(struct cpp_demangle_data *ddata) +{ + struct vector_str *output, v; + size_t limit, p_idx, subst_str_len; + int rtn; + char *subst_str; + + if (ddata == NULL || *ddata->cur != 'N') + return (0); + if (*(++ddata->cur) == '\0') + return (0); + + do { + switch (*ddata->cur) { + case 'r': + ddata->mem_rst = true; + break; + case 'V': + ddata->mem_vat = true; + break; + case 'K': + ddata->mem_cst = true; + break; + case 'R': + ddata->mem_ref = true; + break; + case 'O': + ddata->mem_rref = true; + break; + default: + goto next; + } + } while (*(++ddata->cur)); + +next: + output = ddata->cur_output; + if (!vector_str_init(&v)) + return (0); + + rtn = 0; + limit = 0; + for (;;) { + p_idx = output->size; + switch (*ddata->cur) { + case 'I': + if (!cpp_demangle_read_tmpl_args(ddata)) + goto clean; + break; + case 'S': + if (!cpp_demangle_read_subst(ddata)) + goto clean; + break; + case 'T': + if (!cpp_demangle_read_tmpl_param(ddata)) + goto clean; + break; + default: + if (!cpp_demangle_read_uqname(ddata)) + goto clean; + } + + if (p_idx == output->size) + goto next_comp; + if ((subst_str = vector_str_substr(output, p_idx, + output->size - 1, &subst_str_len)) == NULL) + goto clean; + if (!vector_str_push(&v, subst_str, subst_str_len)) { + free(subst_str); + goto clean; + } + free(subst_str); + + if (!cpp_demangle_push_subst_v(ddata, &v)) + goto clean; + + next_comp: + if (*ddata->cur == 'E') + break; + else if (*ddata->cur != 'I' && *ddata->cur != 'C' && + *ddata->cur != 'D' && p_idx != output->size) { + if (!DEM_PUSH_STR(ddata, "::")) + goto clean; + if (!VEC_PUSH_STR(&v, "::")) + goto clean; + } + if (limit++ > CPP_DEMANGLE_TRY_LIMIT) + goto clean; + } + + ++ddata->cur; + rtn = 1; + +clean: + vector_str_dest(&v); + + return (rtn); +} + +/* + * read number + * number ::= [n] + */ +static int +cpp_demangle_read_number(struct cpp_demangle_data *ddata, long *rtn) +{ + long len, negative_factor; + + if (ddata == NULL || rtn == NULL) + return (0); + + negative_factor = 1; + if (*ddata->cur == 'n') { + negative_factor = -1; + + ++ddata->cur; + } + if (ELFTC_ISDIGIT(*ddata->cur) == 0) + return (0); + + errno = 0; + if ((len = strtol(ddata->cur, (char **) NULL, 10)) == 0 && + errno != 0) + return (0); + + while (ELFTC_ISDIGIT(*ddata->cur) != 0) + ++ddata->cur; + + assert(len >= 0); + assert(negative_factor == 1 || negative_factor == -1); + + *rtn = len * negative_factor; + + return (1); +} + +static int +cpp_demangle_read_number_as_string(struct cpp_demangle_data *ddata, char **str) +{ + long n; + + if (!cpp_demangle_read_number(ddata, &n)) { + *str = NULL; + return (0); + } + + if (asprintf(str, "%ld", n) < 0) { + *str = NULL; + return (0); + } + + return (1); +} + +static int +cpp_demangle_read_nv_offset(struct cpp_demangle_data *ddata) +{ + + if (ddata == NULL) + return (0); + + if (!DEM_PUSH_STR(ddata, "offset : ")) + return (0); + + return (cpp_demangle_read_offset_number(ddata)); +} + +/* read offset, offset are nv-offset, v-offset */ +static int +cpp_demangle_read_offset(struct cpp_demangle_data *ddata) +{ + + if (ddata == NULL) + return (0); + + if (*ddata->cur == 'h') { + ++ddata->cur; + return (cpp_demangle_read_nv_offset(ddata)); + } else if (*ddata->cur == 'v') { + ++ddata->cur; + return (cpp_demangle_read_v_offset(ddata)); + } + + return (0); +} + +static int +cpp_demangle_read_offset_number(struct cpp_demangle_data *ddata) +{ + bool negative; + const char *start; + + if (ddata == NULL || *ddata->cur == '\0') + return (0); + + /* offset could be negative */ + if (*ddata->cur == 'n') { + negative = true; + start = ddata->cur + 1; + } else { + negative = false; + start = ddata->cur; + } + + while (*ddata->cur != '_') + ++ddata->cur; + + if (negative && !DEM_PUSH_STR(ddata, "-")) + return (0); + + assert(start != NULL); + + if (!cpp_demangle_push_str(ddata, start, ddata->cur - start)) + return (0); + if (!DEM_PUSH_STR(ddata, " ")) + return (0); + + ++ddata->cur; + + return (1); +} + +static int +cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata, + struct vector_type_qualifier *v) +{ + size_t class_type_len, i, idx, p_idx; + int p_func_type, rtn; + char *class_type; + + if (ddata == NULL || *ddata->cur != 'M' || *(++ddata->cur) == '\0') + return (0); + + p_idx = ddata->output.size; + if (!cpp_demangle_read_type(ddata, NULL)) + return (0); + + if ((class_type = vector_str_substr(&ddata->output, p_idx, + ddata->output.size - 1, &class_type_len)) == NULL) + return (0); + + rtn = 0; + idx = ddata->output.size; + for (i = p_idx; i < idx; ++i) + if (!vector_str_pop(&ddata->output)) + goto clean1; + + if (!vector_read_cmd_push(&ddata->cmd, READ_PTRMEM, v)) + goto clean1; + + if (!vector_str_push(&ddata->class_type, class_type, class_type_len)) + goto clean2; + + p_func_type = ddata->func_type; + if (!cpp_demangle_read_type(ddata, NULL)) + goto clean3; + + if (p_func_type == ddata->func_type) { + if (!DEM_PUSH_STR(ddata, " ")) + goto clean3; + if (!cpp_demangle_push_str(ddata, class_type, class_type_len)) + goto clean3; + if (!DEM_PUSH_STR(ddata, "::*")) + goto clean3; + } + + rtn = 1; +clean3: + if (!vector_str_pop(&ddata->class_type)) + rtn = 0; +clean2: + if (!vector_read_cmd_pop(&ddata->cmd)) + rtn = 0; +clean1: + free(class_type); + + vector_type_qualifier_dest(v); + if (!vector_type_qualifier_init(v)) + return (0); + + return (rtn); +} + +/* read source-name, source-name is */ +static int +cpp_demangle_read_sname(struct cpp_demangle_data *ddata) +{ + long len; + int err; + + if (ddata == NULL || cpp_demangle_read_number(ddata, &len) == 0 || + len <= 0) + return (0); + + if (len == 12 && (memcmp("_GLOBAL__N_1", ddata->cur, 12) == 0)) + err = DEM_PUSH_STR(ddata, "(anonymous namespace)"); + else + err = cpp_demangle_push_str(ddata, ddata->cur, len); + + if (err == 0) + return (0); + + assert(ddata->output.size > 0); + if (vector_read_cmd_find(&ddata->cmd, READ_TMPL) == NULL) + ddata->last_sname = + ddata->output.container[ddata->output.size - 1]; + + ddata->cur += len; + + return (1); +} + +static int +cpp_demangle_read_subst(struct cpp_demangle_data *ddata) +{ + long nth; + + if (ddata == NULL || *ddata->cur == '\0') + return (0); + + /* abbreviations of the form Sx */ + switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { + case SIMPLE_HASH('S', 'a'): + /* std::allocator */ + if (!DEM_PUSH_STR(ddata, "std::allocator")) + return (0); + ddata->cur += 2; + if (*ddata->cur == 'I') + return (cpp_demangle_read_subst_stdtmpl(ddata, + "std::allocator")); + return (1); + + case SIMPLE_HASH('S', 'b'): + /* std::basic_string */ + if (!DEM_PUSH_STR(ddata, "std::basic_string")) + return (0); + ddata->cur += 2; + if (*ddata->cur == 'I') + return (cpp_demangle_read_subst_stdtmpl(ddata, + "std::basic_string")); + return (1); + + case SIMPLE_HASH('S', 'd'): + /* std::basic_iostream > */ + if (!DEM_PUSH_STR(ddata, "std::basic_iostream >")) + return (0); + ddata->last_sname = "basic_iostream"; + ddata->cur += 2; + if (*ddata->cur == 'I') + return (cpp_demangle_read_subst_stdtmpl(ddata, + "std::basic_iostream >")); + return (1); + + case SIMPLE_HASH('S', 'i'): + /* std::basic_istream > */ + if (!DEM_PUSH_STR(ddata, "std::basic_istream >")) + return (0); + ddata->last_sname = "basic_istream"; + ddata->cur += 2; + if (*ddata->cur == 'I') + return (cpp_demangle_read_subst_stdtmpl(ddata, + "std::basic_istream >")); + return (1); + + case SIMPLE_HASH('S', 'o'): + /* std::basic_ostream > */ + if (!DEM_PUSH_STR(ddata, "std::basic_ostream >")) + return (0); + ddata->last_sname = "basic_ostream"; + ddata->cur += 2; + if (*ddata->cur == 'I') + return (cpp_demangle_read_subst_stdtmpl(ddata, + "std::basic_ostream >")); + return (1); + + case SIMPLE_HASH('S', 's'): + /* + * std::basic_string, + * std::allocator > + * + * a.k.a std::string + */ + if (!DEM_PUSH_STR(ddata, "std::basic_string, std::allocator >")) + return (0); + ddata->last_sname = "string"; + ddata->cur += 2; + if (*ddata->cur == 'I') + return (cpp_demangle_read_subst_stdtmpl(ddata, + "std::basic_string," + " std::allocator >")); + return (1); + + case SIMPLE_HASH('S', 't'): + /* std:: */ + return (cpp_demangle_read_subst_std(ddata)); + } + + if (*(++ddata->cur) == '\0') + return (0); + + /* Skip unknown substitution abbreviations. */ + if (!(*ddata->cur >= '0' && *ddata->cur <= '9') && + !(*ddata->cur >= 'A' && *ddata->cur <= 'Z') && + *ddata->cur != '_') { + ++ddata->cur; + return (1); + } + + /* substitution */ + if (*ddata->cur == '_') + return (cpp_demangle_get_subst(ddata, 0)); + else { + errno = 0; + /* substitution number is base 36 */ + if ((nth = strtol(ddata->cur, (char **) NULL, 36)) == 0 && + errno != 0) + return (0); + + /* first was '_', so increase one */ + ++nth; + + while (*ddata->cur != '_') + ++ddata->cur; + + assert(nth > 0); + + return (cpp_demangle_get_subst(ddata, nth)); + } + + /* NOTREACHED */ + return (0); +} + +static int +cpp_demangle_read_subst_std(struct cpp_demangle_data *ddata) +{ + struct vector_str *output, v; + size_t p_idx, subst_str_len; + int rtn; + char *subst_str; + + if (ddata == NULL) + return (0); + + if (!vector_str_init(&v)) + return (0); + + subst_str = NULL; + rtn = 0; + if (!DEM_PUSH_STR(ddata, "std::")) + goto clean; + + if (!VEC_PUSH_STR(&v, "std::")) + goto clean; + + ddata->cur += 2; + + output = ddata->cur_output; + + p_idx = output->size; + if (!cpp_demangle_read_uqname(ddata)) + goto clean; + + if ((subst_str = vector_str_substr(output, p_idx, output->size - 1, + &subst_str_len)) == NULL) + goto clean; + + if (!vector_str_push(&v, subst_str, subst_str_len)) + goto clean; + + if (!cpp_demangle_push_subst_v(ddata, &v)) + goto clean; + + if (*ddata->cur == 'I') { + p_idx = output->size; + if (!cpp_demangle_read_tmpl_args(ddata)) + goto clean; + free(subst_str); + if ((subst_str = vector_str_substr(output, p_idx, + output->size - 1, &subst_str_len)) == NULL) + goto clean; + if (!vector_str_push(&v, subst_str, subst_str_len)) + goto clean; + if (!cpp_demangle_push_subst_v(ddata, &v)) + goto clean; + } + + rtn = 1; +clean: + free(subst_str); + vector_str_dest(&v); + + return (rtn); +} + +static int +cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *ddata, + const char *str) +{ + struct vector_str *output; + size_t p_idx, substr_len, len; + int rtn; + char *subst_str, *substr; + + if (ddata == NULL || str == NULL) + return (0); + + if ((len = strlen(str)) == 0) + return (0); + + output = ddata->cur_output; + + p_idx = output->size; + substr = NULL; + subst_str = NULL; + + if (!cpp_demangle_read_tmpl_args(ddata)) + return (0); + if ((substr = vector_str_substr(output, p_idx, output->size - 1, + &substr_len)) == NULL) + return (0); + + rtn = 0; + if ((subst_str = malloc(sizeof(char) * (substr_len + len + 1))) == + NULL) + goto clean; + + memcpy(subst_str, str, len); + memcpy(subst_str + len, substr, substr_len); + subst_str[substr_len + len] = '\0'; + + if (!cpp_demangle_push_subst(ddata, subst_str, substr_len + len)) + goto clean; + + rtn = 1; +clean: + free(subst_str); + free(substr); + + return (rtn); +} + +static int +cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *ddata) +{ + + if (ddata == NULL || *ddata->cur == '\0') + return (0); + + switch (*ddata->cur) { + case 'L': + return (cpp_demangle_read_expr_primary(ddata)); + case 'X': + ++ddata->cur; + if (!cpp_demangle_read_expression(ddata)) + return (0); + return (*ddata->cur++ == 'E'); + } + + return (cpp_demangle_read_type(ddata, NULL)); +} + +static int +cpp_demangle_read_tmpl_args(struct cpp_demangle_data *ddata) +{ + struct vector_str *v; + size_t arg_len, idx, limit, size; + char *arg; + + if (ddata == NULL || *ddata->cur == '\0') + return (0); + + ++ddata->cur; + + if (!vector_read_cmd_push(&ddata->cmd, READ_TMPL, NULL)) + return (0); + + if (!DEM_PUSH_STR(ddata, "<")) + return (0); + + limit = 0; + v = &ddata->output; + for (;;) { + idx = v->size; + if (!cpp_demangle_read_tmpl_arg(ddata)) + return (0); + if ((arg = vector_str_substr(v, idx, v->size - 1, &arg_len)) == + NULL) + return (0); + if (!vector_str_find(&ddata->tmpl, arg, arg_len) && + !vector_str_push(&ddata->tmpl, arg, arg_len)) { + free(arg); + return (0); + } + + free(arg); + + if (*ddata->cur == 'E') { + ++ddata->cur; + size = v->size; + assert(size > 0); + if (!strncmp(v->container[size - 1], ">", 1)) { + if (!DEM_PUSH_STR(ddata, " >")) + return (0); + } else if (!DEM_PUSH_STR(ddata, ">")) + return (0); + ddata->is_tmpl = true; + break; + } else if (*ddata->cur != 'I' && + !DEM_PUSH_STR(ddata, ", ")) + return (0); + + if (limit++ > CPP_DEMANGLE_TRY_LIMIT) + return (0); + } + + return (vector_read_cmd_pop(&ddata->cmd)); +} + +/* + * Read template parameter that forms in 'T[number]_'. + * This function much like to read_subst but only for types. + */ +static int +cpp_demangle_read_tmpl_param(struct cpp_demangle_data *ddata) +{ + long nth; + + if (ddata == NULL || *ddata->cur != 'T') + return (0); + + ++ddata->cur; + + if (*ddata->cur == '_') + return (cpp_demangle_get_tmpl_param(ddata, 0)); + else { + + errno = 0; + if ((nth = strtol(ddata->cur, (char **) NULL, 36)) == 0 && + errno != 0) + return (0); + + /* T_ is first */ + ++nth; + + while (*ddata->cur != '_') + ++ddata->cur; + + assert(nth > 0); + + return (cpp_demangle_get_tmpl_param(ddata, nth)); + } + + /* NOTREACHED */ + return (0); +} + +static int +cpp_demangle_read_type(struct cpp_demangle_data *ddata, + struct type_delimit *td) +{ + struct vector_type_qualifier v; + struct vector_str *output, sv; + size_t p_idx, type_str_len, subst_str_len; + int extern_c, is_builtin; + long len; + const char *p; + char *type_str, *exp_str, *num_str, *subst_str; + bool skip_ref_qualifier, omit_void; + + if (ddata == NULL) + return (0); + + output = ddata->cur_output; + if (td) { + if (td->paren == false) { + if (!DEM_PUSH_STR(ddata, "(")) + return (0); + if (ddata->output.size < 2) + return (0); + td->paren = true; + } + + if (!td->firstp) { + if (*ddata->cur != 'I') { + if (!DEM_PUSH_STR(ddata, ", ")) + return (0); + } + } + } + + assert(output != NULL); + /* + * [r, V, K] [P, R, O, C, G, U] builtin, function, class-enum, array + * pointer-to-member, template-param, template-template-param, subst + */ + + if (!vector_type_qualifier_init(&v)) + return (0); + + extern_c = 0; + is_builtin = 1; + p_idx = output->size; + type_str = exp_str = num_str = NULL; + skip_ref_qualifier = false; + +again: + + /* Clear ref-qualifier flag */ + if (*ddata->cur != 'R' && *ddata->cur != 'O' && *ddata->cur != 'E') + ddata->ref_qualifier = false; + + /* builtin type */ + switch (*ddata->cur) { + case 'a': + /* signed char */ + if (!DEM_PUSH_STR(ddata, "signed char")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'A': + /* array type */ + if (!cpp_demangle_read_array(ddata)) + goto clean; + is_builtin = 0; + goto rtn; + + case 'b': + /* bool */ + if (!DEM_PUSH_STR(ddata, "bool")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'C': + /* complex pair */ + if (!vector_type_qualifier_push(&v, TYPE_CMX)) + goto clean; + ++ddata->cur; + if (td) + td->firstp = false; + goto again; + + case 'c': + /* char */ + if (!DEM_PUSH_STR(ddata, "char")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'd': + /* double */ + if (!DEM_PUSH_STR(ddata, "double")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'D': + ++ddata->cur; + switch (*ddata->cur) { + case 'a': + /* auto */ + if (!DEM_PUSH_STR(ddata, "auto")) + goto clean; + ++ddata->cur; + break; + case 'c': + /* decltype(auto) */ + if (!DEM_PUSH_STR(ddata, "decltype(auto)")) + goto clean; + ++ddata->cur; + break; + case 'd': + /* IEEE 754r decimal floating point (64 bits) */ + if (!DEM_PUSH_STR(ddata, "decimal64")) + goto clean; + ++ddata->cur; + break; + case 'e': + /* IEEE 754r decimal floating point (128 bits) */ + if (!DEM_PUSH_STR(ddata, "decimal128")) + goto clean; + ++ddata->cur; + break; + case 'f': + /* IEEE 754r decimal floating point (32 bits) */ + if (!DEM_PUSH_STR(ddata, "decimal32")) + goto clean; + ++ddata->cur; + break; + case 'h': + /* IEEE 754r half-precision floating point (16 bits) */ + if (!DEM_PUSH_STR(ddata, "half")) + goto clean; + ++ddata->cur; + break; + case 'i': + /* char32_t */ + if (!DEM_PUSH_STR(ddata, "char32_t")) + goto clean; + ++ddata->cur; + break; + case 'n': + /* std::nullptr_t (i.e., decltype(nullptr)) */ + if (!DEM_PUSH_STR(ddata, "decltype(nullptr)")) + goto clean; + ++ddata->cur; + break; + case 's': + /* char16_t */ + if (!DEM_PUSH_STR(ddata, "char16_t")) + goto clean; + ++ddata->cur; + break; + case 'v': + /* gcc vector_size extension. */ + ++ddata->cur; + if (*ddata->cur == '_') { + ++ddata->cur; + if (!cpp_demangle_read_expression_flat(ddata, + &exp_str)) + goto clean; + if (!VEC_PUSH_STR(&v.ext_name, exp_str)) + goto clean; + } else { + if (!cpp_demangle_read_number_as_string(ddata, + &num_str)) + goto clean; + if (!VEC_PUSH_STR(&v.ext_name, num_str)) + goto clean; + } + if (*ddata->cur != '_') + goto clean; + ++ddata->cur; + if (!vector_type_qualifier_push(&v, TYPE_VEC)) + goto clean; + if (td) + td->firstp = false; + goto again; + default: + goto clean; + } + goto rtn; + + case 'e': + /* long double */ + if (!DEM_PUSH_STR(ddata, "long double")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'E': + /* unexpected end except ref-qualifiers */ + if (ddata->ref_qualifier && ddata->is_functype) { + skip_ref_qualifier = true; + /* Pop the delimiter. */ + cpp_demangle_pop_str(ddata); + goto rtn; + } + goto clean; + + case 'f': + /* float */ + if (!DEM_PUSH_STR(ddata, "float")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'F': + /* function */ + if (!cpp_demangle_read_function(ddata, &extern_c, &v)) + goto clean; + is_builtin = 0; + goto rtn; + + case 'g': + /* __float128 */ + if (!DEM_PUSH_STR(ddata, "__float128")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'G': + /* imaginary */ + if (!vector_type_qualifier_push(&v, TYPE_IMG)) + goto clean; + ++ddata->cur; + if (td) + td->firstp = false; + goto again; + + case 'h': + /* unsigned char */ + if (!DEM_PUSH_STR(ddata, "unsigned char")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'i': + /* int */ + if (!DEM_PUSH_STR(ddata, "int")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'I': + /* template args. */ + /* handles */ + p_idx = output->size; + if (!cpp_demangle_read_tmpl_args(ddata)) + goto clean; + if ((subst_str = vector_str_substr(output, p_idx, + output->size - 1, &subst_str_len)) == NULL) + goto clean; + if (!vector_str_init(&sv)) { + free(subst_str); + goto clean; + } + if (!vector_str_push(&sv, subst_str, subst_str_len)) { + free(subst_str); + vector_str_dest(&sv); + goto clean; + } + free(subst_str); + if (!cpp_demangle_push_subst_v(ddata, &sv)) { + vector_str_dest(&sv); + goto clean; + } + vector_str_dest(&sv); + goto rtn; + + case 'j': + /* unsigned int */ + if (!DEM_PUSH_STR(ddata, "unsigned int")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'K': + /* const */ + if (!vector_type_qualifier_push(&v, TYPE_CST)) + goto clean; + ++ddata->cur; + if (td) + td->firstp = false; + goto again; + + case 'l': + /* long */ + if (!DEM_PUSH_STR(ddata, "long")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'm': + /* unsigned long */ + if (!DEM_PUSH_STR(ddata, "unsigned long")) + goto clean; + + ++ddata->cur; + + goto rtn; + case 'M': + /* pointer to member */ + if (!cpp_demangle_read_pointer_to_member(ddata, &v)) + goto clean; + is_builtin = 0; + goto rtn; + + case 'n': + /* __int128 */ + if (!DEM_PUSH_STR(ddata, "__int128")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'o': + /* unsigned __int128 */ + if (!DEM_PUSH_STR(ddata, "unsigned __int128")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'O': + /* rvalue reference */ + if (ddata->ref_qualifier) + goto clean; + if (!vector_type_qualifier_push(&v, TYPE_RREF)) + goto clean; + ddata->ref_qualifier = true; + ddata->ref_qualifier_type = TYPE_RREF; + ++ddata->cur; + if (td) + td->firstp = false; + goto again; + + case 'P': + /* pointer */ + if (!vector_type_qualifier_push(&v, TYPE_PTR)) + goto clean; + ++ddata->cur; + if (td) + td->firstp = false; + goto again; + + case 'r': + /* restrict */ + if (!vector_type_qualifier_push(&v, TYPE_RST)) + goto clean; + ++ddata->cur; + if (td) + td->firstp = false; + goto again; + + case 'R': + /* reference */ + if (ddata->ref_qualifier) + goto clean; + if (!vector_type_qualifier_push(&v, TYPE_REF)) + goto clean; + ddata->ref_qualifier = true; + ddata->ref_qualifier_type = TYPE_REF; + ++ddata->cur; + if (td) + td->firstp = false; + goto again; + + case 's': + /* short, local string */ + if (!DEM_PUSH_STR(ddata, "short")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'S': + /* substitution */ + if (!cpp_demangle_read_subst(ddata)) + goto clean; + is_builtin = 0; + goto rtn; + + case 't': + /* unsigned short */ + if (!DEM_PUSH_STR(ddata, "unsigned short")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'T': + /* template parameter */ + if (!cpp_demangle_read_tmpl_param(ddata)) + goto clean; + is_builtin = 0; + goto rtn; + + case 'u': + /* vendor extended builtin */ + ++ddata->cur; + if (!cpp_demangle_read_sname(ddata)) + goto clean; + is_builtin = 0; + goto rtn; + + case 'U': + /* vendor extended type qualifier */ + ++ddata->cur; + if (!cpp_demangle_read_number(ddata, &len)) + goto clean; + if (len <= 0) + goto clean; + if (!vector_str_push(&v.ext_name, ddata->cur, len)) + return (0); + ddata->cur += len; + if (!vector_type_qualifier_push(&v, TYPE_EXT)) + goto clean; + if (td) + td->firstp = false; + goto again; + + case 'v': + /* void */ + omit_void = false; + if (td && td->firstp) { + /* + * peek into next bytes and see if we should omit + * the "void". + */ + omit_void = true; + for (p = ddata->cur + 1; *p != '\0'; p++) { + if (*p == 'E') + break; + if (*p != 'R' && *p != 'O') { + omit_void = false; + break; + } + } + } + if (!omit_void && !DEM_PUSH_STR(ddata, "void")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'V': + /* volatile */ + if (!vector_type_qualifier_push(&v, TYPE_VAT)) + goto clean; + ++ddata->cur; + if (td) + td->firstp = false; + goto again; + + case 'w': + /* wchar_t */ + if (!DEM_PUSH_STR(ddata, "wchar_t")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'x': + /* long long */ + if (!DEM_PUSH_STR(ddata, "long long")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'y': + /* unsigned long long */ + if (!DEM_PUSH_STR(ddata, "unsigned long long")) + goto clean; + ++ddata->cur; + goto rtn; + + case 'z': + /* ellipsis */ + if (!DEM_PUSH_STR(ddata, "...")) + goto clean; + ++ddata->cur; + goto rtn; + } + + if (!cpp_demangle_read_name(ddata)) + goto clean; + + is_builtin = 0; +rtn: + + type_str = vector_str_substr(output, p_idx, output->size - 1, + &type_str_len); + + if (is_builtin == 0) { + if (!vector_str_find(&ddata->subst, type_str, type_str_len) && + !vector_str_push(&ddata->subst, type_str, type_str_len)) + goto clean; + } + + if (!skip_ref_qualifier && + !cpp_demangle_push_type_qualifier(ddata, &v, type_str)) + goto clean; + + if (td) + td->firstp = false; + + free(type_str); + free(exp_str); + free(num_str); + vector_type_qualifier_dest(&v); + + return (1); +clean: + free(type_str); + free(exp_str); + free(num_str); + vector_type_qualifier_dest(&v); + + return (0); +} + +static int +cpp_demangle_read_type_flat(struct cpp_demangle_data *ddata, char **str) +{ + struct vector_str *output; + size_t i, p_idx, idx, type_len; + char *type; + + output = ddata->cur_output; + + p_idx = output->size; + + if (!cpp_demangle_read_type(ddata, NULL)) + return (0); + + if ((type = vector_str_substr(output, p_idx, output->size - 1, + &type_len)) == NULL) + return (0); + + idx = output->size; + for (i = p_idx; i < idx; ++i) { + if (!vector_str_pop(output)) { + free(type); + return (0); + } + } + + *str = type; + + return (1); +} + +/* + * read unqualified-name, unqualified name are operator-name, ctor-dtor-name, + * source-name + */ +static int +cpp_demangle_read_uqname(struct cpp_demangle_data *ddata) +{ + size_t len; + + if (ddata == NULL || *ddata->cur == '\0') + return (0); + + /* operator name */ + switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { + case SIMPLE_HASH('a', 'a'): + /* operator && */ + if (!DEM_PUSH_STR(ddata, "operator&&")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('a', 'd'): + /* operator & (unary) */ + if (!DEM_PUSH_STR(ddata, "operator&")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('a', 'n'): + /* operator & */ + if (!DEM_PUSH_STR(ddata, "operator&")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('a', 'N'): + /* operator &= */ + if (!DEM_PUSH_STR(ddata, "operator&=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('a', 'S'): + /* operator = */ + if (!DEM_PUSH_STR(ddata, "operator=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('c', 'l'): + /* operator () */ + if (!DEM_PUSH_STR(ddata, "operator()")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('c', 'm'): + /* operator , */ + if (!DEM_PUSH_STR(ddata, "operator,")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('c', 'o'): + /* operator ~ */ + if (!DEM_PUSH_STR(ddata, "operator~")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('c', 'v'): + /* operator (cast) */ + if (!DEM_PUSH_STR(ddata, "operator(cast)")) + return (0); + ddata->cur += 2; + return (cpp_demangle_read_type(ddata, NULL)); + + case SIMPLE_HASH('d', 'a'): + /* operator delete [] */ + if (!DEM_PUSH_STR(ddata, "operator delete []")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('d', 'e'): + /* operator * (unary) */ + if (!DEM_PUSH_STR(ddata, "operator*")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('d', 'l'): + /* operator delete */ + if (!DEM_PUSH_STR(ddata, "operator delete")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('d', 'v'): + /* operator / */ + if (!DEM_PUSH_STR(ddata, "operator/")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('d', 'V'): + /* operator /= */ + if (!DEM_PUSH_STR(ddata, "operator/=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('e', 'o'): + /* operator ^ */ + if (!DEM_PUSH_STR(ddata, "operator^")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('e', 'O'): + /* operator ^= */ + if (!DEM_PUSH_STR(ddata, "operator^=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('e', 'q'): + /* operator == */ + if (!DEM_PUSH_STR(ddata, "operator==")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('g', 'e'): + /* operator >= */ + if (!DEM_PUSH_STR(ddata, "operator>=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('g', 't'): + /* operator > */ + if (!DEM_PUSH_STR(ddata, "operator>")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('i', 'x'): + /* operator [] */ + if (!DEM_PUSH_STR(ddata, "operator[]")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('l', 'e'): + /* operator <= */ + if (!DEM_PUSH_STR(ddata, "operator<=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('l', 's'): + /* operator << */ + if (!DEM_PUSH_STR(ddata, "operator<<")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('l', 'S'): + /* operator <<= */ + if (!DEM_PUSH_STR(ddata, "operator<<=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('l', 't'): + /* operator < */ + if (!DEM_PUSH_STR(ddata, "operator<")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('m', 'i'): + /* operator - */ + if (!DEM_PUSH_STR(ddata, "operator-")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('m', 'I'): + /* operator -= */ + if (!DEM_PUSH_STR(ddata, "operator-=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('m', 'l'): + /* operator * */ + if (!DEM_PUSH_STR(ddata, "operator*")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('m', 'L'): + /* operator *= */ + if (!DEM_PUSH_STR(ddata, "operator*=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('m', 'm'): + /* operator -- */ + if (!DEM_PUSH_STR(ddata, "operator--")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('n', 'a'): + /* operator new[] */ + if (!DEM_PUSH_STR(ddata, "operator new []")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('n', 'e'): + /* operator != */ + if (!DEM_PUSH_STR(ddata, "operator!=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('n', 'g'): + /* operator - (unary) */ + if (!DEM_PUSH_STR(ddata, "operator-")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('n', 't'): + /* operator ! */ + if (!DEM_PUSH_STR(ddata, "operator!")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('n', 'w'): + /* operator new */ + if (!DEM_PUSH_STR(ddata, "operator new")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('o', 'o'): + /* operator || */ + if (!DEM_PUSH_STR(ddata, "operator||")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('o', 'r'): + /* operator | */ + if (!DEM_PUSH_STR(ddata, "operator|")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('o', 'R'): + /* operator |= */ + if (!DEM_PUSH_STR(ddata, "operator|=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('p', 'l'): + /* operator + */ + if (!DEM_PUSH_STR(ddata, "operator+")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('p', 'L'): + /* operator += */ + if (!DEM_PUSH_STR(ddata, "operator+=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('p', 'm'): + /* operator ->* */ + if (!DEM_PUSH_STR(ddata, "operator->*")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('p', 'p'): + /* operator ++ */ + if (!DEM_PUSH_STR(ddata, "operator++")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('p', 's'): + /* operator + (unary) */ + if (!DEM_PUSH_STR(ddata, "operator+")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('p', 't'): + /* operator -> */ + if (!DEM_PUSH_STR(ddata, "operator->")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('q', 'u'): + /* operator ? */ + if (!DEM_PUSH_STR(ddata, "operator?")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('r', 'm'): + /* operator % */ + if (!DEM_PUSH_STR(ddata, "operator%")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('r', 'M'): + /* operator %= */ + if (!DEM_PUSH_STR(ddata, "operator%=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('r', 's'): + /* operator >> */ + if (!DEM_PUSH_STR(ddata, "operator>>")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('r', 'S'): + /* operator >>= */ + if (!DEM_PUSH_STR(ddata, "operator>>=")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('r', 'z'): + /* operator sizeof */ + if (!DEM_PUSH_STR(ddata, "operator sizeof ")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('s', 'r'): + /* scope resolution operator */ + if (!DEM_PUSH_STR(ddata, "scope resolution operator ")) + return (0); + ddata->cur += 2; + return (1); + + case SIMPLE_HASH('s', 'v'): + /* operator sizeof */ + if (!DEM_PUSH_STR(ddata, "operator sizeof ")) + return (0); + ddata->cur += 2; + return (1); + } + + /* vendor extened operator */ + if (*ddata->cur == 'v' && ELFTC_ISDIGIT(*(ddata->cur + 1))) { + if (!DEM_PUSH_STR(ddata, "vendor extened operator ")) + return (0); + if (!cpp_demangle_push_str(ddata, ddata->cur + 1, 1)) + return (0); + ddata->cur += 2; + return (cpp_demangle_read_sname(ddata)); + } + + /* ctor-dtor-name */ + switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { + case SIMPLE_HASH('C', '1'): + case SIMPLE_HASH('C', '2'): + case SIMPLE_HASH('C', '3'): + if (ddata->last_sname == NULL) + return (0); + if ((len = strlen(ddata->last_sname)) == 0) + return (0); + if (!DEM_PUSH_STR(ddata, "::")) + return (0); + if (!cpp_demangle_push_str(ddata, ddata->last_sname, len)) + return (0); + ddata->cur +=2; + return (1); + + case SIMPLE_HASH('D', '0'): + case SIMPLE_HASH('D', '1'): + case SIMPLE_HASH('D', '2'): + if (ddata->last_sname == NULL) + return (0); + if ((len = strlen(ddata->last_sname)) == 0) + return (0); + if (!DEM_PUSH_STR(ddata, "::~")) + return (0); + if (!cpp_demangle_push_str(ddata, ddata->last_sname, len)) + return (0); + ddata->cur +=2; + return (1); + } + + /* source name */ + if (ELFTC_ISDIGIT(*ddata->cur) != 0) + return (cpp_demangle_read_sname(ddata)); + + /* local source name */ + if (*ddata->cur == 'L') + return (cpp_demangle_local_source_name(ddata)); + + return (1); +} + +/* + * Read local source name. + * + * References: + * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775 + * http://gcc.gnu.org/viewcvs?view=rev&revision=124467 + */ +static int +cpp_demangle_local_source_name(struct cpp_demangle_data *ddata) +{ + /* L */ + if (ddata == NULL || *ddata->cur != 'L') + return (0); + ++ddata->cur; + + /* source name */ + if (!cpp_demangle_read_sname(ddata)) + return (0); + + /* discriminator */ + if (*ddata->cur == '_') { + ++ddata->cur; + while (ELFTC_ISDIGIT(*ddata->cur) != 0) + ++ddata->cur; + } + + return (1); +} + +static int +cpp_demangle_read_v_offset(struct cpp_demangle_data *ddata) +{ + + if (ddata == NULL) + return (0); + + if (!DEM_PUSH_STR(ddata, "offset : ")) + return (0); + + if (!cpp_demangle_read_offset_number(ddata)) + return (0); + + if (!DEM_PUSH_STR(ddata, "virtual offset : ")) + return (0); + + return (!cpp_demangle_read_offset_number(ddata)); +} + +/* + * Decode floating point representation to string + * Return new allocated string or NULL + * + * Todo + * Replace these functions to macro. + */ +static char * +decode_fp_to_double(const char *p, size_t len) +{ + double f; + size_t rtn_len, limit, i; + int byte; + char *rtn; + + if (p == NULL || len == 0 || len % 2 != 0 || len / 2 > sizeof(double)) + return (NULL); + + memset(&f, 0, sizeof(double)); + + for (i = 0; i < len / 2; ++i) { + byte = hex_to_dec(p[len - i * 2 - 1]) + + hex_to_dec(p[len - i * 2 - 2]) * 16; + + if (byte < 0 || byte > 255) + return (NULL); + +#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN + ((unsigned char *)&f)[i] = (unsigned char)(byte); +#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + ((unsigned char *)&f)[sizeof(double) - i - 1] = + (unsigned char)(byte); +#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + } + + rtn_len = 64; + limit = 0; +again: + if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL) + return (NULL); + + if (snprintf(rtn, rtn_len, "%fld", f) >= (int)rtn_len) { + free(rtn); + if (limit++ > FLOAT_SPRINTF_TRY_LIMIT) + return (NULL); + rtn_len *= BUFFER_GROWFACTOR; + goto again; + } + + return rtn; +} + +static char * +decode_fp_to_float(const char *p, size_t len) +{ + size_t i, rtn_len, limit; + float f; + int byte; + char *rtn; + + if (p == NULL || len == 0 || len % 2 != 0 || len / 2 > sizeof(float)) + return (NULL); + + memset(&f, 0, sizeof(float)); + + for (i = 0; i < len / 2; ++i) { + byte = hex_to_dec(p[len - i * 2 - 1]) + + hex_to_dec(p[len - i * 2 - 2]) * 16; + if (byte < 0 || byte > 255) + return (NULL); +#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN + ((unsigned char *)&f)[i] = (unsigned char)(byte); +#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + ((unsigned char *)&f)[sizeof(float) - i - 1] = + (unsigned char)(byte); +#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + } + + rtn_len = 64; + limit = 0; +again: + if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL) + return (NULL); + + if (snprintf(rtn, rtn_len, "%ff", f) >= (int)rtn_len) { + free(rtn); + if (limit++ > FLOAT_SPRINTF_TRY_LIMIT) + return (NULL); + rtn_len *= BUFFER_GROWFACTOR; + goto again; + } + + return rtn; +} + +static char * +decode_fp_to_float128(const char *p, size_t len) +{ + long double f; + size_t rtn_len, limit, i; + int byte; + unsigned char buf[FLOAT_QUADRUPLE_BYTES]; + char *rtn; + + switch(sizeof(long double)) { + case FLOAT_QUADRUPLE_BYTES: + return (decode_fp_to_long_double(p, len)); + case FLOAT_EXTENED_BYTES: + if (p == NULL || len == 0 || len % 2 != 0 || + len / 2 > FLOAT_QUADRUPLE_BYTES) + return (NULL); + + memset(buf, 0, FLOAT_QUADRUPLE_BYTES); + + for (i = 0; i < len / 2; ++i) { + byte = hex_to_dec(p[len - i * 2 - 1]) + + hex_to_dec(p[len - i * 2 - 2]) * 16; + if (byte < 0 || byte > 255) + return (NULL); +#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN + buf[i] = (unsigned char)(byte); +#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + buf[FLOAT_QUADRUPLE_BYTES - i -1] = + (unsigned char)(byte); +#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + } + memset(&f, 0, FLOAT_EXTENED_BYTES); + +#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN + memcpy(&f, buf, FLOAT_EXTENED_BYTES); +#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + memcpy(&f, buf + 6, FLOAT_EXTENED_BYTES); +#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + + rtn_len = 256; + limit = 0; +again: + if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL) + return (NULL); + + if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) { + free(rtn); + if (limit++ > FLOAT_SPRINTF_TRY_LIMIT) + return (NULL); + rtn_len *= BUFFER_GROWFACTOR; + goto again; + } + + return (rtn); + default: + return (NULL); + } +} + +static char * +decode_fp_to_float80(const char *p, size_t len) +{ + long double f; + size_t rtn_len, limit, i; + int byte; + unsigned char buf[FLOAT_EXTENED_BYTES]; + char *rtn; + + switch(sizeof(long double)) { + case FLOAT_QUADRUPLE_BYTES: + if (p == NULL || len == 0 || len % 2 != 0 || + len / 2 > FLOAT_EXTENED_BYTES) + return (NULL); + + memset(buf, 0, FLOAT_EXTENED_BYTES); + + for (i = 0; i < len / 2; ++i) { + byte = hex_to_dec(p[len - i * 2 - 1]) + + hex_to_dec(p[len - i * 2 - 2]) * 16; + + if (byte < 0 || byte > 255) + return (NULL); + +#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN + buf[i] = (unsigned char)(byte); +#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + buf[FLOAT_EXTENED_BYTES - i -1] = + (unsigned char)(byte); +#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + } + + memset(&f, 0, FLOAT_QUADRUPLE_BYTES); + +#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN + memcpy(&f, buf, FLOAT_EXTENED_BYTES); +#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + memcpy((unsigned char *)(&f) + 6, buf, FLOAT_EXTENED_BYTES); +#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + + rtn_len = 256; + limit = 0; +again: + if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL) + return (NULL); + + if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) { + free(rtn); + if (limit++ > FLOAT_SPRINTF_TRY_LIMIT) + return (NULL); + rtn_len *= BUFFER_GROWFACTOR; + goto again; + } + + return (rtn); + case FLOAT_EXTENED_BYTES: + return (decode_fp_to_long_double(p, len)); + default: + return (NULL); + } +} + +static char * +decode_fp_to_long_double(const char *p, size_t len) +{ + long double f; + size_t rtn_len, limit, i; + int byte; + char *rtn; + + if (p == NULL || len == 0 || len % 2 != 0 || + len / 2 > sizeof(long double)) + return (NULL); + + memset(&f, 0, sizeof(long double)); + + for (i = 0; i < len / 2; ++i) { + byte = hex_to_dec(p[len - i * 2 - 1]) + + hex_to_dec(p[len - i * 2 - 2]) * 16; + + if (byte < 0 || byte > 255) + return (NULL); + +#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN + ((unsigned char *)&f)[i] = (unsigned char)(byte); +#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + ((unsigned char *)&f)[sizeof(long double) - i - 1] = + (unsigned char)(byte); +#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */ + } + + rtn_len = 256; + limit = 0; +again: + if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL) + return (NULL); + + if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) { + free(rtn); + if (limit++ > FLOAT_SPRINTF_TRY_LIMIT) + return (NULL); + rtn_len *= BUFFER_GROWFACTOR; + goto again; + } + + return (rtn); +} + +/* Simple hex to integer function used by decode_to_* function. */ +static int +hex_to_dec(char c) +{ + + switch (c) { + case '0': + return (0); + case '1': + return (1); + case '2': + return (2); + case '3': + return (3); + case '4': + return (4); + case '5': + return (5); + case '6': + return (6); + case '7': + return (7); + case '8': + return (8); + case '9': + return (9); + case 'a': + return (10); + case 'b': + return (11); + case 'c': + return (12); + case 'd': + return (13); + case 'e': + return (14); + case 'f': + return (15); + default: + return (-1); + } +} + +/** + * @brief Test input string is mangled by IA-64 C++ ABI style. + * + * Test string heads with "_Z" or "_GLOBAL__I_". + * @return Return 0 at false. + */ +bool +is_cpp_mangled_gnu3(const char *org) +{ + size_t len; + + len = strlen(org); + return ((len > 2 && *org == '_' && *(org + 1) == 'Z') || + (len > 11 && !strncmp(org, "_GLOBAL__I_", 11))); +} + +static void +vector_read_cmd_dest(struct vector_read_cmd *v) +{ + + if (v == NULL) + return; + + free(v->r_container); +} + +static struct read_cmd_item * +vector_read_cmd_find(struct vector_read_cmd *v, enum read_cmd dst) +{ + int i; + + if (v == NULL || dst == READ_FAIL) + return (NULL); + + for (i = (int) v->size - 1; i >= 0; i--) + if (v->r_container[i].cmd == dst) + return (&v->r_container[i]); + + return (NULL); +} + +static int +vector_read_cmd_init(struct vector_read_cmd *v) +{ + + if (v == NULL) + return (0); + + v->size = 0; + v->capacity = VECTOR_DEF_CAPACITY; + + if ((v->r_container = malloc(sizeof(*v->r_container) * v->capacity)) + == NULL) + return (0); + + return (1); +} + +static int +vector_read_cmd_pop(struct vector_read_cmd *v) +{ + + if (v == NULL || v->size == 0) + return (0); + + --v->size; + v->r_container[v->size].cmd = READ_FAIL; + v->r_container[v->size].data = NULL; + + return (1); +} + +static int +vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd, void *data) +{ + struct read_cmd_item *tmp_r_ctn; + size_t tmp_cap; + size_t i; + + if (v == NULL) + return (0); + + if (v->size == v->capacity) { + tmp_cap = v->capacity * BUFFER_GROWFACTOR; + if ((tmp_r_ctn = malloc(sizeof(*tmp_r_ctn) * tmp_cap)) == NULL) + return (0); + for (i = 0; i < v->size; ++i) + tmp_r_ctn[i] = v->r_container[i]; + free(v->r_container); + v->r_container = tmp_r_ctn; + v->capacity = tmp_cap; + } + + v->r_container[v->size].cmd = cmd; + v->r_container[v->size].data = data; + ++v->size; + + return (1); +} + +static void +vector_type_qualifier_dest(struct vector_type_qualifier *v) +{ + + if (v == NULL) + return; + + free(v->q_container); + vector_str_dest(&v->ext_name); +} + +/* size, capacity, ext_name */ +static int +vector_type_qualifier_init(struct vector_type_qualifier *v) +{ + + if (v == NULL) + return (0); + + v->size = 0; + v->capacity = VECTOR_DEF_CAPACITY; + + if ((v->q_container = malloc(sizeof(enum type_qualifier) * v->capacity)) + == NULL) + return (0); + + assert(v->q_container != NULL); + + if (vector_str_init(&v->ext_name) == false) { + free(v->q_container); + return (0); + } + + return (1); +} + +static int +vector_type_qualifier_push(struct vector_type_qualifier *v, + enum type_qualifier t) +{ + enum type_qualifier *tmp_ctn; + size_t tmp_cap; + size_t i; + + if (v == NULL) + return (0); + + if (v->size == v->capacity) { + tmp_cap = v->capacity * BUFFER_GROWFACTOR; + if ((tmp_ctn = malloc(sizeof(enum type_qualifier) * tmp_cap)) + == NULL) + return (0); + for (i = 0; i < v->size; ++i) + tmp_ctn[i] = v->q_container[i]; + free(v->q_container); + v->q_container = tmp_ctn; + v->capacity = tmp_cap; + } + + v->q_container[v->size] = t; + ++v->size; + + return (1); +} diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc_hash.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_hash.c new file mode 100644 index 0000000..6cc54b9 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/libelftc_hash.c @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 2013, Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * An implementation of the Fowler-Noll-Vo hash function. + * + * References: + * - http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + * - http://www.isthe.com/chongo/tech/comp/fnv/ + */ + +#include + +#include + +#include "_libelftc.h" + +ELFTC_VCSID("$Id: libelftc_hash.c 2870 2013-01-07 10:38:43Z jkoshy $"); + +/* + * Use the size of an 'int' to determine the magic numbers used by the + * hash function. + */ + +#if INT_MAX == 2147483647UL +#define FNV_PRIME 16777619UL +#define FNV_OFFSET 2166136261UL +#elif INT_MAX == 18446744073709551615ULL +#define FNV_PRIME 1099511628211ULL +#define FNV_OFFSET 14695981039346656037ULL +#else +#error sizeof(int) is unknown. +#endif + +unsigned int +libelftc_hash_string(const char *s) +{ + char c; + unsigned int hash; + + for (hash = FNV_OFFSET; (c = *s) != '\0'; s++) { + hash ^= c; + hash *= FNV_PRIME; + } + + return (hash); +} diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc_vstr.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_vstr.c new file mode 100644 index 0000000..934b5db --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/libelftc_vstr.c @@ -0,0 +1,359 @@ +/*- + * Copyright (c) 2008 Hyogeol Lee + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "_libelftc.h" + +ELFTC_VCSID("$Id: libelftc_vstr.c 3531 2017-06-05 05:08:43Z kaiwang27 $"); + +/** + * @file vector_str.c + * @brief Dynamic vector data for string implementation. + * + * Resemble to std::vector in C++. + */ + +static size_t get_strlen_sum(const struct vector_str *v); +static bool vector_str_grow(struct vector_str *v); + +static size_t +get_strlen_sum(const struct vector_str *v) +{ + size_t i, len = 0; + + if (v == NULL) + return (0); + + assert(v->size > 0); + + for (i = 0; i < v->size; ++i) + len += strlen(v->container[i]); + + return (len); +} + +/** + * @brief Deallocate resource in vector_str. + */ +void +vector_str_dest(struct vector_str *v) +{ + size_t i; + + if (v == NULL) + return; + + for (i = 0; i < v->size; ++i) + free(v->container[i]); + + free(v->container); +} + +/** + * @brief Find string in vector_str. + * @param v Destination vector. + * @param o String to find. + * @param l Length of the string. + * @return -1 at failed, 0 at not found, 1 at found. + */ +int +vector_str_find(const struct vector_str *v, const char *o, size_t l) +{ + size_t i; + + if (v == NULL || o == NULL) + return (-1); + + for (i = 0; i < v->size; ++i) + if (strncmp(v->container[i], o, l) == 0) + return (1); + + return (0); +} + +/** + * @brief Get new allocated flat string from vector. + * + * If l is not NULL, return length of the string. + * @param v Destination vector. + * @param l Length of the string. + * @return NULL at failed or NUL terminated new allocated string. + */ +char * +vector_str_get_flat(const struct vector_str *v, size_t *l) +{ + ssize_t elem_pos, elem_size, rtn_size; + size_t i; + char *rtn; + + if (v == NULL || v->size == 0) + return (NULL); + + if ((rtn_size = get_strlen_sum(v)) == 0) + return (NULL); + + if ((rtn = malloc(sizeof(char) * (rtn_size + 1))) == NULL) + return (NULL); + + elem_pos = 0; + for (i = 0; i < v->size; ++i) { + elem_size = strlen(v->container[i]); + + memcpy(rtn + elem_pos, v->container[i], elem_size); + + elem_pos += elem_size; + } + + rtn[rtn_size] = '\0'; + + if (l != NULL) + *l = rtn_size; + + return (rtn); +} + +static bool +vector_str_grow(struct vector_str *v) +{ + size_t i, tmp_cap; + char **tmp_ctn; + + if (v == NULL) + return (false); + + assert(v->capacity > 0); + + tmp_cap = v->capacity * BUFFER_GROWFACTOR; + + assert(tmp_cap > v->capacity); + + if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL) + return (false); + + for (i = 0; i < v->size; ++i) + tmp_ctn[i] = v->container[i]; + + free(v->container); + + v->container = tmp_ctn; + v->capacity = tmp_cap; + + return (true); +} + +/** + * @brief Initialize vector_str. + * @return false at failed, true at success. + */ +bool +vector_str_init(struct vector_str *v) +{ + + if (v == NULL) + return (false); + + v->size = 0; + v->capacity = VECTOR_DEF_CAPACITY; + + assert(v->capacity > 0); + + if ((v->container = malloc(sizeof(char *) * v->capacity)) == NULL) + return (false); + + assert(v->container != NULL); + + return (true); +} + +/** + * @brief Remove last element in vector_str. + * @return false at failed, true at success. + */ +bool +vector_str_pop(struct vector_str *v) +{ + + if (v == NULL) + return (false); + + if (v->size == 0) + return (true); + + --v->size; + + free(v->container[v->size]); + v->container[v->size] = NULL; + + return (true); +} + +/** + * @brief Push back string to vector. + * @return false at failed, true at success. + */ +bool +vector_str_push(struct vector_str *v, const char *str, size_t len) +{ + + if (v == NULL || str == NULL) + return (false); + + if (v->size == v->capacity && vector_str_grow(v) == false) + return (false); + + if ((v->container[v->size] = malloc(sizeof(char) * (len + 1))) == NULL) + return (false); + + snprintf(v->container[v->size], len + 1, "%s", str); + + ++v->size; + + return (true); +} + +/** + * @brief Push front org vector to det vector. + * @return false at failed, true at success. + */ +bool +vector_str_push_vector_head(struct vector_str *dst, struct vector_str *org) +{ + size_t i, j, tmp_cap; + char **tmp_ctn; + + if (dst == NULL || org == NULL) + return (false); + + tmp_cap = (dst->size + org->size) * BUFFER_GROWFACTOR; + + if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL) + return (false); + + for (i = 0; i < org->size; ++i) + if ((tmp_ctn[i] = strdup(org->container[i])) == NULL) { + for (j = 0; j < i; ++j) + free(tmp_ctn[j]); + + free(tmp_ctn); + + return (false); + } + + for (i = 0; i < dst->size; ++i) + tmp_ctn[i + org->size] = dst->container[i]; + + free(dst->container); + + dst->container = tmp_ctn; + dst->capacity = tmp_cap; + dst->size += org->size; + + return (true); +} + +/** + * @brief Push org vector to the tail of det vector. + * @return false at failed, true at success. + */ +bool +vector_str_push_vector(struct vector_str *dst, struct vector_str *org) +{ + size_t i, j, tmp_cap; + char **tmp_ctn; + + if (dst == NULL || org == NULL) + return (false); + + tmp_cap = (dst->size + org->size) * BUFFER_GROWFACTOR; + + if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL) + return (false); + + for (i = 0; i < dst->size; ++i) + tmp_ctn[i] = dst->container[i]; + + for (i = 0; i < org->size; ++i) + if ((tmp_ctn[i + dst->size] = strdup(org->container[i])) == + NULL) { + for (j = 0; j < i + dst->size; ++j) + free(tmp_ctn[j]); + + free(tmp_ctn); + + return (false); + } + + free(dst->container); + + dst->container = tmp_ctn; + dst->capacity = tmp_cap; + dst->size += org->size; + + return (true); +} + +/** + * @brief Get new allocated flat string from vector between begin and end. + * + * If r_len is not NULL, string length will be returned. + * @return NULL at failed or NUL terminated new allocated string. + */ +char * +vector_str_substr(const struct vector_str *v, size_t begin, size_t end, + size_t *r_len) +{ + size_t cur, i, len; + char *rtn; + + if (v == NULL || begin > end) + return (NULL); + + len = 0; + for (i = begin; i < end + 1; ++i) + len += strlen(v->container[i]); + + if ((rtn = malloc(sizeof(char) * (len + 1))) == NULL) + return (NULL); + + if (r_len != NULL) + *r_len = len; + + cur = 0; + for (i = begin; i < end + 1; ++i) { + len = strlen(v->container[i]); + memcpy(rtn + cur, v->container[i], len); + cur += len; + } + rtn[cur] = '\0'; + + return (rtn); +} diff --git a/rtemstoolkit/elftoolchain/libelftc/make-toolchain-version b/rtemstoolkit/elftoolchain/libelftc/make-toolchain-version new file mode 100755 index 0000000..0cdf370 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/make-toolchain-version @@ -0,0 +1,110 @@ +#!/bin/sh +# +# This script generates a project-wide version identifier for use by +# the `elftc_version()' API. +# +# $Id: make-toolchain-version 3414 2016-02-16 22:55:28Z jkoshy $ + +# +# Defaults. +# +buildhost=`uname -s` +elftcname="elftoolchain" +options="e:h:o:r:t:" +top="" +version="HEAD" +versionfile="elftc_version.c" +progname=`basename ${0}` + +usage() +{ + exec >&2 + + # Print a message, if supplied. + if [ -n "${*}" ]; then echo "##${@}"; fi + + echo "Usage: ${progname} [options]" + echo " Generate a toolchain-wide version number" + echo " -e PROJECTNAME Set the project name [default: ${elftcname}]." + echo " -h HOSTOS Set the build OS [default: ${buildhost}]." + echo " -o OUTPUT Set the output file [default: ${versionfile}]." + echo " -r VERSION Set the version string [default: ${version}]." + echo " -t TOPDIR Set the top-of-tree directory [required]." + exit 1 +} + +# +# Parse options. +# + +while getopts ${options} option +do + case ${option} in + 'e') elftcname="${OPTARG}" ;; + 'h') buildhost="${OPTARG}" ;; + 'o') versionfile="${OPTARG}" ;; + 'r') version="${OPTARG}" ;; + 't') top="${OPTARG}" ;; + '?') usage ;; + esac +done + +[ -n "${top}" ] || usage + +# Try to determine the in-tree revision number. +# +# This script attempts to handle the case where our sources have been +# incorporated into an operating system's base sources. +# +# - If SVN is detected, we use the `svninfo' tool to determine the +# in-tree revision number. +# - If CVS is detected, we use the string `unknown'. +# - Otherwise, we use `git --describe'. + +curdir=`pwd` +cd ${top} || usage "ERROR: Cannot change directory to \"${top}\"." + +if [ -d CVS ]; then # Look for CVS (NetBSD). + versionstring=" cvs:unknown" +else # Try git (DragonFlyBSD). + gitversion="$(git describe --all --dirty --long 2> /dev/null)" + if [ -n "${gitversion}" ]; then + versionstring=" git:${gitversion}" + else # Assume an SVN checkout (SourceForge or FreeBSD). + svnversion="$(svnversion)" + if [ -n "${svnversion}" ]; then + versionstring=" svn:$(svnversion)" + fi + fi +fi + +if [ -z "${versionstring}" ]; then + echo "ERROR: cannot determine a revision number." 1>&2 + exit 1 +fi + +cd ${curdir} || usage "Cannot change back to ${curdir}." + +# +# Only replace the source file if its content has changed. +# +tmpfile=`mktemp ${TMPDIR:-/tmp}/MV.XXXXXXX` +trap "rm -f ${tmpfile};" 0 1 2 3 15 + +cat > ${tmpfile} < +#include + +const char * +elftc_version(void) +{ + return "${elftcname} ${version} ${buildhost}${versionstring}"; +} +EOF + +if ! cmp -s ${tmpfile} ${versionfile}; then + echo "@ ${progname}: building \"${versionfile}\"." + cp ${tmpfile} ${versionfile} || exit ${?} +fi diff --git a/rtemstoolkit/elftoolchain/libelftc/os.FreeBSD.mk b/rtemstoolkit/elftoolchain/libelftc/os.FreeBSD.mk new file mode 100644 index 0000000..8079a5b --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/os.FreeBSD.mk @@ -0,0 +1,7 @@ +# +# Building for a FreeBSD target. +# +# $Id: os.freebsd.mk 189 2008-07-20 10:38:08Z jkoshy $ + +# Symbol versioning support [FreeBSD 7.X and later] +VERSION_MAP= ${.CURDIR}/Version.map diff --git a/rtemstoolkit/elftoolchain/libelftc/os.Linux.mk b/rtemstoolkit/elftoolchain/libelftc/os.Linux.mk new file mode 100644 index 0000000..d99117d --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/os.Linux.mk @@ -0,0 +1,3 @@ +# $Id: os.Linux.mk 3210 2015-05-17 13:40:49Z kaiwang27 $ + +CFLAGS+= -Wall -D_GNU_SOURCE diff --git a/rtemstoolkit/elftoolchain/libelftc/os.NetBSD.mk b/rtemstoolkit/elftoolchain/libelftc/os.NetBSD.mk new file mode 100644 index 0000000..ae214e3 --- /dev/null +++ b/rtemstoolkit/elftoolchain/libelftc/os.NetBSD.mk @@ -0,0 +1,2 @@ +# TODO(#511): Revert after the source tree is -Wconversion clean. +WARNS=5 diff --git a/rtemstoolkit/wscript b/rtemstoolkit/wscript index 4c30935..4b5fa34 100644 --- a/rtemstoolkit/wscript +++ b/rtemstoolkit/wscript @@ -170,6 +170,7 @@ def conf_elftoolchain(conf): def bld_elftoolchain(bld, conf): libelf = 'elftoolchain/libelf/' + libelftc = 'elftoolchain/libelftc/' libdwarf = 'elftoolchain/libdwarf/' libelf_m4_rule = '${M4} -D SRCDIR=../rtemstoolkit/' + libelf[:-1] + ' ${SRC} > ${TGT}' libdwarf_m4_rule = '${M4} -D SRCDIR=../rtemstoolkit/' + libdwarf[:-1] + ' ${SRC} > ${TGT}' @@ -334,6 +335,29 @@ def bld_elftoolchain(bld, conf): libdwarf + 'libdwarf_sections.c', libdwarf + 'libdwarf_str.c'] + libdwarf_m4_source) + bld.stlib(target = 'elftc', + features = 'c', + install_path = None, + includes = [bld.bldnode.abspath(), + 'elftoolchain/libelf', + 'elftoolchain/libelftc', + 'elftoolchain/common'] + includes, + cflags = conf['cflags'], + source =[libelftc + 'elftc_bfdtarget.c', + libelftc + 'elftc_copyfile.c', + libelftc + 'elftc_demangle.c', + libelftc + 'elftc_reloc_type_str.c', + libelftc + 'elftc_set_timestamps.c', + libelftc + 'elftc_string_table.c', + libelftc + 'elftc_timestamp.c', + libelftc + 'elftc_version.c', + libelftc + 'libelftc_bfdtarget.c', + libelftc + 'libelftc_dem_arm.c', + libelftc + 'libelftc_dem_gnu2.c', + libelftc + 'libelftc_dem_gnu3.c', + libelftc + 'libelftc_hash.c', + libelftc + 'libelftc_vstr.c']) + # # Libiberty module. # -- cgit v1.2.3