MFHead @ r275232
This commit is contained in:
commit
840e70929b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/building-blocks/; revision=275233
@ -48,7 +48,6 @@ cd(4) ken Pre-commit review requested.
|
|||||||
pass(4) ken Pre-commit review requested.
|
pass(4) ken Pre-commit review requested.
|
||||||
ch(4) ken Pre-commit review requested.
|
ch(4) ken Pre-commit review requested.
|
||||||
em(4) jfv Pre-commit review requested.
|
em(4) jfv Pre-commit review requested.
|
||||||
tdfx(4) cokane Just keep me informed of changes, try not to break it.
|
|
||||||
sendmail gshapiro Pre-commit review requested.
|
sendmail gshapiro Pre-commit review requested.
|
||||||
etc/mail gshapiro Pre-commit review requested.
|
etc/mail gshapiro Pre-commit review requested.
|
||||||
Keep in sync with -STABLE.
|
Keep in sync with -STABLE.
|
||||||
@ -118,7 +117,6 @@ lib/libc/stdtime edwin Heads-up appreciated, since parts of this code
|
|||||||
is maintained by a third party source.
|
is maintained by a third party source.
|
||||||
sbin/routed bms Pre-commit review; notify vendor at rhyolite.com
|
sbin/routed bms Pre-commit review; notify vendor at rhyolite.com
|
||||||
isci(4) jimharris Pre-commit review requested.
|
isci(4) jimharris Pre-commit review requested.
|
||||||
3dfx cokane Pre-commit review preferred.
|
|
||||||
cmx daniel@roe.ch Pre-commit review preferred.
|
cmx daniel@roe.ch Pre-commit review preferred.
|
||||||
filemon obrien Pre-commit review preferred.
|
filemon obrien Pre-commit review preferred.
|
||||||
sysdoc trhodes Pre-commit review preferred.
|
sysdoc trhodes Pre-commit review preferred.
|
||||||
|
@ -38,6 +38,12 @@
|
|||||||
# xargs -n1 | sort | uniq -d;
|
# xargs -n1 | sort | uniq -d;
|
||||||
# done
|
# done
|
||||||
|
|
||||||
|
# 20141126: convert sbin/mdconfig/tests to ATF format tests
|
||||||
|
OLD_FILES+=usr/tests/sbin/mdconfig/legacy_test
|
||||||
|
OLD_FILES+=usr/tests/sbin/mdconfig/mdconfig.test
|
||||||
|
OLD_FILES+=usr/tests/sbin/mdconfig/run.pl
|
||||||
|
# 20141126: remove xform_ipip decapsulation fallback
|
||||||
|
OLD_FILES+=usr/include/netipsec/ipip_var.h
|
||||||
# 20141109: faith/faithd removal
|
# 20141109: faith/faithd removal
|
||||||
OLD_FILES+=etc/rc.d/faith
|
OLD_FILES+=etc/rc.d/faith
|
||||||
OLD_FILES+=usr/share/man/man4/faith.4.gz
|
OLD_FILES+=usr/share/man/man4/faith.4.gz
|
||||||
@ -134,10 +140,12 @@ OLD_FILES+=usr/include/readline/chardefs.h
|
|||||||
OLD_FILES+=usr/include/readline/history.h
|
OLD_FILES+=usr/include/readline/history.h
|
||||||
OLD_FILES+=usr/include/readline/keymaps.h
|
OLD_FILES+=usr/include/readline/keymaps.h
|
||||||
OLD_FILES+=usr/include/readline/readline.h
|
OLD_FILES+=usr/include/readline/readline.h
|
||||||
|
OLD_FILES+=usr/include/readline/tilde.h
|
||||||
OLD_FILES+=usr/include/readline/rlconf.h
|
OLD_FILES+=usr/include/readline/rlconf.h
|
||||||
OLD_FILES+=usr/include/readline/rlstdc.h
|
OLD_FILES+=usr/include/readline/rlstdc.h
|
||||||
OLD_FILES+=usr/include/readline/rltypedefs.h
|
OLD_FILES+=usr/include/readline/rltypedefs.h
|
||||||
OLD_FILES+=usr/include/readline/rltypedefs.h
|
OLD_FILES+=usr/include/readline/rltypedefs.h
|
||||||
|
OLD_DIRS+=usr/include/readline
|
||||||
OLD_FILES+=usr/share/info/readline.info.gz
|
OLD_FILES+=usr/share/info/readline.info.gz
|
||||||
OLD_FILES+=usr/share/man/man3/readline.3.gz
|
OLD_FILES+=usr/share/man/man3/readline.3.gz
|
||||||
# 20140625: csup removal
|
# 20140625: csup removal
|
||||||
|
@ -40,8 +40,7 @@ MLINKS= csh.1 tcsh.1
|
|||||||
# utilities of the same name are handled with the associated manpage,
|
# utilities of the same name are handled with the associated manpage,
|
||||||
# builtin.1 in share/man/man1/.
|
# builtin.1 in share/man/man1/.
|
||||||
|
|
||||||
DPADD= ${LIBTERMCAPW} ${LIBCRYPT}
|
LIBADD= termcapw crypt
|
||||||
LDADD= -ltermcapw -lcrypt
|
|
||||||
|
|
||||||
LINKS= ${BINDIR}/csh ${BINDIR}/tcsh
|
LINKS= ${BINDIR}/csh ${BINDIR}/tcsh
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ SRCS= df.c vfslist.c
|
|||||||
|
|
||||||
CFLAGS+= -I${MOUNT}
|
CFLAGS+= -I${MOUNT}
|
||||||
|
|
||||||
DPADD= ${LIBUTIL} ${LIBXO}
|
LIBADD= xo util
|
||||||
LDADD= -lutil -lxo
|
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
.include <bsd.prog.mk>
|
||||||
|
@ -9,8 +9,7 @@ MLINKS= ed.1 red.1
|
|||||||
|
|
||||||
.if ${MK_OPENSSL} != "no" && ${MK_ED_CRYPTO} != "no"
|
.if ${MK_OPENSSL} != "no" && ${MK_ED_CRYPTO} != "no"
|
||||||
CFLAGS+=-DDES
|
CFLAGS+=-DDES
|
||||||
DPADD= ${LIBCRYPTO}
|
LIBADD= crypto
|
||||||
LDADD= -lcrypto
|
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
.include <bsd.prog.mk>
|
||||||
|
@ -5,14 +5,12 @@
|
|||||||
|
|
||||||
PROG= ls
|
PROG= ls
|
||||||
SRCS= cmp.c ls.c print.c util.c
|
SRCS= cmp.c ls.c print.c util.c
|
||||||
DPADD= ${LIBUTIL}
|
LIBADD= util
|
||||||
LDADD= -lutil
|
|
||||||
|
|
||||||
.if !defined(RELEASE_CRUNCH) && \
|
.if !defined(RELEASE_CRUNCH) && \
|
||||||
${MK_LS_COLORS} != no
|
${MK_LS_COLORS} != no
|
||||||
CFLAGS+= -DCOLORLS
|
CFLAGS+= -DCOLORLS
|
||||||
DPADD+= ${LIBTERMCAPW}
|
LIBADD+= termcapw
|
||||||
LDADD+= -ltermcapw
|
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
.include <bsd.prog.mk>
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
|
|
||||||
PROG= pkill
|
PROG= pkill
|
||||||
|
|
||||||
DPADD= ${LIBKVM}
|
LIBADD= kvm
|
||||||
LDADD= -lkvm
|
|
||||||
|
|
||||||
LINKS= ${BINDIR}/pkill ${BINDIR}/pgrep
|
LINKS= ${BINDIR}/pkill ${BINDIR}/pgrep
|
||||||
MLINKS= pkill.1 pgrep.1
|
MLINKS= pkill.1 pgrep.1
|
||||||
|
@ -11,7 +11,6 @@ SRCS= fmt.c keyword.c nlist.c print.c ps.c
|
|||||||
# on large systems.
|
# on large systems.
|
||||||
#
|
#
|
||||||
CFLAGS+=-DLAZY_PS
|
CFLAGS+=-DLAZY_PS
|
||||||
DPADD= ${LIBM} ${LIBKVM} ${LIBJAIL}
|
LIBADD= m kvm jail
|
||||||
LDADD= -lm -lkvm -ljail
|
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
.include <bsd.prog.mk>
|
||||||
|
@ -14,11 +14,7 @@ MAN= rmail.8
|
|||||||
WARNS?= 2
|
WARNS?= 2
|
||||||
CFLAGS+=-I${SENDMAIL_DIR}/include -I.
|
CFLAGS+=-I${SENDMAIL_DIR}/include -I.
|
||||||
|
|
||||||
LIBSMDIR= ${.OBJDIR}/../../lib/libsm
|
LIBADD= sm
|
||||||
LIBSM= ${LIBSMDIR}/libsm.a
|
|
||||||
|
|
||||||
DPADD= ${LIBSM}
|
|
||||||
LDADD= ${LIBSM}
|
|
||||||
|
|
||||||
SRCS+= sm_os.h
|
SRCS+= sm_os.h
|
||||||
CLEANFILES+=sm_os.h
|
CLEANFILES+=sm_os.h
|
||||||
|
@ -18,8 +18,7 @@ SRCS= ${SHSRCS} ${GENSRCS} ${GENHDRS}
|
|||||||
# utilities of the same name are handled with the associated manpage,
|
# utilities of the same name are handled with the associated manpage,
|
||||||
# builtin.1 in share/man/man1/.
|
# builtin.1 in share/man/man1/.
|
||||||
|
|
||||||
DPADD= ${LIBEDIT} ${LIBTERMCAPW}
|
LIBADD= edit
|
||||||
LDADD= -ledit -ltermcapw
|
|
||||||
|
|
||||||
CFLAGS+=-DSHELL -I. -I${.CURDIR}
|
CFLAGS+=-DSHELL -I. -I${.CURDIR}
|
||||||
# for debug:
|
# for debug:
|
||||||
|
@ -1211,13 +1211,13 @@ dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat)
|
|||||||
#if defined(__FreeBSD__)
|
#if defined(__FreeBSD__)
|
||||||
if (sh.sh_size == 0)
|
if (sh.sh_size == 0)
|
||||||
continue;
|
continue;
|
||||||
if (is_elf_obj && (sh.sh_type == SHT_PROGBITS ||
|
if (sh.sh_type == SHT_PROGBITS || sh.sh_type == SHT_NOBITS) {
|
||||||
sh.sh_type == SHT_NOBITS)) {
|
|
||||||
alignmask = sh.sh_addralign - 1;
|
alignmask = sh.sh_addralign - 1;
|
||||||
mapbase += alignmask;
|
mapbase += alignmask;
|
||||||
mapbase &= ~alignmask;
|
mapbase &= ~alignmask;
|
||||||
sh.sh_addr = mapbase;
|
sh.sh_addr = mapbase;
|
||||||
dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr;
|
if (is_elf_obj)
|
||||||
|
dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr;
|
||||||
mapbase += sh.sh_size;
|
mapbase += sh.sh_size;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -545,8 +545,9 @@ dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
|
|||||||
|
|
||||||
for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) {
|
for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) {
|
||||||
if (strcmp(pip->pi_fname, fname) == 0 &&
|
if (strcmp(pip->pi_fname, fname) == 0 &&
|
||||||
((rname == NULL && pip->pi_rname[0] == '\0') ||
|
((rname == NULL && pip->pi_rname == NULL) ||
|
||||||
(rname != NULL && strcmp(pip->pi_rname, rname)) == 0))
|
(rname != NULL && pip->pi_rname != NULL &&
|
||||||
|
strcmp(pip->pi_rname, rname) == 0)))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
contrib/elftoolchain/addr2line/Makefile
Normal file
15
contrib/elftoolchain/addr2line/Makefile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# $Id: Makefile 2066 2011-10-26 15:40:28Z jkoshy $
|
||||||
|
|
||||||
|
TOP= ..
|
||||||
|
|
||||||
|
PROG= addr2line
|
||||||
|
SRCS= addr2line.c
|
||||||
|
|
||||||
|
WARNS?= 6
|
||||||
|
|
||||||
|
DPADD= ${LIBELF} ${LIBELFTC} ${LIBDWARF}
|
||||||
|
LDADD= -lelftc -ldwarf -lelf
|
||||||
|
|
||||||
|
MAN1= addr2line.1
|
||||||
|
|
||||||
|
.include "${TOP}/mk/elftoolchain.prog.mk"
|
159
contrib/elftoolchain/addr2line/addr2line.1
Normal file
159
contrib/elftoolchain/addr2line/addr2line.1
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
.\" Copyright (c) 2009,2010 Joseph Koshy <jkoshy@users.sourceforge.net>
|
||||||
|
.\" 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: addr2line.1 2066 2011-10-26 15:40:28Z jkoshy $
|
||||||
|
.\"
|
||||||
|
.Dd July 25, 2010
|
||||||
|
.Os
|
||||||
|
.Dt ADDR2LINE 1
|
||||||
|
.Sh NAME
|
||||||
|
.Nm addr2line
|
||||||
|
.Nd translate program addresses to source file names and line numbers
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl b Ar target | Fl -target Ns = Ns Ar target
|
||||||
|
.Op Fl e Ar pathname | Fl -exe Ns = Ns Ar pathname
|
||||||
|
.Op Fl f | Fl -functions
|
||||||
|
.Op Fl j Ar sectionname | Fl -section Ns = Ns Ar sectionname
|
||||||
|
.Op Fl s | Fl -basename
|
||||||
|
.Op Fl C | Fl -demangle
|
||||||
|
.Op Fl H | Fl -help
|
||||||
|
.Op Fl V | Fl -version
|
||||||
|
.Op Ar hexaddress Ns ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility translates program addresses specified by the command line
|
||||||
|
arguments
|
||||||
|
.Ar hexaddress
|
||||||
|
to their corresponding source file names and line numbers.
|
||||||
|
If no arguments are given to
|
||||||
|
.Nm ,
|
||||||
|
it will read these addresses from standard input.
|
||||||
|
.Pp
|
||||||
|
Program addresses specified by arguments
|
||||||
|
.Ar hexaddress
|
||||||
|
are encoded using the conventions accepted by
|
||||||
|
.Xr strtoull 3 .
|
||||||
|
.Pp
|
||||||
|
By default,
|
||||||
|
.Nm
|
||||||
|
will use the executable
|
||||||
|
.Dq Pa a.out .
|
||||||
|
The
|
||||||
|
.Fl e
|
||||||
|
option may be used to specified a different ELF object.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility recognizes the following options:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl b Ar target | Fl -target Ns = Ns Ar target
|
||||||
|
This option is recognized by
|
||||||
|
.Nm
|
||||||
|
but is ignored.
|
||||||
|
It is supported for compatibility with GNU binutils.
|
||||||
|
.It Fl e Ar pathname | Fl -exe Ns = Ns Ar pathname
|
||||||
|
Use the ELF object specified by argument
|
||||||
|
.Ar pathname
|
||||||
|
to translate addresses.
|
||||||
|
If this option is not specified,
|
||||||
|
.Nm
|
||||||
|
will use the file
|
||||||
|
.Dq Pa a.out .
|
||||||
|
.It Fl f | Fl -functions
|
||||||
|
Display function names in addition to file and line number information.
|
||||||
|
.It Fl j Ar sectionname | Fl -section Ns = Ns Ar sectionname
|
||||||
|
The values specified by arguments
|
||||||
|
.Ar hexaddress
|
||||||
|
are to be treated as offsets into the section named
|
||||||
|
.Ar sectionname .
|
||||||
|
.It Fl s | -basename
|
||||||
|
Display only the base name for each file name.
|
||||||
|
.It Fl C | Fl -demangle
|
||||||
|
Demangle C++ names.
|
||||||
|
.It Fl H | Fl -help
|
||||||
|
Print a help message.
|
||||||
|
.It Fl V | Fl -version
|
||||||
|
Print a version identifier and exit.
|
||||||
|
.El
|
||||||
|
.Sh OUTPUT FORMAT
|
||||||
|
If the
|
||||||
|
.Fl f
|
||||||
|
option was not specified,
|
||||||
|
.Nm
|
||||||
|
will print the file name and line number for each address specified
|
||||||
|
on a separate line.
|
||||||
|
.Pp
|
||||||
|
If the
|
||||||
|
.Fl f
|
||||||
|
option was specified,
|
||||||
|
.Nm
|
||||||
|
will print a line containing the name of the function corresponding
|
||||||
|
to program address
|
||||||
|
.Ar hexaddress ,
|
||||||
|
followed by a line with the file name and line number.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility prints the file name and line number using the format
|
||||||
|
.Dq FILENAME:LINENUMBER .
|
||||||
|
.Pp
|
||||||
|
If a file or function name could not be determined,
|
||||||
|
.Nm
|
||||||
|
will print a question mark in their place.
|
||||||
|
If the line number could not be determined,
|
||||||
|
.Nm
|
||||||
|
will print a zero in its place.
|
||||||
|
.Sh EXAMPLES
|
||||||
|
To map address 080483c4 in the default executable
|
||||||
|
.Pa a.out
|
||||||
|
to a source file name and line number use:
|
||||||
|
.D1 "% addr2line 080483c4"
|
||||||
|
.Pp
|
||||||
|
To map address 080483c4 in executable
|
||||||
|
.Pa helloworld ,
|
||||||
|
use:
|
||||||
|
.D1 "% addr2line -e helloworld 080483c4"
|
||||||
|
.Pp
|
||||||
|
To have
|
||||||
|
.Nm
|
||||||
|
act as a filter reading addresses from its standard input use:
|
||||||
|
.D1 "% addr2line"
|
||||||
|
.Pp
|
||||||
|
To print the function name corresponding to an address in addition to
|
||||||
|
its source file and line number use:
|
||||||
|
.D1 "% addr2line -f 080483c4"
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Ex -std
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr nm 1 ,
|
||||||
|
.Xr elfdump 1 ,
|
||||||
|
.Xr elfcopy 1 ,
|
||||||
|
.Xr strtoull 3
|
||||||
|
.Sh AUTHORS
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility was written by
|
||||||
|
.An "Kai Wang" Aq kaiwang27@users.sourceforge.net .
|
410
contrib/elftoolchain/addr2line/addr2line.c
Normal file
410
contrib/elftoolchain/addr2line/addr2line.c
Normal file
@ -0,0 +1,410 @@
|
|||||||
|
/*-
|
||||||
|
* 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.
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <dwarf.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <gelf.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <libdwarf.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "_elftc.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: addr2line.c 2185 2011-11-19 16:07:16Z jkoshy $");
|
||||||
|
|
||||||
|
static struct option longopts[] = {
|
||||||
|
{"target" , required_argument, NULL, 'b'},
|
||||||
|
{"demangle", no_argument, NULL, 'C'},
|
||||||
|
{"exe", required_argument, NULL, 'e'},
|
||||||
|
{"functions", no_argument, NULL, 'f'},
|
||||||
|
{"section", required_argument, NULL, 'j'},
|
||||||
|
{"basename", no_argument, NULL, 's'},
|
||||||
|
{"help", no_argument, NULL, 'H'},
|
||||||
|
{"version", no_argument, NULL, 'V'},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
static int demangle, func, base;
|
||||||
|
static char unknown[] = { '?', '?', '\0' };
|
||||||
|
static Dwarf_Addr section_base;
|
||||||
|
|
||||||
|
#define USAGE_MESSAGE "\
|
||||||
|
Usage: %s [options] hexaddress...\n\
|
||||||
|
Map program addresses to source file names and line numbers.\n\n\
|
||||||
|
Options:\n\
|
||||||
|
-b TGT | --target=TGT (Accepted but ignored).\n\
|
||||||
|
-e EXE | --exec=EXE Use program \"EXE\" to translate addresses.\n\
|
||||||
|
-f | --functions Display function names.\n\
|
||||||
|
-j NAME | --section=NAME Values are offsets into section \"NAME\".\n\
|
||||||
|
-s | --basename Only show the base name for each file name.\n\
|
||||||
|
-C | --demangle Demangle C++ names.\n\
|
||||||
|
-H | --help Print a help message.\n\
|
||||||
|
-V | --version Print a version identifier and exit.\n"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
version(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
search_func(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr addr,
|
||||||
|
const char **rlt_func)
|
||||||
|
{
|
||||||
|
Dwarf_Die ret_die, spec_die;
|
||||||
|
Dwarf_Error de;
|
||||||
|
Dwarf_Half tag;
|
||||||
|
Dwarf_Unsigned lopc, hipc;
|
||||||
|
Dwarf_Off ref;
|
||||||
|
Dwarf_Attribute sub_at, spec_at;
|
||||||
|
char *func0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (*rlt_func != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (dwarf_tag(die, &tag, &de)) {
|
||||||
|
warnx("dwarf_tag: %s", dwarf_errmsg(de));
|
||||||
|
goto cont_search;
|
||||||
|
}
|
||||||
|
if (tag == DW_TAG_subprogram) {
|
||||||
|
if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ||
|
||||||
|
dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de))
|
||||||
|
goto cont_search;
|
||||||
|
if (addr < lopc || addr >= hipc)
|
||||||
|
goto cont_search;
|
||||||
|
|
||||||
|
/* Found it! */
|
||||||
|
|
||||||
|
*rlt_func = unknown;
|
||||||
|
ret = dwarf_attr(die, DW_AT_name, &sub_at, &de);
|
||||||
|
if (ret == DW_DLV_ERROR)
|
||||||
|
return;
|
||||||
|
if (ret == DW_DLV_OK) {
|
||||||
|
if (dwarf_formstring(sub_at, &func0, &de))
|
||||||
|
*rlt_func = unknown;
|
||||||
|
else
|
||||||
|
*rlt_func = func0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If DW_AT_name is not present, but DW_AT_specification is
|
||||||
|
* present, then probably the actual name is in the DIE
|
||||||
|
* referenced by DW_AT_specification.
|
||||||
|
*/
|
||||||
|
if (dwarf_attr(die, DW_AT_specification, &spec_at, &de))
|
||||||
|
return;
|
||||||
|
if (dwarf_global_formref(spec_at, &ref, &de))
|
||||||
|
return;
|
||||||
|
if (dwarf_offdie(dbg, ref, &spec_die, &de))
|
||||||
|
return;
|
||||||
|
if (dwarf_attrval_string(spec_die, DW_AT_name, rlt_func, &de))
|
||||||
|
*rlt_func = unknown;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cont_search:
|
||||||
|
|
||||||
|
/* Search children. */
|
||||||
|
ret = dwarf_child(die, &ret_die, &de);
|
||||||
|
if (ret == DW_DLV_ERROR)
|
||||||
|
errx(EXIT_FAILURE, "dwarf_child: %s", dwarf_errmsg(de));
|
||||||
|
else if (ret == DW_DLV_OK)
|
||||||
|
search_func(dbg, ret_die, addr, rlt_func);
|
||||||
|
|
||||||
|
/* Search sibling. */
|
||||||
|
ret = dwarf_siblingof(dbg, die, &ret_die, &de);
|
||||||
|
if (ret == DW_DLV_ERROR)
|
||||||
|
errx(EXIT_FAILURE, "dwarf_siblingof: %s", dwarf_errmsg(de));
|
||||||
|
else if (ret == DW_DLV_OK)
|
||||||
|
search_func(dbg, ret_die, addr, rlt_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
translate(Dwarf_Debug dbg, const char* addrstr)
|
||||||
|
{
|
||||||
|
Dwarf_Die die;
|
||||||
|
Dwarf_Line *lbuf;
|
||||||
|
Dwarf_Error de;
|
||||||
|
Dwarf_Half tag;
|
||||||
|
Dwarf_Unsigned lopc, hipc, addr, lineno, plineno;
|
||||||
|
Dwarf_Signed lcount;
|
||||||
|
Dwarf_Addr lineaddr, plineaddr;
|
||||||
|
const char *funcname;
|
||||||
|
char *file, *file0, *pfile;
|
||||||
|
char demangled[1024];
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
addr = strtoull(addrstr, NULL, 16);
|
||||||
|
addr += section_base;
|
||||||
|
lineno = 0;
|
||||||
|
file = unknown;
|
||||||
|
|
||||||
|
while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
&de)) == DW_DLV_OK) {
|
||||||
|
die = NULL;
|
||||||
|
while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) {
|
||||||
|
if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
|
||||||
|
warnx("dwarf_tag failed: %s",
|
||||||
|
dwarf_errmsg(de));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* XXX: What about DW_TAG_partial_unit? */
|
||||||
|
if (tag == DW_TAG_compile_unit)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (die == NULL) {
|
||||||
|
warnx("could not find DW_TAG_compile_unit die");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) &&
|
||||||
|
!dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) {
|
||||||
|
/*
|
||||||
|
* Check if the address falls into the PC range of
|
||||||
|
* this CU.
|
||||||
|
*/
|
||||||
|
if (addr < lopc || addr >= hipc)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dwarf_srclines(die, &lbuf, &lcount, &de) != DW_DLV_OK) {
|
||||||
|
warnx("dwarf_srclines: %s", dwarf_errmsg(de));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
plineaddr = ~0ULL;
|
||||||
|
plineno = 0;
|
||||||
|
pfile = unknown;
|
||||||
|
for (i = 0; i < lcount; i++) {
|
||||||
|
if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) {
|
||||||
|
warnx("dwarf_lineaddr: %s",
|
||||||
|
dwarf_errmsg(de));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (dwarf_lineno(lbuf[i], &lineno, &de)) {
|
||||||
|
warnx("dwarf_lineno: %s",
|
||||||
|
dwarf_errmsg(de));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (dwarf_linesrc(lbuf[i], &file0, &de)) {
|
||||||
|
warnx("dwarf_linesrc: %s",
|
||||||
|
dwarf_errmsg(de));
|
||||||
|
} else
|
||||||
|
file = file0;
|
||||||
|
if (addr == lineaddr)
|
||||||
|
goto out;
|
||||||
|
else if (addr < lineaddr && addr > plineaddr) {
|
||||||
|
lineno = plineno;
|
||||||
|
file = pfile;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
plineaddr = lineaddr;
|
||||||
|
plineno = lineno;
|
||||||
|
pfile = file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
funcname = NULL;
|
||||||
|
if (ret == DW_DLV_OK && func)
|
||||||
|
search_func(dbg, die, addr, &funcname);
|
||||||
|
|
||||||
|
if (func) {
|
||||||
|
if (funcname == NULL)
|
||||||
|
funcname = unknown;
|
||||||
|
if (demangle &&
|
||||||
|
!elftc_demangle(funcname, demangled, sizeof(demangled), 0))
|
||||||
|
printf("%s\n", demangled);
|
||||||
|
else
|
||||||
|
printf("%s\n", funcname);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) printf("%s:%ju\n", base ? basename(file) : file, lineno);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset internal CU pointer, so we will start from the first CU
|
||||||
|
* next round.
|
||||||
|
*/
|
||||||
|
while (ret != DW_DLV_NO_ENTRY) {
|
||||||
|
if (ret == DW_DLV_ERROR)
|
||||||
|
errx(EXIT_FAILURE, "dwarf_next_cu_header: %s",
|
||||||
|
dwarf_errmsg(de));
|
||||||
|
ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
&de);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
find_section_base(const char *exe, Elf *e, const char *section)
|
||||||
|
{
|
||||||
|
Dwarf_Addr off;
|
||||||
|
Elf_Scn *scn;
|
||||||
|
GElf_Ehdr eh;
|
||||||
|
GElf_Shdr sh;
|
||||||
|
size_t shstrndx;
|
||||||
|
int elferr;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (gelf_getehdr(e, &eh) != &eh) {
|
||||||
|
warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!elf_getshstrndx(e, &shstrndx)) {
|
||||||
|
warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) elf_errno();
|
||||||
|
off = 0;
|
||||||
|
scn = NULL;
|
||||||
|
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||||
|
if (gelf_getshdr(scn, &sh) == NULL) {
|
||||||
|
warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL)
|
||||||
|
goto next;
|
||||||
|
if (!strcmp(section, name)) {
|
||||||
|
if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) {
|
||||||
|
/*
|
||||||
|
* For executables, section base is the virtual
|
||||||
|
* address of the specified section.
|
||||||
|
*/
|
||||||
|
section_base = sh.sh_addr;
|
||||||
|
} else if (eh.e_type == ET_REL) {
|
||||||
|
/*
|
||||||
|
* For relocatables, section base is the
|
||||||
|
* relative offset of the specified section
|
||||||
|
* to the start of the first section.
|
||||||
|
*/
|
||||||
|
section_base = off;
|
||||||
|
} else
|
||||||
|
warnx("unknown e_type %u", eh.e_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
next:
|
||||||
|
off += sh.sh_size;
|
||||||
|
}
|
||||||
|
elferr = elf_errno();
|
||||||
|
if (elferr != 0)
|
||||||
|
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
|
||||||
|
|
||||||
|
errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
Elf *e;
|
||||||
|
Dwarf_Debug dbg;
|
||||||
|
Dwarf_Error de;
|
||||||
|
const char *exe, *section;
|
||||||
|
char line[1024];
|
||||||
|
int fd, i, opt;
|
||||||
|
|
||||||
|
exe = NULL;
|
||||||
|
section = NULL;
|
||||||
|
while ((opt = getopt_long(argc, argv, "b:Ce:fj:sHV", longopts, NULL)) !=
|
||||||
|
-1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'b':
|
||||||
|
/* ignored */
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
demangle = 1;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
exe = optarg;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
func = 1;
|
||||||
|
break;
|
||||||
|
case 'j':
|
||||||
|
section = optarg;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
base = 1;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
usage();
|
||||||
|
case 'V':
|
||||||
|
version();
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argv += optind;
|
||||||
|
argc -= optind;
|
||||||
|
|
||||||
|
if (exe == NULL)
|
||||||
|
exe = "a.out";
|
||||||
|
|
||||||
|
if ((fd = open(exe, O_RDONLY)) < 0)
|
||||||
|
err(EXIT_FAILURE, "%s", exe);
|
||||||
|
|
||||||
|
if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de))
|
||||||
|
errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de));
|
||||||
|
|
||||||
|
if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK)
|
||||||
|
errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de));
|
||||||
|
|
||||||
|
if (section)
|
||||||
|
find_section_base(exe, e, section);
|
||||||
|
else
|
||||||
|
section_base = 0;
|
||||||
|
|
||||||
|
if (argc > 0)
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
translate(dbg, argv[i]);
|
||||||
|
else
|
||||||
|
while (fgets(line, sizeof(line), stdin) != NULL)
|
||||||
|
translate(dbg, line);
|
||||||
|
|
||||||
|
dwarf_finish(dbg, &de);
|
||||||
|
|
||||||
|
(void) elf_end(e);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
15
contrib/elftoolchain/cxxfilt/Makefile
Normal file
15
contrib/elftoolchain/cxxfilt/Makefile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# $Id: Makefile 2066 2011-10-26 15:40:28Z jkoshy $
|
||||||
|
|
||||||
|
TOP= ..
|
||||||
|
|
||||||
|
PROG= c++filt
|
||||||
|
SRCS= cxxfilt.c
|
||||||
|
|
||||||
|
WARNS?= 6
|
||||||
|
|
||||||
|
DPADD= ${LIBELFTC} ${LIBELF}
|
||||||
|
LDADD= -lelftc -lelf
|
||||||
|
|
||||||
|
MAN1= c++filt.1
|
||||||
|
|
||||||
|
.include "${TOP}/mk/elftoolchain.prog.mk"
|
109
contrib/elftoolchain/cxxfilt/c++filt.1
Normal file
109
contrib/elftoolchain/cxxfilt/c++filt.1
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
.\" Copyright (c) 2009-2011 Joseph Koshy <jkoshy@users.sourceforge.net>
|
||||||
|
.\" 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: c++filt.1 2175 2011-11-16 05:51:49Z jkoshy $
|
||||||
|
.\"
|
||||||
|
.Dd August 24, 2011
|
||||||
|
.Os
|
||||||
|
.Dt C++FILT 1
|
||||||
|
.Sh NAME
|
||||||
|
.Nm c++filt
|
||||||
|
.Nd decode C++ symbols
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl -help
|
||||||
|
.Op Fl _ | Fl -strip-underscores
|
||||||
|
.Op Fl n | Fl -no-strip-underscores
|
||||||
|
.Op Fl p | Fl -no-params
|
||||||
|
.Op Fl s Ar scheme | Fl -format Ns = Ns Ar scheme
|
||||||
|
.Op Fl V | Fl -version
|
||||||
|
.Op Ar encoded-names ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility translates encoded C++ symbol names to human-readable form.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility has two operating modes.
|
||||||
|
.Bl -bullet
|
||||||
|
.It
|
||||||
|
If arguments
|
||||||
|
.Ar encoded-names
|
||||||
|
are not specified, then
|
||||||
|
.Nm
|
||||||
|
will act as a filter, reading from standard input
|
||||||
|
and writing to standard output.
|
||||||
|
.It
|
||||||
|
If arguments
|
||||||
|
.Ar encoded-names
|
||||||
|
are specified, then
|
||||||
|
.Nm
|
||||||
|
will decode each such argument in turn, writing its decoded form
|
||||||
|
to standard output.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility recognizes the following options:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl -help
|
||||||
|
Print a help message and exit.
|
||||||
|
.It Fl _ | Fl -strip-underscores
|
||||||
|
Remove a leading underscore from symbol names prior to decoding them.
|
||||||
|
.It Fl n | Fl -no-strip-underscores
|
||||||
|
Do not remove leading underscores from names.
|
||||||
|
.It Fl p | Fl -no-params
|
||||||
|
This option is recognized but ignored.
|
||||||
|
.It Fl s Ar scheme | Fl -format Ns = Ns Ar scheme
|
||||||
|
Select the encoding scheme to use.
|
||||||
|
Argument
|
||||||
|
.Ar scheme
|
||||||
|
can be one of the following:
|
||||||
|
.Bl -tag -width "gnu-v5"
|
||||||
|
.It Ar arm
|
||||||
|
Use the encoding scheme specified by the C++ Annotated Reference Manual.
|
||||||
|
.It Ar auto
|
||||||
|
Guess the encoding scheme from the input.
|
||||||
|
.It Ar gnu
|
||||||
|
Use the encoding scheme used by the GNU C++ compiler.
|
||||||
|
.It Ar gnu-v3
|
||||||
|
Use the encoding scheme used by the GNU C++ compiler, version 3.
|
||||||
|
.El
|
||||||
|
.It Fl V | Fl -version
|
||||||
|
Print a version identifier for
|
||||||
|
.Nm
|
||||||
|
and exit.
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Ex -std
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr nm 1 ,
|
||||||
|
.Xr strip 1 ,
|
||||||
|
.Xr elftc_demangle 3
|
||||||
|
.Sh AUTHORS
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility was written by
|
||||||
|
.An "Kai Wang" Aq kaiwang27@users.sourceforge.net .
|
224
contrib/elftoolchain/cxxfilt/cxxfilt.c
Normal file
224
contrib/elftoolchain/cxxfilt/cxxfilt.c
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
/*-
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "_elftc.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: cxxfilt.c 2185 2011-11-19 16:07:16Z jkoshy $");
|
||||||
|
|
||||||
|
#define STRBUFSZ 8192
|
||||||
|
|
||||||
|
static int stripus = 0;
|
||||||
|
static int noparam = 0;
|
||||||
|
static int format = 0;
|
||||||
|
|
||||||
|
enum options
|
||||||
|
{
|
||||||
|
OPTION_HELP,
|
||||||
|
OPTION_VERSION
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct option longopts[] =
|
||||||
|
{
|
||||||
|
{"format", required_argument, NULL, 's'},
|
||||||
|
{"help", no_argument, NULL, OPTION_HELP},
|
||||||
|
{"no-params", no_argument, NULL, 'p'},
|
||||||
|
{"no-strip-underscores", no_argument, NULL, 'n'},
|
||||||
|
{"strip-underscores", no_argument, NULL, '_'},
|
||||||
|
{"version", no_argument, NULL, 'V'},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char *fname;
|
||||||
|
int fvalue;
|
||||||
|
} flist[] = {
|
||||||
|
{"auto", 0},
|
||||||
|
{"arm", ELFTC_DEM_ARM},
|
||||||
|
{"gnu", ELFTC_DEM_GNU2},
|
||||||
|
{"gnu-v3", ELFTC_DEM_GNU3}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define USAGE_MESSAGE "\
|
||||||
|
Usage: %s [options] [encoded-names...]\n\
|
||||||
|
Translate C++ symbol names to human-readable form.\n\n\
|
||||||
|
Options:\n\
|
||||||
|
-_ | --strip-underscores Remove leading underscores prior to decoding.\n\
|
||||||
|
-n | --no-strip-underscores Do not remove leading underscores.\n\
|
||||||
|
-p | --no-params (Accepted but ignored).\n\
|
||||||
|
-s SCHEME | --format=SCHEME Select the encoding scheme to use.\n\
|
||||||
|
Valid schemes are: 'arm', 'auto', 'gnu' and\n\
|
||||||
|
'gnu-v3'.\n\
|
||||||
|
--help Print a help message.\n\
|
||||||
|
--version Print a version identifier and exit.\n"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
version(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
find_format(const char *fstr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; (size_t) i < sizeof(flist) / sizeof(flist[0]); i++) {
|
||||||
|
if (!strcmp(fstr, flist[i].fname))
|
||||||
|
return (flist[i].fvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
demangle(char *name, int strict, int *pos)
|
||||||
|
{
|
||||||
|
static char dem[STRBUFSZ];
|
||||||
|
char nb[STRBUFSZ];
|
||||||
|
int p, t;
|
||||||
|
|
||||||
|
if (stripus && *name == '_') {
|
||||||
|
strncpy(nb, name + 1, sizeof(nb) - 1);
|
||||||
|
t = 1;
|
||||||
|
} else {
|
||||||
|
strncpy(nb, name, sizeof(nb) - 1);
|
||||||
|
t = 0;
|
||||||
|
}
|
||||||
|
nb[sizeof(nb) - 1] = '\0';
|
||||||
|
|
||||||
|
p = strlen(nb);
|
||||||
|
if (p <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (elftc_demangle(nb, dem, sizeof(dem), format) < 0) {
|
||||||
|
if (!strict && p > 1) {
|
||||||
|
nb[--p] = '\0';
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos != NULL)
|
||||||
|
*pos = t ? p + 1 : p;
|
||||||
|
|
||||||
|
return (dem);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *dem, buf[STRBUFSZ];
|
||||||
|
int c, i, p, s, opt;
|
||||||
|
|
||||||
|
while ((opt = getopt_long(argc, argv, "_nps:V", longopts, NULL)) !=
|
||||||
|
-1) {
|
||||||
|
switch (opt) {
|
||||||
|
case '_':
|
||||||
|
stripus = 1;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
stripus = 0;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
noparam = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if ((format = find_format(optarg)) < 0)
|
||||||
|
errx(EXIT_FAILURE, "unsupported format: %s",
|
||||||
|
optarg);
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
version();
|
||||||
|
/* NOT REACHED */
|
||||||
|
case OPTION_HELP:
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
/* NOT REACHED */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argv += optind;
|
||||||
|
argc -= optind;
|
||||||
|
|
||||||
|
if (*argv != NULL) {
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
if ((dem = demangle(argv[i], 1, NULL)) == NULL)
|
||||||
|
fprintf(stderr, "Failed: %s\n", argv[i]);
|
||||||
|
else
|
||||||
|
printf("%s\n", dem);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p = 0;
|
||||||
|
for (;;) {
|
||||||
|
c = fgetc(stdin);
|
||||||
|
if (c == EOF || !isprint(c) || strchr(" \t\n", c)) {
|
||||||
|
if (p > 0) {
|
||||||
|
buf[p] = '\0';
|
||||||
|
if ((dem = demangle(buf, 0, &s)) ==
|
||||||
|
NULL)
|
||||||
|
printf("%s", buf);
|
||||||
|
else {
|
||||||
|
printf("%s", dem);
|
||||||
|
for (i = s; i < p; i++)
|
||||||
|
putchar(buf[i]);
|
||||||
|
}
|
||||||
|
p = 0;
|
||||||
|
}
|
||||||
|
if (c == EOF)
|
||||||
|
break;
|
||||||
|
if (isprint(c) || strchr(" \t\n", c))
|
||||||
|
putchar(c);
|
||||||
|
} else {
|
||||||
|
if ((size_t) p >= sizeof(buf) - 1)
|
||||||
|
warnx("buffer overflowed");
|
||||||
|
else
|
||||||
|
buf[p++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
41
contrib/elftoolchain/elfcopy/Makefile
Normal file
41
contrib/elftoolchain/elfcopy/Makefile
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# $Id: Makefile 2290 2011-12-04 07:20:46Z jkoshy $
|
||||||
|
|
||||||
|
TOP= ..
|
||||||
|
|
||||||
|
PROG= elfcopy
|
||||||
|
|
||||||
|
SRCS= archive.c ascii.c binary.c main.c sections.c segments.c symbols.c
|
||||||
|
|
||||||
|
WARNS?= 5
|
||||||
|
|
||||||
|
DPADD= ${LIBELF} ${LIBELFTC}
|
||||||
|
LDADD= -lelf -lelftc
|
||||||
|
|
||||||
|
.if !defined(LIBELF_AR)
|
||||||
|
LDADD+= -larchive
|
||||||
|
.endif
|
||||||
|
|
||||||
|
MAN= elfcopy.1 mcs.1 strip.1
|
||||||
|
|
||||||
|
NO_SHARED?= yes
|
||||||
|
|
||||||
|
LINKS= ${BINDIR}/elfcopy ${BINDIR}/strip \
|
||||||
|
${BINDIR}/elfcopy ${BINDIR}/mcs
|
||||||
|
|
||||||
|
EXTRA_TARGETS= strip mcs
|
||||||
|
|
||||||
|
CLEANFILES+= ${EXTRA_TARGETS}
|
||||||
|
|
||||||
|
# Create in-place symbolic links to "elfcopy" at build time.
|
||||||
|
|
||||||
|
all: ${EXTRA_TARGETS}
|
||||||
|
|
||||||
|
${EXTRA_TARGETS}: ${PROG}
|
||||||
|
ln -s ${PROG} ${.TARGET}
|
||||||
|
|
||||||
|
.include "${TOP}/mk/elftoolchain.prog.mk"
|
||||||
|
|
||||||
|
.if ${OS_HOST} == "OpenBSD"
|
||||||
|
CFLAGS+= -I/usr/local/include
|
||||||
|
LDFLAGS+= -L/usr/local/lib
|
||||||
|
.endif
|
528
contrib/elftoolchain/elfcopy/archive.c
Normal file
528
contrib/elftoolchain/elfcopy/archive.c
Normal file
@ -0,0 +1,528 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2007-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.
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifndef LIBELF_AR
|
||||||
|
#include <archive.h>
|
||||||
|
#include <archive_entry.h>
|
||||||
|
#endif /* ! LIBELF_AR */
|
||||||
|
|
||||||
|
#include "elfcopy.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: archive.c 2370 2011-12-29 12:48:12Z jkoshy $");
|
||||||
|
|
||||||
|
#define _ARMAG_LEN 8 /* length of ar magic string */
|
||||||
|
#define _ARHDR_LEN 60 /* length of ar header */
|
||||||
|
#define _INIT_AS_CAP 128 /* initial archive string table size */
|
||||||
|
#define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */
|
||||||
|
#define _INIT_SYMNAME_CAP 1024 /* initial sn table size */
|
||||||
|
#define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */
|
||||||
|
|
||||||
|
#ifndef LIBELF_AR
|
||||||
|
static void ac_read_objs(struct elfcopy *ecp, int ifd);
|
||||||
|
static void ac_write_cleanup(struct elfcopy *ecp);
|
||||||
|
static void ac_write_data(struct archive *a, const void *buf, size_t s);
|
||||||
|
static void ac_write_objs(struct elfcopy *ecp, int ofd);
|
||||||
|
#endif /* ! LIBELF_AR */
|
||||||
|
static void add_to_ar_str_table(struct elfcopy *elfcopy, const char *name);
|
||||||
|
static void add_to_ar_sym_table(struct elfcopy *ecp, const char *name);
|
||||||
|
static void extract_arsym(struct elfcopy *ecp);
|
||||||
|
static void process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj);
|
||||||
|
static void sync_ar(struct elfcopy *ecp);
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
char *tempfile;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* Output to a temporary file. */
|
||||||
|
create_tempfile(&tempfile, &fd);
|
||||||
|
if ((ecp->eout = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "elf_begin() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT);
|
||||||
|
create_elf(ecp);
|
||||||
|
elf_end(ecp->ein);
|
||||||
|
elf_end(ecp->eout);
|
||||||
|
free(obj->buf);
|
||||||
|
obj->buf = NULL;
|
||||||
|
|
||||||
|
/* Extract archive symbols. */
|
||||||
|
if (lseek(fd, 0, SEEK_SET) < 0)
|
||||||
|
err(EXIT_FAILURE, "lseek failed for '%s'", tempfile);
|
||||||
|
if ((ecp->eout = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "elf_begin() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
extract_arsym(ecp);
|
||||||
|
elf_end(ecp->eout);
|
||||||
|
|
||||||
|
if (fstat(fd, &sb) == -1)
|
||||||
|
err(EXIT_FAILURE, "fstat %s failed", tempfile);
|
||||||
|
if (lseek(fd, 0, SEEK_SET) < 0)
|
||||||
|
err(EXIT_FAILURE, "lseek %s failed", tempfile);
|
||||||
|
obj->size = sb.st_size;
|
||||||
|
if ((obj->maddr = malloc(obj->size)) == NULL)
|
||||||
|
err(EXIT_FAILURE, "memory allocation failed for '%s'",
|
||||||
|
tempfile);
|
||||||
|
if ((size_t) read(fd, obj->maddr, obj->size) != obj->size)
|
||||||
|
err(EXIT_FAILURE, "read failed for '%s'", tempfile);
|
||||||
|
if (unlink(tempfile))
|
||||||
|
err(EXIT_FAILURE, "unlink %s failed", tempfile);
|
||||||
|
free(tempfile);
|
||||||
|
close(fd);
|
||||||
|
if (strlen(obj->name) > _MAXNAMELEN_SVR4)
|
||||||
|
add_to_ar_str_table(ecp, obj->name);
|
||||||
|
ecp->rela_off += _ARHDR_LEN + obj->size + obj->size % 2;
|
||||||
|
STAILQ_INSERT_TAIL(&ecp->v_arobj, obj, objs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append to the archive string table buffer.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
add_to_ar_str_table(struct elfcopy *ecp, const char *name)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (ecp->as == NULL) {
|
||||||
|
ecp->as_cap = _INIT_AS_CAP;
|
||||||
|
ecp->as_sz = 0;
|
||||||
|
if ((ecp->as = malloc(ecp->as_cap)) == NULL)
|
||||||
|
err(EXIT_FAILURE, "malloc failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The space required for holding one member name in as table includes:
|
||||||
|
* strlen(name) + (1 for '/') + (1 for '\n') + (possibly 1 for padding).
|
||||||
|
*/
|
||||||
|
while (ecp->as_sz + strlen(name) + 3 > ecp->as_cap) {
|
||||||
|
ecp->as_cap *= 2;
|
||||||
|
ecp->as = realloc(ecp->as, ecp->as_cap);
|
||||||
|
if (ecp->as == NULL)
|
||||||
|
err(EXIT_FAILURE, "realloc failed");
|
||||||
|
}
|
||||||
|
strncpy(&ecp->as[ecp->as_sz], name, strlen(name));
|
||||||
|
ecp->as_sz += strlen(name);
|
||||||
|
ecp->as[ecp->as_sz++] = '/';
|
||||||
|
ecp->as[ecp->as_sz++] = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append to the archive symbol table buffer.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
add_to_ar_sym_table(struct elfcopy *ecp, const char *name)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (ecp->s_so == NULL) {
|
||||||
|
if ((ecp->s_so = malloc(_INIT_SYMOFF_CAP)) == NULL)
|
||||||
|
err(EXIT_FAILURE, "malloc failed");
|
||||||
|
ecp->s_so_cap = _INIT_SYMOFF_CAP;
|
||||||
|
ecp->s_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecp->s_sn == NULL) {
|
||||||
|
if ((ecp->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL)
|
||||||
|
err(EXIT_FAILURE, "malloc failed");
|
||||||
|
ecp->s_sn_cap = _INIT_SYMNAME_CAP;
|
||||||
|
ecp->s_sn_sz = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecp->s_cnt * sizeof(uint32_t) >= ecp->s_so_cap) {
|
||||||
|
ecp->s_so_cap *= 2;
|
||||||
|
ecp->s_so = realloc(ecp->s_so, ecp->s_so_cap);
|
||||||
|
if (ecp->s_so == NULL)
|
||||||
|
err(EXIT_FAILURE, "realloc failed");
|
||||||
|
}
|
||||||
|
ecp->s_so[ecp->s_cnt] = ecp->rela_off;
|
||||||
|
ecp->s_cnt++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The space required for holding one symbol name in sn table includes:
|
||||||
|
* strlen(name) + (1 for '\n') + (possibly 1 for padding).
|
||||||
|
*/
|
||||||
|
while (ecp->s_sn_sz + strlen(name) + 2 > ecp->s_sn_cap) {
|
||||||
|
ecp->s_sn_cap *= 2;
|
||||||
|
ecp->s_sn = realloc(ecp->s_sn, ecp->s_sn_cap);
|
||||||
|
if (ecp->s_sn == NULL)
|
||||||
|
err(EXIT_FAILURE, "realloc failed");
|
||||||
|
}
|
||||||
|
strncpy(&ecp->s_sn[ecp->s_sn_sz], name, strlen(name));
|
||||||
|
ecp->s_sn_sz += strlen(name);
|
||||||
|
ecp->s_sn[ecp->s_sn_sz++] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sync_ar(struct elfcopy *ecp)
|
||||||
|
{
|
||||||
|
size_t s_sz; /* size of archive symbol table. */
|
||||||
|
size_t pm_sz; /* size of pseudo members */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pad the symbol name string table. It is treated specially because
|
||||||
|
* symbol name table should be padded by a '\0', not the common '\n'
|
||||||
|
* for other members. The size of sn table includes the pad bit.
|
||||||
|
*/
|
||||||
|
if (ecp->s_cnt != 0 && ecp->s_sn_sz % 2 != 0)
|
||||||
|
ecp->s_sn[ecp->s_sn_sz++] = '\0';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Archive string table is padded by a "\n" as the normal members.
|
||||||
|
* The difference is that the size of archive string table counts
|
||||||
|
* in the pad bit, while normal members' size fileds do not.
|
||||||
|
*/
|
||||||
|
if (ecp->as != NULL && ecp->as_sz % 2 != 0)
|
||||||
|
ecp->as[ecp->as_sz++] = '\n';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is a symbol table, calculate the size of pseudo members,
|
||||||
|
* convert previously stored relative offsets to absolute ones, and
|
||||||
|
* then make them Big Endian.
|
||||||
|
*
|
||||||
|
* absolute_offset = htobe32(relative_offset + size_of_pseudo_members)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ecp->s_cnt != 0) {
|
||||||
|
s_sz = (ecp->s_cnt + 1) * sizeof(uint32_t) + ecp->s_sn_sz;
|
||||||
|
pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz);
|
||||||
|
if (ecp->as != NULL)
|
||||||
|
pm_sz += _ARHDR_LEN + ecp->as_sz;
|
||||||
|
for (i = 0; (size_t)i < ecp->s_cnt; i++)
|
||||||
|
*(ecp->s_so + i) = htobe32(*(ecp->s_so + i) +
|
||||||
|
pm_sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract global symbols from archive members.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
extract_arsym(struct elfcopy *ecp)
|
||||||
|
{
|
||||||
|
Elf_Scn *scn;
|
||||||
|
GElf_Shdr shdr;
|
||||||
|
GElf_Sym sym;
|
||||||
|
Elf_Data *data;
|
||||||
|
char *name;
|
||||||
|
size_t n, shstrndx;
|
||||||
|
int elferr, tabndx, len, i;
|
||||||
|
|
||||||
|
if (elf_kind(ecp->eout) != ELF_K_ELF) {
|
||||||
|
warnx("internal: cannot extract symbols from non-elf object");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (elf_getshstrndx(ecp->eout, &shstrndx) == 0) {
|
||||||
|
warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabndx = -1;
|
||||||
|
scn = NULL;
|
||||||
|
while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) {
|
||||||
|
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
||||||
|
warnx("elf_getshdr failed: %s", elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((name = elf_strptr(ecp->eout, shstrndx, shdr.sh_name)) ==
|
||||||
|
NULL) {
|
||||||
|
warnx("elf_strptr failed: %s", elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp(name, ".strtab") == 0) {
|
||||||
|
tabndx = elf_ndxscn(scn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elferr = elf_errno();
|
||||||
|
if (elferr != 0)
|
||||||
|
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
|
||||||
|
|
||||||
|
/* Ignore members without symbol table. */
|
||||||
|
if (tabndx == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
scn = NULL;
|
||||||
|
while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) {
|
||||||
|
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
||||||
|
warnx("elf_getshdr failed: %s", elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (shdr.sh_type != SHT_SYMTAB)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
data = NULL;
|
||||||
|
n = 0;
|
||||||
|
while (n < shdr.sh_size &&
|
||||||
|
(data = elf_getdata(scn, data)) != NULL) {
|
||||||
|
len = data->d_size / shdr.sh_entsize;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (gelf_getsym(data, i, &sym) != &sym) {
|
||||||
|
warnx("gelf_getsym failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keep only global or weak symbols */
|
||||||
|
if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL &&
|
||||||
|
GELF_ST_BIND(sym.st_info) != STB_WEAK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* keep only defined symbols */
|
||||||
|
if (sym.st_shndx == SHN_UNDEF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((name = elf_strptr(ecp->eout, tabndx,
|
||||||
|
sym.st_name)) == NULL) {
|
||||||
|
warnx("elf_strptr failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_ar_sym_table(ecp, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elferr = elf_errno();
|
||||||
|
if (elferr != 0)
|
||||||
|
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef LIBELF_AR
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenient wrapper for general libarchive error handling.
|
||||||
|
*/
|
||||||
|
#define AC(CALL) do { \
|
||||||
|
if ((CALL)) \
|
||||||
|
errx(EXIT_FAILURE, "%s", archive_error_string(a)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* Earlier versions of libarchive had some functions that returned 'void'. */
|
||||||
|
#if ARCHIVE_VERSION_NUMBER >= 2000000
|
||||||
|
#define ACV(CALL) AC(CALL)
|
||||||
|
#else
|
||||||
|
#define ACV(CALL) do { \
|
||||||
|
(CALL); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
ac_detect_ar(int ifd)
|
||||||
|
{
|
||||||
|
struct archive *a;
|
||||||
|
struct archive_entry *entry;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = -1;
|
||||||
|
if ((a = archive_read_new()) == NULL)
|
||||||
|
return (0);
|
||||||
|
archive_read_support_compression_none(a);
|
||||||
|
archive_read_support_format_ar(a);
|
||||||
|
if (archive_read_open_fd(a, ifd, 10240) == ARCHIVE_OK)
|
||||||
|
r = archive_read_next_header(a, &entry);
|
||||||
|
archive_read_close(a);
|
||||||
|
archive_read_finish(a);
|
||||||
|
|
||||||
|
return (r == ARCHIVE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ac_create_ar(struct elfcopy *ecp, int ifd, int ofd)
|
||||||
|
{
|
||||||
|
|
||||||
|
ac_read_objs(ecp, ifd);
|
||||||
|
sync_ar(ecp);
|
||||||
|
ac_write_objs(ecp, ofd);
|
||||||
|
ac_write_cleanup(ecp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ac_read_objs(struct elfcopy *ecp, int ifd)
|
||||||
|
{
|
||||||
|
struct archive *a;
|
||||||
|
struct archive_entry *entry;
|
||||||
|
struct ar_obj *obj;
|
||||||
|
const char *name;
|
||||||
|
char *buff;
|
||||||
|
size_t size;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
ecp->rela_off = 0;
|
||||||
|
if (lseek(ifd, 0, SEEK_SET) == -1)
|
||||||
|
err(EXIT_FAILURE, "lseek failed");
|
||||||
|
if ((a = archive_read_new()) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "%s", archive_error_string(a));
|
||||||
|
archive_read_support_compression_none(a);
|
||||||
|
archive_read_support_format_ar(a);
|
||||||
|
AC(archive_read_open_fd(a, ifd, 10240));
|
||||||
|
for(;;) {
|
||||||
|
r = archive_read_next_header(a, &entry);
|
||||||
|
if (r == ARCHIVE_FATAL)
|
||||||
|
errx(EXIT_FAILURE, "%s", archive_error_string(a));
|
||||||
|
if (r == ARCHIVE_EOF)
|
||||||
|
break;
|
||||||
|
if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY)
|
||||||
|
warnx("%s", archive_error_string(a));
|
||||||
|
if (r == ARCHIVE_RETRY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
name = archive_entry_pathname(entry);
|
||||||
|
|
||||||
|
/* skip pseudo members. */
|
||||||
|
if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
size = archive_entry_size(entry);
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
if ((buff = malloc(size)) == NULL)
|
||||||
|
err(EXIT_FAILURE, "malloc failed");
|
||||||
|
if (archive_read_data(a, buff, size) != (ssize_t)size) {
|
||||||
|
warnx("%s", archive_error_string(a));
|
||||||
|
free(buff);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((obj = malloc(sizeof(*obj))) == NULL)
|
||||||
|
err(EXIT_FAILURE, "malloc failed");
|
||||||
|
if ((obj->name = strdup(name)) == NULL)
|
||||||
|
err(EXIT_FAILURE, "strdup failed");
|
||||||
|
obj->buf = buff;
|
||||||
|
obj->uid = archive_entry_uid(entry);
|
||||||
|
obj->gid = archive_entry_gid(entry);
|
||||||
|
obj->md = archive_entry_mode(entry);
|
||||||
|
obj->mtime = archive_entry_mtime(entry);
|
||||||
|
if ((ecp->ein = elf_memory(buff, size)) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "elf_memory() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
if (elf_kind(ecp->ein) != ELF_K_ELF)
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"file format not recognized");
|
||||||
|
process_ar_obj(ecp, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AC(archive_read_close(a));
|
||||||
|
ACV(archive_read_finish(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ac_write_objs(struct elfcopy *ecp, int ofd)
|
||||||
|
{
|
||||||
|
struct archive *a;
|
||||||
|
struct archive_entry *entry;
|
||||||
|
struct ar_obj *obj;
|
||||||
|
int nr;
|
||||||
|
|
||||||
|
if ((a = archive_write_new()) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "%s", archive_error_string(a));
|
||||||
|
archive_write_set_format_ar_svr4(a);
|
||||||
|
archive_write_set_compression_none(a);
|
||||||
|
AC(archive_write_open_fd(a, ofd));
|
||||||
|
|
||||||
|
/* Write the archive symbol table, even if it's empty. */
|
||||||
|
entry = archive_entry_new();
|
||||||
|
archive_entry_copy_pathname(entry, "/");
|
||||||
|
archive_entry_set_mtime(entry, time(NULL), 0);
|
||||||
|
archive_entry_set_size(entry, (ecp->s_cnt + 1) * sizeof(uint32_t) +
|
||||||
|
ecp->s_sn_sz);
|
||||||
|
AC(archive_write_header(a, entry));
|
||||||
|
nr = htobe32(ecp->s_cnt);
|
||||||
|
ac_write_data(a, &nr, sizeof(uint32_t));
|
||||||
|
ac_write_data(a, ecp->s_so, sizeof(uint32_t) * ecp->s_cnt);
|
||||||
|
ac_write_data(a, ecp->s_sn, ecp->s_sn_sz);
|
||||||
|
archive_entry_free(entry);
|
||||||
|
|
||||||
|
/* Write the archive string table, if exist. */
|
||||||
|
if (ecp->as != NULL) {
|
||||||
|
entry = archive_entry_new();
|
||||||
|
archive_entry_copy_pathname(entry, "//");
|
||||||
|
archive_entry_set_size(entry, ecp->as_sz);
|
||||||
|
AC(archive_write_header(a, entry));
|
||||||
|
ac_write_data(a, ecp->as, ecp->as_sz);
|
||||||
|
archive_entry_free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write normal members. */
|
||||||
|
STAILQ_FOREACH(obj, &ecp->v_arobj, objs) {
|
||||||
|
entry = archive_entry_new();
|
||||||
|
archive_entry_copy_pathname(entry, obj->name);
|
||||||
|
archive_entry_set_uid(entry, obj->uid);
|
||||||
|
archive_entry_set_gid(entry, obj->gid);
|
||||||
|
archive_entry_set_mode(entry, obj->md);
|
||||||
|
archive_entry_set_size(entry, obj->size);
|
||||||
|
archive_entry_set_mtime(entry, obj->mtime, 0);
|
||||||
|
archive_entry_set_filetype(entry, AE_IFREG);
|
||||||
|
AC(archive_write_header(a, entry));
|
||||||
|
ac_write_data(a, obj->maddr, obj->size);
|
||||||
|
archive_entry_free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
AC(archive_write_close(a));
|
||||||
|
ACV(archive_write_finish(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ac_write_cleanup(struct elfcopy *ecp)
|
||||||
|
{
|
||||||
|
struct ar_obj *obj, *obj_temp;
|
||||||
|
|
||||||
|
STAILQ_FOREACH_SAFE(obj, &ecp->v_arobj, objs, obj_temp) {
|
||||||
|
STAILQ_REMOVE(&ecp->v_arobj, obj, ar_obj, objs);
|
||||||
|
if (obj->maddr != NULL)
|
||||||
|
free(obj->maddr);
|
||||||
|
free(obj->name);
|
||||||
|
free(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ecp->as);
|
||||||
|
free(ecp->s_so);
|
||||||
|
free(ecp->s_sn);
|
||||||
|
ecp->as = NULL;
|
||||||
|
ecp->s_so = NULL;
|
||||||
|
ecp->s_sn = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wrapper for archive_write_data().
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ac_write_data(struct archive *a, const void *buf, size_t s)
|
||||||
|
{
|
||||||
|
if (archive_write_data(a, buf, s) != (ssize_t)s)
|
||||||
|
errx(EXIT_FAILURE, "%s", archive_error_string(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ! LIBELF_AR */
|
1078
contrib/elftoolchain/elfcopy/ascii.c
Normal file
1078
contrib/elftoolchain/elfcopy/ascii.c
Normal file
File diff suppressed because it is too large
Load Diff
286
contrib/elftoolchain/elfcopy/binary.c
Normal file
286
contrib/elftoolchain/elfcopy/binary.c
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2010,2011 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.
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <gelf.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "elfcopy.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: binary.c 2358 2011-12-19 18:22:32Z kaiwang27 $");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert ELF object to `binary'. Sections with SHF_ALLOC flag set
|
||||||
|
* are copied to the result binary. The relative offsets for each section
|
||||||
|
* are retained, so the result binary file might contain "holes".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
create_binary(int ifd, int ofd)
|
||||||
|
{
|
||||||
|
Elf *e;
|
||||||
|
Elf_Scn *scn;
|
||||||
|
Elf_Data *d;
|
||||||
|
GElf_Shdr sh;
|
||||||
|
off_t base, off;
|
||||||
|
int elferr;
|
||||||
|
|
||||||
|
if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "elf_begin() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
base = 0;
|
||||||
|
if (lseek(ofd, base, SEEK_SET) < 0)
|
||||||
|
err(EXIT_FAILURE, "lseek failed");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find base offset in the first iteration.
|
||||||
|
*/
|
||||||
|
base = -1;
|
||||||
|
scn = NULL;
|
||||||
|
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||||
|
if (gelf_getshdr(scn, &sh) == NULL) {
|
||||||
|
warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
|
||||||
|
(void) elf_errno();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((sh.sh_flags & SHF_ALLOC) == 0 ||
|
||||||
|
sh.sh_type == SHT_NOBITS ||
|
||||||
|
sh.sh_size == 0)
|
||||||
|
continue;
|
||||||
|
if (base == -1 || (off_t) sh.sh_offset < base)
|
||||||
|
base = sh.sh_offset;
|
||||||
|
}
|
||||||
|
elferr = elf_errno();
|
||||||
|
if (elferr != 0)
|
||||||
|
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
|
||||||
|
|
||||||
|
if (base == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out sections in the second iteration.
|
||||||
|
*/
|
||||||
|
scn = NULL;
|
||||||
|
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||||
|
if (gelf_getshdr(scn, &sh) == NULL) {
|
||||||
|
warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
|
||||||
|
(void) elf_errno();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((sh.sh_flags & SHF_ALLOC) == 0 ||
|
||||||
|
sh.sh_type == SHT_NOBITS ||
|
||||||
|
sh.sh_size == 0)
|
||||||
|
continue;
|
||||||
|
(void) elf_errno();
|
||||||
|
if ((d = elf_getdata(scn, NULL)) == NULL) {
|
||||||
|
elferr = elf_errno();
|
||||||
|
if (elferr != 0)
|
||||||
|
warnx("elf_getdata failed: %s", elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (d->d_buf == NULL || d->d_size == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* lseek to section offset relative to `base'. */
|
||||||
|
off = sh.sh_offset - base;
|
||||||
|
if (lseek(ofd, off, SEEK_SET) < 0)
|
||||||
|
err(EXIT_FAILURE, "lseek failed");
|
||||||
|
|
||||||
|
/* Write out section contents. */
|
||||||
|
if (write(ofd, d->d_buf, d->d_size) != (ssize_t) d->d_size)
|
||||||
|
err(EXIT_FAILURE, "write failed");
|
||||||
|
}
|
||||||
|
elferr = elf_errno();
|
||||||
|
if (elferr != 0)
|
||||||
|
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _SYMBOL_NAMSZ 1024
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert `binary' to ELF object. The input `binary' is converted to
|
||||||
|
* a relocatable (.o) file, a few symbols will also be created to make
|
||||||
|
* it easier to access the binary data in other compilation units.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
create_elf_from_binary(struct elfcopy *ecp, int ifd, const char *ifn)
|
||||||
|
{
|
||||||
|
char name[_SYMBOL_NAMSZ];
|
||||||
|
struct section *sec, *sec_temp, *shtab;
|
||||||
|
struct stat sb;
|
||||||
|
GElf_Ehdr oeh;
|
||||||
|
GElf_Shdr sh;
|
||||||
|
void *content;
|
||||||
|
uint64_t off, data_start, data_end, data_size;
|
||||||
|
|
||||||
|
/* Reset internal section list. */
|
||||||
|
if (!TAILQ_EMPTY(&ecp->v_sec))
|
||||||
|
TAILQ_FOREACH_SAFE(sec, &ecp->v_sec, sec_list, sec_temp) {
|
||||||
|
TAILQ_REMOVE(&ecp->v_sec, sec, sec_list);
|
||||||
|
free(sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat(ifd, &sb) == -1)
|
||||||
|
err(EXIT_FAILURE, "fstat failed");
|
||||||
|
|
||||||
|
/* Read the input binary file to a internal buffer. */
|
||||||
|
if ((content = malloc(sb.st_size)) == NULL)
|
||||||
|
err(EXIT_FAILURE, "malloc failed");
|
||||||
|
if (read(ifd, content, sb.st_size) != sb.st_size)
|
||||||
|
err(EXIT_FAILURE, "read failed");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: copy the input binary to output binary verbatim if -O is not
|
||||||
|
* specified.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Create EHDR for output .o file. */
|
||||||
|
if (gelf_newehdr(ecp->eout, ecp->oec) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "gelf_newehdr failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
if (gelf_getehdr(ecp->eout, &oeh) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
/* Initialise e_ident fields. */
|
||||||
|
oeh.e_ident[EI_CLASS] = ecp->oec;
|
||||||
|
oeh.e_ident[EI_DATA] = ecp->oed;
|
||||||
|
/*
|
||||||
|
* TODO: Set OSABI according to the OS platform where elfcopy(1)
|
||||||
|
* was build. (probably)
|
||||||
|
*/
|
||||||
|
oeh.e_ident[EI_OSABI] = ELFOSABI_NONE;
|
||||||
|
oeh.e_machine = ecp->oem;
|
||||||
|
oeh.e_type = ET_REL;
|
||||||
|
oeh.e_entry = 0;
|
||||||
|
|
||||||
|
ecp->flags |= RELOCATABLE;
|
||||||
|
|
||||||
|
/* Create .shstrtab section */
|
||||||
|
init_shstrtab(ecp);
|
||||||
|
ecp->shstrtab->off = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create `.data' section which contains the binary data. The
|
||||||
|
* section is inserted immediately after EHDR.
|
||||||
|
*/
|
||||||
|
off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT);
|
||||||
|
if (off == 0)
|
||||||
|
errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
|
||||||
|
(void) create_external_section(ecp, ".data", NULL, content, sb.st_size,
|
||||||
|
off, SHT_PROGBITS, ELF_T_BYTE, SHF_ALLOC | SHF_WRITE, 1, 0, 1);
|
||||||
|
|
||||||
|
/* Insert .shstrtab after .data section. */
|
||||||
|
if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "elf_newscn failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
insert_to_sec_list(ecp, ecp->shstrtab, 1);
|
||||||
|
|
||||||
|
/* Insert section header table here. */
|
||||||
|
shtab = insert_shtab(ecp, 1);
|
||||||
|
|
||||||
|
/* Count in .symtab and .strtab section headers. */
|
||||||
|
shtab->sz += gelf_fsize(ecp->eout, ELF_T_SHDR, 2, EV_CURRENT);
|
||||||
|
|
||||||
|
#define _GEN_SYMNAME(S) do { \
|
||||||
|
snprintf(name, sizeof(name), "%s%s%s", "_binary_", ifn, S); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create symbol table.
|
||||||
|
*/
|
||||||
|
create_external_symtab(ecp);
|
||||||
|
data_start = 0;
|
||||||
|
data_end = data_start + sb.st_size;
|
||||||
|
data_size = sb.st_size;
|
||||||
|
_GEN_SYMNAME("_start");
|
||||||
|
add_to_symtab(ecp, name, data_start, 0, 1,
|
||||||
|
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1);
|
||||||
|
_GEN_SYMNAME("_end");
|
||||||
|
add_to_symtab(ecp, name, data_end, 0, 1,
|
||||||
|
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1);
|
||||||
|
_GEN_SYMNAME("_size");
|
||||||
|
add_to_symtab(ecp, name, data_size, 0, SHN_ABS,
|
||||||
|
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1);
|
||||||
|
finalize_external_symtab(ecp);
|
||||||
|
create_symtab_data(ecp);
|
||||||
|
#undef _GEN_SYMNAME
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the underlying ehdr. Note that it should be called
|
||||||
|
* before elf_setshstrndx() since it will overwrite e->e_shstrndx.
|
||||||
|
*/
|
||||||
|
if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
|
||||||
|
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
/* Generate section name string table (.shstrtab). */
|
||||||
|
ecp->flags |= SYMTAB_EXIST;
|
||||||
|
set_shstrtab(ecp);
|
||||||
|
|
||||||
|
/* Update sh_name pointer for each section header entry. */
|
||||||
|
update_shdr(ecp, 0);
|
||||||
|
|
||||||
|
/* Properly set sh_link field of .symtab section. */
|
||||||
|
if (gelf_getshdr(ecp->symtab->os, &sh) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "692 gelf_getshdr() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
sh.sh_link = elf_ndxscn(ecp->strtab->os);
|
||||||
|
if (!gelf_update_shdr(ecp->symtab->os, &sh))
|
||||||
|
errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
/* Renew oeh to get the updated e_shstrndx. */
|
||||||
|
if (gelf_getehdr(ecp->eout, &oeh) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
/* Resync section offsets. */
|
||||||
|
resync_sections(ecp);
|
||||||
|
|
||||||
|
/* Store SHDR offset in EHDR. */
|
||||||
|
oeh.e_shoff = shtab->off;
|
||||||
|
|
||||||
|
/* Update ehdr since we modified e_shoff. */
|
||||||
|
if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
|
||||||
|
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
/* Write out the output elf object. */
|
||||||
|
if (elf_update(ecp->eout, ELF_C_WRITE) < 0)
|
||||||
|
errx(EXIT_FAILURE, "elf_update() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
/* Release allocated resource. */
|
||||||
|
free(content);
|
||||||
|
free_elf(ecp);
|
||||||
|
}
|
323
contrib/elftoolchain/elfcopy/elfcopy.1
Normal file
323
contrib/elftoolchain/elfcopy/elfcopy.1
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
.\" Copyright (c) 2008-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: elfcopy.1 2373 2011-12-30 07:13:44Z jkoshy $
|
||||||
|
.\"
|
||||||
|
.Dd October 03, 2011
|
||||||
|
.Os
|
||||||
|
.Dt ELFCOPY 1
|
||||||
|
.Sh NAME
|
||||||
|
.Nm elfcopy
|
||||||
|
.Nd copy and translate object files
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl I Ar objformat | Fl s Ar objformat | Fl -input-target= Ns Ar objformat
|
||||||
|
.Op Fl K Ar symbolname | Fl -keep-symbol= Ns Ar symbolname
|
||||||
|
.Op Fl L Ar symbolname | Fl -localize-symbol= Ns Ar symbolname
|
||||||
|
.Op Fl N Ar symbolname | Fl -strip-symbol= Ns Ar symbolname
|
||||||
|
.Op Fl O Ar objformat | Fl -output-target= Ns Ar objformat
|
||||||
|
.Op Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname
|
||||||
|
.Op Fl S | Fl -strip-all
|
||||||
|
.Op Fl V | Fl -version
|
||||||
|
.Op Fl W Ar symbolname | Fl -weaken-symbol= Ns Ar symbolname
|
||||||
|
.Op Fl X | Fl -discard-locals
|
||||||
|
.Op Fl d | Fl g | Fl -strip-debug
|
||||||
|
.Op Fl h | Fl -help
|
||||||
|
.Op Fl j Ar sectionname | Fl -only-section= Ns Ar sectionname
|
||||||
|
.Op Fl p | Fl -preserve-dates
|
||||||
|
.Op Fl w | Fl -wildcard
|
||||||
|
.Op Fl x | Fl -discard-all
|
||||||
|
.Op Fl -add-section Ar sectionname Ns = Ns Ar filename
|
||||||
|
.Oo
|
||||||
|
.Fl -adjust-section-vma Ar section Ns {+|-|=} Ns Ar val |
|
||||||
|
.Fl -change-section-address Ar section Ns {+|-|=} Ns Ar val
|
||||||
|
.Oc
|
||||||
|
.Oo
|
||||||
|
.Fl -adjust-start Ns = Ns Ar increment |
|
||||||
|
.Fl -change-start Ns = Ns Ar increment
|
||||||
|
.Oc
|
||||||
|
.Oo
|
||||||
|
.Fl -adjust-vma Ns = Ns Ar increment |
|
||||||
|
.Fl -change-addresses Ns = Ns Ar increment
|
||||||
|
.Oc
|
||||||
|
.Op Fl -adjust-warnings | Fl -change-warnings
|
||||||
|
.Op Fl -change-section-lma Ar section Ns {+|-|=} Ns Ar val
|
||||||
|
.Op Fl -change-section-vma Ar section Ns {+|-|=} Ns Ar val
|
||||||
|
.Op Fl -gap-fill Ns = Ns Ar val
|
||||||
|
.Op Fl -no-adjust-warnings | Fl -no-change-warnings
|
||||||
|
.Op Fl -only-keep-debug
|
||||||
|
.Op Fl -pad-to Ns = Ns Ar address
|
||||||
|
.Op Fl -prefix-alloc-sections Ns = Ns Ar string
|
||||||
|
.Op Fl -prefix-sections Ns = Ns Ar string
|
||||||
|
.Op Fl -prefix-symbols Ns = Ns Ar string
|
||||||
|
.Op Fl -rename-section Ar oldname Ns = Ns Ar newname Ns Op Ar ,flags
|
||||||
|
.Op Fl -set-section-flags Ar sectionname Ns = Ns Ar flags
|
||||||
|
.Op Fl -set-start Ns = Ns Ar address
|
||||||
|
.Op Fl -srec-forceS3
|
||||||
|
.Op Fl -srec-len Ns = Ns Ar val
|
||||||
|
.Op Fl -strip-unneeded
|
||||||
|
.Ar infile
|
||||||
|
.Op Ar outfile
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility copies the content of the ELF object named by argument
|
||||||
|
.Ar infile
|
||||||
|
to that named by argument
|
||||||
|
.Ar outfile ,
|
||||||
|
transforming it according to the command line options specified.
|
||||||
|
If argument
|
||||||
|
.Ar outfile
|
||||||
|
is not specified,
|
||||||
|
.Nm
|
||||||
|
will create a temporary file and will subsequently rename it as
|
||||||
|
.Ar infile .
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility supports the following options:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl I Ar objformat | Fl s Ar objformat | Fl -input-target= Ns Ar objformat
|
||||||
|
Specify that the input file named by the argument
|
||||||
|
.Ar infile
|
||||||
|
is in the object format specified by the argument
|
||||||
|
.Ar objformat .
|
||||||
|
.It Fl K Ar symbolname | Fl -keep-symbol= Ns Ar symbolname
|
||||||
|
Copy the symbol named by argument
|
||||||
|
.Ar symbolname
|
||||||
|
to the output.
|
||||||
|
.It Fl L Ar symbolname | Fl -localize-symbol= Ns Ar symbolname
|
||||||
|
Make the symbol named by argument
|
||||||
|
.Ar symbolname
|
||||||
|
local to the output file.
|
||||||
|
.It Fl N Ar symbol | Fl -strip-symbol= Ns Ar symbolname
|
||||||
|
Do not copy the symbol named by argument
|
||||||
|
.Ar symbolname
|
||||||
|
to the output.
|
||||||
|
.It Fl O Ar objformat | Fl -output-target= Ns Ar objformat
|
||||||
|
Write the output file using the object format specified in argument
|
||||||
|
.Ar objformat .
|
||||||
|
.It Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname
|
||||||
|
Remove any section with name
|
||||||
|
.Ar sectionname
|
||||||
|
from the output file.
|
||||||
|
.It Fl S | Fl -strip-all
|
||||||
|
Do not copy symbol and relocation information to the target file.
|
||||||
|
.It Fl V | Fl -version
|
||||||
|
Print a version identifier and exit.
|
||||||
|
.It Fl W Ar symbolname | Fl -weaken-symbol= Ns Ar symbolname
|
||||||
|
Mark the symbol named by argument
|
||||||
|
.Ar symbolname
|
||||||
|
as weak in the output.
|
||||||
|
.It Fl X | Fl -discard-locals
|
||||||
|
Do not copy compiler generated local symbols to the output.
|
||||||
|
.It Fl d | Fl g | Fl -strip-debug
|
||||||
|
Do not copy debugging information to the target file.
|
||||||
|
.It Fl h | Fl -help
|
||||||
|
Display a help message and exit.
|
||||||
|
.It Fl j Ar sectionname | Fl -only-section= Ns Ar sectionname
|
||||||
|
Copy only the section named by argument
|
||||||
|
.Ar sectionname
|
||||||
|
to the output.
|
||||||
|
.It Fl p | Fl -preserve-dates
|
||||||
|
Set the access and modification times of the output file to the
|
||||||
|
same as those of the input.
|
||||||
|
.It Fl w | Fl -wildcard
|
||||||
|
Use shell-style patterns to name symbols.
|
||||||
|
The following meta-characters are recognized in patterns:
|
||||||
|
.Bl -tag -width "...." -compact
|
||||||
|
.It Li !
|
||||||
|
If this is the first character of the pattern, invert the sense of the
|
||||||
|
pattern match.
|
||||||
|
.It Li *
|
||||||
|
Matches any string of characters in a symbol name.
|
||||||
|
.It Li ?
|
||||||
|
Matches zero or one character in a symbol name.
|
||||||
|
.It Li [
|
||||||
|
Mark the start of a character class.
|
||||||
|
.It Li \e
|
||||||
|
Remove the special meaning of the next character in the pattern.
|
||||||
|
.It Li ]
|
||||||
|
Mark the end of a character class.
|
||||||
|
.El
|
||||||
|
.It Fl x | Fl -discard-all
|
||||||
|
Do not copy non-global symbols to the output.
|
||||||
|
.It Fl -add-section Ar sectionname Ns = Ns Ar filename
|
||||||
|
Add a new section to the output file with name
|
||||||
|
.Ar sectionname .
|
||||||
|
The contents of the section are taken from the file named by
|
||||||
|
argument
|
||||||
|
.Ar filename .
|
||||||
|
The size of the section will be the number of bytes in file
|
||||||
|
.Ar filename .
|
||||||
|
.It Xo
|
||||||
|
.Fl -adjust-section-vma Ar section Ns {+|-|=} Ns Ar val |
|
||||||
|
.Fl -change-section-address Ar section Ns {+|-|=} Ns Ar val
|
||||||
|
.Xc
|
||||||
|
Depending on the operator specified, increase, decrease or set both
|
||||||
|
the virtual memory address and the load memory address of the section
|
||||||
|
named by the argument
|
||||||
|
.Ar section .
|
||||||
|
The argument
|
||||||
|
.Ar val
|
||||||
|
specifies the desired increment, decrement or new value for the
|
||||||
|
address.
|
||||||
|
.It Xo
|
||||||
|
.Fl -adjust-start Ns = Ns Ar increment |
|
||||||
|
.Fl -change-start Ns = Ns Ar increment
|
||||||
|
.Xc
|
||||||
|
Increase the entry point address of the output ELF object by the value
|
||||||
|
specified in the argument
|
||||||
|
.Ar increment .
|
||||||
|
.It Xo
|
||||||
|
.Fl -adjust-vma Ns = Ns Ar increment |
|
||||||
|
.Fl -change-addresses Ns = Ns Ar increment
|
||||||
|
.Xc
|
||||||
|
Increase the virtual memory address and the load memory address of all
|
||||||
|
sections by the value specified by the argument
|
||||||
|
.Ar increment .
|
||||||
|
.It Fl -adjust-warnings | Fl -change-warnings
|
||||||
|
Issue a warning if the section specified by the options
|
||||||
|
.Fl -change-section-address ,
|
||||||
|
.Fl -change-section-lma
|
||||||
|
or
|
||||||
|
.Fl -change-section-vma
|
||||||
|
does not exist in the input object.
|
||||||
|
This is the default.
|
||||||
|
.It Fl -change-section-lma Ar section Ns {+|-|=} Ns Ar val
|
||||||
|
Change or set the load memory address of the section named by the
|
||||||
|
argument
|
||||||
|
.Ar section .
|
||||||
|
Depending on the operator specified, the value in argument
|
||||||
|
.Ar val
|
||||||
|
will be used as an increment, a decrement or as the new value
|
||||||
|
of the load memory address.
|
||||||
|
.It Fl -change-section-vma Ar section Ns {+|-|=} Ns Ar val
|
||||||
|
Change or set the virtual memory address of the section named by the
|
||||||
|
argument
|
||||||
|
.Ar section .
|
||||||
|
Depending on the operator specified, the value in argument
|
||||||
|
.Ar val
|
||||||
|
will be used as an increment, a decrement or as the new value
|
||||||
|
of the virtual memory address.
|
||||||
|
.It Fl -gap-fill Ns = Ns Ar val
|
||||||
|
Fill the gaps between sections with the byte value specified by
|
||||||
|
the argument
|
||||||
|
.Ar val .
|
||||||
|
.It Fl -no-adjust-warnings | Fl -no-change-warnings
|
||||||
|
Do not issue a warning if the section specified by the options
|
||||||
|
.Fl -change-section-address ,
|
||||||
|
.Fl -change-section-lma
|
||||||
|
or
|
||||||
|
.Fl -change-section-vma
|
||||||
|
is missing in the input object.
|
||||||
|
.It Fl -only-keep-debug
|
||||||
|
Copy only debugging information to the output file.
|
||||||
|
.It Fl -pad-to Ns = Ns Ar address
|
||||||
|
Pad the load memory address of the output object to the value
|
||||||
|
specified by the argument
|
||||||
|
.Ar address
|
||||||
|
by increasing the size of the section with the highest load memory
|
||||||
|
address.
|
||||||
|
.It Fl -prefix-alloc-sections Ns = Ns Ar string
|
||||||
|
Prefix the section names of all the allocated sections with
|
||||||
|
.Ar string .
|
||||||
|
.It Fl -prefix-sections Ns = Ns Ar string
|
||||||
|
Prefix the section names of all the sections with
|
||||||
|
.Ar string .
|
||||||
|
.It Fl -prefix-symbols Ns = Ns Ar string
|
||||||
|
Prefix the symbol names of all the symbols with
|
||||||
|
.Ar string .
|
||||||
|
.It Fl -rename-section Ar oldname Ns = Ns Ar newname Ns Op Ar ,flags
|
||||||
|
Rename the section named by argument
|
||||||
|
.Ar oldname
|
||||||
|
to
|
||||||
|
.Ar newname ,
|
||||||
|
optionally changing the sections flags to that specified by argument
|
||||||
|
.Ar flags .
|
||||||
|
Allowed values for the argument
|
||||||
|
.Ar flags
|
||||||
|
are as for option
|
||||||
|
.Fl -set-section-flags
|
||||||
|
below.
|
||||||
|
.It Fl -set-section-flags Ar sectionname Ns = Ns Ar flags
|
||||||
|
Set the flags for the section named by argument
|
||||||
|
.Ar sectionname
|
||||||
|
to those specified by argument
|
||||||
|
.Ar flags .
|
||||||
|
Argument
|
||||||
|
.Ar flags
|
||||||
|
is a comma separated list of the following flag names:
|
||||||
|
.Bl -tag -width "readonly" -compact
|
||||||
|
.It alloc
|
||||||
|
The section occupies space in the output file.
|
||||||
|
.It code
|
||||||
|
The section contains machine instructions.
|
||||||
|
.It contents
|
||||||
|
This flag is accepted but is ignored.
|
||||||
|
.It data
|
||||||
|
The section contains writeable data.
|
||||||
|
.It debug
|
||||||
|
The section holds debugging information.
|
||||||
|
.It load
|
||||||
|
The section is loadable.
|
||||||
|
.It noload
|
||||||
|
The section should not be loaded into memory.
|
||||||
|
.It readonly
|
||||||
|
The section is not writable.
|
||||||
|
.It rom
|
||||||
|
The section contains ROM'able contents.
|
||||||
|
.It share
|
||||||
|
This flag is accepted but is ignored.
|
||||||
|
.El
|
||||||
|
.It Fl -set-start Ns = Ns Ar address
|
||||||
|
Set the start address of the output ELF object to the value specified
|
||||||
|
by the argument
|
||||||
|
.Ar address .
|
||||||
|
.It Fl -srec-forceS3
|
||||||
|
Only generate S-records of type
|
||||||
|
.Dq S3 .
|
||||||
|
This option is only meaningful when the output target is set to
|
||||||
|
.Dq srec .
|
||||||
|
.It Fl -srec-len Ns = Ns Ar val
|
||||||
|
Set the maximum length of an S-record line to
|
||||||
|
.Ar val .
|
||||||
|
This option is only meaningful when the output target is set to
|
||||||
|
.Dq srec .
|
||||||
|
.It Fl -strip-unneeded
|
||||||
|
Do not copy symbols that are not needed for relocation processing.
|
||||||
|
.El
|
||||||
|
.Sh DIAGNOSTICS
|
||||||
|
.Ex -std
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr ar 1 ,
|
||||||
|
.Xr ld 1 ,
|
||||||
|
.Xr mcs 1 ,
|
||||||
|
.Xr strip 1 ,
|
||||||
|
.Xr elf 3 ,
|
||||||
|
.Xr ar 5 ,
|
||||||
|
.Xr elf 5
|
||||||
|
.Sh HISTORY
|
||||||
|
.Nm
|
||||||
|
has been implemented by
|
||||||
|
.An "Kai Wang" Aq kaiwang27@users.sourceforge.net .
|
313
contrib/elftoolchain/elfcopy/elfcopy.h
Normal file
313
contrib/elftoolchain/elfcopy/elfcopy.h
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2007-2013 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.
|
||||||
|
* 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: elfcopy.h 2970 2013-12-01 15:22:12Z kaiwang27 $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <gelf.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
|
||||||
|
#include "_elftc.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* User specified symbol operation (strip, keep, localize, globalize,
|
||||||
|
* weaken, rename, etc).
|
||||||
|
*/
|
||||||
|
struct symop {
|
||||||
|
const char *name;
|
||||||
|
const char *newname;
|
||||||
|
|
||||||
|
#define SYMOP_KEEP 0x0001U
|
||||||
|
#define SYMOP_STRIP 0x0002U
|
||||||
|
#define SYMOP_GLOBALIZE 0x0004U
|
||||||
|
#define SYMOP_LOCALIZE 0x0008U
|
||||||
|
#define SYMOP_KEEPG 0x0010U
|
||||||
|
#define SYMOP_WEAKEN 0x0020U
|
||||||
|
#define SYMOP_REDEF 0x0040U
|
||||||
|
|
||||||
|
unsigned int op;
|
||||||
|
|
||||||
|
STAILQ_ENTRY(symop) symop_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* File containing symbol list. */
|
||||||
|
struct symfile {
|
||||||
|
dev_t dev;
|
||||||
|
ino_t ino;
|
||||||
|
size_t size;
|
||||||
|
char *data;
|
||||||
|
unsigned int op;
|
||||||
|
|
||||||
|
STAILQ_ENTRY(symfile) symfile_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Sections to copy/remove/rename/... */
|
||||||
|
struct sec_action {
|
||||||
|
const char *name;
|
||||||
|
const char *addopt;
|
||||||
|
const char *newname;
|
||||||
|
const char *string;
|
||||||
|
uint64_t lma;
|
||||||
|
uint64_t vma;
|
||||||
|
int64_t lma_adjust;
|
||||||
|
int64_t vma_adjust;
|
||||||
|
|
||||||
|
#define SF_ALLOC 0x0001U
|
||||||
|
#define SF_LOAD 0x0002U
|
||||||
|
#define SF_NOLOAD 0x0004U
|
||||||
|
#define SF_READONLY 0x0008U
|
||||||
|
#define SF_DEBUG 0x0010U
|
||||||
|
#define SF_CODE 0x0020U
|
||||||
|
#define SF_DATA 0x0040U
|
||||||
|
#define SF_ROM 0x0080U
|
||||||
|
#define SF_SHARED 0X0100U
|
||||||
|
#define SF_CONTENTS 0x0200U
|
||||||
|
|
||||||
|
int flags;
|
||||||
|
int add;
|
||||||
|
int append;
|
||||||
|
int compress;
|
||||||
|
int copy;
|
||||||
|
int print;
|
||||||
|
int remove;
|
||||||
|
int rename;
|
||||||
|
int setflags;
|
||||||
|
int setlma;
|
||||||
|
int setvma;
|
||||||
|
|
||||||
|
STAILQ_ENTRY(sec_action) sac_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Sections to add from file. */
|
||||||
|
struct sec_add {
|
||||||
|
char *name;
|
||||||
|
char *content;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
STAILQ_ENTRY(sec_add) sadd_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct segment;
|
||||||
|
|
||||||
|
/* Internal data structure for sections. */
|
||||||
|
struct section {
|
||||||
|
struct segment *seg; /* containing segment */
|
||||||
|
const char *name; /* section name */
|
||||||
|
char *newname; /* new section name */
|
||||||
|
Elf_Scn *is; /* input scn */
|
||||||
|
Elf_Scn *os; /* output scn */
|
||||||
|
void *buf; /* section content */
|
||||||
|
uint8_t *pad; /* section padding */
|
||||||
|
uint64_t off; /* section offset */
|
||||||
|
uint64_t sz; /* section size */
|
||||||
|
uint64_t cap; /* section capacity */
|
||||||
|
uint64_t align; /* section alignment */
|
||||||
|
uint64_t type; /* section type */
|
||||||
|
uint64_t vma; /* section virtual addr */
|
||||||
|
uint64_t lma; /* section load addr */
|
||||||
|
uint64_t pad_sz;/* section padding size */
|
||||||
|
int loadable; /* whether loadable */
|
||||||
|
int pseudo;
|
||||||
|
int nocopy;
|
||||||
|
|
||||||
|
TAILQ_ENTRY(section) sec_list; /* next section */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Internal data structure for segments. */
|
||||||
|
struct segment {
|
||||||
|
uint64_t addr; /* load addr */
|
||||||
|
uint64_t off; /* file offset */
|
||||||
|
uint64_t fsz; /* file size */
|
||||||
|
uint64_t msz; /* memory size */
|
||||||
|
uint64_t type; /* segment type */
|
||||||
|
int remove; /* whether remove */
|
||||||
|
int nsec; /* number of sections contained */
|
||||||
|
struct section **v_sec; /* list of sections contained */
|
||||||
|
|
||||||
|
STAILQ_ENTRY(segment) seg_list; /* next segment */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In-memory representation of ar(1) archive member(object).
|
||||||
|
*/
|
||||||
|
struct ar_obj {
|
||||||
|
char *name; /* member name */
|
||||||
|
char *buf; /* member content */
|
||||||
|
void *maddr; /* mmap start address */
|
||||||
|
uid_t uid; /* user id */
|
||||||
|
gid_t gid; /* group id */
|
||||||
|
mode_t md; /* octal file permissions */
|
||||||
|
size_t size; /* member size */
|
||||||
|
time_t mtime; /* modification time */
|
||||||
|
|
||||||
|
STAILQ_ENTRY(ar_obj) objs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure encapsulates the "global" data for "elfcopy" program.
|
||||||
|
*/
|
||||||
|
struct elfcopy {
|
||||||
|
const char *progname; /* program name */
|
||||||
|
int iec; /* elfclass of input object */
|
||||||
|
Elftc_Bfd_Target_Flavor itf; /* flavour of input object */
|
||||||
|
Elftc_Bfd_Target_Flavor otf; /* flavour of output object */
|
||||||
|
const char *otgt; /* output target name */
|
||||||
|
int oec; /* elfclass of output object */
|
||||||
|
unsigned char oed; /* endianess of output object */
|
||||||
|
int oem; /* EM_XXX of output object */
|
||||||
|
int abi; /* OSABI of output object */
|
||||||
|
Elf *ein; /* ELF descriptor of input object */
|
||||||
|
Elf *eout; /* ELF descriptor of output object */
|
||||||
|
int iphnum; /* num. of input object phdr entries */
|
||||||
|
int ophnum; /* num. of output object phdr entries */
|
||||||
|
int nos; /* num. of output object sections */
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STRIP_NONE = 0,
|
||||||
|
STRIP_ALL,
|
||||||
|
STRIP_DEBUG,
|
||||||
|
STRIP_NONDEBUG,
|
||||||
|
STRIP_UNNEEDED
|
||||||
|
} strip;
|
||||||
|
|
||||||
|
#define EXECUTABLE 0x00000001U
|
||||||
|
#define DYNAMIC 0x00000002U
|
||||||
|
#define RELOCATABLE 0x00000004U
|
||||||
|
#define SYMTAB_EXIST 0x00000010U
|
||||||
|
#define SYMTAB_INTACT 0x00000020U
|
||||||
|
#define KEEP_GLOBAL 0x00000040U
|
||||||
|
#define DISCARD_LOCAL 0x00000080U
|
||||||
|
#define WEAKEN_ALL 0x00000100U
|
||||||
|
#define PRESERVE_DATE 0x00001000U
|
||||||
|
#define SREC_FORCE_S3 0x00002000U
|
||||||
|
#define SREC_FORCE_LEN 0x00004000U
|
||||||
|
#define SET_START 0x00008000U
|
||||||
|
#define GAP_FILL 0x00010000U
|
||||||
|
#define WILDCARD 0x00020000U
|
||||||
|
#define NO_CHANGE_WARN 0x00040000U
|
||||||
|
#define SEC_ADD 0x00080000U
|
||||||
|
#define SEC_APPEND 0x00100000U
|
||||||
|
#define SEC_COMPRESS 0x00200000U
|
||||||
|
#define SEC_PRINT 0x00400000U
|
||||||
|
#define SEC_REMOVE 0x00800000U
|
||||||
|
#define SEC_COPY 0x01000000U
|
||||||
|
#define DISCARD_LLABEL 0x02000000U
|
||||||
|
|
||||||
|
int flags; /* elfcopy run control flags. */
|
||||||
|
int64_t change_addr; /* Section address adjustment. */
|
||||||
|
int64_t change_start; /* Entry point adjustment. */
|
||||||
|
uint64_t set_start; /* Entry point value. */
|
||||||
|
unsigned long srec_len; /* S-Record length. */
|
||||||
|
uint64_t pad_to; /* load address padding. */
|
||||||
|
uint8_t fill; /* gap fill value. */
|
||||||
|
char *prefix_sec; /* section prefix. */
|
||||||
|
char *prefix_alloc; /* alloc section prefix. */
|
||||||
|
char *prefix_sym; /* symbol prefix. */
|
||||||
|
char *debuglink; /* GNU debuglink file. */
|
||||||
|
struct section *symtab; /* .symtab section. */
|
||||||
|
struct section *strtab; /* .strtab section. */
|
||||||
|
struct section *shstrtab; /* .shstrtab section. */
|
||||||
|
uint64_t *secndx; /* section index map. */
|
||||||
|
uint64_t *symndx; /* symbol index map. */
|
||||||
|
unsigned char *v_rel; /* symbols needed by relocation. */
|
||||||
|
unsigned char *v_secsym; /* sections with section symbol. */
|
||||||
|
STAILQ_HEAD(, segment) v_seg; /* list of segments. */
|
||||||
|
STAILQ_HEAD(, sec_action) v_sac;/* list of section operations. */
|
||||||
|
STAILQ_HEAD(, sec_add) v_sadd; /* list of sections to add. */
|
||||||
|
STAILQ_HEAD(, symop) v_symop; /* list of symbols operations. */
|
||||||
|
STAILQ_HEAD(, symfile) v_symfile; /* list of symlist files. */
|
||||||
|
TAILQ_HEAD(, section) v_sec; /* list of sections. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fields for the ar(1) archive.
|
||||||
|
*/
|
||||||
|
char *as; /* buffer for archive string table. */
|
||||||
|
size_t as_sz; /* current size of as table. */
|
||||||
|
size_t as_cap; /* capacity of as table buffer. */
|
||||||
|
uint32_t s_cnt; /* current number of symbols. */
|
||||||
|
uint32_t *s_so; /* symbol offset table. */
|
||||||
|
size_t s_so_cap; /* capacity of so table buffer. */
|
||||||
|
char *s_sn; /* symbol name table */
|
||||||
|
size_t s_sn_cap; /* capacity of sn table buffer. */
|
||||||
|
size_t s_sn_sz; /* current size of sn table. */
|
||||||
|
off_t rela_off; /* offset relative to pseudo members. */
|
||||||
|
STAILQ_HEAD(, ar_obj) v_arobj; /* archive object(member) list. */
|
||||||
|
};
|
||||||
|
|
||||||
|
void add_section(struct elfcopy *_ecp, const char *_optarg);
|
||||||
|
void add_to_shstrtab(struct elfcopy *_ecp, const char *_name);
|
||||||
|
void add_to_symop_list(struct elfcopy *_ecp, const char *_name,
|
||||||
|
const char *_newname, unsigned int _op);
|
||||||
|
void add_to_symtab(struct elfcopy *_ecp, const char *_name,
|
||||||
|
uint64_t _st_value, uint64_t _st_size, uint16_t _st_shndx,
|
||||||
|
unsigned char _st_info, unsigned char _st_other, int _ndx_known);
|
||||||
|
int add_to_inseg_list(struct elfcopy *_ecp, struct section *_sec);
|
||||||
|
void adjust_addr(struct elfcopy *_ecp);
|
||||||
|
void copy_content(struct elfcopy *_ecp);
|
||||||
|
void copy_data(struct section *_s);
|
||||||
|
void copy_phdr(struct elfcopy *_ecp);
|
||||||
|
void copy_shdr(struct elfcopy *_ecp, struct section *_s, const char *_name,
|
||||||
|
int _copy, int _sec_flags);
|
||||||
|
void create_binary(int _ifd, int _ofd);
|
||||||
|
void create_elf(struct elfcopy *_ecp);
|
||||||
|
void create_elf_from_binary(struct elfcopy *_ecp, int _ifd, const char *ifn);
|
||||||
|
void create_elf_from_ihex(struct elfcopy *_ecp, int _ifd);
|
||||||
|
void create_elf_from_srec(struct elfcopy *_ecp, int _ifd);
|
||||||
|
struct section *create_external_section(struct elfcopy *_ecp, const char *_name,
|
||||||
|
char *_newname, void *_buf, uint64_t _size, uint64_t _off, uint64_t _stype,
|
||||||
|
Elf_Type _dtype, uint64_t flags, uint64_t _align, uint64_t _vma,
|
||||||
|
int _loadable);
|
||||||
|
void create_external_symtab(struct elfcopy *_ecp);
|
||||||
|
void create_ihex(int _ifd, int _ofd);
|
||||||
|
void create_scn(struct elfcopy *_ecp);
|
||||||
|
void create_srec(struct elfcopy *_ecp, int _ifd, int _ofd, const char *_ofn);
|
||||||
|
void create_symtab(struct elfcopy *_ecp);
|
||||||
|
void create_symtab_data(struct elfcopy *_ecp);
|
||||||
|
void create_tempfile(char **_fn, int *_fd);
|
||||||
|
void finalize_external_symtab(struct elfcopy *_ecp);
|
||||||
|
void free_elf(struct elfcopy *_ecp);
|
||||||
|
void free_sec_act(struct elfcopy *_ecp);
|
||||||
|
void free_sec_add(struct elfcopy *_ecp);
|
||||||
|
void free_symtab(struct elfcopy *_ecp);
|
||||||
|
void init_shstrtab(struct elfcopy *_ecp);
|
||||||
|
void insert_to_sec_list(struct elfcopy *_ecp, struct section *_sec,
|
||||||
|
int _tail);
|
||||||
|
struct section *insert_shtab(struct elfcopy *_ecp, int tail);
|
||||||
|
int is_remove_reloc_sec(struct elfcopy *_ecp, uint32_t _sh_info);
|
||||||
|
int is_remove_section(struct elfcopy *_ecp, const char *_name);
|
||||||
|
struct sec_action *lookup_sec_act(struct elfcopy *_ecp,
|
||||||
|
const char *_name, int _add);
|
||||||
|
struct symop *lookup_symop_list(struct elfcopy *_ecp, const char *_name,
|
||||||
|
unsigned int _op);
|
||||||
|
void resync_sections(struct elfcopy *_ecp);
|
||||||
|
void set_shstrtab(struct elfcopy *_ecp);
|
||||||
|
void setup_phdr(struct elfcopy *_ecp);
|
||||||
|
void update_shdr(struct elfcopy *_ecp, int _update_link);
|
||||||
|
|
||||||
|
#ifndef LIBELF_AR
|
||||||
|
int ac_detect_ar(int _ifd);
|
||||||
|
void ac_create_ar(struct elfcopy *_ecp, int _ifd, int _ofd);
|
||||||
|
#endif /* ! LIBELF_AR */
|
1500
contrib/elftoolchain/elfcopy/main.c
Normal file
1500
contrib/elftoolchain/elfcopy/main.c
Normal file
File diff suppressed because it is too large
Load Diff
125
contrib/elftoolchain/elfcopy/mcs.1
Normal file
125
contrib/elftoolchain/elfcopy/mcs.1
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
.\" 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: mcs.1 2247 2011-11-29 08:41:34Z jkoshy $
|
||||||
|
.\"
|
||||||
|
.Dd November 29, 2011
|
||||||
|
.Os
|
||||||
|
.Dt MCS 1
|
||||||
|
.Sh NAME
|
||||||
|
.Nm mcs
|
||||||
|
.Nd manipulate the comment section of an ELF object
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl a Ar string
|
||||||
|
.Op Fl c
|
||||||
|
.Op Fl n Ar name
|
||||||
|
.Op Fl p
|
||||||
|
.Ar
|
||||||
|
.Nm
|
||||||
|
.Fl d
|
||||||
|
.Op Fl n Ar name
|
||||||
|
.Ar
|
||||||
|
.Nm
|
||||||
|
.Fl h | Fl -help
|
||||||
|
.Nm
|
||||||
|
.Fl V | Fl -version
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility is used to manipulate comment sections in an ELF object.
|
||||||
|
If a command-line argument
|
||||||
|
.Ar file
|
||||||
|
names an
|
||||||
|
.Xr ar 1
|
||||||
|
archive, then
|
||||||
|
.Nm
|
||||||
|
will operate on the ELF objects contained in the archive.
|
||||||
|
.Pp
|
||||||
|
By default
|
||||||
|
.Nm
|
||||||
|
operates on the ELF section named
|
||||||
|
.Dq .comment .
|
||||||
|
This may be changed using the
|
||||||
|
.Fl n
|
||||||
|
option.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility supports the following options:
|
||||||
|
.Bl -tag -width ".Fl a Ar string"
|
||||||
|
.It Fl a Ar string
|
||||||
|
Append the text in
|
||||||
|
.Ar string
|
||||||
|
to the comment section.
|
||||||
|
This option may be specified multiple times.
|
||||||
|
.It Fl c
|
||||||
|
Compress the comment section by removing duplicate entries.
|
||||||
|
.It Fl d
|
||||||
|
Delete the comment section from the ELF object.
|
||||||
|
.It Fl h | Fl -help
|
||||||
|
Display a usage message and exit.
|
||||||
|
.It Fl n Ar name
|
||||||
|
Operate on the section named
|
||||||
|
.Ar name .
|
||||||
|
.It Fl p
|
||||||
|
Print the contents of the comment section.
|
||||||
|
This step is taken after actions specified by the
|
||||||
|
.Fl a
|
||||||
|
and
|
||||||
|
.Fl c
|
||||||
|
options (if any) are completed.
|
||||||
|
.It Fl V | Fl -version
|
||||||
|
Print a version identifier and exit.
|
||||||
|
.El
|
||||||
|
.Sh COMPATIBILITY
|
||||||
|
The behavior of the
|
||||||
|
.Nm
|
||||||
|
utility differs from its SVR4 counterpart in the following ways:
|
||||||
|
.Bl -bullet -compact
|
||||||
|
.It
|
||||||
|
If the
|
||||||
|
.Fl d
|
||||||
|
option is specified, it causes any
|
||||||
|
.Fl a ,
|
||||||
|
.Fl c
|
||||||
|
and
|
||||||
|
.Fl p
|
||||||
|
options present to be ignored.
|
||||||
|
.It
|
||||||
|
The order of options
|
||||||
|
.Fl a ,
|
||||||
|
.Fl c ,
|
||||||
|
.Fl d ,
|
||||||
|
and
|
||||||
|
.Fl p
|
||||||
|
on the command line is not significant.
|
||||||
|
.El
|
||||||
|
.Sh DIAGNOSTICS
|
||||||
|
.Ex -std
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr ar 1 ,
|
||||||
|
.Xr elfcopy 1 ,
|
||||||
|
.Xr ld 1 ,
|
||||||
|
.Xr nm 1 ,
|
||||||
|
.Xr strip 1
|
1518
contrib/elftoolchain/elfcopy/sections.c
Normal file
1518
contrib/elftoolchain/elfcopy/sections.c
Normal file
File diff suppressed because it is too large
Load Diff
493
contrib/elftoolchain/elfcopy/segments.c
Normal file
493
contrib/elftoolchain/elfcopy/segments.c
Normal file
@ -0,0 +1,493 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2007-2010,2012 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.
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <gelf.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "elfcopy.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: segments.c 2542 2012-08-12 16:14:15Z kaiwang27 $");
|
||||||
|
|
||||||
|
static void insert_to_inseg_list(struct segment *seg, struct section *sec);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* elfcopy's segment handling is relatively simpler and less powerful than
|
||||||
|
* libbfd. Program headers are modified or copied from input to output objects,
|
||||||
|
* but never re-generated. As a result, if the input object has incorrect
|
||||||
|
* program headers, the output object's program headers will remain incorrect
|
||||||
|
* or become even worse.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether a section is "loadable". If so, add it to the
|
||||||
|
* corresponding segment list(s) and return 1.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
add_to_inseg_list(struct elfcopy *ecp, struct section *s)
|
||||||
|
{
|
||||||
|
struct segment *seg;
|
||||||
|
int loadable;
|
||||||
|
|
||||||
|
if (ecp->ophnum == 0)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Segment is a different view of an ELF object. One segment can
|
||||||
|
* contain one or more sections, and one section can be included
|
||||||
|
* in one or more segments, or not included in any segment at all.
|
||||||
|
* We call those sections which can be found in one or more segments
|
||||||
|
* "loadable" sections, and call the rest "unloadable" sections.
|
||||||
|
* We keep track of "loadable" sections in their containing
|
||||||
|
* segment(s)' v_sec queue. These information are later used to
|
||||||
|
* recalculate the extents of segments, when sections are removed,
|
||||||
|
* for example.
|
||||||
|
*/
|
||||||
|
loadable = 0;
|
||||||
|
STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
|
||||||
|
if (s->off < seg->off)
|
||||||
|
continue;
|
||||||
|
if (s->off + s->sz > seg->off + seg->fsz &&
|
||||||
|
s->type != SHT_NOBITS)
|
||||||
|
continue;
|
||||||
|
if (s->off + s->sz > seg->off + seg->msz)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
insert_to_inseg_list(seg, s);
|
||||||
|
if (seg->type == PT_LOAD)
|
||||||
|
s->seg = seg;
|
||||||
|
s->lma = seg->addr + (s->off - seg->off);
|
||||||
|
loadable = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (loadable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
adjust_addr(struct elfcopy *ecp)
|
||||||
|
{
|
||||||
|
struct section *s, *s0;
|
||||||
|
struct segment *seg;
|
||||||
|
struct sec_action *sac;
|
||||||
|
uint64_t dl, lma, old_vma, start, end;
|
||||||
|
int found, i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply VMA and global LMA changes in the first iteration.
|
||||||
|
*/
|
||||||
|
TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
|
||||||
|
|
||||||
|
/* Only adjust loadable section's address. */
|
||||||
|
if (!s->loadable || s->seg == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Apply global LMA adjustment. */
|
||||||
|
if (ecp->change_addr != 0)
|
||||||
|
s->lma += ecp->change_addr;
|
||||||
|
|
||||||
|
if (!s->pseudo) {
|
||||||
|
old_vma = s->vma;
|
||||||
|
|
||||||
|
/* Apply global VMA adjustment. */
|
||||||
|
if (ecp->change_addr != 0)
|
||||||
|
s->vma += ecp->change_addr;
|
||||||
|
|
||||||
|
/* Apply section VMA adjustment. */
|
||||||
|
sac = lookup_sec_act(ecp, s->name, 0);
|
||||||
|
if (sac == NULL)
|
||||||
|
continue;
|
||||||
|
if (sac->setvma)
|
||||||
|
s->vma = sac->vma;
|
||||||
|
if (sac->vma_adjust != 0)
|
||||||
|
s->vma += sac->vma_adjust;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply sections LMA change in the second iteration.
|
||||||
|
*/
|
||||||
|
TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
|
||||||
|
|
||||||
|
/* Only adjust loadable section's LMA. */
|
||||||
|
if (!s->loadable || s->seg == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if there is a LMA change request for this
|
||||||
|
* section.
|
||||||
|
*/
|
||||||
|
sac = lookup_sec_act(ecp, s->name, 0);
|
||||||
|
if (sac == NULL)
|
||||||
|
continue;
|
||||||
|
if (!sac->setlma && sac->lma_adjust == 0)
|
||||||
|
continue;
|
||||||
|
lma = s->lma;
|
||||||
|
if (sac->setlma)
|
||||||
|
lma = sac->lma;
|
||||||
|
if (sac->lma_adjust != 0)
|
||||||
|
lma += sac->lma_adjust;
|
||||||
|
if (lma == s->lma)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the LMA change is viable.
|
||||||
|
*
|
||||||
|
* 1. Check if the new LMA is properly aligned accroding to
|
||||||
|
* section alignment.
|
||||||
|
*
|
||||||
|
* 2. Compute the new extent of segment that contains this
|
||||||
|
* section, make sure it doesn't overlap with other
|
||||||
|
* segments.
|
||||||
|
*/
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("LMA for section %s: %#jx\n", s->name, lma);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (lma % s->align != 0)
|
||||||
|
errx(EXIT_FAILURE, "The load address %#jx for "
|
||||||
|
"section %s is not aligned to %ju",
|
||||||
|
(uintmax_t) lma, s->name, s->align);
|
||||||
|
|
||||||
|
if (lma < s->lma) {
|
||||||
|
/* Move section to lower address. */
|
||||||
|
if (lma < s->lma - s->seg->addr)
|
||||||
|
errx(EXIT_FAILURE, "Not enough space to move "
|
||||||
|
"section %s load address to %#jx", s->name,
|
||||||
|
(uintmax_t) lma);
|
||||||
|
start = lma - (s->lma - s->seg->addr);
|
||||||
|
if (s == s->seg->v_sec[s->seg->nsec - 1])
|
||||||
|
end = start + s->seg->msz;
|
||||||
|
else
|
||||||
|
end = s->seg->addr + s->seg->msz;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Move section to upper address. */
|
||||||
|
if (s == s->seg->v_sec[0])
|
||||||
|
start = lma;
|
||||||
|
else
|
||||||
|
start = s->seg->addr;
|
||||||
|
end = lma + (s->seg->addr + s->seg->msz - s->lma);
|
||||||
|
if (end < start)
|
||||||
|
errx(EXIT_FAILURE, "Not enough space to move "
|
||||||
|
"section %s load address to %#jx", s->name,
|
||||||
|
(uintmax_t) lma);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("new extent for segment containing %s: (%#jx,%#jx)\n",
|
||||||
|
s->name, start, end);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
|
||||||
|
if (seg == s->seg || seg->type != PT_LOAD)
|
||||||
|
continue;
|
||||||
|
if (start > seg->addr + seg->msz)
|
||||||
|
continue;
|
||||||
|
if (end < seg->addr)
|
||||||
|
continue;
|
||||||
|
errx(EXIT_FAILURE, "The extent of segment containing "
|
||||||
|
"section %s overlaps with segment(%#jx,%#jx)",
|
||||||
|
s->name, seg->addr, seg->addr + seg->msz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update section LMA and file offset.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (lma < s->lma) {
|
||||||
|
/*
|
||||||
|
* To move a section to lower load address, we decrease
|
||||||
|
* the load addresses of the section and all the
|
||||||
|
* sections that are before it, and we increase the
|
||||||
|
* file offsets of all the sections that are after it.
|
||||||
|
*/
|
||||||
|
dl = s->lma - lma;
|
||||||
|
for (i = 0; i < s->seg->nsec; i++) {
|
||||||
|
s0 = s->seg->v_sec[i];
|
||||||
|
s0->lma -= dl;
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("section %s LMA set to %#jx\n",
|
||||||
|
s0->name, (uintmax_t) s0->lma);
|
||||||
|
#endif
|
||||||
|
if (s0 == s)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (i = i + 1; i < s->seg->nsec; i++) {
|
||||||
|
s0 = s->seg->v_sec[i];
|
||||||
|
s0->off += dl;
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("section %s offset set to %#jx\n",
|
||||||
|
s0->name, (uintmax_t) s0->off);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* To move a section to upper load address, we increase
|
||||||
|
* the load addresses of the section and all the
|
||||||
|
* sections that are after it, and we increase the
|
||||||
|
* their file offsets too unless the section in question
|
||||||
|
* is the first in its containing segment.
|
||||||
|
*/
|
||||||
|
dl = lma - s->lma;
|
||||||
|
for (i = 0; i < s->seg->nsec; i++)
|
||||||
|
if (s->seg->v_sec[i] == s)
|
||||||
|
break;
|
||||||
|
if (i >= s->seg->nsec)
|
||||||
|
errx(EXIT_FAILURE, "Internal: section `%s' not"
|
||||||
|
" found in its containing segement",
|
||||||
|
s->name);
|
||||||
|
for (; i < s->seg->nsec; i++) {
|
||||||
|
s0 = s->seg->v_sec[i];
|
||||||
|
s0->lma += dl;
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("section %s LMA set to %#jx\n",
|
||||||
|
s0->name, (uintmax_t) s0->lma);
|
||||||
|
#endif
|
||||||
|
if (s != s->seg->v_sec[0]) {
|
||||||
|
s0->off += dl;
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("section %s offset set to %#jx\n",
|
||||||
|
s0->name, (uintmax_t) s0->off);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply load address padding.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ecp->pad_to != 0) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the section with highest load address.
|
||||||
|
*/
|
||||||
|
|
||||||
|
s = NULL;
|
||||||
|
STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
|
||||||
|
if (seg->type != PT_LOAD)
|
||||||
|
continue;
|
||||||
|
for (i = seg->nsec - 1; i >= 0; i--)
|
||||||
|
if (seg->v_sec[i]->type != SHT_NOBITS)
|
||||||
|
break;
|
||||||
|
if (i < 0)
|
||||||
|
continue;
|
||||||
|
if (s == NULL)
|
||||||
|
s = seg->v_sec[i];
|
||||||
|
else {
|
||||||
|
s0 = seg->v_sec[i];
|
||||||
|
if (s0->lma > s->lma)
|
||||||
|
s = s0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s == NULL)
|
||||||
|
goto issue_warn;
|
||||||
|
|
||||||
|
/* No need to pad if the pad_to address is lower. */
|
||||||
|
if (ecp->pad_to <= s->lma + s->sz)
|
||||||
|
goto issue_warn;
|
||||||
|
|
||||||
|
s->pad_sz = ecp->pad_to - (s->lma + s->sz);
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("pad section %s load to address %#jx by %#jx\n", s->name,
|
||||||
|
(uintmax_t) ecp->pad_to, (uintmax_t) s->pad_sz);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_warn:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Issue a warning if there are VMA/LMA adjust requests for
|
||||||
|
* some nonexistent sections.
|
||||||
|
*/
|
||||||
|
if ((ecp->flags & NO_CHANGE_WARN) == 0) {
|
||||||
|
STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
|
||||||
|
if (!sac->setvma && !sac->setlma &&
|
||||||
|
!sac->vma_adjust && !sac->lma_adjust)
|
||||||
|
continue;
|
||||||
|
found = 0;
|
||||||
|
TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
|
||||||
|
if (s->pseudo || s->name == NULL)
|
||||||
|
continue;
|
||||||
|
if (!strcmp(s->name, sac->name)) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
warnx("cannot find section `%s'", sac->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_to_inseg_list(struct segment *seg, struct section *sec)
|
||||||
|
{
|
||||||
|
struct section *s;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
seg->nsec++;
|
||||||
|
seg->v_sec = realloc(seg->v_sec, seg->nsec * sizeof(*seg->v_sec));
|
||||||
|
if (seg->v_sec == NULL)
|
||||||
|
err(EXIT_FAILURE, "realloc failed");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sort the section in order of offset.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (i = seg->nsec - 1; i > 0; i--) {
|
||||||
|
s = seg->v_sec[i - 1];
|
||||||
|
if (sec->off >= s->off) {
|
||||||
|
seg->v_sec[i] = sec;
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
seg->v_sec[i] = s;
|
||||||
|
}
|
||||||
|
if (i == 0)
|
||||||
|
seg->v_sec[0] = sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setup_phdr(struct elfcopy *ecp)
|
||||||
|
{
|
||||||
|
struct segment *seg;
|
||||||
|
GElf_Phdr iphdr;
|
||||||
|
size_t iphnum;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (elf_getphnum(ecp->ein, &iphnum) == 0)
|
||||||
|
errx(EXIT_FAILURE, "elf_getphnum failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
ecp->ophnum = ecp->iphnum = iphnum;
|
||||||
|
if (iphnum == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If --only-keep-debug is specified, discard all program headers. */
|
||||||
|
if (ecp->strip == STRIP_NONDEBUG) {
|
||||||
|
ecp->ophnum = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; (size_t)i < iphnum; i++) {
|
||||||
|
if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
|
||||||
|
errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
if ((seg = calloc(1, sizeof(*seg))) == NULL)
|
||||||
|
err(EXIT_FAILURE, "calloc failed");
|
||||||
|
seg->addr = iphdr.p_vaddr;
|
||||||
|
seg->off = iphdr.p_offset;
|
||||||
|
seg->fsz = iphdr.p_filesz;
|
||||||
|
seg->msz = iphdr.p_memsz;
|
||||||
|
seg->type = iphdr.p_type;
|
||||||
|
STAILQ_INSERT_TAIL(&ecp->v_seg, seg, seg_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
copy_phdr(struct elfcopy *ecp)
|
||||||
|
{
|
||||||
|
struct segment *seg;
|
||||||
|
struct section *s;
|
||||||
|
GElf_Phdr iphdr, ophdr;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
|
||||||
|
if (seg->type == PT_PHDR) {
|
||||||
|
if (!TAILQ_EMPTY(&ecp->v_sec)) {
|
||||||
|
s = TAILQ_FIRST(&ecp->v_sec);
|
||||||
|
if (s->pseudo)
|
||||||
|
seg->addr = s->lma +
|
||||||
|
gelf_fsize(ecp->eout, ELF_T_EHDR,
|
||||||
|
1, EV_CURRENT);
|
||||||
|
}
|
||||||
|
seg->fsz = seg->msz = gelf_fsize(ecp->eout, ELF_T_PHDR,
|
||||||
|
ecp->ophnum, EV_CURRENT);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg->fsz = seg->msz = 0;
|
||||||
|
for (i = 0; i < seg->nsec; i++) {
|
||||||
|
s = seg->v_sec[i];
|
||||||
|
seg->msz = s->off + s->sz - seg->off;
|
||||||
|
if (s->type != SHT_NOBITS)
|
||||||
|
seg->fsz = seg->msz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate space for program headers, note that libelf keep
|
||||||
|
* track of the number in internal variable, and a call to
|
||||||
|
* elf_update is needed to update e_phnum of ehdr.
|
||||||
|
*/
|
||||||
|
if (gelf_newphdr(ecp->eout, ecp->ophnum) == NULL)
|
||||||
|
errx(EXIT_FAILURE, "gelf_newphdr() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This elf_update() call is to update the e_phnum field in
|
||||||
|
* ehdr. It's necessary because later we will call gelf_getphdr(),
|
||||||
|
* which does sanity check by comparing ndx argument with e_phnum.
|
||||||
|
*/
|
||||||
|
if (elf_update(ecp->eout, ELF_C_NULL) < 0)
|
||||||
|
errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* iphnum == ophnum, since we don't remove program headers even if
|
||||||
|
* they no longer contain sections.
|
||||||
|
*/
|
||||||
|
i = 0;
|
||||||
|
STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
|
||||||
|
if (i >= ecp->iphnum)
|
||||||
|
break;
|
||||||
|
if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
|
||||||
|
errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
if (gelf_getphdr(ecp->eout, i, &ophdr) != &ophdr)
|
||||||
|
errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
ophdr.p_type = iphdr.p_type;
|
||||||
|
ophdr.p_vaddr = seg->addr;
|
||||||
|
ophdr.p_paddr = seg->addr;
|
||||||
|
ophdr.p_flags = iphdr.p_flags;
|
||||||
|
ophdr.p_align = iphdr.p_align;
|
||||||
|
ophdr.p_offset = seg->off;
|
||||||
|
ophdr.p_filesz = seg->fsz;
|
||||||
|
ophdr.p_memsz = seg->msz;
|
||||||
|
if (!gelf_update_phdr(ecp->eout, i, &ophdr))
|
||||||
|
err(EXIT_FAILURE, "gelf_update_phdr failed :%s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
132
contrib/elftoolchain/elfcopy/strip.1
Normal file
132
contrib/elftoolchain/elfcopy/strip.1
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
.\" 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: strip.1 2069 2011-10-26 15:53:48Z jkoshy $
|
||||||
|
.\"
|
||||||
|
.Dd September 17, 2011
|
||||||
|
.Os
|
||||||
|
.Dt STRIP 1
|
||||||
|
.Sh NAME
|
||||||
|
.Nm strip
|
||||||
|
.Nd discard information from ELF objects
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl d | Fl g | Fl S | Fl -strip-debug
|
||||||
|
.Op Fl h | Fl -help
|
||||||
|
.Op Fl -only-keep-debug
|
||||||
|
.Op Fl o Ar outputfile | Fl -output-file= Ns Ar outputfile
|
||||||
|
.Op Fl p | Fl -preserve-dates
|
||||||
|
.Op Fl s | Fl -strip-all
|
||||||
|
.Op Fl -strip-unneeded
|
||||||
|
.Op Fl w | Fl -wildcard
|
||||||
|
.Op Fl x | Fl -discard-all
|
||||||
|
.Op Fl I Ar format | Fl -input-target= Ns Ar format
|
||||||
|
.Op Fl K Ar symbol | Fl -keep-symbol= Ns Ar symbol
|
||||||
|
.Op Fl N Ar symbol | Fl -strip-symbol= Ns Ar symbol
|
||||||
|
.Op Fl O Ar format | Fl -output-target= Ns Ar format
|
||||||
|
.Op Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname
|
||||||
|
.Op Fl V | Fl -version
|
||||||
|
.Op Fl X | Fl -discard-locals
|
||||||
|
.Ar
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility is used to discard information from ELF objects.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility supports the following options:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl d | Fl g | Fl S | Fl -strip-debug
|
||||||
|
Remove debugging symbols only.
|
||||||
|
.It Fl h | Fl -help
|
||||||
|
Print a help message and exit.
|
||||||
|
.It Fl -only-keep-debug
|
||||||
|
Remove all content except that which would be used for debugging.
|
||||||
|
.It Fl o Ar outputfile | Fl -output-file= Ns Ar outputfile
|
||||||
|
Write the stripped object to file
|
||||||
|
.Ar outputfile .
|
||||||
|
The default behaviour is to modify objects in place.
|
||||||
|
.It Fl p | Fl -preserve-dates
|
||||||
|
Preserve the object's access and modification times.
|
||||||
|
.It Fl s | Fl -strip-all
|
||||||
|
Remove all symbols.
|
||||||
|
.It Fl -strip-unneeded
|
||||||
|
Remove all symbols not needed for further relocation processing.
|
||||||
|
.It Fl w | Fl -wildcard
|
||||||
|
Use shell-style patterns to name symbols.
|
||||||
|
The following meta-characters are recognized in patterns:
|
||||||
|
.Bl -tag -width "...." -compact
|
||||||
|
.It Li !
|
||||||
|
If this is the first character of the pattern, invert the sense of the
|
||||||
|
pattern match.
|
||||||
|
.It Li *
|
||||||
|
Matches any string of characters in a symbol name.
|
||||||
|
.It Li ?
|
||||||
|
Matches zero or one character in a symbol name.
|
||||||
|
.It Li [
|
||||||
|
Mark the start of a character class.
|
||||||
|
.It Li \e
|
||||||
|
Remove the special meaning of the next character in the pattern.
|
||||||
|
.It Li ]
|
||||||
|
Mark the end of a character class.
|
||||||
|
.El
|
||||||
|
.It Fl x | Fl -discard-all
|
||||||
|
Discard all non-global symbols.
|
||||||
|
.It Fl I Ar format | Fl -input-target= Ns Ar format
|
||||||
|
These options are accepted, but are ignored.
|
||||||
|
.It Fl K Ar symbol | Fl -keep-symbol= Ns Ar symbol
|
||||||
|
Keep the symbol
|
||||||
|
.Ar symbol
|
||||||
|
even if it would otherwise be stripped.
|
||||||
|
This option may be specified multiple times.
|
||||||
|
.It Fl N Ar symbol | Fl -strip-symbol= Ns Ar symbol
|
||||||
|
Remove the symbol
|
||||||
|
.Ar symbol
|
||||||
|
even if it would otherwise have been kept.
|
||||||
|
This option may be specified multiple times.
|
||||||
|
.It Fl O Ar format | Fl -output-target= Ns Ar format
|
||||||
|
Set the output file format to
|
||||||
|
.Ar format .
|
||||||
|
For the full list of supported formats, please see the documentation
|
||||||
|
for function
|
||||||
|
.Xr elftc_bfd_find_target 3 .
|
||||||
|
.It Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname
|
||||||
|
Remove the section named by the argument
|
||||||
|
.Ar sectionname .
|
||||||
|
This option may be specified multiple times.
|
||||||
|
.It Fl V | Fl -version
|
||||||
|
Print a version identifier and exit.
|
||||||
|
.It Fl X | Fl -discard-locals
|
||||||
|
Remove compiler-generated local symbols.
|
||||||
|
.El
|
||||||
|
.Sh DIAGNOSTICS
|
||||||
|
.Ex -std
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr ar 1 ,
|
||||||
|
.Xr elfcopy 1 ,
|
||||||
|
.Xr ld 1 ,
|
||||||
|
.Xr mcs 1 ,
|
||||||
|
.Xr elf 3 ,
|
||||||
|
.Xr elftc_bfd_find_target 3 ,
|
||||||
|
.Xr fnmatch 3
|
1040
contrib/elftoolchain/elfcopy/symbols.c
Normal file
1040
contrib/elftoolchain/elfcopy/symbols.c
Normal file
File diff suppressed because it is too large
Load Diff
65
contrib/elftoolchain/libelftc/Makefile
Normal file
65
contrib/elftoolchain/libelftc/Makefile
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# $Id: Makefile 2859 2013-01-05 09:21:54Z jkoshy $
|
||||||
|
|
||||||
|
TOP= ${.CURDIR}/..
|
||||||
|
|
||||||
|
LIB= elftc
|
||||||
|
|
||||||
|
SRCS= elftc_bfdtarget.c \
|
||||||
|
elftc_copyfile.c \
|
||||||
|
elftc_demangle.c \
|
||||||
|
elftc_set_timestamps.c \
|
||||||
|
elftc_string_table.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
|
||||||
|
|
||||||
|
CLEANFILES+= elftc_version.c
|
||||||
|
|
||||||
|
LDADD+= -lelf
|
||||||
|
|
||||||
|
MAN= elftc.3 \
|
||||||
|
elftc_bfd_find_target.3 \
|
||||||
|
elftc_copyfile.3 \
|
||||||
|
elftc_demangle.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 \
|
||||||
|
elftc_symbol_table_create.3 elftc_symbol_table_create_nested.3 \
|
||||||
|
elftc_symbol_table_create.3 elftc_symbol_table_delete_name.3 \
|
||||||
|
elftc_symbol_table_create.3 elftc_symbol_table_delete_entry.3 \
|
||||||
|
elftc_symbol_table_create.3 elftc_symbol_table_destroy.3 \
|
||||||
|
elftc_symbol_table_create.3 elftc_symbol_table_from_section.3 \
|
||||||
|
elftc_symbol_table_create.3 elftc_symbol_table_insert.3 \
|
||||||
|
elftc_symbol_table_create.3 elftc_symbol_table_iterate.3 \
|
||||||
|
elftc_symbol_table_create.3 elftc_symbol_table_lookup.3 \
|
||||||
|
elftc_symbol_table_create.3 elftc_symbol_table_to_image.3
|
||||||
|
|
||||||
|
.if !make(clean) && !make(clobber)
|
||||||
|
.BEGIN: .SILENT
|
||||||
|
${.CURDIR}/make-toolchain-version -t ${TOP} -r ${RELEASE} \
|
||||||
|
-h ${OS_HOST}
|
||||||
|
.endif
|
||||||
|
|
||||||
|
.include "${TOP}/mk/elftoolchain.lib.mk"
|
18
contrib/elftoolchain/libelftc/Version.map
Normal file
18
contrib/elftoolchain/libelftc/Version.map
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* $Id: Version.map 2574 2012-09-11 15:11:59Z jkoshy $
|
||||||
|
*/
|
||||||
|
|
||||||
|
R1.0 {
|
||||||
|
global:
|
||||||
|
elftc_bfd_find_target;
|
||||||
|
elftc_bfd_target_byteorder;
|
||||||
|
elftc_bfd_target_class;
|
||||||
|
elftc_bfd_target_flavor;
|
||||||
|
elftc_bfd_target_machine;
|
||||||
|
elftc_copyfile;
|
||||||
|
elftc_demangle;
|
||||||
|
elftc_set_timestamps;
|
||||||
|
elftc_version;
|
||||||
|
local:
|
||||||
|
*;
|
||||||
|
};
|
89
contrib/elftoolchain/libelftc/_libelftc.h
Normal file
89
contrib/elftoolchain/libelftc/_libelftc.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2009 Kai Wang
|
||||||
|
* Copyright (c) 2007,2008 Hyogeol Lee <hyogeollee@gmail.com>
|
||||||
|
* 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 2856 2013-01-04 16:00:26Z jkoshy $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBELFTC_H_
|
||||||
|
#define __LIBELFTC_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
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_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);
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif /* __LIBELFTC_H */
|
83
contrib/elftoolchain/libelftc/elftc.3
Normal file
83
contrib/elftoolchain/libelftc/elftc.3
Normal file
@ -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
|
189
contrib/elftoolchain/libelftc/elftc_bfd_find_target.3
Normal file
189
contrib/elftoolchain/libelftc/elftc_bfd_find_target.3
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
.\" 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 2251 2011-11-30 16:50:06Z jkoshy $
|
||||||
|
.\"
|
||||||
|
.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" "ELF Class"
|
||||||
|
.It Em Name Ta Em "Object Format" Ta Em "Byte Order" Ta Em "ELF Class"
|
||||||
|
.It Li binary Ta Binary Ta - Ta -
|
||||||
|
.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-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 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-littlemips Ta ELF Ta LSB Ta 64
|
||||||
|
.It Li elf64-powerpc 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-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 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
|
75
contrib/elftoolchain/libelftc/elftc_bfdtarget.c
Normal file
75
contrib/elftoolchain/libelftc/elftc_bfdtarget.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*-
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
|
||||||
|
#include "_libelftc.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: elftc_bfdtarget.c 2251 2011-11-30 16:50:06Z jkoshy $");
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
73
contrib/elftoolchain/libelftc/elftc_copyfile.3
Normal file
73
contrib/elftoolchain/libelftc/elftc_copyfile.3
Normal file
@ -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
|
107
contrib/elftoolchain/libelftc/elftc_copyfile.c
Normal file
107
contrib/elftoolchain/libelftc/elftc_copyfile.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*-
|
||||||
|
* 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 <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "libelftc.h"
|
||||||
|
#include "_libelftc.h"
|
||||||
|
|
||||||
|
#if ELFTC_HAVE_MMAP
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: elftc_copyfile.c 2318 2011-12-11 10:54:27Z jkoshy $");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy the contents referenced by 'ifd' to 'ofd'. Returns 0 on
|
||||||
|
* success and -1 on error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
elftc_copyfile(int ifd, int ofd)
|
||||||
|
{
|
||||||
|
int buf_mmapped;
|
||||||
|
struct stat sb;
|
||||||
|
char *b, *buf;
|
||||||
|
ssize_t nw;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
#if ELFTC_HAVE_MMAP
|
||||||
|
/*
|
||||||
|
* Prefer mmap() if it is available.
|
||||||
|
*/
|
||||||
|
buf = mmap(NULL, sb.st_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 == NULL) {
|
||||||
|
if ((buf = malloc(sb.st_size)) == NULL)
|
||||||
|
return (-1);
|
||||||
|
if (read(ifd, buf, sb.st_size) != sb.st_size)
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write data to the output file descriptor.
|
||||||
|
*/
|
||||||
|
for (n = sb.st_size, b = buf; n > 0; n -= nw, b += nw)
|
||||||
|
if ((nw = write(ofd, b, n)) <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Release the input buffer. */
|
||||||
|
#if ELFTC_HAVE_MMAP
|
||||||
|
if (buf_mmapped && munmap(buf, sb.st_size) < 0)
|
||||||
|
return (-1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!buf_mmapped)
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return (n > 0 ? -1 : 0);
|
||||||
|
}
|
||||||
|
|
116
contrib/elftoolchain/libelftc/elftc_demangle.3
Normal file
116
contrib/elftoolchain/libelftc/elftc_demangle.3
Normal file
@ -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 2065 2011-10-26 15:24:47Z jkoshy $
|
||||||
|
.\"
|
||||||
|
.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
|
110
contrib/elftoolchain/libelftc/elftc_demangle.c
Normal file
110
contrib/elftoolchain/libelftc/elftc_demangle.c
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*-
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libelf.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "_libelftc.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: elftc_demangle.c 2065 2011-10-26 15:24:47Z jkoshy $");
|
||||||
|
|
||||||
|
static int
|
||||||
|
is_mangled(const char *s, 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, int style, 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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
84
contrib/elftoolchain/libelftc/elftc_set_timestamps.3
Normal file
84
contrib/elftoolchain/libelftc/elftc_set_timestamps.3
Normal file
@ -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 .
|
85
contrib/elftoolchain/libelftc/elftc_set_timestamps.c
Normal file
85
contrib/elftoolchain/libelftc/elftc_set_timestamps.c
Normal file
@ -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 <sys/types.h>
|
||||||
|
|
||||||
|
#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 <sys/time.h>
|
||||||
|
#else
|
||||||
|
#include <utime.h>
|
||||||
|
#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
|
||||||
|
}
|
392
contrib/elftoolchain/libelftc/elftc_string_table.c
Normal file
392
contrib/elftoolchain/libelftc/elftc_string_table.c
Normal file
@ -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 <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <gelf.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
227
contrib/elftoolchain/libelftc/elftc_string_table_create.3
Normal file
227
contrib/elftoolchain/libelftc/elftc_string_table_create.3
Normal file
@ -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
|
529
contrib/elftoolchain/libelftc/elftc_symbol_table_create.3
Normal file
529
contrib/elftoolchain/libelftc/elftc_symbol_table_create.3
Normal file
@ -0,0 +1,529 @@
|
|||||||
|
.\" 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_symbol_table_create.3 2825 2012-12-29 14:25:33Z jkoshy $
|
||||||
|
.\"
|
||||||
|
.Dd December 29, 2012
|
||||||
|
.Os
|
||||||
|
.Dt ELFTC_SYMBOL_TABLE_CREATE 3
|
||||||
|
.Sh NAME
|
||||||
|
.Nm elftc_elf_symbol_table_from_section ,
|
||||||
|
.Nm elftc_symbol_table_count ,
|
||||||
|
.Nm elftc_symbol_table_create ,
|
||||||
|
.Nm elftc_symbol_table_create_nested ,
|
||||||
|
.Nm elftc_symbol_table_delete_name ,
|
||||||
|
.Nm elftc_symbol_table_delete_entry ,
|
||||||
|
.Nm elftc_symbol_table_destroy ,
|
||||||
|
.Nm elftc_symbol_table_insert ,
|
||||||
|
.Nm elftc_symbol_table_iterate ,
|
||||||
|
.Nm elftc_symbol_table_lookup ,
|
||||||
|
.Nm elftc_symbol_table_lookup_value ,
|
||||||
|
.Nm elftc_symbol_table_replace ,
|
||||||
|
.Nm elftc_symbol_table_sort ,
|
||||||
|
.Nm elftc_symbol_table_step
|
||||||
|
.Nd symbol table management routines
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.In libelftc.h
|
||||||
|
.Bd -literal
|
||||||
|
typedef struct _Elftc_Symbol_Table Elftc_Symbol_Table;
|
||||||
|
|
||||||
|
typedef struct _Elftc_Symbol {
|
||||||
|
... library private fields ...
|
||||||
|
const char *sym_name;
|
||||||
|
uintptr_t sym_value;
|
||||||
|
} Elftc_Symbol;
|
||||||
|
.Ed
|
||||||
|
.Ft size_t
|
||||||
|
.Fn elftc_symbol_table_count "Elftc_Symbol_Table *table"
|
||||||
|
.Ft "Elftc_Symbol_Table *"
|
||||||
|
.Fo elftc_symbol_table_create
|
||||||
|
.Fa "size_t entrysize"
|
||||||
|
.Fa "int sizehint"
|
||||||
|
.Fc
|
||||||
|
.Ft "Elftc_Symbol_Table *"
|
||||||
|
.Fo elftc_symbol_table_create_nested
|
||||||
|
.Fa "Elftc_Symbol_Table *table"
|
||||||
|
.Fa "int sizehint"
|
||||||
|
.Fc
|
||||||
|
.Ft int
|
||||||
|
.Fo elftc_symbol_table_delete_name
|
||||||
|
.Fa "Elftc_Symbol_Table *table"
|
||||||
|
.Fa "const char *name"
|
||||||
|
.Fc
|
||||||
|
.Ft int
|
||||||
|
.Fo elftc_symbol_table_delete_entry
|
||||||
|
.Fa "Elftc_Symbol_Table *table"
|
||||||
|
.Fa "Elftc_Symbol *entry"
|
||||||
|
.Fc
|
||||||
|
.Ft int
|
||||||
|
.Fn elftc_symbol_table_destroy "Elftc_Symbol_Table *table"
|
||||||
|
.Ft "Elftc_Symbol *entry"
|
||||||
|
.Fo elftc_symbol_table_insert
|
||||||
|
.Fa "Elftc_Symbol_Table *table"
|
||||||
|
.Fa "const char *symbolname"
|
||||||
|
.Fa "int *status"
|
||||||
|
.Fc
|
||||||
|
.Ft int
|
||||||
|
.Fo elftc_symbol_table_iterate
|
||||||
|
.Fa "Elftc_Symbol_Table *table"
|
||||||
|
.Fa "int (*iterfn)(Elftc_Symbol *entry, void *cookie)"
|
||||||
|
.Fa "void *cookie"
|
||||||
|
.Fc
|
||||||
|
.Ft "Elftc_Symbol *"
|
||||||
|
.Fo elftc_symbol_table_lookup
|
||||||
|
.Fa "Elftc_Symbol_Table *table"
|
||||||
|
.Fa "const char *symbolname"
|
||||||
|
.Fc
|
||||||
|
.Ft "Elftc_Elf_Symbol *"
|
||||||
|
.Fo elftc_symbol_table_lookup_value
|
||||||
|
.Fa "Elftc_Symbol_Table *table"
|
||||||
|
.Fa "uintptr_t value"
|
||||||
|
.Fa "int searchflags"
|
||||||
|
.Fc
|
||||||
|
.Ft int
|
||||||
|
.Fo elftc_symbol_table_replace
|
||||||
|
.Fa "Elftc_Symbol_Table *table"
|
||||||
|
.Fa "Elftc_Symbol *sym1"
|
||||||
|
.Fa "Elftc_Symbol *sym2"
|
||||||
|
.Fc
|
||||||
|
.Ft int
|
||||||
|
.Fo elftc_symbol_table_sort
|
||||||
|
.Fa "Elftc_Symbol_Table *table"
|
||||||
|
.Fa "int (*cmpfn)(Elftc_Symbol *s1, Elftc_Symbol *s2)"
|
||||||
|
.Fc
|
||||||
|
.Ft "Elftc_Symbol *"
|
||||||
|
.Fo elftc_symbol_table_step
|
||||||
|
.Fa "Elftc_Symbol_Table *table"
|
||||||
|
.Fa "Elftc_Symbol *cursym"
|
||||||
|
.Fa "int direction"
|
||||||
|
.Fc
|
||||||
|
.Bd -literal
|
||||||
|
typedef struct _Elftc_Elf_Symbol {
|
||||||
|
... library private fields ...
|
||||||
|
const char *sym_name;
|
||||||
|
Gelf_Sym sym_elf;
|
||||||
|
} Elftc_Elf_Symbol;
|
||||||
|
.Ed
|
||||||
|
.Ft "Elftc_Symbol_Table *"
|
||||||
|
.Fo elftc_elf_symbol_table_from_section
|
||||||
|
.Fa "Elf_Scn *symscn"
|
||||||
|
.Fa "Elf_Scn *strscn"
|
||||||
|
.Fc
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
This manual page documents convenience routines for handling symbol
|
||||||
|
tables.
|
||||||
|
Two flavors of symbol tables are supported:
|
||||||
|
.Bl -bullet -compact
|
||||||
|
.It
|
||||||
|
.Dq Regular
|
||||||
|
symbol tables supporting insertion, deletion and lookup of entries by
|
||||||
|
name or by value, sorting of entries, and stepping through entries in
|
||||||
|
the table's current traversal order.
|
||||||
|
.It
|
||||||
|
.Dq ELF-centric
|
||||||
|
symbol tables support additional operations for conversions to and
|
||||||
|
from the symbol table format understood by
|
||||||
|
.Lb libelf .
|
||||||
|
.El
|
||||||
|
The default traversal order for a symbol table is the order in which
|
||||||
|
entries were inserted into it.
|
||||||
|
This traversal order may be changed using function
|
||||||
|
.Fn elftc_symbol_table_sort .
|
||||||
|
.Ss Operations on Regular Symbol Tables
|
||||||
|
Regular symbol tables use symbols that are subtypes of
|
||||||
|
.Vt Elftc_Symbol ,
|
||||||
|
as described in the section
|
||||||
|
.Sx "Structure of a Symbol Table Entry"
|
||||||
|
below.
|
||||||
|
.Pp
|
||||||
|
Function
|
||||||
|
.Fn elftc_symbol_table_count
|
||||||
|
returns the number of entries currently in the symbol table.
|
||||||
|
.Pp
|
||||||
|
Function
|
||||||
|
.Fn elftc_symbol_table_create
|
||||||
|
creates a new, empty symbol table.
|
||||||
|
The argument
|
||||||
|
.Ar entrysize
|
||||||
|
specifies the size of each symbol table entry, as described
|
||||||
|
in the section
|
||||||
|
.Sx "Structure of a Symbol Table Entry"
|
||||||
|
below.
|
||||||
|
The argument
|
||||||
|
.Ar sizehint
|
||||||
|
specifies the expected number of symbol table entries.
|
||||||
|
If
|
||||||
|
.Ar sizehint
|
||||||
|
is zero, an implementation-defined default will be used.
|
||||||
|
.Pp
|
||||||
|
Function
|
||||||
|
.Fn elftc_symbol_table_create_nested
|
||||||
|
creates a symbol table whose search scope nests inside that of a
|
||||||
|
parent symbol table.
|
||||||
|
The argument
|
||||||
|
.Ar parent
|
||||||
|
specifies the parent symbol table to nest under.
|
||||||
|
The argument
|
||||||
|
.Ar sizehint
|
||||||
|
specifies the expected number of symbol table entries.
|
||||||
|
If
|
||||||
|
.Ar sizehint
|
||||||
|
is zero, an implementation-defined default will be used instead.
|
||||||
|
.Pp
|
||||||
|
The function
|
||||||
|
.Fn elftc_symbol_table_delete_name
|
||||||
|
removes the symbol entry named by the argument
|
||||||
|
.Ar name
|
||||||
|
from the symbol table specified by argument
|
||||||
|
.Ar table ,
|
||||||
|
according to the rules described in section
|
||||||
|
.Sx "Symbol Search Rules" .
|
||||||
|
.Pp
|
||||||
|
The function
|
||||||
|
.Fn elftc_symbol_table_delete_entry
|
||||||
|
removes the symbol table entry specified by argument
|
||||||
|
.Ar entry
|
||||||
|
from the symbol table specified by argument
|
||||||
|
.Ar table .
|
||||||
|
.Pp
|
||||||
|
Function
|
||||||
|
.Fn elftc_symbol_table_destroy
|
||||||
|
is used to destroy a symbol table and free up its internal
|
||||||
|
resources.
|
||||||
|
.Pp
|
||||||
|
The function
|
||||||
|
.Fn elftc_symbol_table_insert
|
||||||
|
inserts a symbol entry for the name specified by argument
|
||||||
|
.Ar symbolname
|
||||||
|
into the symbol table specified by argument
|
||||||
|
.Ar table ,
|
||||||
|
returning a pointer to a symbol table entry.
|
||||||
|
The argument
|
||||||
|
.Ar status
|
||||||
|
should point to a location that will be updated with one of
|
||||||
|
the following values:
|
||||||
|
.Bl -tag -width indent -compact -offset indent
|
||||||
|
.It Dv ELFTC_INSERT_ERROR
|
||||||
|
An error occured during insertion of the symbol.
|
||||||
|
.It Dv ELFTC_INSERT_EXISTING
|
||||||
|
The name in argument
|
||||||
|
.Ar symbolname
|
||||||
|
was already in the symbol table, and a pointer to the existing
|
||||||
|
symbol table entry is being returned.
|
||||||
|
.It Dv ELFTC_INSERT_NEW
|
||||||
|
A new symbol table entry was allocated for the symbol name
|
||||||
|
in
|
||||||
|
.Ar symbolname .
|
||||||
|
The application will need to initialize the application-specific
|
||||||
|
fields of the symbol table entry.
|
||||||
|
.El
|
||||||
|
Insertion obeys the scoping rules described in section
|
||||||
|
.Sx "Symbol Search Rules" .
|
||||||
|
.Pp
|
||||||
|
The function
|
||||||
|
.Fn elftc_symbol_table_iterate
|
||||||
|
iterates over the symbol table specifed by argument
|
||||||
|
.Ar table ,
|
||||||
|
applying the function pointed to by argument
|
||||||
|
.Ar iterfn
|
||||||
|
to each symbol table entry.
|
||||||
|
The return value from the function
|
||||||
|
.Ar iterfn
|
||||||
|
controls progress of the iteration:
|
||||||
|
.Bl -tag -width indent -compact -offset indent
|
||||||
|
.It Dv ELFTC_ITERATE_ABORT
|
||||||
|
Terminates the iteration.
|
||||||
|
.It Dv ELFTC_ITERATE_CONTINUE
|
||||||
|
Iteration will continue on to the next element in the symbol table.
|
||||||
|
.El
|
||||||
|
Argument
|
||||||
|
.Ar cookie
|
||||||
|
will be passed to each invocation of
|
||||||
|
.Ar iterfn ,
|
||||||
|
and may be used to track persistent state.
|
||||||
|
The ordering of symbol table entries presented to function
|
||||||
|
.Ar iterfn
|
||||||
|
is not defined.
|
||||||
|
The behavior of the iteration is undefined if
|
||||||
|
.Ar iterfn
|
||||||
|
adds or deletes symbol entries from a symbol table that currently
|
||||||
|
being iterated through.
|
||||||
|
.Pp
|
||||||
|
Function
|
||||||
|
.Fn elftc_symbol_table_lookup
|
||||||
|
returns the symbol entry corresponding to the name of the symbol
|
||||||
|
in argument
|
||||||
|
.Ar symbolname .
|
||||||
|
.Pp
|
||||||
|
Function
|
||||||
|
.Fn elftc_symbol_table_lookup_value
|
||||||
|
returns the symbol entry that has a
|
||||||
|
.Va sym_value
|
||||||
|
field that is closest to the value specified in argument
|
||||||
|
.Ar value .
|
||||||
|
The argument
|
||||||
|
.Ar table
|
||||||
|
should point to a symbol table, that has been sorted
|
||||||
|
by a prior call to
|
||||||
|
.Fn elftc_symbol_table_sort .
|
||||||
|
The argument
|
||||||
|
.Ar searchflags
|
||||||
|
can be a combination of the following flags:
|
||||||
|
.Bl -tag -width indent -compact -offset indent
|
||||||
|
.It Dv ELFTC_SEARCH_FORWARD
|
||||||
|
Find the symbol entry with the next higher value in its
|
||||||
|
.Va sym_value
|
||||||
|
field.
|
||||||
|
.It Dv ELFTC_SEARCH_BACKWARD
|
||||||
|
Find the symbol entry with next lower value in its
|
||||||
|
.Va sym_value
|
||||||
|
field.
|
||||||
|
.El
|
||||||
|
If both
|
||||||
|
.Dv ELFTC_SEARCH_FORWARD
|
||||||
|
and
|
||||||
|
.Dv ELFTC_SEARCH_BACKWARD
|
||||||
|
are specified, then this function will return the symbol that is
|
||||||
|
closest to the argument
|
||||||
|
.Ar value .
|
||||||
|
.Pp
|
||||||
|
Function
|
||||||
|
.Fn elftc_symbol_table_replace
|
||||||
|
moves the symbol table entry pointed to by argument
|
||||||
|
.Ar sym2
|
||||||
|
into the traversal position for the entry pointed to by
|
||||||
|
.Ar sym1 ,
|
||||||
|
and implicitly deletes the entry pointed to by argument
|
||||||
|
.Ar sym1 .
|
||||||
|
Argument
|
||||||
|
.Ar table
|
||||||
|
should point to a valid symbol table.
|
||||||
|
.Pp
|
||||||
|
Function
|
||||||
|
.Fn elftc_symbol_table_sort
|
||||||
|
is used to define an ordering of symbol entries in a symbol
|
||||||
|
table.
|
||||||
|
This ordering will be associated with the symbol table till the next
|
||||||
|
call to function
|
||||||
|
.Fn elftc_symbol_table_insert ,
|
||||||
|
.Fn elftc_symbol_table_delete_name
|
||||||
|
or
|
||||||
|
.Fn elftc_symbol_table_delete_entry .
|
||||||
|
The argument
|
||||||
|
.Ar cmpfn
|
||||||
|
should point to a function that compares two symbol entries pointed
|
||||||
|
to by
|
||||||
|
.Ar s1
|
||||||
|
and
|
||||||
|
.Ar s2
|
||||||
|
and returns -1, 0, or 1, depending whether
|
||||||
|
.Ar s1
|
||||||
|
is less, equal to, or greater than
|
||||||
|
.Ar s2
|
||||||
|
respectively.
|
||||||
|
.Pp
|
||||||
|
Function
|
||||||
|
.Fn elftc_symbol_table_step
|
||||||
|
is used to step to the next symbol in a sorted symbol table.
|
||||||
|
Argument
|
||||||
|
.Ar table
|
||||||
|
should point to a symbol table.
|
||||||
|
The argument
|
||||||
|
.Ar cursym
|
||||||
|
specifies the current symbol.
|
||||||
|
The argument
|
||||||
|
.Ar direction
|
||||||
|
specifies the direction to step:
|
||||||
|
.Bl -tag -width indent -compact -offset ident
|
||||||
|
.It Dv ELFTC_STEP_NEXT
|
||||||
|
Return the symbol which follows the argument
|
||||||
|
.Ar cursym
|
||||||
|
in the current traversal order.
|
||||||
|
If argument
|
||||||
|
.Ar cursym
|
||||||
|
is NULL, return the first symbol in the current
|
||||||
|
traversal order.
|
||||||
|
.It Dv ELFTC_STEP_PREVIOUS
|
||||||
|
Return the symbol which precedes the argument
|
||||||
|
.Ar cursym
|
||||||
|
in the current traversal order.
|
||||||
|
If argument
|
||||||
|
.Ar cursym
|
||||||
|
is NULL, return the last symbol in the current
|
||||||
|
traversal order.
|
||||||
|
.El
|
||||||
|
.Ss Operations on ELF-centric symbol tables
|
||||||
|
ELF-centric symbol tables use symbols that are subtypes of
|
||||||
|
.Vt Elftc_Elf_Symbol ,
|
||||||
|
as described in the section
|
||||||
|
.Sx "Structure of a Symbol Table Entry"
|
||||||
|
below.
|
||||||
|
.Pp
|
||||||
|
In addition to the operations on regular symbol tables listed above,
|
||||||
|
these symbol tables may be used with the following additional
|
||||||
|
functions.
|
||||||
|
.Pp
|
||||||
|
The function
|
||||||
|
.Fn elftc_elf_symbol_table_from_section
|
||||||
|
builds a symbol table from the contents of an ELF section.
|
||||||
|
The argument
|
||||||
|
.Ar symscn
|
||||||
|
should reference an ELF section of type
|
||||||
|
.Dv SHT_SYMTAB
|
||||||
|
or
|
||||||
|
.Dv SHT_DYNSYM .
|
||||||
|
The argument
|
||||||
|
.Ar strscn
|
||||||
|
should reference an ELF section of type
|
||||||
|
.Dv SHT_STRTAB
|
||||||
|
containing the string table associated wit section
|
||||||
|
.Ar symscn .
|
||||||
|
.Ss Structure of a Symbol Table Entry
|
||||||
|
The symbol tables managed by
|
||||||
|
.Lb libelftc
|
||||||
|
are collections of symbol table entries.
|
||||||
|
Each entry should be a subtype of one of the
|
||||||
|
.Vt Elftc_Symbol
|
||||||
|
or
|
||||||
|
.Vt Elftc_Elf_Symbol
|
||||||
|
types.
|
||||||
|
In other words, each entry should have an
|
||||||
|
.Vt Elftc_Symbol
|
||||||
|
or
|
||||||
|
.Vt Elftc_Elf_Symbol
|
||||||
|
structure as its first member, before any application specific
|
||||||
|
fields.
|
||||||
|
For example:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
struct _MySymbol {
|
||||||
|
Elftc_Symbol sym_base;
|
||||||
|
... other application-specific fields ...
|
||||||
|
};
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The size of the combined entry is indicated to the library
|
||||||
|
at the time of creating a new symbol table.
|
||||||
|
Applications may then cast the returned pointers from these
|
||||||
|
routines to the appropriate type:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
struct _MySymbol *mysym;
|
||||||
|
|
||||||
|
mysym = (struct _MySymbol *) elftc_symbol_table_lookup(table,
|
||||||
|
name);
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Vt Elftc_Symbol
|
||||||
|
type has two public fields:
|
||||||
|
.Bl -tag -width ".Va sym_value" -compact -offset indent
|
||||||
|
.It Va sym_name
|
||||||
|
Points to a NUL-terminated string containing the symbol's name.
|
||||||
|
The application should not change the value of this field.
|
||||||
|
.It Va sym_value
|
||||||
|
The value associated with this symbol.
|
||||||
|
This field is entirely under the application's control.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Vt Elftc_Elf_Symbol
|
||||||
|
type has two public fields:
|
||||||
|
.Bl -tag -width ".Va sym_value" -compact -offset indent
|
||||||
|
.It Va sym_name
|
||||||
|
Points to a NUL-terminated string containing the symbol's name.
|
||||||
|
The application should not change the value of this field.
|
||||||
|
.It Va sym_elf
|
||||||
|
A structure of type
|
||||||
|
.Vt Gelf_Sym
|
||||||
|
containing ELF symbol information.
|
||||||
|
This field is entirely under the application's control.
|
||||||
|
.El
|
||||||
|
.Ss Symbol Search Rules
|
||||||
|
During lookups, symbols are looked up first in the symbol table passed in
|
||||||
|
to the
|
||||||
|
.Fn elftc_symbol_table_lookup
|
||||||
|
function.
|
||||||
|
If the specified symbol is not found, and if the symbol table has a
|
||||||
|
parent, then the search continues recursively up the chain of parent
|
||||||
|
symbol tables till either a matching symbol is found or till there are
|
||||||
|
no more parent symbol tables to search in.
|
||||||
|
.Pp
|
||||||
|
Insertions and deletion only work on the specified symbol table and
|
||||||
|
do not recurse into parent symbol tables.
|
||||||
|
.Ss Memory Management
|
||||||
|
The
|
||||||
|
.Lb libelftc
|
||||||
|
manages its memory allocations.
|
||||||
|
Applications should not free the pointers returned by the
|
||||||
|
API documented in this manual page.
|
||||||
|
.Sh RETURN VALUES
|
||||||
|
Function
|
||||||
|
.Fn elftc_symbol_table_count
|
||||||
|
returns a count of the number of symbol table entries as an unsigned
|
||||||
|
value.
|
||||||
|
.Pp
|
||||||
|
Functions
|
||||||
|
.Fn elftc_symbol_table_create ,
|
||||||
|
.Fn elftc_symbol_table_create_nested
|
||||||
|
and
|
||||||
|
.Fn elftc_symbol_table_from_section
|
||||||
|
return a pointer to an opaque structure of type
|
||||||
|
.Vt Elftc_Symbol_Table
|
||||||
|
on success, or return NULL in case of an error.
|
||||||
|
.Pp
|
||||||
|
Functions
|
||||||
|
.Fn elftc_symbol_table_delete_name ,
|
||||||
|
.Fn elftc_symbol_table_delete_name
|
||||||
|
.Fn elftc_symbol_table_destroy ,
|
||||||
|
.Fn elftc_symbol_table_replace
|
||||||
|
and
|
||||||
|
.Fn elftc_symbol_table_sort
|
||||||
|
return a non-zero value on success, or return zero in case of an error.
|
||||||
|
.Pp
|
||||||
|
Functions
|
||||||
|
.Fn elftc_symbol_table_insert ,
|
||||||
|
.Fn elftc_symbol_table_lookup
|
||||||
|
and
|
||||||
|
.Fn elftc_symbol_table_lookup_value
|
||||||
|
return a pointer to a structure that is a subtype of
|
||||||
|
.Vt Elftc_Symbol
|
||||||
|
on success, or return NULL in case of an error.
|
||||||
|
.Pp
|
||||||
|
The function
|
||||||
|
.Fn elftc_symbol_table_step
|
||||||
|
return a pointer to a structure that is a subtype of
|
||||||
|
.Vt Elftc_Symbol
|
||||||
|
on success.
|
||||||
|
The function returns NULL if there are no more elements in the
|
||||||
|
specified traversal direction.
|
||||||
|
.Pp
|
||||||
|
The function
|
||||||
|
.Fn elftc_symbol_table_iterate
|
||||||
|
returns
|
||||||
|
.Dv ELFTC_ITERATE_SUCCESS
|
||||||
|
if the symbol table was successfully traversed, or
|
||||||
|
.Dv ELFTC_ITERATE_ABORT
|
||||||
|
in case the iteration function aborted the traversal.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr dwarf 3 ,
|
||||||
|
.Xr elf 3 ,
|
||||||
|
.Xr elftc 3
|
79
contrib/elftoolchain/libelftc/elftc_version.3
Normal file
79
contrib/elftoolchain/libelftc/elftc_version.3
Normal file
@ -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 <sys/types.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
|
||||||
|
(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.
|
89
contrib/elftoolchain/libelftc/libelftc.h
Normal file
89
contrib/elftoolchain/libelftc/libelftc.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*-
|
||||||
|
* 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 2863 2013-01-06 03:18:32Z jkoshy $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBELFTC_H_
|
||||||
|
#define _LIBELFTC_H_
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <libelf.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
} 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
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
const char *elftc_version(void);
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif /* _LIBELFTC_H_ */
|
383
contrib/elftoolchain/libelftc/libelftc_bfdtarget.c
Normal file
383
contrib/elftoolchain/libelftc/libelftc_bfdtarget.c
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
/*-
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <libelf.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
|
||||||
|
#include "_libelftc.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: libelftc_bfdtarget.c 2251 2011-11-30 16:50:06Z jkoshy $");
|
||||||
|
|
||||||
|
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-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 = "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-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-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-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 = NULL,
|
||||||
|
.bt_type = ETF_NONE,
|
||||||
|
},
|
||||||
|
};
|
1227
contrib/elftoolchain/libelftc/libelftc_dem_arm.c
Normal file
1227
contrib/elftoolchain/libelftc/libelftc_dem_arm.c
Normal file
File diff suppressed because it is too large
Load Diff
1376
contrib/elftoolchain/libelftc/libelftc_dem_gnu2.c
Normal file
1376
contrib/elftoolchain/libelftc/libelftc_dem_gnu2.c
Normal file
File diff suppressed because it is too large
Load Diff
3238
contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c
Normal file
3238
contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c
Normal file
File diff suppressed because it is too large
Load Diff
70
contrib/elftoolchain/libelftc/libelftc_hash.c
Normal file
70
contrib/elftoolchain/libelftc/libelftc_hash.c
Normal file
@ -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 <sys/types.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
318
contrib/elftoolchain/libelftc/libelftc_vstr.c
Normal file
318
contrib/elftoolchain/libelftc/libelftc_vstr.c
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2008 Hyogeol Lee <hyogeollee@gmail.com>
|
||||||
|
* 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 <sys/types.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "_libelftc.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: libelftc_vstr.c 2065 2011-10-26 15:24:47Z jkoshy $");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file vector_str.c
|
||||||
|
* @brief Dynamic vector data for string implementation.
|
||||||
|
*
|
||||||
|
* Resemble to std::vector<std::string> 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 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);
|
||||||
|
}
|
104
contrib/elftoolchain/libelftc/make-toolchain-version
Executable file
104
contrib/elftoolchain/libelftc/make-toolchain-version
Executable file
@ -0,0 +1,104 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# This script generates a project-wide version identifier for use by
|
||||||
|
# the `elftc_version()' API.
|
||||||
|
#
|
||||||
|
# $Id: make-toolchain-version 2583 2012-09-14 09:49:25Z 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 .svn ]; then # FreeBSD and SF.Net sources.
|
||||||
|
versionstring=" svn:"$(svnversion)
|
||||||
|
elif [ -d CVS ]; then # NetBSD.
|
||||||
|
versionstring=" cvs:unknown"
|
||||||
|
else # DragonFlyBSD.
|
||||||
|
versionstring=" git:"$(git describe --all --dirty --long 2> /dev/null)
|
||||||
|
|
||||||
|
# Cannot determine an in-tree version number.
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
versionstring=""
|
||||||
|
fi
|
||||||
|
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} <<EOF
|
||||||
|
/* WARNING: Generated by "${progname}". */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
|
||||||
|
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
|
7
contrib/elftoolchain/libelftc/os.FreeBSD.mk
Normal file
7
contrib/elftoolchain/libelftc/os.FreeBSD.mk
Normal file
@ -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
|
3
contrib/elftoolchain/libelftc/os.Linux.mk
Normal file
3
contrib/elftoolchain/libelftc/os.Linux.mk
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# $Id: os.Linux.mk 994 2010-06-13 10:39:19Z jkoshy $
|
||||||
|
|
||||||
|
CFLAGS+= -Wall
|
13
contrib/elftoolchain/nm/Makefile
Normal file
13
contrib/elftoolchain/nm/Makefile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
# $Id: Makefile 2076 2011-10-27 03:50:33Z jkoshy $
|
||||||
|
|
||||||
|
TOP= ..
|
||||||
|
|
||||||
|
PROG= nm
|
||||||
|
SRCS= nm.c
|
||||||
|
|
||||||
|
WARNS?= 6
|
||||||
|
|
||||||
|
LDADD= -ldwarf -lelftc -lelf
|
||||||
|
|
||||||
|
.include "${TOP}/mk/elftoolchain.prog.mk"
|
334
contrib/elftoolchain/nm/nm.1
Normal file
334
contrib/elftoolchain/nm/nm.1
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
.\" Copyright (c) 2007 Hyogeol Lee <hyogeollee@gmail.com>
|
||||||
|
.\" 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: nm.1 2377 2012-01-03 07:10:59Z jkoshy $
|
||||||
|
.\"
|
||||||
|
.Dd January 3, 2012
|
||||||
|
.Os
|
||||||
|
.Dt NM 1
|
||||||
|
.Sh NAME
|
||||||
|
.Nm nm
|
||||||
|
.Nd display symbolic information in object files
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl -debug-syms
|
||||||
|
.Op Fl -defined-only
|
||||||
|
.Op Fl -demangle Ns Op = Ns style
|
||||||
|
.Op Fl -dynamic
|
||||||
|
.Op Fl -help
|
||||||
|
.Op Fl -line-numbers
|
||||||
|
.Op Fl -no-demangle
|
||||||
|
.Op Fl -no-sort
|
||||||
|
.Op Fl -numeric-sort
|
||||||
|
.Op Fl -print-armap
|
||||||
|
.Op Fl -print-file-name
|
||||||
|
.Op Fl -print-size
|
||||||
|
.Op Fl -radix= Ns Ar format
|
||||||
|
.Op Fl -reverse-sort
|
||||||
|
.Op Fl -size-sort
|
||||||
|
.Op Fl -undefined-only
|
||||||
|
.Op Fl -version
|
||||||
|
.Op Fl A
|
||||||
|
.Op Fl B
|
||||||
|
.Op Fl C Op Ar style
|
||||||
|
.Op Fl D
|
||||||
|
.Op Fl P
|
||||||
|
.Op Fl V
|
||||||
|
.Op Fl a
|
||||||
|
.Op Fl e
|
||||||
|
.Op Fl g
|
||||||
|
.Op Fl h
|
||||||
|
.Op Fl l
|
||||||
|
.Op Fl n
|
||||||
|
.Op Fl o
|
||||||
|
.Op Fl p
|
||||||
|
.Op Fl r
|
||||||
|
.Op Fl S
|
||||||
|
.Op Fl s
|
||||||
|
.Op Fl t Ar format
|
||||||
|
.Op Fl u
|
||||||
|
.Op Fl x
|
||||||
|
.Ar
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility displays symbolic information in the object files,
|
||||||
|
executables, and object library files named by its arguments.
|
||||||
|
Lack of symbolic information in an otherwise valid input
|
||||||
|
file, is not considered to be an error.
|
||||||
|
If no files are specified on the command line,
|
||||||
|
.Nm
|
||||||
|
will attempt to read
|
||||||
|
.Pa a.out .
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility recognizes the following options:
|
||||||
|
.Bl -tag -width ".Fl d Ar argument"
|
||||||
|
.It Fl -debug-syms
|
||||||
|
Display all symbols, including debugger-only symbols.
|
||||||
|
.It Fl -defined-only
|
||||||
|
Display only defined symbols.
|
||||||
|
.It Fl -demangle Ns Op = Ns Ar style
|
||||||
|
Decode (demangle) low-level symbol names into human-readable names.
|
||||||
|
Supported values for argument
|
||||||
|
.Ar style
|
||||||
|
are
|
||||||
|
.Sq auto ,
|
||||||
|
.Sq gnu-v2 ,
|
||||||
|
.Sq gnu-v3
|
||||||
|
and
|
||||||
|
.Sq arm.
|
||||||
|
If argument
|
||||||
|
.Ar style
|
||||||
|
is not specified, it is taken to be
|
||||||
|
.Sq auto .
|
||||||
|
.It Fl -dynamic
|
||||||
|
Only display dynamic symbols.
|
||||||
|
This option is only meaningful for shared libraries.
|
||||||
|
.It Fl -help
|
||||||
|
Display a help message and exit.
|
||||||
|
.It Fl -format Ns = Ns Ar format
|
||||||
|
Display output in the format specified by argument
|
||||||
|
.Ar format .
|
||||||
|
Supported values for the format argument are
|
||||||
|
.Sq bsd ,
|
||||||
|
.Sq sysv ,
|
||||||
|
and
|
||||||
|
.Sq posix .
|
||||||
|
The default output format is
|
||||||
|
.Sq bsd .
|
||||||
|
.It Fl -line-numbers
|
||||||
|
Display the filename and line number associated a symbol using
|
||||||
|
any debugging information present in the input file.
|
||||||
|
For defined symbols, look up the line number associated with
|
||||||
|
the address of the symbol.
|
||||||
|
For undefined symbols, look up the line number associated with
|
||||||
|
a relocation entry that refers to the symbol.
|
||||||
|
If line number information can be determined, it is displayed after
|
||||||
|
other symbol information.
|
||||||
|
.It Fl -no-demangle
|
||||||
|
Do not demangle symbol names (default).
|
||||||
|
.It Fl -no-sort
|
||||||
|
Do not sort symbols.
|
||||||
|
.It Fl -numeric-sort
|
||||||
|
Sort symbols numerically by address instead of alphabetically by name.
|
||||||
|
.It Fl -print-armap
|
||||||
|
For
|
||||||
|
.Xr ar 1
|
||||||
|
archives, include the index of the archive's members.
|
||||||
|
.It Fl -print-file-name
|
||||||
|
Write the full pathname or library name of an object on each line,
|
||||||
|
before the rest of the information for a symbol.
|
||||||
|
If this option is not specified,
|
||||||
|
.Nm
|
||||||
|
will only identify an input file once, before its symbols are
|
||||||
|
listed.
|
||||||
|
.It Fl -print-size
|
||||||
|
Print the size of each symbol instead of its value.
|
||||||
|
.It Fl -radix Ns = Ns Ar radix
|
||||||
|
Print numeric values using the specified radix.
|
||||||
|
Supported values for argument
|
||||||
|
.Ar radix
|
||||||
|
are
|
||||||
|
.Sq d
|
||||||
|
for decimal,
|
||||||
|
.Sq o
|
||||||
|
for octal, and
|
||||||
|
.Sq x
|
||||||
|
for hexadecimal.
|
||||||
|
.It Fl -reverse-sort
|
||||||
|
Reverse the order of the sort.
|
||||||
|
.It Fl -size-sort
|
||||||
|
Sort symbols by size instead of alphabetically by name.
|
||||||
|
.It Fl -undefined-only
|
||||||
|
Display only undefined symbols.
|
||||||
|
.It Fl -version
|
||||||
|
Display the version identifier for
|
||||||
|
.Nm
|
||||||
|
and exit.
|
||||||
|
.It Fl A
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -print-file-name .
|
||||||
|
.It Fl B
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -format= Ns Ar bsd .
|
||||||
|
.It Fl C Op Ar style
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -demangle Ns Op = Ns Ar style .
|
||||||
|
.It Fl D
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -dynamic .
|
||||||
|
.It Fl F Ar format
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -format Ns = Ns Ar format .
|
||||||
|
.It Fl P
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -format Ns = Ns Ar posix .
|
||||||
|
.It Fl S
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -print-size .
|
||||||
|
.It Fl V
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -version .
|
||||||
|
.It Fl a
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -debug-syms .
|
||||||
|
.It Fl e
|
||||||
|
Only display information for global and static symbols.
|
||||||
|
.It Fl f
|
||||||
|
Produce full output (default).
|
||||||
|
.It Fl g
|
||||||
|
Only display information about global (external) symbols.
|
||||||
|
.It Fl h
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -help .
|
||||||
|
.It Fl l
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -line-numbers .
|
||||||
|
.It Fl n
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -numeric-sort .
|
||||||
|
.It Fl o
|
||||||
|
If POSIX output was specified using the
|
||||||
|
.Fl F Ar posix
|
||||||
|
or
|
||||||
|
.Fl P
|
||||||
|
options, this option is equivalent to specifying
|
||||||
|
.Fl -radix Ns = Ns Sq Ar o .
|
||||||
|
If POSIX output was not specified, this option
|
||||||
|
acts as a synonym for the
|
||||||
|
.Fl -print-file-name
|
||||||
|
option.
|
||||||
|
.It Fl p
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -no-sort .
|
||||||
|
.It Fl v
|
||||||
|
Equivalent to option
|
||||||
|
.Fl n .
|
||||||
|
.It Fl r
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -reverse-sort
|
||||||
|
.It Fl s
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -print-armap .
|
||||||
|
.It Fl t Ar radix
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -radix= Ns Ar radix .
|
||||||
|
.It Fl u
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -undefined-only .
|
||||||
|
.It Fl x
|
||||||
|
Write numeric values in hexadecimal (equivalent to -t x).
|
||||||
|
.El
|
||||||
|
.Sh OUTPUT FORMAT
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility can present its information in a number of formats, numeric
|
||||||
|
radices and sort orders.
|
||||||
|
By default
|
||||||
|
.Nm
|
||||||
|
uses BSD style output, a hexadecimal radix, without output sorted
|
||||||
|
alphabetically by name and without demangling of names.
|
||||||
|
.Pp
|
||||||
|
For each symbol listed,
|
||||||
|
.Nm
|
||||||
|
presents the following information:
|
||||||
|
.Bl -bullet -compact
|
||||||
|
.It
|
||||||
|
The library or object name, if options
|
||||||
|
.Fl A
|
||||||
|
or
|
||||||
|
.Fl -print-file-name
|
||||||
|
were specified.
|
||||||
|
.It
|
||||||
|
The symbol name.
|
||||||
|
.It
|
||||||
|
The type of the symbol denoted by a single character as below:
|
||||||
|
.Bl -tag -compact -width indent
|
||||||
|
.It A
|
||||||
|
A global, absolute symbol.
|
||||||
|
.It B
|
||||||
|
A global
|
||||||
|
.Dq bss
|
||||||
|
(uninitialized data) symbol.
|
||||||
|
.It C
|
||||||
|
A
|
||||||
|
.Dq common
|
||||||
|
symbol, representing uninitialized data.
|
||||||
|
.It D
|
||||||
|
A global symbol naming initialized data.
|
||||||
|
.It N
|
||||||
|
A debugger symbol.
|
||||||
|
.It R
|
||||||
|
A read-only data symbol.
|
||||||
|
.It T
|
||||||
|
A global text symbol.
|
||||||
|
.It U
|
||||||
|
An undefined symbol.
|
||||||
|
.It V
|
||||||
|
A weak object.
|
||||||
|
.It W
|
||||||
|
A weak reference.
|
||||||
|
.It a
|
||||||
|
A local absolute symbol.
|
||||||
|
.It b
|
||||||
|
A local
|
||||||
|
.Dq bss
|
||||||
|
(uninitialized data) symbol.
|
||||||
|
.It d
|
||||||
|
A local data symbol.
|
||||||
|
.It t
|
||||||
|
A local text symbol.
|
||||||
|
.It v
|
||||||
|
A weak object that is undefined.
|
||||||
|
.It w
|
||||||
|
A weak symbol that is undefined.
|
||||||
|
.It ?
|
||||||
|
None of the above.
|
||||||
|
.El
|
||||||
|
.It
|
||||||
|
The value of the symbol.
|
||||||
|
.It
|
||||||
|
The size of the symbol if applicable.
|
||||||
|
.It
|
||||||
|
Line number information, if available and if options
|
||||||
|
.Fl l
|
||||||
|
or
|
||||||
|
.Fl -line-numbers
|
||||||
|
were specified.
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Ex -std
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr ar 1 ,
|
||||||
|
.Xr objdump 1 ,
|
||||||
|
.Xr ranlib 1 ,
|
||||||
|
.Xr elf 3
|
||||||
|
.Sh AUTHORS
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility and this manual page were written by
|
||||||
|
.An Hyogeol Lee Aq hyogeollee@gmail.com .
|
2096
contrib/elftoolchain/nm/nm.c
Normal file
2096
contrib/elftoolchain/nm/nm.c
Normal file
File diff suppressed because it is too large
Load Diff
11
contrib/elftoolchain/size/Makefile
Normal file
11
contrib/elftoolchain/size/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# $Id: Makefile 2043 2011-10-23 14:49:16Z jkoshy $
|
||||||
|
|
||||||
|
TOP= ..
|
||||||
|
|
||||||
|
PROG= size
|
||||||
|
WARNS?= 6
|
||||||
|
LDADD= -lelftc -lelf
|
||||||
|
DPADD= ${LIBELFTC} ${LIBELF}
|
||||||
|
|
||||||
|
.include "${TOP}/mk/elftoolchain.prog.mk"
|
||||||
|
|
257
contrib/elftoolchain/size/size.1
Normal file
257
contrib/elftoolchain/size/size.1
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
.\" Copyright (c) 2007 S.Sam Arun Raj
|
||||||
|
.\" Copyright (c) 2008,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.
|
||||||
|
.\"
|
||||||
|
.\" $Id: size.1 2043 2011-10-23 14:49:16Z jkoshy $
|
||||||
|
.\"
|
||||||
|
.Dd August 25, 2011
|
||||||
|
.Dt SIZE 1
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm size
|
||||||
|
.Nd "display section sizes and total size of ELF objects"
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl -format= Ns Ar format
|
||||||
|
.Op Fl -help
|
||||||
|
.Op Fl -radix= Ns Ar radix
|
||||||
|
.Op Fl -totals
|
||||||
|
.Op Fl -version
|
||||||
|
.Op Fl ABVdhotx
|
||||||
|
.Op Ar
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility
|
||||||
|
lists the sizes of ELF sections, and optionally the total size, for
|
||||||
|
each input
|
||||||
|
.Ar file
|
||||||
|
specified on the command line.
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility can operate on ELF objects, on
|
||||||
|
.Xr ar 1
|
||||||
|
archives containing ELF objects, and on core dumps.
|
||||||
|
If no file name is specified on the command-line,
|
||||||
|
.Pa a.out
|
||||||
|
is assumed.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility recognized the following options:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl -format= Ns Ar format
|
||||||
|
Display output using the format specified by argument
|
||||||
|
.Ar format .
|
||||||
|
Supported values for this argument are:
|
||||||
|
.Sq berkeley
|
||||||
|
and
|
||||||
|
.Sq sysv .
|
||||||
|
The default output format is
|
||||||
|
.Sq berkeley .
|
||||||
|
See
|
||||||
|
.Sx Display Formats
|
||||||
|
below for more information.
|
||||||
|
.It Fl -help
|
||||||
|
Display a help message and exit.
|
||||||
|
.It Fl -radix= Ns Ar radix
|
||||||
|
Display numeric values using the radix specified by argument
|
||||||
|
.Ar radix .
|
||||||
|
Supported values for
|
||||||
|
.Ar radix
|
||||||
|
are 8, 10 and 16.
|
||||||
|
The default radix is 10.
|
||||||
|
.It Fl -totals
|
||||||
|
Shows cumulative totals of section sizes from all objects.
|
||||||
|
This option is ignored for System V style output.
|
||||||
|
.It Fl -version
|
||||||
|
Display a version identifier and exit.
|
||||||
|
.It Fl A
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -format= Ns Ar sysv .
|
||||||
|
.It Fl B
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -format= Ns Ar berkeley .
|
||||||
|
.It Fl V
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -version .
|
||||||
|
.It Fl d
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -radix= Ns Ar 10 .
|
||||||
|
.It Fl h
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -help .
|
||||||
|
.It Fl o
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -radix= Ns Ar 8 .
|
||||||
|
.It Fl t
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -totals .
|
||||||
|
.It Fl x
|
||||||
|
Equivalent to specifying option
|
||||||
|
.Fl -radix= Ns Ar 16 .
|
||||||
|
.El
|
||||||
|
.Sh DISPLAY FORMATS
|
||||||
|
.Ss Berkeley Style Output
|
||||||
|
If
|
||||||
|
.Sq berkeley
|
||||||
|
style output is in effect, an initial header line naming fields will
|
||||||
|
be output, followed by one line of output for each ELF object specified
|
||||||
|
on the command line or found in an archive.
|
||||||
|
.Pp
|
||||||
|
Each line will contain the following whitespace separated fields
|
||||||
|
in order:
|
||||||
|
.Bl -enum -compact
|
||||||
|
.It
|
||||||
|
The size of the text segment in the object.
|
||||||
|
.It
|
||||||
|
The size of the data segment in the object.
|
||||||
|
.It
|
||||||
|
The size of the
|
||||||
|
.Sq bss
|
||||||
|
segment in the object.
|
||||||
|
.It
|
||||||
|
The total size of the object in either decimal or octal.
|
||||||
|
Decimal output is used if the specified output radix for numeric values
|
||||||
|
is 10 or 16.
|
||||||
|
Octal output is used if the radix being used for numeric values
|
||||||
|
is 8.
|
||||||
|
.It
|
||||||
|
The total size of the object in hexadecimal.
|
||||||
|
.It
|
||||||
|
The file name of the object.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
If option
|
||||||
|
.Fl -totals
|
||||||
|
was specified, an additional line in the same format as above will be
|
||||||
|
output at the end containing the sum of the respective fields.
|
||||||
|
The file name field for the line will contain the string
|
||||||
|
.Sq (TOTALS) .
|
||||||
|
.Ss System V Style Output
|
||||||
|
If System V style output is selected,
|
||||||
|
.Nm
|
||||||
|
will output the following information for each object:
|
||||||
|
.Bl -enum -compact
|
||||||
|
.It
|
||||||
|
The name of the object followed by a colon.
|
||||||
|
.It
|
||||||
|
A header line containing the names of fields of subsequent lines.
|
||||||
|
.It
|
||||||
|
One line per section present in the object.
|
||||||
|
Each line has three fields:
|
||||||
|
.Bl -enum -compact
|
||||||
|
.It
|
||||||
|
The name of the section.
|
||||||
|
.It
|
||||||
|
Its size, in the selected radix for numeric values.
|
||||||
|
.It
|
||||||
|
The address associated with the section, in the selected numeric radix.
|
||||||
|
.El
|
||||||
|
.It
|
||||||
|
A line whose section name field contains the string
|
||||||
|
.Sq Total
|
||||||
|
and whose size field contains the sum of all reported section sizes.
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Ex -std
|
||||||
|
.Sh EXAMPLES
|
||||||
|
To display the section sizes for
|
||||||
|
.Pa /bin/ls
|
||||||
|
use:
|
||||||
|
.Bd -literal
|
||||||
|
$ size /bin/ls
|
||||||
|
text data bss dec hex filename
|
||||||
|
20975 540 392 21907 5593 /bin/ls
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
To display sizes and total for
|
||||||
|
.Pa /bin/ls
|
||||||
|
and
|
||||||
|
.Pa /bin/dd
|
||||||
|
in hexadecimal, use:
|
||||||
|
.Bd -literal
|
||||||
|
$ size -tx /bin/ls /bin/dd
|
||||||
|
text data bss dec hex filename
|
||||||
|
0x51ef 0x21c 0x188 21907 5593 /bin/ls
|
||||||
|
0x3df5 0x170 0x200 16741 4165 /bin/dd
|
||||||
|
0x8fe4 0x38c 0x388 38648 96f8 (TOTALS)
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
To display section sizes for
|
||||||
|
.Pa /bin/ls
|
||||||
|
in System V format use:
|
||||||
|
.Bd -literal
|
||||||
|
$ size -A /bin/ls
|
||||||
|
/bin/ls :
|
||||||
|
section size addr
|
||||||
|
\&.interp 21 4194704
|
||||||
|
\&.note.ABI-tag 24 4194728
|
||||||
|
\&.hash 624 4194752
|
||||||
|
\&.dynsym 2088 4195376
|
||||||
|
\&.dynstr 810 4197464
|
||||||
|
\&.rela.dyn 120 4198280
|
||||||
|
\&.rela.plt 1656 4198400
|
||||||
|
\&.init 19 4200056
|
||||||
|
\&.plt 1120 4200076
|
||||||
|
\&.text 15224 4201200
|
||||||
|
\&.fini 14 4216424
|
||||||
|
\&.rodata 1472 4216448
|
||||||
|
\&.data 80 5267456
|
||||||
|
\&.eh_frame 1624 5267536
|
||||||
|
\&.dynamic 384 5269160
|
||||||
|
\&.ctors 16 5269544
|
||||||
|
\&.dtors 16 5269560
|
||||||
|
\&.jcr 8 5269576
|
||||||
|
\&.got 576 5269584
|
||||||
|
\&.bss 528 5270176
|
||||||
|
\&.comment 686 0
|
||||||
|
Total 27110
|
||||||
|
.Ed
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr ar 1 ,
|
||||||
|
.Xr nm 1 ,
|
||||||
|
.Xr objdump 1 ,
|
||||||
|
.Xr readelf 1 ,
|
||||||
|
.Xr strings 1 ,
|
||||||
|
.Xr elf 3 ,
|
||||||
|
.Xr gelf 3
|
||||||
|
.Rs
|
||||||
|
.%A "AT&T Unix Systems Labs"
|
||||||
|
.%T "System V Application Binary Interface"
|
||||||
|
.%O http://www.sco.com/developers/gabi/
|
||||||
|
.Re
|
||||||
|
.Sh HISTORY
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility first appeared in
|
||||||
|
.At v6 .
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An -nosplit
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility was re-written by
|
||||||
|
.An S. Sam Arun Raj Aq samarunraj@gmail.com
|
||||||
|
This manual page was written by
|
||||||
|
.An S. Sam Arun Raj Aq samarunraj@gmail.com
|
914
contrib/elftoolchain/size/size.c
Normal file
914
contrib/elftoolchain/size/size.c
Normal file
@ -0,0 +1,914 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2007 S.Sam Arun Raj
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <gelf.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "_elftc.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: size.c 2350 2011-12-19 10:20:06Z jkoshy $");
|
||||||
|
|
||||||
|
#define BUF_SIZE 1024
|
||||||
|
#define ELF_ALIGN(val,x) (((val)+(x)-1) & ~((x)-1))
|
||||||
|
#define SIZE_VERSION_STRING "size 1.0"
|
||||||
|
|
||||||
|
enum return_code {
|
||||||
|
RETURN_OK,
|
||||||
|
RETURN_NOINPUT,
|
||||||
|
RETURN_DATAERR,
|
||||||
|
RETURN_USAGE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum output_style {
|
||||||
|
STYLE_BERKELEY,
|
||||||
|
STYLE_SYSV
|
||||||
|
};
|
||||||
|
|
||||||
|
enum radix_style {
|
||||||
|
RADIX_OCTAL,
|
||||||
|
RADIX_DECIMAL,
|
||||||
|
RADIX_HEX
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint64_t bss_size, data_size, text_size, total_size;
|
||||||
|
static uint64_t bss_size_total, data_size_total, text_size_total;
|
||||||
|
static int show_totals;
|
||||||
|
static int size_option;
|
||||||
|
static enum radix_style radix = RADIX_DECIMAL;
|
||||||
|
static enum output_style style = STYLE_BERKELEY;
|
||||||
|
static const char *default_args[2] = { "a.out", NULL };
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
int row;
|
||||||
|
int col;
|
||||||
|
int *width;
|
||||||
|
char ***tbl;
|
||||||
|
} *tb;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OPT_FORMAT,
|
||||||
|
OPT_RADIX
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct option size_longopts[] = {
|
||||||
|
{ "format", required_argument, &size_option, OPT_FORMAT },
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ "radix", required_argument, &size_option, OPT_RADIX },
|
||||||
|
{ "totals", no_argument, NULL, 't' },
|
||||||
|
{ "version", no_argument, NULL, 'V' },
|
||||||
|
{ NULL, 0, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void berkeley_calc(GElf_Shdr *);
|
||||||
|
static void berkeley_footer(const char *, const char *, const char *);
|
||||||
|
static void berkeley_header(void);
|
||||||
|
static void berkeley_totals(void);
|
||||||
|
static int handle_core(char const *, Elf *elf, GElf_Ehdr *);
|
||||||
|
static void handle_core_note(Elf *, GElf_Ehdr *, GElf_Phdr *, char **);
|
||||||
|
static int handle_elf(char const *);
|
||||||
|
static void handle_phdr(Elf *, GElf_Ehdr *, GElf_Phdr *, uint32_t,
|
||||||
|
const char *);
|
||||||
|
static void show_version(void);
|
||||||
|
static void sysv_header(const char *, Elf_Arhdr *);
|
||||||
|
static void sysv_footer(void);
|
||||||
|
static void sysv_calc(Elf *, GElf_Ehdr *, GElf_Shdr *);
|
||||||
|
static void usage(void);
|
||||||
|
static void tbl_new(int);
|
||||||
|
static void tbl_print(const char *, int);
|
||||||
|
static void tbl_print_num(uint64_t, enum radix_style, int);
|
||||||
|
static void tbl_append(void);
|
||||||
|
static void tbl_flush(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* size utility using elf(3) and gelf(3) API to list section sizes and
|
||||||
|
* total in elf files. Supports only elf files (core dumps in elf
|
||||||
|
* included) that can be opened by libelf, other formats are not supported.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int ch, r, rc;
|
||||||
|
const char **files, *fn;
|
||||||
|
|
||||||
|
rc = RETURN_OK;
|
||||||
|
|
||||||
|
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||||
|
errx(EXIT_FAILURE, "ELF library initialization failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
while ((ch = getopt_long(argc, argv, "ABVdhotx", size_longopts,
|
||||||
|
NULL)) != -1)
|
||||||
|
switch((char)ch) {
|
||||||
|
case 'A':
|
||||||
|
style = STYLE_SYSV;
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
style = STYLE_BERKELEY;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
show_version();
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
radix = RADIX_DECIMAL;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
radix = RADIX_OCTAL;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
show_totals = 1;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
radix = RADIX_HEX;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
switch (size_option) {
|
||||||
|
case OPT_FORMAT:
|
||||||
|
if (*optarg == 's' || *optarg == 'S')
|
||||||
|
style = STYLE_SYSV;
|
||||||
|
else if (*optarg == 'b' || *optarg == 'B')
|
||||||
|
style = STYLE_BERKELEY;
|
||||||
|
else {
|
||||||
|
warnx("unrecognized format \"%s\".",
|
||||||
|
optarg);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPT_RADIX:
|
||||||
|
r = strtol(optarg, NULL, 10);
|
||||||
|
if (r == 8)
|
||||||
|
radix = RADIX_OCTAL;
|
||||||
|
else if (r == 10)
|
||||||
|
radix = RADIX_DECIMAL;
|
||||||
|
else if (r == 16)
|
||||||
|
radix = RADIX_HEX;
|
||||||
|
else {
|
||||||
|
warnx("unsupported radix \"%s\".",
|
||||||
|
optarg);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err(EXIT_FAILURE, "Error in option handling.");
|
||||||
|
/*NOTREACHED*/
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case '?':
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
files = (argc == 0) ? default_args : (void *) argv;
|
||||||
|
|
||||||
|
while ((fn = *files) != NULL) {
|
||||||
|
rc = handle_elf(fn);
|
||||||
|
if (rc != RETURN_OK)
|
||||||
|
warnx(rc == RETURN_NOINPUT ?
|
||||||
|
"'%s': No such file" :
|
||||||
|
"%s: File format not recognized", fn);
|
||||||
|
files++;
|
||||||
|
}
|
||||||
|
if (style == STYLE_BERKELEY) {
|
||||||
|
if (show_totals)
|
||||||
|
berkeley_totals();
|
||||||
|
tbl_flush();
|
||||||
|
}
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Elf_Data *
|
||||||
|
xlatetom(Elf *elf, GElf_Ehdr *elfhdr, void *_src, void *_dst,
|
||||||
|
Elf_Type type, size_t size)
|
||||||
|
{
|
||||||
|
Elf_Data src, dst;
|
||||||
|
|
||||||
|
src.d_buf = _src;
|
||||||
|
src.d_type = type;
|
||||||
|
src.d_version = elfhdr->e_version;
|
||||||
|
src.d_size = size;
|
||||||
|
dst.d_buf = _dst;
|
||||||
|
dst.d_version = elfhdr->e_version;
|
||||||
|
dst.d_size = size;
|
||||||
|
return (gelf_xlatetom(elf, &dst, &src, elfhdr->e_ident[EI_DATA]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NOTE_OFFSET_32(nhdr, namesz, offset) \
|
||||||
|
((char *)nhdr + sizeof(Elf32_Nhdr) + \
|
||||||
|
ELF_ALIGN((int32_t)namesz, 4) + offset)
|
||||||
|
|
||||||
|
#define NOTE_OFFSET_64(nhdr, namesz, offset) \
|
||||||
|
((char *)nhdr + sizeof(Elf32_Nhdr) + \
|
||||||
|
ELF_ALIGN((int32_t)namesz, 8) + offset)
|
||||||
|
|
||||||
|
#define PID32(nhdr, namesz, offset) \
|
||||||
|
(pid_t)*((int *)((uintptr_t)NOTE_OFFSET_32(nhdr, \
|
||||||
|
namesz, offset)));
|
||||||
|
|
||||||
|
#define PID64(nhdr, namesz, offset) \
|
||||||
|
(pid_t)*((int *)((uintptr_t)NOTE_OFFSET_64(nhdr, \
|
||||||
|
namesz, offset)));
|
||||||
|
|
||||||
|
#define NEXT_NOTE(elfhdr, descsz, namesz, offset) do { \
|
||||||
|
if (elfhdr->e_ident[EI_CLASS] == ELFCLASS32) { \
|
||||||
|
offset += ELF_ALIGN((int32_t)descsz, 4) + \
|
||||||
|
sizeof(Elf32_Nhdr) + \
|
||||||
|
ELF_ALIGN((int32_t)namesz, 4); \
|
||||||
|
} else { \
|
||||||
|
offset += ELF_ALIGN((int32_t)descsz, 8) + \
|
||||||
|
sizeof(Elf32_Nhdr) + \
|
||||||
|
ELF_ALIGN((int32_t)namesz, 8); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse individual note entries inside a PT_NOTE segment.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
handle_core_note(Elf *elf, GElf_Ehdr *elfhdr, GElf_Phdr *phdr,
|
||||||
|
char **cmd_line)
|
||||||
|
{
|
||||||
|
size_t max_size;
|
||||||
|
uint64_t raw_size;
|
||||||
|
GElf_Off offset;
|
||||||
|
static pid_t pid;
|
||||||
|
uintptr_t ver;
|
||||||
|
Elf32_Nhdr *nhdr, nhdr_l;
|
||||||
|
static int reg_pseudo = 0, reg2_pseudo = 0, regxfp_pseudo = 0;
|
||||||
|
char buf[BUF_SIZE], *data, *name;
|
||||||
|
|
||||||
|
if (elf == NULL || elfhdr == NULL || phdr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
data = elf_rawfile(elf, &max_size);
|
||||||
|
offset = phdr->p_offset;
|
||||||
|
while (data != NULL && offset < phdr->p_offset + phdr->p_filesz) {
|
||||||
|
nhdr = (Elf32_Nhdr *)(uintptr_t)((char*)data + offset);
|
||||||
|
memset(&nhdr_l, 0, sizeof(Elf32_Nhdr));
|
||||||
|
if (!xlatetom(elf, elfhdr, &nhdr->n_type, &nhdr_l.n_type,
|
||||||
|
ELF_T_WORD, sizeof(Elf32_Word)) ||
|
||||||
|
!xlatetom(elf, elfhdr, &nhdr->n_descsz, &nhdr_l.n_descsz,
|
||||||
|
ELF_T_WORD, sizeof(Elf32_Word)) ||
|
||||||
|
!xlatetom(elf, elfhdr, &nhdr->n_namesz, &nhdr_l.n_namesz,
|
||||||
|
ELF_T_WORD, sizeof(Elf32_Word)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
name = (char *)((char *)nhdr + sizeof(Elf32_Nhdr));
|
||||||
|
switch (nhdr_l.n_type) {
|
||||||
|
case NT_PRSTATUS: {
|
||||||
|
raw_size = 0;
|
||||||
|
if (elfhdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD &&
|
||||||
|
nhdr_l.n_namesz == 0x8 &&
|
||||||
|
!strcmp(name,"FreeBSD")) {
|
||||||
|
if (elfhdr->e_ident[EI_CLASS] == ELFCLASS32) {
|
||||||
|
raw_size = (uint64_t)*((uint32_t *)
|
||||||
|
(uintptr_t)(name +
|
||||||
|
ELF_ALIGN((int32_t)
|
||||||
|
nhdr_l.n_namesz, 4) + 8));
|
||||||
|
ver = (uintptr_t)NOTE_OFFSET_32(nhdr,
|
||||||
|
nhdr_l.n_namesz,0);
|
||||||
|
if (*((int *)ver) == 1)
|
||||||
|
pid = PID32(nhdr,
|
||||||
|
nhdr_l.n_namesz, 24);
|
||||||
|
} else {
|
||||||
|
raw_size = *((uint64_t *)(uintptr_t)
|
||||||
|
(name + ELF_ALIGN((int32_t)
|
||||||
|
nhdr_l.n_namesz, 8) + 16));
|
||||||
|
ver = (uintptr_t)NOTE_OFFSET_64(nhdr,
|
||||||
|
nhdr_l.n_namesz,0);
|
||||||
|
if (*((int *)ver) == 1)
|
||||||
|
pid = PID64(nhdr,
|
||||||
|
nhdr_l.n_namesz, 40);
|
||||||
|
}
|
||||||
|
xlatetom(elf, elfhdr, &raw_size, &raw_size,
|
||||||
|
ELF_T_WORD, sizeof(uint64_t));
|
||||||
|
xlatetom(elf, elfhdr, &pid, &pid, ELF_T_WORD,
|
||||||
|
sizeof(pid_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw_size != 0 && style == STYLE_SYSV) {
|
||||||
|
(void) snprintf(buf, BUF_SIZE, "%s/%d",
|
||||||
|
".reg", pid);
|
||||||
|
tbl_append();
|
||||||
|
tbl_print(buf, 0);
|
||||||
|
tbl_print_num(raw_size, radix, 1);
|
||||||
|
tbl_print_num(0, radix, 2);
|
||||||
|
if (!reg_pseudo) {
|
||||||
|
tbl_append();
|
||||||
|
tbl_print(".reg", 0);
|
||||||
|
tbl_print_num(raw_size, radix, 1);
|
||||||
|
tbl_print_num(0, radix, 2);
|
||||||
|
reg_pseudo = 1;
|
||||||
|
text_size_total += raw_size;
|
||||||
|
}
|
||||||
|
text_size_total += raw_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_FPREGSET: /* same as NT_PRFPREG */
|
||||||
|
if (style == STYLE_SYSV) {
|
||||||
|
(void) snprintf(buf, BUF_SIZE,
|
||||||
|
"%s/%d", ".reg2", pid);
|
||||||
|
tbl_append();
|
||||||
|
tbl_print(buf, 0);
|
||||||
|
tbl_print_num(nhdr_l.n_descsz, radix, 1);
|
||||||
|
tbl_print_num(0, radix, 2);
|
||||||
|
if (!reg2_pseudo) {
|
||||||
|
tbl_append();
|
||||||
|
tbl_print(".reg2", 0);
|
||||||
|
tbl_print_num(nhdr_l.n_descsz, radix,
|
||||||
|
1);
|
||||||
|
tbl_print_num(0, radix, 2);
|
||||||
|
reg2_pseudo = 1;
|
||||||
|
text_size_total += nhdr_l.n_descsz;
|
||||||
|
}
|
||||||
|
text_size_total += nhdr_l.n_descsz;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_AUXV:
|
||||||
|
if (style == STYLE_SYSV) {
|
||||||
|
tbl_append();
|
||||||
|
tbl_print(".auxv", 0);
|
||||||
|
tbl_print_num(nhdr_l.n_descsz, radix, 1);
|
||||||
|
tbl_print_num(0, radix, 2);
|
||||||
|
text_size_total += nhdr_l.n_descsz;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_PRXFPREG:
|
||||||
|
if (style == STYLE_SYSV) {
|
||||||
|
(void) snprintf(buf, BUF_SIZE, "%s/%d",
|
||||||
|
".reg-xfp", pid);
|
||||||
|
tbl_append();
|
||||||
|
tbl_print(buf, 0);
|
||||||
|
tbl_print_num(nhdr_l.n_descsz, radix, 1);
|
||||||
|
tbl_print_num(0, radix, 2);
|
||||||
|
if (!regxfp_pseudo) {
|
||||||
|
tbl_append();
|
||||||
|
tbl_print(".reg-xfp", 0);
|
||||||
|
tbl_print_num(nhdr_l.n_descsz, radix,
|
||||||
|
1);
|
||||||
|
tbl_print_num(0, radix, 2);
|
||||||
|
regxfp_pseudo = 1;
|
||||||
|
text_size_total += nhdr_l.n_descsz;
|
||||||
|
}
|
||||||
|
text_size_total += nhdr_l.n_descsz;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_PSINFO:
|
||||||
|
case NT_PRPSINFO: {
|
||||||
|
/* FreeBSD 64-bit */
|
||||||
|
if (nhdr_l.n_descsz == 0x78 &&
|
||||||
|
!strcmp(name,"FreeBSD")) {
|
||||||
|
*cmd_line = strdup(NOTE_OFFSET_64(nhdr,
|
||||||
|
nhdr_l.n_namesz, 33));
|
||||||
|
/* FreeBSD 32-bit */
|
||||||
|
} else if (nhdr_l.n_descsz == 0x6c &&
|
||||||
|
!strcmp(name,"FreeBSD")) {
|
||||||
|
*cmd_line = strdup(NOTE_OFFSET_32(nhdr,
|
||||||
|
nhdr_l.n_namesz, 25));
|
||||||
|
}
|
||||||
|
/* Strip any trailing spaces */
|
||||||
|
if (*cmd_line != NULL) {
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
s = *cmd_line + strlen(*cmd_line);
|
||||||
|
while (s > *cmd_line) {
|
||||||
|
if (*(s-1) != 0x20) break;
|
||||||
|
s--;
|
||||||
|
}
|
||||||
|
*s = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NT_PSTATUS:
|
||||||
|
case NT_LWPSTATUS:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
NEXT_NOTE(elfhdr, nhdr_l.n_descsz, nhdr_l.n_namesz, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handles program headers except for PT_NOTE, when sysv output stlye is
|
||||||
|
* choosen, prints out the segment name and length. For berkely output
|
||||||
|
* style only PT_LOAD segments are handled, and text,
|
||||||
|
* data, bss size is calculated for them.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
handle_phdr(Elf *elf, GElf_Ehdr *elfhdr, GElf_Phdr *phdr,
|
||||||
|
uint32_t idx, const char *name)
|
||||||
|
{
|
||||||
|
uint64_t addr, size;
|
||||||
|
int split;
|
||||||
|
char buf[BUF_SIZE];
|
||||||
|
|
||||||
|
if (elf == NULL || elfhdr == NULL || phdr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size = addr = 0;
|
||||||
|
split = (phdr->p_memsz > 0) && (phdr->p_filesz > 0) &&
|
||||||
|
(phdr->p_memsz > phdr->p_filesz);
|
||||||
|
|
||||||
|
if (style == STYLE_SYSV) {
|
||||||
|
(void) snprintf(buf, BUF_SIZE,
|
||||||
|
"%s%d%s", name, idx, (split ? "a" : ""));
|
||||||
|
tbl_append();
|
||||||
|
tbl_print(buf, 0);
|
||||||
|
tbl_print_num(phdr->p_filesz, radix, 1);
|
||||||
|
tbl_print_num(phdr->p_vaddr, radix, 2);
|
||||||
|
text_size_total += phdr->p_filesz;
|
||||||
|
if (split) {
|
||||||
|
size = phdr->p_memsz - phdr->p_filesz;
|
||||||
|
addr = phdr->p_vaddr + phdr->p_filesz;
|
||||||
|
(void) snprintf(buf, BUF_SIZE, "%s%d%s", name,
|
||||||
|
idx, "b");
|
||||||
|
text_size_total += phdr->p_memsz - phdr->p_filesz;
|
||||||
|
tbl_append();
|
||||||
|
tbl_print(buf, 0);
|
||||||
|
tbl_print_num(size, radix, 1);
|
||||||
|
tbl_print_num(addr, radix, 2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (phdr->p_type != PT_LOAD)
|
||||||
|
return;
|
||||||
|
if ((phdr->p_flags & PF_W) && !(phdr->p_flags & PF_X)) {
|
||||||
|
data_size += phdr->p_filesz;
|
||||||
|
if (split)
|
||||||
|
data_size += phdr->p_memsz - phdr->p_filesz;
|
||||||
|
} else {
|
||||||
|
text_size += phdr->p_filesz;
|
||||||
|
if (split)
|
||||||
|
text_size += phdr->p_memsz - phdr->p_filesz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a core dump file, this function maps program headers to segments.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
handle_core(char const *name, Elf *elf, GElf_Ehdr *elfhdr)
|
||||||
|
{
|
||||||
|
GElf_Phdr phdr;
|
||||||
|
uint32_t i;
|
||||||
|
char *core_cmdline;
|
||||||
|
const char *seg_name;
|
||||||
|
|
||||||
|
if (name == NULL || elf == NULL || elfhdr == NULL)
|
||||||
|
return (RETURN_DATAERR);
|
||||||
|
if (elfhdr->e_shnum != 0 || elfhdr->e_type != ET_CORE)
|
||||||
|
return (RETURN_DATAERR);
|
||||||
|
|
||||||
|
seg_name = core_cmdline = NULL;
|
||||||
|
if (style == STYLE_SYSV)
|
||||||
|
sysv_header(name, NULL);
|
||||||
|
else
|
||||||
|
berkeley_header();
|
||||||
|
|
||||||
|
for (i = 0; i < elfhdr->e_phnum; i++) {
|
||||||
|
if (gelf_getphdr(elf, i, &phdr) != NULL) {
|
||||||
|
if (phdr.p_type == PT_NOTE) {
|
||||||
|
handle_phdr(elf, elfhdr, &phdr, i, "note");
|
||||||
|
handle_core_note(elf, elfhdr, &phdr,
|
||||||
|
&core_cmdline);
|
||||||
|
} else {
|
||||||
|
switch(phdr.p_type) {
|
||||||
|
case PT_NULL:
|
||||||
|
seg_name = "null";
|
||||||
|
break;
|
||||||
|
case PT_LOAD:
|
||||||
|
seg_name = "load";
|
||||||
|
break;
|
||||||
|
case PT_DYNAMIC:
|
||||||
|
seg_name = "dynamic";
|
||||||
|
break;
|
||||||
|
case PT_INTERP:
|
||||||
|
seg_name = "interp";
|
||||||
|
break;
|
||||||
|
case PT_SHLIB:
|
||||||
|
seg_name = "shlib";
|
||||||
|
break;
|
||||||
|
case PT_PHDR:
|
||||||
|
seg_name = "phdr";
|
||||||
|
break;
|
||||||
|
case PT_GNU_EH_FRAME:
|
||||||
|
seg_name = "eh_frame_hdr";
|
||||||
|
break;
|
||||||
|
case PT_GNU_STACK:
|
||||||
|
seg_name = "stack";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
seg_name = "segment";
|
||||||
|
}
|
||||||
|
handle_phdr(elf, elfhdr, &phdr, i, seg_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style == STYLE_BERKELEY) {
|
||||||
|
if (core_cmdline != NULL) {
|
||||||
|
berkeley_footer(core_cmdline, name,
|
||||||
|
"core file invoked as");
|
||||||
|
} else {
|
||||||
|
berkeley_footer(core_cmdline, name, "core file");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sysv_footer();
|
||||||
|
if (core_cmdline != NULL) {
|
||||||
|
(void) printf(" (core file invoked as %s)\n\n",
|
||||||
|
core_cmdline);
|
||||||
|
} else {
|
||||||
|
(void) printf(" (core file)\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(core_cmdline);
|
||||||
|
return (RETURN_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given an elf object,ar(1) filename, and based on the output style
|
||||||
|
* and radix format the various sections and their length will be printed
|
||||||
|
* or the size of the text, data, bss sections will be printed out.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
handle_elf(char const *name)
|
||||||
|
{
|
||||||
|
GElf_Ehdr elfhdr;
|
||||||
|
GElf_Shdr shdr;
|
||||||
|
Elf *elf, *elf1;
|
||||||
|
Elf_Arhdr *arhdr;
|
||||||
|
Elf_Scn *scn;
|
||||||
|
Elf_Cmd elf_cmd;
|
||||||
|
int exit_code, fd;
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
return (RETURN_NOINPUT);
|
||||||
|
|
||||||
|
if ((fd = open(name, O_RDONLY, 0)) < 0)
|
||||||
|
return (RETURN_NOINPUT);
|
||||||
|
|
||||||
|
elf_cmd = ELF_C_READ;
|
||||||
|
elf1 = elf_begin(fd, elf_cmd, NULL);
|
||||||
|
while ((elf = elf_begin(fd, elf_cmd, elf1)) != NULL) {
|
||||||
|
arhdr = elf_getarhdr(elf);
|
||||||
|
if (elf_kind(elf) == ELF_K_NONE && arhdr == NULL) {
|
||||||
|
(void) elf_end(elf);
|
||||||
|
(void) elf_end(elf1);
|
||||||
|
(void) close(fd);
|
||||||
|
return (RETURN_DATAERR);
|
||||||
|
}
|
||||||
|
if (elf_kind(elf) != ELF_K_ELF ||
|
||||||
|
(gelf_getehdr(elf, &elfhdr) == NULL)) {
|
||||||
|
elf_cmd = elf_next(elf);
|
||||||
|
(void) elf_end(elf);
|
||||||
|
warnx("%s: File format not recognized",
|
||||||
|
arhdr->ar_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Core dumps are handled seperately */
|
||||||
|
if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) {
|
||||||
|
exit_code = handle_core(name, elf, &elfhdr);
|
||||||
|
(void) elf_end(elf);
|
||||||
|
(void) elf_end(elf1);
|
||||||
|
(void) close(fd);
|
||||||
|
return (exit_code);
|
||||||
|
} else {
|
||||||
|
scn = NULL;
|
||||||
|
if (style == STYLE_BERKELEY) {
|
||||||
|
berkeley_header();
|
||||||
|
while ((scn = elf_nextscn(elf, scn)) != NULL) {
|
||||||
|
if (gelf_getshdr(scn, &shdr) != NULL)
|
||||||
|
berkeley_calc(&shdr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sysv_header(name, arhdr);
|
||||||
|
scn = NULL;
|
||||||
|
while ((scn = elf_nextscn(elf, scn)) != NULL) {
|
||||||
|
if (gelf_getshdr(scn, &shdr) != NULL)
|
||||||
|
sysv_calc(elf, &elfhdr, &shdr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (style == STYLE_BERKELEY) {
|
||||||
|
if (arhdr != NULL) {
|
||||||
|
berkeley_footer(name, arhdr->ar_name,
|
||||||
|
"ex");
|
||||||
|
} else {
|
||||||
|
berkeley_footer(name, NULL, "ex");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sysv_footer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elf_cmd = elf_next(elf);
|
||||||
|
(void) elf_end(elf);
|
||||||
|
}
|
||||||
|
(void) elf_end(elf1);
|
||||||
|
(void) close(fd);
|
||||||
|
return (RETURN_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sysv formatting helper functions.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
sysv_header(const char *name, Elf_Arhdr *arhdr)
|
||||||
|
{
|
||||||
|
|
||||||
|
text_size_total = 0;
|
||||||
|
if (arhdr != NULL)
|
||||||
|
(void) printf("%s (ex %s):\n", arhdr->ar_name, name);
|
||||||
|
else
|
||||||
|
(void) printf("%s :\n", name);
|
||||||
|
tbl_new(3);
|
||||||
|
tbl_append();
|
||||||
|
tbl_print("section", 0);
|
||||||
|
tbl_print("size", 1);
|
||||||
|
tbl_print("addr", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sysv_calc(Elf *elf, GElf_Ehdr *elfhdr, GElf_Shdr *shdr)
|
||||||
|
{
|
||||||
|
char *section_name;
|
||||||
|
|
||||||
|
section_name = elf_strptr(elf, elfhdr->e_shstrndx,
|
||||||
|
(size_t) shdr->sh_name);
|
||||||
|
if ((shdr->sh_type == SHT_SYMTAB ||
|
||||||
|
shdr->sh_type == SHT_STRTAB || shdr->sh_type == SHT_RELA ||
|
||||||
|
shdr->sh_type == SHT_REL) && shdr->sh_addr == 0)
|
||||||
|
return;
|
||||||
|
tbl_append();
|
||||||
|
tbl_print(section_name, 0);
|
||||||
|
tbl_print_num(shdr->sh_size, radix, 1);
|
||||||
|
tbl_print_num(shdr->sh_addr, radix, 2);
|
||||||
|
text_size_total += shdr->sh_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sysv_footer(void)
|
||||||
|
{
|
||||||
|
tbl_append();
|
||||||
|
tbl_print("Total", 0);
|
||||||
|
tbl_print_num(text_size_total, radix, 1);
|
||||||
|
tbl_flush();
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* berkeley style output formatting helper functions.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
berkeley_header(void)
|
||||||
|
{
|
||||||
|
static int printed;
|
||||||
|
|
||||||
|
text_size = data_size = bss_size = 0;
|
||||||
|
if (!printed) {
|
||||||
|
tbl_new(6);
|
||||||
|
tbl_append();
|
||||||
|
tbl_print("text", 0);
|
||||||
|
tbl_print("data", 1);
|
||||||
|
tbl_print("bss", 2);
|
||||||
|
if (radix == RADIX_OCTAL)
|
||||||
|
tbl_print("oct", 3);
|
||||||
|
else
|
||||||
|
tbl_print("dec", 3);
|
||||||
|
tbl_print("hex", 4);
|
||||||
|
tbl_print("filename", 5);
|
||||||
|
printed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
berkeley_calc(GElf_Shdr *shdr)
|
||||||
|
{
|
||||||
|
if (shdr != NULL) {
|
||||||
|
if (!(shdr->sh_flags & SHF_ALLOC))
|
||||||
|
return;
|
||||||
|
if ((shdr->sh_flags & SHF_ALLOC) &&
|
||||||
|
((shdr->sh_flags & SHF_EXECINSTR) ||
|
||||||
|
!(shdr->sh_flags & SHF_WRITE)))
|
||||||
|
text_size += shdr->sh_size;
|
||||||
|
else if ((shdr->sh_flags & SHF_ALLOC) &&
|
||||||
|
(shdr->sh_flags & SHF_WRITE) &&
|
||||||
|
(shdr->sh_type != SHT_NOBITS))
|
||||||
|
data_size += shdr->sh_size;
|
||||||
|
else
|
||||||
|
bss_size += shdr->sh_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
berkeley_totals(void)
|
||||||
|
{
|
||||||
|
long unsigned int grand_total;
|
||||||
|
|
||||||
|
grand_total = text_size_total + data_size_total + bss_size_total;
|
||||||
|
tbl_append();
|
||||||
|
tbl_print_num(text_size_total, radix, 0);
|
||||||
|
tbl_print_num(data_size_total, radix, 1);
|
||||||
|
tbl_print_num(bss_size_total, radix, 2);
|
||||||
|
if (radix == RADIX_OCTAL)
|
||||||
|
tbl_print_num(grand_total, RADIX_OCTAL, 3);
|
||||||
|
else
|
||||||
|
tbl_print_num(grand_total, RADIX_DECIMAL, 3);
|
||||||
|
tbl_print_num(grand_total, RADIX_HEX, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
berkeley_footer(const char *name, const char *ar_name, const char *msg)
|
||||||
|
{
|
||||||
|
char buf[BUF_SIZE];
|
||||||
|
|
||||||
|
total_size = text_size + data_size + bss_size;
|
||||||
|
if (show_totals) {
|
||||||
|
text_size_total += text_size;
|
||||||
|
bss_size_total += bss_size;
|
||||||
|
data_size_total += data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbl_append();
|
||||||
|
tbl_print_num(text_size, radix, 0);
|
||||||
|
tbl_print_num(data_size, radix, 1);
|
||||||
|
tbl_print_num(bss_size, radix, 2);
|
||||||
|
if (radix == RADIX_OCTAL)
|
||||||
|
tbl_print_num(total_size, RADIX_OCTAL, 3);
|
||||||
|
else
|
||||||
|
tbl_print_num(total_size, RADIX_DECIMAL, 3);
|
||||||
|
tbl_print_num(total_size, RADIX_HEX, 4);
|
||||||
|
if (ar_name != NULL && name != NULL)
|
||||||
|
(void) snprintf(buf, BUF_SIZE, "%s (%s %s)", ar_name, msg,
|
||||||
|
name);
|
||||||
|
else if (ar_name != NULL && name == NULL)
|
||||||
|
(void) snprintf(buf, BUF_SIZE, "%s (%s)", ar_name, msg);
|
||||||
|
else
|
||||||
|
(void) snprintf(buf, BUF_SIZE, "%s", name);
|
||||||
|
tbl_print(buf, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
tbl_new(int col)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(tb == NULL);
|
||||||
|
assert(col > 0);
|
||||||
|
if ((tb = calloc(1, sizeof(*tb))) == NULL)
|
||||||
|
err(EXIT_FAILURE, "calloc");
|
||||||
|
if ((tb->tbl = calloc(col, sizeof(*tb->tbl))) == NULL)
|
||||||
|
err(EXIT_FAILURE, "calloc");
|
||||||
|
if ((tb->width = calloc(col, sizeof(*tb->width))) == NULL)
|
||||||
|
err(EXIT_FAILURE, "calloc");
|
||||||
|
tb->col = col;
|
||||||
|
tb->row = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tbl_print(const char *s, int col)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
assert(tb != NULL && tb->col > 0 && tb->row > 0 && col < tb->col);
|
||||||
|
assert(s != NULL && tb->tbl[col][tb->row - 1] == NULL);
|
||||||
|
if ((tb->tbl[col][tb->row - 1] = strdup(s)) == NULL)
|
||||||
|
err(EXIT_FAILURE, "strdup");
|
||||||
|
len = strlen(s);
|
||||||
|
if (len > tb->width[col])
|
||||||
|
tb->width[col] = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tbl_print_num(uint64_t num, enum radix_style rad, int col)
|
||||||
|
{
|
||||||
|
char buf[BUF_SIZE];
|
||||||
|
|
||||||
|
(void) snprintf(buf, BUF_SIZE, (rad == RADIX_DECIMAL ? "%ju" :
|
||||||
|
((rad == RADIX_OCTAL) ? "0%jo" : "0x%jx")), (uintmax_t) num);
|
||||||
|
tbl_print(buf, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tbl_append(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
assert(tb != NULL && tb->col > 0);
|
||||||
|
tb->row++;
|
||||||
|
for (i = 0; i < tb->col; i++) {
|
||||||
|
tb->tbl[i] = realloc(tb->tbl[i], sizeof(*tb->tbl[i]) * tb->row);
|
||||||
|
if (tb->tbl[i] == NULL)
|
||||||
|
err(EXIT_FAILURE, "realloc");
|
||||||
|
tb->tbl[i][tb->row - 1] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tbl_flush(void)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if (tb == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert(tb->col > 0);
|
||||||
|
for (i = 0; i < tb->row; i++) {
|
||||||
|
if (style == STYLE_BERKELEY)
|
||||||
|
printf(" ");
|
||||||
|
for (j = 0; j < tb->col; j++) {
|
||||||
|
str = (tb->tbl[j][i] != NULL ? tb->tbl[j][i] : "");
|
||||||
|
if (style == STYLE_SYSV && j == 0)
|
||||||
|
printf("%-*s", tb->width[j], str);
|
||||||
|
else if (style == STYLE_BERKELEY && j == tb->col - 1)
|
||||||
|
printf("%s", str);
|
||||||
|
else
|
||||||
|
printf("%*s", tb->width[j], str);
|
||||||
|
if (j == tb->col -1)
|
||||||
|
putchar('\n');
|
||||||
|
else
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < tb->col; i++) {
|
||||||
|
for (j = 0; j < tb->row; j++) {
|
||||||
|
if (tb->tbl[i][j])
|
||||||
|
free(tb->tbl[i][j]);
|
||||||
|
}
|
||||||
|
free(tb->tbl[i]);
|
||||||
|
}
|
||||||
|
free(tb->tbl);
|
||||||
|
free(tb->width);
|
||||||
|
free(tb);
|
||||||
|
tb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define USAGE_MESSAGE "\
|
||||||
|
Usage: %s [options] file ...\n\
|
||||||
|
Display sizes of ELF sections.\n\n\
|
||||||
|
Options:\n\
|
||||||
|
--format=format Display output in specified format. Supported\n\
|
||||||
|
values are `berkeley' and `sysv'.\n\
|
||||||
|
--help Display this help message and exit.\n\
|
||||||
|
--radix=radix Display numeric values in the specified radix.\n\
|
||||||
|
Supported values are: 8, 10 and 16.\n\
|
||||||
|
--totals Show cumulative totals of section sizes.\n\
|
||||||
|
--version Display a version identifier and exit.\n\
|
||||||
|
-A Equivalent to `--format=sysv'.\n\
|
||||||
|
-B Equivalent to `--format=berkeley'.\n\
|
||||||
|
-V Equivalent to `--version'.\n\
|
||||||
|
-d Equivalent to `--radix=10'.\n\
|
||||||
|
-h Same as option --help.\n\
|
||||||
|
-o Equivalent to `--radix=8'.\n\
|
||||||
|
-t Equivalent to option --totals.\n\
|
||||||
|
-x Equivalent to `--radix=16'.\n"
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
show_version(void)
|
||||||
|
{
|
||||||
|
(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
11
contrib/elftoolchain/strings/Makefile
Normal file
11
contrib/elftoolchain/strings/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# $Id: Makefile 2044 2011-10-23 14:52:59Z jkoshy $
|
||||||
|
|
||||||
|
TOP= ..
|
||||||
|
|
||||||
|
PROG= strings
|
||||||
|
WARNS?= 6
|
||||||
|
DPADD= ${LIBELFTC} ${LIBELF}
|
||||||
|
LDADD= -lelftc -lelf
|
||||||
|
|
||||||
|
.include "${TOP}/mk/elftoolchain.prog.mk"
|
||||||
|
|
162
contrib/elftoolchain/strings/strings.1
Normal file
162
contrib/elftoolchain/strings/strings.1
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
.\" Copyright (c) 2007 S.Sam Arun Raj
|
||||||
|
.\" 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.
|
||||||
|
.\"
|
||||||
|
.\" $Id: strings.1 2352 2011-12-19 11:21:10Z jkoshy $
|
||||||
|
.\"
|
||||||
|
.Dd December 19, 2011
|
||||||
|
.Dt STRINGS 1
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm strings
|
||||||
|
.Nd "print the strings of printable characters in files"
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl a | Fl -all
|
||||||
|
.Op Fl e Ar encoding | Fl -encoding= Ns Ar encoding
|
||||||
|
.Op Fl f | Fl -print-file-name
|
||||||
|
.Op Fl h | Fl -help
|
||||||
|
.Op Fl n Ar number | Fl -bytes= Ns Ar number | Fl Ar number
|
||||||
|
.Op Fl o
|
||||||
|
.Op Fl t Ar radix | Fl -radix= Ns Ar radix
|
||||||
|
.Op Fl v | Fl -version
|
||||||
|
.Op Ar
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
For each
|
||||||
|
.Ar file
|
||||||
|
specified, the
|
||||||
|
.Nm
|
||||||
|
utility prints contiguous sequences of printable
|
||||||
|
characters that are at least
|
||||||
|
.Va n
|
||||||
|
characters long and are followed by an unprintable character.
|
||||||
|
The default value of
|
||||||
|
.Va n
|
||||||
|
is 4.
|
||||||
|
By default, the
|
||||||
|
.Nm
|
||||||
|
utility only scans the initialized and loaded sections of ELF objects;
|
||||||
|
for other file types, the entire file is scanned.
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility is mainly used for determining the contents of non-text files.
|
||||||
|
.Pp
|
||||||
|
If no file name is specified as an argument, standard input is read.
|
||||||
|
.Pp
|
||||||
|
The following options are available:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl a | Fl -all
|
||||||
|
For ELF objects, scan the entire file for printable strings.
|
||||||
|
.It Fl e Ar encoding | Fl -encoding= Ns Ar encoding
|
||||||
|
Select the character encoding to be used while searching for strings.
|
||||||
|
Valid values for argument
|
||||||
|
.Ar encoding
|
||||||
|
are:
|
||||||
|
.Bl -tag -width indent -compact
|
||||||
|
.It Ar s
|
||||||
|
for single 7-bit-byte characters (ASCII, ISO 8859).
|
||||||
|
.It Ar S
|
||||||
|
for single 8-bit-byte characters.
|
||||||
|
.It Ar l
|
||||||
|
for 16-bit little-endian.
|
||||||
|
.It Ar b
|
||||||
|
for 16-bit big-endian.
|
||||||
|
.It Ar L
|
||||||
|
for 32-bit little-endian.
|
||||||
|
.It Ar B
|
||||||
|
for 32-bit big-endian.
|
||||||
|
.El
|
||||||
|
The default is to assume that characters are encoded using a single
|
||||||
|
7-bit byte.
|
||||||
|
.It Fl f | Fl -print-file-name
|
||||||
|
Print the name of the file before each string.
|
||||||
|
.It Fl h | Fl -help
|
||||||
|
Print a usage summary and exit.
|
||||||
|
.It Xo
|
||||||
|
.Fl n Ar number |
|
||||||
|
.Fl -bytes= Ns Ar number |
|
||||||
|
.Fl Ar number
|
||||||
|
.Xc
|
||||||
|
Print the contiguous character sequence of at least
|
||||||
|
.Ar number
|
||||||
|
characters long, instead of the default of 4 characters.
|
||||||
|
.It Fl o
|
||||||
|
Equivalent to specifying
|
||||||
|
.Fl t Ar o .
|
||||||
|
.It Fl t Ar radix | Fl -radix= Ns Ar radix
|
||||||
|
Print the offset from the start of the file before each string
|
||||||
|
using the specified radix.
|
||||||
|
Valid values for argument
|
||||||
|
.Ar radix
|
||||||
|
are:
|
||||||
|
.Bl -tag -width indent -compact
|
||||||
|
.It Ar d
|
||||||
|
for decimal
|
||||||
|
.It Ar o
|
||||||
|
for octal
|
||||||
|
.It Ar x
|
||||||
|
for hexadecimal
|
||||||
|
.El
|
||||||
|
.It Fl v | Fl -version
|
||||||
|
Display a version identifier and exit.
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Ex -std
|
||||||
|
.Sh EXAMPLES
|
||||||
|
To display strings in
|
||||||
|
.Pa /bin/ls
|
||||||
|
use:
|
||||||
|
.Dl "$ strings /bin/ls"
|
||||||
|
.Pp
|
||||||
|
To display strings in all sections of
|
||||||
|
.Pa /bin/ln
|
||||||
|
use:
|
||||||
|
.Dl "$ strings -a /bin/ln"
|
||||||
|
.Pp
|
||||||
|
To display strings in all sections of
|
||||||
|
.Pa /bin/cat
|
||||||
|
prefixed with the filename and the offset within the file use:
|
||||||
|
.Dl "$ strings -a -f -t x /bin/cat"
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr ar 1 ,
|
||||||
|
.Xr nm 1 ,
|
||||||
|
.Xr objdump 1 ,
|
||||||
|
.Xr ranlib ,
|
||||||
|
.Xr readelf 1 ,
|
||||||
|
.Xr size 1
|
||||||
|
.Sh HISTORY
|
||||||
|
The first FreeBSD
|
||||||
|
.Nm
|
||||||
|
utility appeared in
|
||||||
|
.Fx v3.
|
||||||
|
It was later discontinued in
|
||||||
|
.Fx v5 ,
|
||||||
|
when i386-only a.out format was dropped in favor of ELF.
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An -nosplit
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility was re-written by
|
||||||
|
.An S.Sam Arun Raj Aq samarunraj@gmail.com .
|
||||||
|
This manual page was written by
|
||||||
|
.An S.Sam Arun Raj Aq samarunraj@gmail.com .
|
454
contrib/elftoolchain/strings/strings.c
Normal file
454
contrib/elftoolchain/strings/strings.c
Normal file
@ -0,0 +1,454 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2007 S.Sam Arun Raj
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <libelf.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
#include <gelf.h>
|
||||||
|
|
||||||
|
#include "_elftc.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: strings.c 2351 2011-12-19 11:20:37Z jkoshy $");
|
||||||
|
|
||||||
|
enum return_code {
|
||||||
|
RETURN_OK,
|
||||||
|
RETURN_NOINPUT,
|
||||||
|
RETURN_SOFTWARE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum radix_style {
|
||||||
|
RADIX_DECIMAL,
|
||||||
|
RADIX_HEX,
|
||||||
|
RADIX_OCTAL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum encoding_style {
|
||||||
|
ENCODING_7BIT,
|
||||||
|
ENCODING_8BIT,
|
||||||
|
ENCODING_16BIT_BIG,
|
||||||
|
ENCODING_16BIT_LITTLE,
|
||||||
|
ENCODING_32BIT_BIG,
|
||||||
|
ENCODING_32BIT_LITTLE
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PRINTABLE(c) \
|
||||||
|
((c) >= 0 && (c) <= 255 && \
|
||||||
|
((c) == '\t' || isprint((c)) || \
|
||||||
|
(encoding == ENCODING_8BIT && (c) > 127)))
|
||||||
|
|
||||||
|
|
||||||
|
int encoding_size, entire_file, min_len, show_filename, show_loc;
|
||||||
|
enum encoding_style encoding;
|
||||||
|
enum radix_style radix;
|
||||||
|
|
||||||
|
static struct option strings_longopts[] = {
|
||||||
|
{ "all", no_argument, NULL, 'a'},
|
||||||
|
{ "bytes", required_argument, NULL, 'n'},
|
||||||
|
{ "encoding", required_argument, NULL, 'e'},
|
||||||
|
{ "help", no_argument, NULL, 'h'},
|
||||||
|
{ "print-file-name", no_argument, NULL, 'f'},
|
||||||
|
{ "radix", required_argument, NULL, 't'},
|
||||||
|
{ "version", no_argument, NULL, 'v'},
|
||||||
|
{ NULL, 0, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
long getcharacter(void);
|
||||||
|
int handle_file(const char *);
|
||||||
|
int handle_elf(const char *, int);
|
||||||
|
int handle_binary(const char *, int);
|
||||||
|
int find_strings(const char *, off_t, off_t);
|
||||||
|
void show_version(void);
|
||||||
|
void usage(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* strings(1) extracts text(contiguous printable characters)
|
||||||
|
* from elf and binary files.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int ch, rc;
|
||||||
|
|
||||||
|
rc = RETURN_OK;
|
||||||
|
min_len = 0;
|
||||||
|
encoding_size = 1;
|
||||||
|
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||||
|
errx(EXIT_FAILURE, "ELF library initialization failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
while ((ch = getopt_long(argc, argv, "1234567890ae:fhn:ot:Vv",
|
||||||
|
strings_longopts, NULL)) != -1)
|
||||||
|
switch((char)ch) {
|
||||||
|
case 'a':
|
||||||
|
entire_file = 1;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
if (*optarg == 's') {
|
||||||
|
encoding = ENCODING_7BIT;
|
||||||
|
} else if (*optarg == 'S') {
|
||||||
|
encoding = ENCODING_8BIT;
|
||||||
|
} else if (*optarg == 'b') {
|
||||||
|
encoding = ENCODING_16BIT_BIG;
|
||||||
|
encoding_size = 2;
|
||||||
|
} else if (*optarg == 'B') {
|
||||||
|
encoding = ENCODING_32BIT_BIG;
|
||||||
|
encoding_size = 4;
|
||||||
|
} else if (*optarg == 'l') {
|
||||||
|
encoding = ENCODING_16BIT_LITTLE;
|
||||||
|
encoding_size = 2;
|
||||||
|
} else if (*optarg == 'L') {
|
||||||
|
encoding = ENCODING_32BIT_LITTLE;
|
||||||
|
encoding_size = 4;
|
||||||
|
} else
|
||||||
|
usage();
|
||||||
|
/* NOTREACHED */
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
show_filename = 1;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
min_len = (int)strtoimax(optarg, (char**)NULL, 10);
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
show_loc = 1;
|
||||||
|
radix = RADIX_OCTAL;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
show_loc = 1;
|
||||||
|
if (*optarg == 'd')
|
||||||
|
radix = RADIX_DECIMAL;
|
||||||
|
else if (*optarg == 'o')
|
||||||
|
radix = RADIX_OCTAL;
|
||||||
|
else if (*optarg == 'x')
|
||||||
|
radix = RADIX_HEX;
|
||||||
|
else
|
||||||
|
usage();
|
||||||
|
/* NOTREACHED */
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
case 'V':
|
||||||
|
show_version();
|
||||||
|
/* NOTREACHED */
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
min_len *= 10;
|
||||||
|
min_len += ch - '0';
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case '?':
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (!min_len)
|
||||||
|
min_len = 4;
|
||||||
|
if (!*argv)
|
||||||
|
rc = handle_file("{standard input}");
|
||||||
|
else while (*argv) {
|
||||||
|
rc = handle_file(*argv);
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
handle_file(const char *name)
|
||||||
|
{
|
||||||
|
int fd, rt;
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
return (RETURN_NOINPUT);
|
||||||
|
if (strcmp("{standard input}", name) != 0) {
|
||||||
|
if (freopen(name, "rb", stdin) == NULL) {
|
||||||
|
warnx("'%s': %s", name, strerror(errno));
|
||||||
|
return (RETURN_NOINPUT);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (find_strings(name, (off_t)0, (off_t)0));
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = fileno(stdin);
|
||||||
|
if (fd < 0)
|
||||||
|
return (RETURN_NOINPUT);
|
||||||
|
rt = handle_elf(name, fd);
|
||||||
|
return (rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Files not understood by handle_elf, will be passed off here and will
|
||||||
|
* treated as a binary file. This would include text file, core dumps ...
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
handle_binary(const char *name, int fd)
|
||||||
|
{
|
||||||
|
struct stat buf;
|
||||||
|
|
||||||
|
memset(&buf, 0, sizeof(struct stat));
|
||||||
|
(void) lseek(fd, (off_t)0, SEEK_SET);
|
||||||
|
if (!fstat(fd, &buf))
|
||||||
|
return (find_strings(name, (off_t)0, buf.st_size));
|
||||||
|
return (RETURN_SOFTWARE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Will analyse a file to see if it ELF, other files including ar(1),
|
||||||
|
* core dumps are passed off and treated as flat binary files. Unlike
|
||||||
|
* GNU size in FreeBSD this routine will not treat ELF object from
|
||||||
|
* different archs as flat binary files(has to overridden using -a).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
handle_elf(const char *name, int fd)
|
||||||
|
{
|
||||||
|
GElf_Ehdr elfhdr;
|
||||||
|
GElf_Shdr shdr;
|
||||||
|
Elf *elf;
|
||||||
|
Elf_Scn *scn;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = RETURN_OK;
|
||||||
|
/* If entire file is choosen, treat it as a binary file */
|
||||||
|
if (entire_file)
|
||||||
|
return (handle_binary(name, fd));
|
||||||
|
|
||||||
|
(void) lseek(fd, (off_t)0, SEEK_SET);
|
||||||
|
elf = elf_begin(fd, ELF_C_READ, NULL);
|
||||||
|
if (elf_kind(elf) != ELF_K_ELF) {
|
||||||
|
(void) elf_end(elf);
|
||||||
|
return (handle_binary(name, fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gelf_getehdr(elf, &elfhdr) == NULL) {
|
||||||
|
(void) elf_end(elf);
|
||||||
|
warnx("%s: ELF file could not be processed", name);
|
||||||
|
return (RETURN_SOFTWARE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) {
|
||||||
|
(void) elf_end(elf);
|
||||||
|
return (handle_binary(name, fd));
|
||||||
|
} else {
|
||||||
|
scn = NULL;
|
||||||
|
while ((scn = elf_nextscn(elf, scn)) != NULL) {
|
||||||
|
if (gelf_getshdr(scn, &shdr) == NULL)
|
||||||
|
continue;
|
||||||
|
if (shdr.sh_type != SHT_NOBITS &&
|
||||||
|
(shdr.sh_flags & SHF_ALLOC) != 0) {
|
||||||
|
rc = find_strings(name, shdr.sh_offset,
|
||||||
|
shdr.sh_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) elf_end(elf);
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieves a character from input stream based on the encoding
|
||||||
|
* type requested.
|
||||||
|
*/
|
||||||
|
long
|
||||||
|
getcharacter(void)
|
||||||
|
{
|
||||||
|
long rt;
|
||||||
|
int i;
|
||||||
|
char buf[4], c;
|
||||||
|
|
||||||
|
rt = EOF;
|
||||||
|
for(i = 0; i < encoding_size; i++) {
|
||||||
|
c = getc(stdin);
|
||||||
|
if (feof(stdin))
|
||||||
|
return (EOF);
|
||||||
|
buf[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(encoding) {
|
||||||
|
case ENCODING_7BIT:
|
||||||
|
case ENCODING_8BIT:
|
||||||
|
rt = buf[0];
|
||||||
|
break;
|
||||||
|
case ENCODING_16BIT_BIG:
|
||||||
|
rt = (buf[0] << 8) | buf[1];
|
||||||
|
break;
|
||||||
|
case ENCODING_16BIT_LITTLE:
|
||||||
|
rt = buf[0] | (buf[1] << 8);
|
||||||
|
break;
|
||||||
|
case ENCODING_32BIT_BIG:
|
||||||
|
rt = ((long) buf[0] << 24) | ((long) buf[1] << 16) |
|
||||||
|
((long) buf[2] << 8) | buf[3];
|
||||||
|
break;
|
||||||
|
case ENCODING_32BIT_LITTLE:
|
||||||
|
rt = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) |
|
||||||
|
((long) buf[3] << 24);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Input stream stdin is read until the end of file is reached or until
|
||||||
|
* the section size is reached in case of ELF files. Contiguous
|
||||||
|
* characters of >= min_size(default 4) will be displayed.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
find_strings(const char *name, off_t offset, off_t size)
|
||||||
|
{
|
||||||
|
off_t cur_off, start_off;
|
||||||
|
char *obuf;
|
||||||
|
long c;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((obuf = (char*)calloc(1, min_len + 1)) == NULL) {
|
||||||
|
(void) fprintf(stderr, "Unable to allocate memory: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
return (RETURN_SOFTWARE);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) fseeko(stdin, offset, SEEK_SET);
|
||||||
|
cur_off = offset;
|
||||||
|
start_off = 0;
|
||||||
|
while(1) {
|
||||||
|
if ((offset + size) && (cur_off >= offset + size))
|
||||||
|
break;
|
||||||
|
start_off = cur_off;
|
||||||
|
memset(obuf, 0, min_len+1);
|
||||||
|
for(i = 0; i < min_len; i++) {
|
||||||
|
c = getcharacter();
|
||||||
|
if (c == EOF && feof(stdin))
|
||||||
|
goto _exit1;
|
||||||
|
if (PRINTABLE(c)) {
|
||||||
|
obuf[i] = c;
|
||||||
|
obuf[i+1] = 0;
|
||||||
|
cur_off += encoding_size;
|
||||||
|
} else {
|
||||||
|
if (encoding == ENCODING_8BIT &&
|
||||||
|
(uint8_t)c > 127) {
|
||||||
|
obuf[i] = c;
|
||||||
|
obuf[i+1] = 0;
|
||||||
|
cur_off += encoding_size;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cur_off += encoding_size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= min_len && ((cur_off <= offset + size) ||
|
||||||
|
!(offset + size))) {
|
||||||
|
if (show_filename)
|
||||||
|
printf ("%s: ", name);
|
||||||
|
if (show_loc) {
|
||||||
|
switch(radix) {
|
||||||
|
case RADIX_DECIMAL:
|
||||||
|
(void) printf("%7ju ",
|
||||||
|
(uintmax_t)start_off);
|
||||||
|
break;
|
||||||
|
case RADIX_HEX:
|
||||||
|
(void) printf("%7jx ",
|
||||||
|
(uintmax_t)start_off);
|
||||||
|
break;
|
||||||
|
case RADIX_OCTAL:
|
||||||
|
(void) printf("%7jo ",
|
||||||
|
(uintmax_t)start_off);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("%s", obuf);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
if ((offset + size) &&
|
||||||
|
(cur_off >= offset + size))
|
||||||
|
break;
|
||||||
|
c = getcharacter();
|
||||||
|
cur_off += encoding_size;
|
||||||
|
if (encoding == ENCODING_8BIT &&
|
||||||
|
(uint8_t)c > 127) {
|
||||||
|
putchar(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!PRINTABLE(c) || c == EOF)
|
||||||
|
break;
|
||||||
|
putchar(c);
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_exit1:
|
||||||
|
free(obuf);
|
||||||
|
return (RETURN_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define USAGE_MESSAGE "\
|
||||||
|
Usage: %s [options] [file...]\n\
|
||||||
|
Print contiguous sequences of printable characters.\n\n\
|
||||||
|
Options:\n\
|
||||||
|
-a | --all Scan the entire file for strings.\n\
|
||||||
|
-e ENC | --encoding=ENC Select the character encoding to use.\n\
|
||||||
|
-f | --print-file-name Print the file name before each string.\n\
|
||||||
|
-h | --help Print a help message and exit.\n\
|
||||||
|
-n N | --bytes=N | -N Print sequences with 'N' or more characters.\n\
|
||||||
|
-o Print offsets in octal.\n\
|
||||||
|
-t R | --radix=R Print offsets using the radix named by 'R'.\n\
|
||||||
|
-v | --version Print a version identifier and exit.\n"
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
show_version(void)
|
||||||
|
{
|
||||||
|
(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
23
contrib/libucl/COPYING
Normal file
23
contrib/libucl/COPYING
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Copyright (c) 2013-2014, Vsevolod Stakhov <vsevolod@highsecure.ru>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
|
@ -4,3 +4,19 @@
|
|||||||
|
|
||||||
- Streamline emitter has been added, so it is now possible to output partial `ucl` objects
|
- Streamline emitter has been added, so it is now possible to output partial `ucl` objects
|
||||||
- Emitter now is more flexible due to emitter_context structure
|
- Emitter now is more flexible due to emitter_context structure
|
||||||
|
|
||||||
|
### 0.5.1
|
||||||
|
- Fixed number of bugs and memory leaks
|
||||||
|
|
||||||
|
### 0.5.2
|
||||||
|
|
||||||
|
- Allow userdata objects to be emitted and destructed
|
||||||
|
- Use userdata objects to store lua function references
|
||||||
|
|
||||||
|
### Libucl 0.6
|
||||||
|
|
||||||
|
- Reworked macro interface
|
||||||
|
|
||||||
|
### Libucl 0.6.1
|
||||||
|
|
||||||
|
- Various utilities fixes
|
||||||
|
@ -4,4 +4,8 @@ EXTRA_DIST = uthash README.md
|
|||||||
pkgconfigdir = $(libdir)/pkgconfig
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
pkgconfig_DATA = libucl.pc
|
pkgconfig_DATA = libucl.pc
|
||||||
|
|
||||||
SUBDIRS = src tests utils doc
|
if LUA_SUB
|
||||||
|
LUA_SUBDIR = lua
|
||||||
|
endif
|
||||||
|
|
||||||
|
SUBDIRS = src tests utils doc $(LUA_SUBDIR)
|
@ -33,6 +33,7 @@ OBJECTS = $(OBJDIR)/ucl_hash.o \
|
|||||||
$(OBJDIR)/ucl_util.o \
|
$(OBJDIR)/ucl_util.o \
|
||||||
$(OBJDIR)/ucl_parser.o \
|
$(OBJDIR)/ucl_parser.o \
|
||||||
$(OBJDIR)/ucl_emitter.o \
|
$(OBJDIR)/ucl_emitter.o \
|
||||||
|
$(OBJDIR)/ucl_emitter_utils.o \
|
||||||
$(OBJDIR)/ucl_schema.o \
|
$(OBJDIR)/ucl_schema.o \
|
||||||
$(OBJDIR)/xxhash.o
|
$(OBJDIR)/xxhash.o
|
||||||
|
|
||||||
@ -51,6 +52,8 @@ $(OBJDIR)/ucl_parser.o: $(SRCDIR)/ucl_parser.c $(HDEPS)
|
|||||||
$(CC) -o $(OBJDIR)/ucl_parser.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_parser.c
|
$(CC) -o $(OBJDIR)/ucl_parser.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_parser.c
|
||||||
$(OBJDIR)/ucl_emitter.o: $(SRCDIR)/ucl_emitter.c $(HDEPS)
|
$(OBJDIR)/ucl_emitter.o: $(SRCDIR)/ucl_emitter.c $(HDEPS)
|
||||||
$(CC) -o $(OBJDIR)/ucl_emitter.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter.c
|
$(CC) -o $(OBJDIR)/ucl_emitter.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter.c
|
||||||
|
$(OBJDIR)/ucl_emitter_utils.o: $(SRCDIR)/ucl_emitter_utils.c $(HDEPS)
|
||||||
|
$(CC) -o $(OBJDIR)/ucl_emitter_utils.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter_utils.c
|
||||||
$(OBJDIR)/ucl_hash.o: $(SRCDIR)/ucl_hash.c $(HDEPS)
|
$(OBJDIR)/ucl_hash.o: $(SRCDIR)/ucl_hash.c $(HDEPS)
|
||||||
$(CC) -o $(OBJDIR)/ucl_hash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_hash.c
|
$(CC) -o $(OBJDIR)/ucl_hash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_hash.c
|
||||||
$(OBJDIR)/ucl_schema.o: $(SRCDIR)/ucl_schema.c $(HDEPS)
|
$(OBJDIR)/ucl_schema.o: $(SRCDIR)/ucl_schema.c $(HDEPS)
|
||||||
@ -61,7 +64,7 @@ $(OBJDIR)/xxhash.o: $(SRCDIR)/xxhash.c $(HDEPS)
|
|||||||
clean:
|
clean:
|
||||||
$(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate
|
$(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate
|
||||||
$(RMDIR) $(OBJDIR)
|
$(RMDIR) $(OBJDIR)
|
||||||
|
|
||||||
# Utils
|
# Utils
|
||||||
|
|
||||||
chargen: utils/chargen.c $(OBJDIR)/$(SONAME)
|
chargen: utils/chargen.c $(OBJDIR)/$(SONAME)
|
||||||
@ -75,7 +78,7 @@ test: $(OBJDIR) $(OBJDIR)/$(SONAME) $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(
|
|||||||
|
|
||||||
run-test: test
|
run-test: test
|
||||||
TEST_DIR=$(TESTDIR) $(TESTDIR)/run_tests.sh $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate
|
TEST_DIR=$(TESTDIR) $(TESTDIR)/run_tests.sh $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate
|
||||||
|
|
||||||
$(OBJDIR)/test_basic: $(TESTDIR)/test_basic.c $(OBJDIR)/$(SONAME)
|
$(OBJDIR)/test_basic: $(TESTDIR)/test_basic.c $(OBJDIR)/$(SONAME)
|
||||||
$(CC) -o $(OBJDIR)/test_basic $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_basic.c $(LD_UCL_FLAGS)
|
$(CC) -o $(OBJDIR)/test_basic $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_basic.c $(LD_UCL_FLAGS)
|
||||||
$(OBJDIR)/test_speed: $(TESTDIR)/test_speed.c $(OBJDIR)/$(SONAME)
|
$(OBJDIR)/test_speed: $(TESTDIR)/test_speed.c $(OBJDIR)/$(SONAME)
|
||||||
|
@ -223,15 +223,57 @@ UCL supports external macros both multiline and single line ones:
|
|||||||
....
|
....
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
There are two internal macros provided by UCL:
|
|
||||||
|
|
||||||
* `include` - read a file `/path/to/file` or an url `http://example.com/file` and include it to the current place of
|
Moreover, each macro can accept an optional list of arguments in braces. These
|
||||||
UCL configuration;
|
arguments themselves are the UCL object that is parsed and passed to a macro as
|
||||||
* `try\_include` - try to read a file or url and include it but do not create a fatal error if a file or url is not accessible;
|
options:
|
||||||
* `includes` - read a file or an url like the previous macro, but fetch and check the signature file (which is obtained
|
|
||||||
by `.sig` suffix appending).
|
|
||||||
|
|
||||||
Public keys which are used for the last command are specified by the concrete UCL user.
|
```nginx
|
||||||
|
.macro(param=value) "something";
|
||||||
|
.macro(param={key=value}) "something";
|
||||||
|
.macro(.include "params.conf") "something";
|
||||||
|
.macro(#this is multiline macro
|
||||||
|
param = [value1, value2]) "something";
|
||||||
|
.macro(key="()") "something";
|
||||||
|
```
|
||||||
|
|
||||||
|
UCL also provide a convenient `include` macro to load content from another files
|
||||||
|
to the current UCL object. This macro accepts either path to file:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
.include "/full/path.conf"
|
||||||
|
.include "./relative/path.conf"
|
||||||
|
.include "${CURDIR}/path.conf"
|
||||||
|
```
|
||||||
|
|
||||||
|
or URL (if ucl is built with url support provided by either `libcurl` or `libfetch`):
|
||||||
|
|
||||||
|
.include "http://example.com/file.conf"
|
||||||
|
|
||||||
|
`.include` macro supports a set of options:
|
||||||
|
|
||||||
|
* `try` (default: **false**) - if this option is `true` than UCL treats errors on loading of
|
||||||
|
this file as non-fatal. For example, such a file can be absent but it won't stop the parsing
|
||||||
|
of the top-level document.
|
||||||
|
* `sign` (default: **false**) - if this option is `true` UCL loads and checks the signature for
|
||||||
|
a file from path named `<FILEPATH>.sig`. Trusted public keys should be provided for UCL API after
|
||||||
|
parser is created but before any configurations are parsed.
|
||||||
|
* `glob` (default: **false**) - if this option is `true` UCL treats the filename as GLOB pattern and load
|
||||||
|
all files that matches the specified pattern (normally the format of patterns is defined in `glob` manual page
|
||||||
|
for your operating system). This option is meaningless for URL includes.
|
||||||
|
* `url` (default: **true**) - allow URL includes.
|
||||||
|
* `priority` (default: 0) - specify priority for the include (see below).
|
||||||
|
|
||||||
|
Priorities are used by UCL parser to manage the policy of objects rewriting during including other files
|
||||||
|
as following:
|
||||||
|
|
||||||
|
* If we have two objects with the same priority then we form an implicit array
|
||||||
|
* If a new object has bigger priority then we overwrite an old one
|
||||||
|
* If a new object has lower priority then we ignore it
|
||||||
|
|
||||||
|
By default, the priority of top-level object is set to zero (lowest priority). Currently,
|
||||||
|
you can define up to 16 priorities (from 0 to 15). Includes with bigger priorities will
|
||||||
|
rewrite keys from the objects with lower priorities as specified by the policy.
|
||||||
|
|
||||||
### Variables support
|
### Variables support
|
||||||
|
|
||||||
@ -317,7 +359,7 @@ ucl: emitted compact json in 0.0991 seconds
|
|||||||
ucl: emitted yaml in 0.1354 seconds
|
ucl: emitted yaml in 0.1354 seconds
|
||||||
```
|
```
|
||||||
|
|
||||||
You can do your own benchmarks by running `make test` in libucl top directory.
|
You can do your own benchmarks by running `make check` in libucl top directory.
|
||||||
|
|
||||||
## Conclusion
|
## Conclusion
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
PROJECT(libucl C)
|
PROJECT(libucl C)
|
||||||
|
|
||||||
SET(LIBUCL_VERSION_MAJOR 0)
|
SET(LIBUCL_VERSION_MAJOR 0)
|
||||||
SET(LIBUCL_VERSION_MINOR 2)
|
SET(LIBUCL_VERSION_MINOR 5)
|
||||||
SET(LIBUCL_VERSION_PATCH 9)
|
SET(LIBUCL_VERSION_PATCH 0)
|
||||||
|
|
||||||
SET(LIBUCL_VERSION "${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}")
|
SET(LIBUCL_VERSION "${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}")
|
||||||
|
|
||||||
@ -86,6 +86,8 @@ INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../uthash")
|
|||||||
SET(UCLSRC ../src/ucl_util.c
|
SET(UCLSRC ../src/ucl_util.c
|
||||||
../src/ucl_parser.c
|
../src/ucl_parser.c
|
||||||
../src/ucl_emitter.c
|
../src/ucl_emitter.c
|
||||||
|
../src/ucl_emitter_streamline.c
|
||||||
|
../src/ucl_emitter_utils.c
|
||||||
../src/ucl_hash.c
|
../src/ucl_hash.c
|
||||||
../src/ucl_schema.c
|
../src/ucl_schema.c
|
||||||
../src/xxhash.c)
|
../src/xxhash.c)
|
||||||
@ -98,6 +100,18 @@ ENDIF (BUILD_SHARED_LIBS)
|
|||||||
ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC})
|
ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC})
|
||||||
SET_TARGET_PROPERTIES(ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
|
SET_TARGET_PROPERTIES(ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
|
||||||
|
|
||||||
|
IF(WITH_LUA)
|
||||||
|
SET(UCL_LUA_SRC ../lua/lua_ucl.c)
|
||||||
|
ADD_LIBRARY(lua-ucl ${LIB_TYPE} ${UCL_LUA_SRC})
|
||||||
|
IF(ENABLE_LUAJIT MATCHES "ON")
|
||||||
|
TARGET_LINK_LIBRARIES(lua-ucl "${LUAJIT_LIBRARY}")
|
||||||
|
ELSE(ENABLE_LUAJIT MATCHES "ON")
|
||||||
|
TARGET_LINK_LIBRARIES(lua-ucl "${LUA_LIBRARY}")
|
||||||
|
ENDIF(ENABLE_LUAJIT MATCHES "ON")
|
||||||
|
TARGET_LINK_LIBRARIES(lua-ucl ucl)
|
||||||
|
SET_TARGET_PROPERTIES(lua-ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
|
||||||
|
ENDIF(WITH_LUA)
|
||||||
|
|
||||||
IF(HAVE_FETCH_H)
|
IF(HAVE_FETCH_H)
|
||||||
TARGET_LINK_LIBRARIES(ucl fetch)
|
TARGET_LINK_LIBRARIES(ucl fetch)
|
||||||
ELSE(HAVE_FETCH_H)
|
ELSE(HAVE_FETCH_H)
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
m4_define([maj_ver], [0])
|
m4_define([maj_ver], [0])
|
||||||
m4_define([med_ver], [5])
|
m4_define([med_ver], [6])
|
||||||
m4_define([min_ver], [0])
|
m4_define([min_ver], [1])
|
||||||
m4_define([so_version], [2:0:0])
|
m4_define([so_version], [3:0:1])
|
||||||
m4_define([ucl_version], [maj_ver.med_ver.min_ver])
|
m4_define([ucl_version], [maj_ver.med_ver.min_ver])
|
||||||
|
|
||||||
AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
|
AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
|
||||||
AC_CONFIG_SRCDIR([configure.ac])
|
AC_CONFIG_SRCDIR([configure.ac])
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign silent-rules -Wall -Wportability no-dist-gzip dist-xz])
|
AM_INIT_AUTOMAKE([1.11 foreign -Wall -Wportability no-dist-gzip dist-xz])
|
||||||
|
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||||
|
|
||||||
UCL_VERSION=ucl_version
|
UCL_VERSION=ucl_version
|
||||||
SO_VERSION=so_version
|
SO_VERSION=so_version
|
||||||
@ -57,6 +58,9 @@ AC_ARG_ENABLE([regex], AS_HELP_STRING([--enable-regex],
|
|||||||
AC_ARG_ENABLE([signatures], AS_HELP_STRING([--enable-signatures],
|
AC_ARG_ENABLE([signatures], AS_HELP_STRING([--enable-signatures],
|
||||||
[Enable signatures check (requires openssl) @<:@default=no@:>@]), [],
|
[Enable signatures check (requires openssl) @<:@default=no@:>@]), [],
|
||||||
[enable_signatures=no])
|
[enable_signatures=no])
|
||||||
|
AC_ARG_ENABLE([lua], AS_HELP_STRING([--enable-lua],
|
||||||
|
[Enable lua API build (requires lua libraries and headers) @<:@default=no@:>@]), [],
|
||||||
|
[enable_lua=no])
|
||||||
AC_ARG_ENABLE([utils],
|
AC_ARG_ENABLE([utils],
|
||||||
AS_HELP_STRING([--enable-utils], [Build and install utils @<:@default=no@:>@]),
|
AS_HELP_STRING([--enable-utils], [Build and install utils @<:@default=no@:>@]),
|
||||||
[case "${enableval}" in
|
[case "${enableval}" in
|
||||||
@ -99,6 +103,21 @@ AS_IF([test "x$enable_regex" = "xyes"], [
|
|||||||
])
|
])
|
||||||
AC_SUBST(LIBREGEX_LIB)
|
AC_SUBST(LIBREGEX_LIB)
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_lua" = "xyes"], [
|
||||||
|
AX_PROG_LUA([5.1], [], [
|
||||||
|
AX_LUA_HEADERS([
|
||||||
|
AX_LUA_LIBS([
|
||||||
|
AC_DEFINE(HAVE_LUA, 1, [Define to 1 for lua support.])
|
||||||
|
with_lua="yes"
|
||||||
|
], [AC_MSG_ERROR([unable to find the lua libraries])
|
||||||
|
])
|
||||||
|
], [AC_MSG_ERROR([unable to find the lua header files])
|
||||||
|
])
|
||||||
|
], [AC_MSG_ERROR([unable to find the lua interpreter])])
|
||||||
|
], [with_lua="no"])
|
||||||
|
|
||||||
|
AM_CONDITIONAL([LUA_SUB], [test "$with_lua" = "yes"])
|
||||||
|
|
||||||
AS_IF([test "x$enable_urls" = "xyes"], [
|
AS_IF([test "x$enable_urls" = "xyes"], [
|
||||||
AC_CHECK_HEADER([fetch.h], [
|
AC_CHECK_HEADER([fetch.h], [
|
||||||
AC_DEFINE(HAVE_FETCH_H, 1, [Define to 1 if you have the <fetch.h> header file.])
|
AC_DEFINE(HAVE_FETCH_H, 1, [Define to 1 if you have the <fetch.h> header file.])
|
||||||
@ -155,9 +174,11 @@ AC_LINK_IFELSE([
|
|||||||
|
|
||||||
AC_CONFIG_FILES(Makefile \
|
AC_CONFIG_FILES(Makefile \
|
||||||
src/Makefile \
|
src/Makefile \
|
||||||
|
lua/Makefile
|
||||||
tests/Makefile \
|
tests/Makefile \
|
||||||
utils/Makefile \
|
utils/Makefile \
|
||||||
doc/Makefile \
|
doc/Makefile \
|
||||||
|
lua/libucl.rockspec \
|
||||||
libucl.pc)
|
libucl.pc)
|
||||||
AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h])
|
AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
194
contrib/libucl/doc/lua_api.md
Normal file
194
contrib/libucl/doc/lua_api.md
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
## Module `ucl`
|
||||||
|
|
||||||
|
This lua module allows to parse objects from strings and to store data into
|
||||||
|
ucl objects. It uses `libucl` C library to parse and manipulate with ucl objects.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
~~~lua
|
||||||
|
local ucl = require("ucl")
|
||||||
|
|
||||||
|
local parser = ucl.parser()
|
||||||
|
local res,err = parser:parse_string('{key=value}')
|
||||||
|
|
||||||
|
if not res then
|
||||||
|
print('parser error: ' .. err)
|
||||||
|
else
|
||||||
|
local obj = parser:get_object()
|
||||||
|
local got = ucl.to_format(obj, 'json')
|
||||||
|
endif
|
||||||
|
|
||||||
|
local table = {
|
||||||
|
str = 'value',
|
||||||
|
num = 100500,
|
||||||
|
null = ucl.null,
|
||||||
|
func = function ()
|
||||||
|
return 'huh'
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
print(ucl.to_format(table, 'ucl'))
|
||||||
|
-- Output:
|
||||||
|
--[[
|
||||||
|
num = 100500;
|
||||||
|
str = "value";
|
||||||
|
null = null;
|
||||||
|
func = "huh";
|
||||||
|
--]]
|
||||||
|
~~~
|
||||||
|
|
||||||
|
###Brief content:
|
||||||
|
|
||||||
|
**Functions**:
|
||||||
|
|
||||||
|
> [`ucl_object_push_lua(L, obj, allow_array)`](#function-ucl_object_push_lual-obj-allow_array)
|
||||||
|
|
||||||
|
> [`ucl.to_format(var, format)`](#function-uclto_formatvar-format)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Methods**:
|
||||||
|
|
||||||
|
> [`parser:parse_file(name)`](#method-parserparse_filename)
|
||||||
|
|
||||||
|
> [`parser:parse_string(input)`](#method-parserparse_stringinput)
|
||||||
|
|
||||||
|
> [`parser:get_object()`](#method-parserget_object)
|
||||||
|
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
The module `ucl` defines the following functions.
|
||||||
|
|
||||||
|
### Function `ucl_object_push_lua(L, obj, allow_array)`
|
||||||
|
|
||||||
|
This is a `C` function to push `UCL` object as lua variable. This function
|
||||||
|
converts `obj` to lua representation using the following conversions:
|
||||||
|
|
||||||
|
- *scalar* values are directly presented by lua objects
|
||||||
|
- *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`,
|
||||||
|
this can be used to pass functions from lua to c and vice-versa
|
||||||
|
- *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations
|
||||||
|
- *objects* are converted to lua tables with string indicies
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
- `L {lua_State}`: lua state pointer
|
||||||
|
- `obj {ucl_object_t}`: object to push
|
||||||
|
- `allow_array {bool}`: expand implicit arrays (should be true for all but partial arrays)
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
|
||||||
|
- `{int}`: `1` if an object is pushed to lua
|
||||||
|
|
||||||
|
Back to [module description](#module-ucl).
|
||||||
|
|
||||||
|
### Function `ucl.to_format(var, format)`
|
||||||
|
|
||||||
|
Converts lua variable `var` to the specified `format`. Formats supported are:
|
||||||
|
|
||||||
|
- `json` - fine printed json
|
||||||
|
- `json-compact` - compacted json
|
||||||
|
- `config` - fine printed configuration
|
||||||
|
- `ucl` - same as `config`
|
||||||
|
- `yaml` - embedded yaml
|
||||||
|
|
||||||
|
If `var` contains function, they are called during output formatting and if
|
||||||
|
they return string value, then this value is used for ouptut.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
- `var {variant}`: any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
|
||||||
|
- `format {string}`: any available format
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
|
||||||
|
- `{string}`: string representation of `var` in the specific `format`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
~~~lua
|
||||||
|
local table = {
|
||||||
|
str = 'value',
|
||||||
|
num = 100500,
|
||||||
|
null = ucl.null,
|
||||||
|
func = function ()
|
||||||
|
return 'huh'
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
print(ucl.to_format(table, 'ucl'))
|
||||||
|
-- Output:
|
||||||
|
--[[
|
||||||
|
num = 100500;
|
||||||
|
str = "value";
|
||||||
|
null = null;
|
||||||
|
func = "huh";
|
||||||
|
--]]
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Back to [module description](#module-ucl).
|
||||||
|
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
The module `ucl` defines the following methods.
|
||||||
|
|
||||||
|
### Method `parser:parse_file(name)`
|
||||||
|
|
||||||
|
Parse UCL object from file.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
- `name {string}`: filename to parse
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
|
||||||
|
- `{bool[, string]}`: if res is `true` then file has been parsed successfully, otherwise an error string is also returned
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
~~~lua
|
||||||
|
local parser = ucl.parser()
|
||||||
|
local res,err = parser:parse_file('/some/file.conf')
|
||||||
|
|
||||||
|
if not res then
|
||||||
|
print('parser error: ' .. err)
|
||||||
|
else
|
||||||
|
-- Do something with object
|
||||||
|
end
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Back to [module description](#module-ucl).
|
||||||
|
|
||||||
|
### Method `parser:parse_string(input)`
|
||||||
|
|
||||||
|
Parse UCL object from file.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
- `input {string}`: string to parse
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
|
||||||
|
- `{bool[, string]}`: if res is `true` then file has been parsed successfully, otherwise an error string is also returned
|
||||||
|
|
||||||
|
Back to [module description](#module-ucl).
|
||||||
|
|
||||||
|
### Method `parser:get_object()`
|
||||||
|
|
||||||
|
Get top object from parser and export it to lua representation.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
|
||||||
|
nothing
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
|
||||||
|
- `{variant or nil}`: ucl object as lua native variable
|
||||||
|
|
||||||
|
Back to [module description](#module-ucl).
|
||||||
|
|
||||||
|
|
||||||
|
Back to [top](#).
|
||||||
|
|
69
contrib/libucl/include/lua_ucl.h
Normal file
69
contrib/libucl/include/lua_ucl.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/* Copyright (c) 2014, Vsevolod Stakhov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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 ''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 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.
|
||||||
|
*/
|
||||||
|
#ifndef LUA_UCL_H_
|
||||||
|
#define LUA_UCL_H_
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include "ucl.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closure structure for lua function storing inside UCL
|
||||||
|
*/
|
||||||
|
struct ucl_lua_funcdata {
|
||||||
|
lua_State *L;
|
||||||
|
int idx;
|
||||||
|
char *ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize lua UCL API
|
||||||
|
*/
|
||||||
|
UCL_EXTERN int luaopen_ucl (lua_State *L);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import UCL object from lua state
|
||||||
|
* @param L lua state
|
||||||
|
* @param idx index of object at the lua stack to convert to UCL
|
||||||
|
* @return new UCL object or NULL, the caller should unref object after using
|
||||||
|
*/
|
||||||
|
UCL_EXTERN ucl_object_t* ucl_object_lua_import (lua_State *L, int idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push an object to lua
|
||||||
|
* @param L lua state
|
||||||
|
* @param obj object to push
|
||||||
|
* @param allow_array traverse over implicit arrays
|
||||||
|
*/
|
||||||
|
UCL_EXTERN int ucl_object_push_lua (lua_State *L,
|
||||||
|
const ucl_object_t *obj, bool allow_array);
|
||||||
|
|
||||||
|
UCL_EXTERN struct ucl_lua_funcdata* ucl_object_toclosure (
|
||||||
|
const ucl_object_t *obj);
|
||||||
|
|
||||||
|
#endif /* LUA_UCL_H_ */
|
@ -147,7 +147,8 @@ typedef enum ucl_emitter {
|
|||||||
typedef enum ucl_parser_flags {
|
typedef enum ucl_parser_flags {
|
||||||
UCL_PARSER_KEY_LOWERCASE = 0x1, /**< Convert all keys to lower case */
|
UCL_PARSER_KEY_LOWERCASE = 0x1, /**< Convert all keys to lower case */
|
||||||
UCL_PARSER_ZEROCOPY = 0x2, /**< Parse input in zero-copy mode if possible */
|
UCL_PARSER_ZEROCOPY = 0x2, /**< Parse input in zero-copy mode if possible */
|
||||||
UCL_PARSER_NO_TIME = 0x4 /**< Do not parse time and treat time values as strings */
|
UCL_PARSER_NO_TIME = 0x4, /**< Do not parse time and treat time values as strings */
|
||||||
|
UCL_PARSER_NO_IMPLICIT_ARRAYS = 0x8 /** Create explicit arrays instead of implicit ones */
|
||||||
} ucl_parser_flags_t;
|
} ucl_parser_flags_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,9 +172,12 @@ typedef enum ucl_string_flags {
|
|||||||
* Basic flags for an object
|
* Basic flags for an object
|
||||||
*/
|
*/
|
||||||
typedef enum ucl_object_flags {
|
typedef enum ucl_object_flags {
|
||||||
UCL_OBJECT_ALLOCATED_KEY = 1, /**< An object has key allocated internally */
|
UCL_OBJECT_ALLOCATED_KEY = 0x1, /**< An object has key allocated internally */
|
||||||
UCL_OBJECT_ALLOCATED_VALUE = 2, /**< An object has a string value allocated internally */
|
UCL_OBJECT_ALLOCATED_VALUE = 0x2, /**< An object has a string value allocated internally */
|
||||||
UCL_OBJECT_NEED_KEY_ESCAPE = 4 /**< The key of an object need to be escaped on output */
|
UCL_OBJECT_NEED_KEY_ESCAPE = 0x4, /**< The key of an object need to be escaped on output */
|
||||||
|
UCL_OBJECT_EPHEMERAL = 0x8, /**< Temporary object that does not need to be freed really */
|
||||||
|
UCL_OBJECT_MULTILINE = 0x10, /**< String should be displayed as multiline string */
|
||||||
|
UCL_OBJECT_MULTIVALUE = 0x20 /**< Object is a key with multiple values */
|
||||||
} ucl_object_flags_t;
|
} ucl_object_flags_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -195,14 +199,21 @@ typedef struct ucl_object_s {
|
|||||||
const char *key; /**< Key of an object */
|
const char *key; /**< Key of an object */
|
||||||
struct ucl_object_s *next; /**< Array handle */
|
struct ucl_object_s *next; /**< Array handle */
|
||||||
struct ucl_object_s *prev; /**< Array handle */
|
struct ucl_object_s *prev; /**< Array handle */
|
||||||
unsigned char* trash_stack[2]; /**< Pointer to allocated chunks */
|
uint32_t keylen; /**< Lenght of a key */
|
||||||
unsigned keylen; /**< Lenght of a key */
|
uint32_t len; /**< Size of an object */
|
||||||
unsigned len; /**< Size of an object */
|
uint32_t ref; /**< Reference count */
|
||||||
enum ucl_type type; /**< Real type */
|
|
||||||
uint16_t ref; /**< Reference count */
|
|
||||||
uint16_t flags; /**< Object flags */
|
uint16_t flags; /**< Object flags */
|
||||||
|
uint16_t type; /**< Real type */
|
||||||
|
unsigned char* trash_stack[2]; /**< Pointer to allocated chunks */
|
||||||
} ucl_object_t;
|
} ucl_object_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor type for userdata objects
|
||||||
|
* @param ud user specified data pointer
|
||||||
|
*/
|
||||||
|
typedef void (*ucl_userdata_dtor)(void *ud);
|
||||||
|
typedef const char* (*ucl_userdata_emitter)(void *ud);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -238,6 +249,31 @@ UCL_EXTERN ucl_object_t* ucl_object_new (void) UCL_WARN_UNUSED_RESULT;
|
|||||||
*/
|
*/
|
||||||
UCL_EXTERN ucl_object_t* ucl_object_typed_new (ucl_type_t type) UCL_WARN_UNUSED_RESULT;
|
UCL_EXTERN ucl_object_t* ucl_object_typed_new (ucl_type_t type) UCL_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new object with type and priority specified
|
||||||
|
* @param type type of a new object
|
||||||
|
* @param priority priority of an object
|
||||||
|
* @return new object
|
||||||
|
*/
|
||||||
|
UCL_EXTERN ucl_object_t* ucl_object_new_full (ucl_type_t type, unsigned priority)
|
||||||
|
UCL_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new object with userdata dtor
|
||||||
|
* @param dtor destructor function
|
||||||
|
* @return new object
|
||||||
|
*/
|
||||||
|
UCL_EXTERN ucl_object_t* ucl_object_new_userdata (ucl_userdata_dtor dtor,
|
||||||
|
ucl_userdata_emitter emitter) UCL_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform deep copy of an object copying everything
|
||||||
|
* @param other object to copy
|
||||||
|
* @return new object with refcount equal to 1
|
||||||
|
*/
|
||||||
|
UCL_EXTERN ucl_object_t * ucl_object_copy (const ucl_object_t *other)
|
||||||
|
UCL_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the type of an object
|
* Return the type of an object
|
||||||
* @return the object type
|
* @return the object type
|
||||||
@ -293,7 +329,7 @@ UCL_EXTERN ucl_object_t* ucl_object_frombool (bool bv) UCL_WARN_UNUSED_RESULT;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a object 'elt' to the hash 'top' and associate it with key 'key'
|
* Insert a object 'elt' to the hash 'top' and associate it with key 'key'
|
||||||
* @param top destination object (will be created automatically if top is NULL)
|
* @param top destination object (must be of type UCL_OBJECT)
|
||||||
* @param elt element to insert (must NOT be NULL)
|
* @param elt element to insert (must NOT be NULL)
|
||||||
* @param key key to associate with this object (either const or preallocated)
|
* @param key key to associate with this object (either const or preallocated)
|
||||||
* @param keylen length of the key (or 0 for NULL terminated keys)
|
* @param keylen length of the key (or 0 for NULL terminated keys)
|
||||||
@ -306,7 +342,7 @@ UCL_EXTERN bool ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
|
|||||||
/**
|
/**
|
||||||
* Replace a object 'elt' to the hash 'top' and associate it with key 'key', old object will be unrefed,
|
* Replace a object 'elt' to the hash 'top' and associate it with key 'key', old object will be unrefed,
|
||||||
* if no object has been found this function works like ucl_object_insert_key()
|
* if no object has been found this function works like ucl_object_insert_key()
|
||||||
* @param top destination object (will be created automatically if top is NULL)
|
* @param top destination object (must be of type UCL_OBJECT)
|
||||||
* @param elt element to insert (must NOT be NULL)
|
* @param elt element to insert (must NOT be NULL)
|
||||||
* @param key key to associate with this object (either const or preallocated)
|
* @param key key to associate with this object (either const or preallocated)
|
||||||
* @param keylen length of the key (or 0 for NULL terminated keys)
|
* @param keylen length of the key (or 0 for NULL terminated keys)
|
||||||
@ -316,6 +352,15 @@ UCL_EXTERN bool ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
|
|||||||
UCL_EXTERN bool ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
|
UCL_EXTERN bool ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
|
||||||
const char *key, size_t keylen, bool copy_key);
|
const char *key, size_t keylen, bool copy_key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge the keys from one object to another object. Overwrite on conflict
|
||||||
|
* @param top destination object (must be of type UCL_OBJECT)
|
||||||
|
* @param elt element to insert (must be of type UCL_OBJECT)
|
||||||
|
* @param copy copy rather than reference the elements
|
||||||
|
* @return true if all keys have been merged
|
||||||
|
*/
|
||||||
|
UCL_EXTERN bool ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a object associated with key 'key', old object will be unrefered,
|
* Delete a object associated with key 'key', old object will be unrefered,
|
||||||
* @param top object
|
* @param top object
|
||||||
@ -335,8 +380,9 @@ UCL_EXTERN bool ucl_object_delete_key (ucl_object_t *top,
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete key from `top` object returning the object deleted. This object is not
|
* Removes `key` from `top` object, returning the object that was removed. This
|
||||||
* released
|
* object is not released, caller must unref the returned object when it is no
|
||||||
|
* longer needed.
|
||||||
* @param top object
|
* @param top object
|
||||||
* @param key key to remove
|
* @param key key to remove
|
||||||
* @param keylen length of the key (or 0 for NULL terminated keys)
|
* @param keylen length of the key (or 0 for NULL terminated keys)
|
||||||
@ -346,8 +392,9 @@ UCL_EXTERN ucl_object_t* ucl_object_pop_keyl (ucl_object_t *top, const char *key
|
|||||||
size_t keylen) UCL_WARN_UNUSED_RESULT;
|
size_t keylen) UCL_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete key from `top` object returning the object deleted. This object is not
|
* Removes `key` from `top` object returning the object that was removed. This
|
||||||
* released
|
* object is not released, caller must unref the returned object when it is no
|
||||||
|
* longer needed.
|
||||||
* @param top object
|
* @param top object
|
||||||
* @param key key to remove
|
* @param key key to remove
|
||||||
* @return removed object or NULL if object has not been found
|
* @return removed object or NULL if object has not been found
|
||||||
@ -356,9 +403,9 @@ UCL_EXTERN ucl_object_t* ucl_object_pop_key (ucl_object_t *top, const char *key)
|
|||||||
UCL_WARN_UNUSED_RESULT;
|
UCL_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a object 'elt' to the hash 'top' and associate it with key 'key', if the specified key exist,
|
* Insert a object 'elt' to the hash 'top' and associate it with key 'key', if
|
||||||
* try to merge its content
|
* the specified key exist, try to merge its content
|
||||||
* @param top destination object (will be created automatically if top is NULL)
|
* @param top destination object (must be of type UCL_OBJECT)
|
||||||
* @param elt element to insert (must NOT be NULL)
|
* @param elt element to insert (must NOT be NULL)
|
||||||
* @param key key to associate with this object (either const or preallocated)
|
* @param key key to associate with this object (either const or preallocated)
|
||||||
* @param keylen length of the key (or 0 for NULL terminated keys)
|
* @param keylen length of the key (or 0 for NULL terminated keys)
|
||||||
@ -369,8 +416,8 @@ UCL_EXTERN bool ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *e
|
|||||||
const char *key, size_t keylen, bool copy_key);
|
const char *key, size_t keylen, bool copy_key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append an element to the front of array object
|
* Append an element to the end of array object
|
||||||
* @param top destination object (will be created automatically if top is NULL)
|
* @param top destination object (must NOT be NULL)
|
||||||
* @param elt element to append (must NOT be NULL)
|
* @param elt element to append (must NOT be NULL)
|
||||||
* @return true if value has been inserted
|
* @return true if value has been inserted
|
||||||
*/
|
*/
|
||||||
@ -379,7 +426,7 @@ UCL_EXTERN bool ucl_array_append (ucl_object_t *top,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Append an element to the start of array object
|
* Append an element to the start of array object
|
||||||
* @param top destination object (will be created automatically if top is NULL)
|
* @param top destination object (must NOT be NULL)
|
||||||
* @param elt element to append (must NOT be NULL)
|
* @param elt element to append (must NOT be NULL)
|
||||||
* @return true if value has been inserted
|
* @return true if value has been inserted
|
||||||
*/
|
*/
|
||||||
@ -387,8 +434,19 @@ UCL_EXTERN bool ucl_array_prepend (ucl_object_t *top,
|
|||||||
ucl_object_t *elt);
|
ucl_object_t *elt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes an element `elt` from the array `top`. Caller must unref the returned object when it is not
|
* Merge all elements of second array into the first array
|
||||||
* needed.
|
* @param top destination array (must be of type UCL_ARRAY)
|
||||||
|
* @param elt array to copy elements from (must be of type UCL_ARRAY)
|
||||||
|
* @param copy copy elements instead of referencing them
|
||||||
|
* @return true if arrays were merged
|
||||||
|
*/
|
||||||
|
UCL_EXTERN bool ucl_array_merge (ucl_object_t *top, ucl_object_t *elt,
|
||||||
|
bool copy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an element `elt` from the array `top`, returning the object that was
|
||||||
|
* removed. This object is not released, caller must unref the returned object
|
||||||
|
* when it is no longer needed.
|
||||||
* @param top array ucl object
|
* @param top array ucl object
|
||||||
* @param elt element to remove
|
* @param elt element to remove
|
||||||
* @return removed element or NULL if `top` is NULL or not an array
|
* @return removed element or NULL if `top` is NULL or not an array
|
||||||
@ -411,35 +469,50 @@ UCL_EXTERN const ucl_object_t* ucl_array_head (const ucl_object_t *top);
|
|||||||
UCL_EXTERN const ucl_object_t* ucl_array_tail (const ucl_object_t *top);
|
UCL_EXTERN const ucl_object_t* ucl_array_tail (const ucl_object_t *top);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the last element from the array `top`. Caller must unref the returned object when it is not
|
* Removes the last element from the array `top`, returning the object that was
|
||||||
* needed.
|
* removed. This object is not released, caller must unref the returned object
|
||||||
|
* when it is no longer needed.
|
||||||
* @param top array ucl object
|
* @param top array ucl object
|
||||||
* @return removed element or NULL if `top` is NULL or not an array
|
* @return removed element or NULL if `top` is NULL or not an array
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN ucl_object_t* ucl_array_pop_last (ucl_object_t *top);
|
UCL_EXTERN ucl_object_t* ucl_array_pop_last (ucl_object_t *top);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return object identified by an index of the array `top`
|
* Removes the first element from the array `top`, returning the object that was
|
||||||
* @param obj object to get a key from (must be of type UCL_ARRAY)
|
* removed. This object is not released, caller must unref the returned object
|
||||||
* @param index index to return
|
* when it is no longer needed.
|
||||||
* @return object at the specified index or NULL if index is not found
|
|
||||||
*/
|
|
||||||
UCL_EXTERN const ucl_object_t* ucl_array_find_index (const ucl_object_t *top,
|
|
||||||
unsigned int index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the first element from the array `top`. Caller must unref the returned object when it is not
|
|
||||||
* needed.
|
|
||||||
* @param top array ucl object
|
* @param top array ucl object
|
||||||
* @return removed element or NULL if `top` is NULL or not an array
|
* @return removed element or NULL if `top` is NULL or not an array
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN ucl_object_t* ucl_array_pop_first (ucl_object_t *top);
|
UCL_EXTERN ucl_object_t* ucl_array_pop_first (ucl_object_t *top);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return object identified by index of the array `top`
|
||||||
|
* @param top object to get a key from (must be of type UCL_ARRAY)
|
||||||
|
* @param index array index to return
|
||||||
|
* @return object at the specified index or NULL if index is not found
|
||||||
|
*/
|
||||||
|
UCL_EXTERN const ucl_object_t* ucl_array_find_index (const ucl_object_t *top,
|
||||||
|
unsigned int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace an element in an array with a different element, returning the object
|
||||||
|
* that was replaced. This object is not released, caller must unref the
|
||||||
|
* returned object when it is no longer needed.
|
||||||
|
* @param top destination object (must be of type UCL_ARRAY)
|
||||||
|
* @param elt element to append (must NOT be NULL)
|
||||||
|
* @param index array index in destination to overwrite with elt
|
||||||
|
* @return object that was replaced or NULL if index is not found
|
||||||
|
*/
|
||||||
|
ucl_object_t *
|
||||||
|
ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
|
||||||
|
unsigned int index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append a element to another element forming an implicit array
|
* Append a element to another element forming an implicit array
|
||||||
* @param head head to append (may be NULL)
|
* @param head head to append (may be NULL)
|
||||||
* @param elt new element
|
* @param elt new element
|
||||||
* @return true if element has been inserted
|
* @return the new implicit array
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN ucl_object_t * ucl_elt_append (ucl_object_t *head,
|
UCL_EXTERN ucl_object_t * ucl_elt_append (ucl_object_t *head,
|
||||||
ucl_object_t *elt);
|
ucl_object_t *elt);
|
||||||
@ -533,7 +606,7 @@ UCL_EXTERN const char* ucl_object_tolstring (const ucl_object_t *obj, size_t *tl
|
|||||||
* Return object identified by a key in the specified object
|
* Return object identified by a key in the specified object
|
||||||
* @param obj object to get a key from (must be of type UCL_OBJECT)
|
* @param obj object to get a key from (must be of type UCL_OBJECT)
|
||||||
* @param key key to search
|
* @param key key to search
|
||||||
* @return object matched the specified key or NULL if key is not found
|
* @return object matching the specified key or NULL if key was not found
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN const ucl_object_t* ucl_object_find_key (const ucl_object_t *obj,
|
UCL_EXTERN const ucl_object_t* ucl_object_find_key (const ucl_object_t *obj,
|
||||||
const char *key);
|
const char *key);
|
||||||
@ -543,7 +616,7 @@ UCL_EXTERN const ucl_object_t* ucl_object_find_key (const ucl_object_t *obj,
|
|||||||
* @param obj object to get a key from (must be of type UCL_OBJECT)
|
* @param obj object to get a key from (must be of type UCL_OBJECT)
|
||||||
* @param key key to search
|
* @param key key to search
|
||||||
* @param klen length of a key
|
* @param klen length of a key
|
||||||
* @return object matched the specified key or NULL if key is not found
|
* @return object matching the specified key or NULL if key was not found
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN const ucl_object_t* ucl_object_find_keyl (const ucl_object_t *obj,
|
UCL_EXTERN const ucl_object_t* ucl_object_find_keyl (const ucl_object_t *obj,
|
||||||
const char *key, size_t klen);
|
const char *key, size_t klen);
|
||||||
@ -575,6 +648,7 @@ UCL_EXTERN const char* ucl_object_keyl (const ucl_object_t *obj, size_t *len);
|
|||||||
/**
|
/**
|
||||||
* Increase reference count for an object
|
* Increase reference count for an object
|
||||||
* @param obj object to ref
|
* @param obj object to ref
|
||||||
|
* @return the referenced object
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN ucl_object_t* ucl_object_ref (const ucl_object_t *obj);
|
UCL_EXTERN ucl_object_t* ucl_object_ref (const ucl_object_t *obj);
|
||||||
|
|
||||||
@ -611,6 +685,21 @@ UCL_EXTERN int ucl_object_compare (const ucl_object_t *o1,
|
|||||||
UCL_EXTERN void ucl_object_array_sort (ucl_object_t *ar,
|
UCL_EXTERN void ucl_object_array_sort (ucl_object_t *ar,
|
||||||
int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2));
|
int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the priority for specific UCL object
|
||||||
|
* @param obj any ucl object
|
||||||
|
* @return priority of an object
|
||||||
|
*/
|
||||||
|
UCL_EXTERN unsigned int ucl_object_get_priority (const ucl_object_t *obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set explicit priority of an object.
|
||||||
|
* @param obj any ucl object
|
||||||
|
* @param priority new priroity value (only 4 least significant bits are considred)
|
||||||
|
*/
|
||||||
|
UCL_EXTERN void ucl_object_set_priority (ucl_object_t *obj,
|
||||||
|
unsigned int priority);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opaque iterator object
|
* Opaque iterator object
|
||||||
*/
|
*/
|
||||||
@ -640,11 +729,14 @@ UCL_EXTERN const ucl_object_t* ucl_iterate_object (const ucl_object_t *obj,
|
|||||||
* Macro handler for a parser
|
* Macro handler for a parser
|
||||||
* @param data the content of macro
|
* @param data the content of macro
|
||||||
* @param len the length of content
|
* @param len the length of content
|
||||||
|
* @param arguments arguments object
|
||||||
* @param ud opaque user data
|
* @param ud opaque user data
|
||||||
* @param err error pointer
|
* @param err error pointer
|
||||||
* @return true if macro has been parsed
|
* @return true if macro has been parsed
|
||||||
*/
|
*/
|
||||||
typedef bool (*ucl_macro_handler) (const unsigned char *data, size_t len, void* ud);
|
typedef bool (*ucl_macro_handler) (const unsigned char *data, size_t len,
|
||||||
|
const ucl_object_t *arguments,
|
||||||
|
void* ud);
|
||||||
|
|
||||||
/* Opaque parser */
|
/* Opaque parser */
|
||||||
struct ucl_parser;
|
struct ucl_parser;
|
||||||
@ -702,12 +794,23 @@ UCL_EXTERN void ucl_parser_set_variables_handler (struct ucl_parser *parser,
|
|||||||
* @param parser parser structure
|
* @param parser parser structure
|
||||||
* @param data the pointer to the beginning of a chunk
|
* @param data the pointer to the beginning of a chunk
|
||||||
* @param len the length of a chunk
|
* @param len the length of a chunk
|
||||||
* @param err if *err is NULL it is set to parser error
|
|
||||||
* @return true if chunk has been added and false in case of error
|
* @return true if chunk has been added and false in case of error
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN bool ucl_parser_add_chunk (struct ucl_parser *parser,
|
UCL_EXTERN bool ucl_parser_add_chunk (struct ucl_parser *parser,
|
||||||
const unsigned char *data, size_t len);
|
const unsigned char *data, size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load new chunk to a parser with the specified priority
|
||||||
|
* @param parser parser structure
|
||||||
|
* @param data the pointer to the beginning of a chunk
|
||||||
|
* @param len the length of a chunk
|
||||||
|
* @param priority the desired priority of a chunk (only 4 least significant bits
|
||||||
|
* are considered for this parameter)
|
||||||
|
* @return true if chunk has been added and false in case of error
|
||||||
|
*/
|
||||||
|
UCL_EXTERN bool ucl_parser_add_chunk_priority (struct ucl_parser *parser,
|
||||||
|
const unsigned char *data, size_t len, unsigned priority);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load ucl object from a string
|
* Load ucl object from a string
|
||||||
* @param parser parser structure
|
* @param parser parser structure
|
||||||
@ -835,7 +938,7 @@ struct ucl_emitter_context {
|
|||||||
/** A set of output operations */
|
/** A set of output operations */
|
||||||
const struct ucl_emitter_operations *ops;
|
const struct ucl_emitter_operations *ops;
|
||||||
/** Current amount of indent tabs */
|
/** Current amount of indent tabs */
|
||||||
unsigned int ident;
|
unsigned int indent;
|
||||||
/** Top level object */
|
/** Top level object */
|
||||||
const ucl_object_t *top;
|
const ucl_object_t *top;
|
||||||
/** The rest of context */
|
/** The rest of context */
|
||||||
|
@ -7,5 +7,5 @@ Name: LibUCL
|
|||||||
Description: Universal configuration library
|
Description: Universal configuration library
|
||||||
Version: @UCL_VERSION@
|
Version: @UCL_VERSION@
|
||||||
Libs: -L${libdir} -lucl
|
Libs: -L${libdir} -lucl
|
||||||
Libs.private: @LIBS_EXTRA@
|
Libs.private: @LIBS_EXTRA@ @LUA_LIB@
|
||||||
Cflags: -I${includedir}/
|
Cflags: -I${includedir}/
|
||||||
|
26
contrib/libucl/lua/Makefile.am
Normal file
26
contrib/libucl/lua/Makefile.am
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
ucl_common_cflags= -I$(top_srcdir)/src \
|
||||||
|
-I$(top_srcdir)/include \
|
||||||
|
-I$(top_srcdir)/uthash \
|
||||||
|
-Wall -W -Wno-unused-parameter -Wno-pointer-sign
|
||||||
|
luaexec_LTLIBRARIES= ucl.la
|
||||||
|
ucl_la_SOURCES= lua_ucl.c
|
||||||
|
ucl_la_CFLAGS= $(ucl_common_cflags) \
|
||||||
|
@LUA_INCLUDE@
|
||||||
|
ucl_la_LDFLAGS = -module -export-dynamic -avoid-version
|
||||||
|
ucl_la_LIBADD= $(top_srcdir)/src/libucl.la \
|
||||||
|
@LIBFETCH_LIBS@ \
|
||||||
|
@LIBCRYPTO_LIB@ \
|
||||||
|
@LIBREGEX_LIB@ \
|
||||||
|
@CURL_LIBS@ \
|
||||||
|
@LUA_LIB@
|
||||||
|
|
||||||
|
include_HEADERS= $(top_srcdir)/include/lua_ucl.h
|
||||||
|
|
||||||
|
ROCKSPEC = $(PACKAGE)-$(VERSION)-1.rockspec
|
||||||
|
EXTRA_DIST = $(PACKAGE).rockspec.in \
|
||||||
|
test.lua
|
||||||
|
DISTCLEANFILES = $(PACKAGE).rockspec
|
||||||
|
|
||||||
|
$(ROCKSPEC): $(PACKAGE).rockspec dist
|
||||||
|
sed -e 's/@MD5@/'`$(MD5SUM) $(distdir).tar.gz | \
|
||||||
|
cut -d " " -f 1`'/g' < $(PACKAGE).rockspec > $@
|
26
contrib/libucl/lua/libucl.rockspec.in
Normal file
26
contrib/libucl/lua/libucl.rockspec.in
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package="@PACKAGE@"
|
||||||
|
version="@VERSION@-1"
|
||||||
|
source = {
|
||||||
|
url = "https://github.com/downloads/vstakhov/@PACKAGE@/@PACKAGE@-@VERSION@.tar.gz",
|
||||||
|
md5 = "@MD5@",
|
||||||
|
dir = "@PACKAGE@-@VERSION@"
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "UCL - json like configuration language",
|
||||||
|
detailed = [[
|
||||||
|
UCL is heavily infused by nginx configuration as the example
|
||||||
|
of a convenient configuration system.
|
||||||
|
However, UCL is fully compatible with JSON format and is able
|
||||||
|
to parse json files.
|
||||||
|
]],
|
||||||
|
homepage = "http://github.com/vstakhov/@PACKAGE@/",
|
||||||
|
license = ""
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1"
|
||||||
|
}
|
||||||
|
build = {
|
||||||
|
type = "command",
|
||||||
|
build_command = "LUA=$(LUA) CPPFLAGS=-I$(LUA_INCDIR) ./configure --prefix=$(PREFIX) --libdir=$(LIBDIR) --datadir=$(LUADIR) && make clean && make",
|
||||||
|
install_command = "make install"
|
||||||
|
}
|
820
contrib/libucl/lua/lua_ucl.c
Normal file
820
contrib/libucl/lua/lua_ucl.c
Normal file
@ -0,0 +1,820 @@
|
|||||||
|
/* Copyright (c) 2014, Vsevolod Stakhov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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 ''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 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file lua ucl bindings
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ucl.h"
|
||||||
|
#include "ucl_internal.h"
|
||||||
|
#include "lua_ucl.h"
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @module ucl
|
||||||
|
* This lua module allows to parse objects from strings and to store data into
|
||||||
|
* ucl objects. It uses `libucl` C library to parse and manipulate with ucl objects.
|
||||||
|
* @example
|
||||||
|
local ucl = require("ucl")
|
||||||
|
|
||||||
|
local parser = ucl.parser()
|
||||||
|
local res,err = parser:parse_string('{key=value}')
|
||||||
|
|
||||||
|
if not res then
|
||||||
|
print('parser error: ' .. err)
|
||||||
|
else
|
||||||
|
local obj = parser:get_object()
|
||||||
|
local got = ucl.to_format(obj, 'json')
|
||||||
|
endif
|
||||||
|
|
||||||
|
local table = {
|
||||||
|
str = 'value',
|
||||||
|
num = 100500,
|
||||||
|
null = ucl.null,
|
||||||
|
func = function ()
|
||||||
|
return 'huh'
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
print(ucl.to_format(table, 'ucl'))
|
||||||
|
-- Output:
|
||||||
|
--[[
|
||||||
|
num = 100500;
|
||||||
|
str = "value";
|
||||||
|
null = null;
|
||||||
|
func = "huh";
|
||||||
|
--]]
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PARSER_META "ucl.parser.meta"
|
||||||
|
#define EMITTER_META "ucl.emitter.meta"
|
||||||
|
#define NULL_META "null.emitter.meta"
|
||||||
|
|
||||||
|
static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj);
|
||||||
|
static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, bool allow_array);
|
||||||
|
static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx);
|
||||||
|
static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx);
|
||||||
|
|
||||||
|
static void *ucl_null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push a single element of an object to lua
|
||||||
|
* @param L
|
||||||
|
* @param key
|
||||||
|
* @param obj
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ucl_object_lua_push_element (lua_State *L, const char *key,
|
||||||
|
const ucl_object_t *obj)
|
||||||
|
{
|
||||||
|
lua_pushstring (L, key);
|
||||||
|
ucl_object_push_lua (L, obj, true);
|
||||||
|
lua_settable (L, -3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lua_ucl_userdata_dtor (void *ud)
|
||||||
|
{
|
||||||
|
struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
|
||||||
|
|
||||||
|
luaL_unref (fd->L, LUA_REGISTRYINDEX, fd->idx);
|
||||||
|
if (fd->ret != NULL) {
|
||||||
|
free (fd->ret);
|
||||||
|
}
|
||||||
|
free (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
lua_ucl_userdata_emitter (void *ud)
|
||||||
|
{
|
||||||
|
struct ucl_lua_funcdata *fd = (struct ucl_lua_funcdata *)ud;
|
||||||
|
const char *out = "";
|
||||||
|
|
||||||
|
lua_rawgeti (fd->L, LUA_REGISTRYINDEX, fd->idx);
|
||||||
|
|
||||||
|
lua_pcall (fd->L, 0, 1, 0);
|
||||||
|
out = lua_tostring (fd->L, -1);
|
||||||
|
|
||||||
|
if (out != NULL) {
|
||||||
|
/* We need to store temporary string in a more appropriate place */
|
||||||
|
if (fd->ret) {
|
||||||
|
free (fd->ret);
|
||||||
|
}
|
||||||
|
fd->ret = strdup (out);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_settop (fd->L, 0);
|
||||||
|
|
||||||
|
return fd->ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push a single object to lua
|
||||||
|
* @param L
|
||||||
|
* @param obj
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj,
|
||||||
|
bool allow_array)
|
||||||
|
{
|
||||||
|
const ucl_object_t *cur;
|
||||||
|
ucl_object_iter_t it = NULL;
|
||||||
|
int nelt = 0;
|
||||||
|
|
||||||
|
if (allow_array && obj->next != NULL) {
|
||||||
|
/* Actually we need to push this as an array */
|
||||||
|
return ucl_object_lua_push_array (L, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optimize allocation by preallocation of table */
|
||||||
|
while (ucl_iterate_object (obj, &it, true) != NULL) {
|
||||||
|
nelt ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_createtable (L, 0, nelt);
|
||||||
|
it = NULL;
|
||||||
|
|
||||||
|
while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
|
||||||
|
ucl_object_lua_push_element (L, ucl_object_key (cur), cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push an array to lua as table indexed by integers
|
||||||
|
* @param L
|
||||||
|
* @param obj
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj)
|
||||||
|
{
|
||||||
|
const ucl_object_t *cur;
|
||||||
|
int i = 1, nelt = 0;
|
||||||
|
|
||||||
|
/* Optimize allocation by preallocation of table */
|
||||||
|
LL_FOREACH (obj, cur) {
|
||||||
|
nelt ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_createtable (L, nelt, 0);
|
||||||
|
|
||||||
|
LL_FOREACH (obj, cur) {
|
||||||
|
ucl_object_push_lua (L, cur, false);
|
||||||
|
lua_rawseti (L, -2, i);
|
||||||
|
i ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push a simple object to lua depending on its actual type
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,
|
||||||
|
bool allow_array)
|
||||||
|
{
|
||||||
|
struct ucl_lua_funcdata *fd;
|
||||||
|
|
||||||
|
if (allow_array && obj->next != NULL) {
|
||||||
|
/* Actually we need to push this as an array */
|
||||||
|
return ucl_object_lua_push_array (L, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (obj->type) {
|
||||||
|
case UCL_BOOLEAN:
|
||||||
|
lua_pushboolean (L, ucl_obj_toboolean (obj));
|
||||||
|
break;
|
||||||
|
case UCL_STRING:
|
||||||
|
lua_pushstring (L, ucl_obj_tostring (obj));
|
||||||
|
break;
|
||||||
|
case UCL_INT:
|
||||||
|
#if LUA_VERSION_NUM >= 501
|
||||||
|
lua_pushinteger (L, ucl_obj_toint (obj));
|
||||||
|
#else
|
||||||
|
lua_pushnumber (L, ucl_obj_toint (obj));
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case UCL_FLOAT:
|
||||||
|
case UCL_TIME:
|
||||||
|
lua_pushnumber (L, ucl_obj_todouble (obj));
|
||||||
|
break;
|
||||||
|
case UCL_NULL:
|
||||||
|
lua_getfield (L, LUA_REGISTRYINDEX, "ucl.null");
|
||||||
|
break;
|
||||||
|
case UCL_USERDATA:
|
||||||
|
fd = (struct ucl_lua_funcdata *)obj->value.ud;
|
||||||
|
lua_rawgeti (L, LUA_REGISTRYINDEX, fd->idx);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lua_pushnil (L);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @function ucl_object_push_lua(L, obj, allow_array)
|
||||||
|
* This is a `C` function to push `UCL` object as lua variable. This function
|
||||||
|
* converts `obj` to lua representation using the following conversions:
|
||||||
|
*
|
||||||
|
* - *scalar* values are directly presented by lua objects
|
||||||
|
* - *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`,
|
||||||
|
* this can be used to pass functions from lua to c and vice-versa
|
||||||
|
* - *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations
|
||||||
|
* - *objects* are converted to lua tables with string indicies
|
||||||
|
* @param {lua_State} L lua state pointer
|
||||||
|
* @param {ucl_object_t} obj object to push
|
||||||
|
* @param {bool} allow_array expand implicit arrays (should be true for all but partial arrays)
|
||||||
|
* @return {int} `1` if an object is pushed to lua
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array)
|
||||||
|
{
|
||||||
|
switch (obj->type) {
|
||||||
|
case UCL_OBJECT:
|
||||||
|
return ucl_object_lua_push_object (L, obj, allow_array);
|
||||||
|
case UCL_ARRAY:
|
||||||
|
return ucl_object_lua_push_array (L, obj->value.av);
|
||||||
|
default:
|
||||||
|
return ucl_object_lua_push_scalar (L, obj, allow_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse lua table into object top
|
||||||
|
* @param L
|
||||||
|
* @param top
|
||||||
|
* @param idx
|
||||||
|
*/
|
||||||
|
static ucl_object_t *
|
||||||
|
ucl_object_lua_fromtable (lua_State *L, int idx)
|
||||||
|
{
|
||||||
|
ucl_object_t *obj, *top = NULL;
|
||||||
|
size_t keylen;
|
||||||
|
const char *k;
|
||||||
|
bool is_array = true;
|
||||||
|
int max = INT_MIN;
|
||||||
|
|
||||||
|
if (idx < 0) {
|
||||||
|
/* For negative indicies we want to invert them */
|
||||||
|
idx = lua_gettop (L) + idx + 1;
|
||||||
|
}
|
||||||
|
/* Check for array */
|
||||||
|
lua_pushnil (L);
|
||||||
|
while (lua_next (L, idx) != 0) {
|
||||||
|
if (lua_type (L, -2) == LUA_TNUMBER) {
|
||||||
|
double num = lua_tonumber (L, -2);
|
||||||
|
if (num == (int)num) {
|
||||||
|
if (num > max) {
|
||||||
|
max = num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Keys are not integer */
|
||||||
|
lua_pop (L, 2);
|
||||||
|
is_array = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Keys are not numeric */
|
||||||
|
lua_pop (L, 2);
|
||||||
|
is_array = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lua_pop (L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table iterate */
|
||||||
|
if (is_array) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
top = ucl_object_typed_new (UCL_ARRAY);
|
||||||
|
for (i = 1; i <= max; i ++) {
|
||||||
|
lua_pushinteger (L, i);
|
||||||
|
lua_gettable (L, idx);
|
||||||
|
obj = ucl_object_lua_fromelt (L, lua_gettop (L));
|
||||||
|
if (obj != NULL) {
|
||||||
|
ucl_array_append (top, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushnil (L);
|
||||||
|
top = ucl_object_typed_new (UCL_OBJECT);
|
||||||
|
while (lua_next (L, idx) != 0) {
|
||||||
|
/* copy key to avoid modifications */
|
||||||
|
k = lua_tolstring (L, -2, &keylen);
|
||||||
|
obj = ucl_object_lua_fromelt (L, lua_gettop (L));
|
||||||
|
|
||||||
|
if (obj != NULL) {
|
||||||
|
ucl_object_insert_key (top, obj, k, keylen, true);
|
||||||
|
}
|
||||||
|
lua_pop (L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a single element from lua to object obj
|
||||||
|
* @param L
|
||||||
|
* @param obj
|
||||||
|
* @param idx
|
||||||
|
*/
|
||||||
|
static ucl_object_t *
|
||||||
|
ucl_object_lua_fromelt (lua_State *L, int idx)
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
double num;
|
||||||
|
ucl_object_t *obj = NULL;
|
||||||
|
struct ucl_lua_funcdata *fd;
|
||||||
|
|
||||||
|
type = lua_type (L, idx);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case LUA_TSTRING:
|
||||||
|
obj = ucl_object_fromstring_common (lua_tostring (L, idx), 0, 0);
|
||||||
|
break;
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
num = lua_tonumber (L, idx);
|
||||||
|
if (num == (int64_t)num) {
|
||||||
|
obj = ucl_object_fromint (num);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
obj = ucl_object_fromdouble (num);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LUA_TBOOLEAN:
|
||||||
|
obj = ucl_object_frombool (lua_toboolean (L, idx));
|
||||||
|
break;
|
||||||
|
case LUA_TUSERDATA:
|
||||||
|
if (lua_topointer (L, idx) == ucl_null) {
|
||||||
|
obj = ucl_object_typed_new (UCL_NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LUA_TTABLE:
|
||||||
|
case LUA_TFUNCTION:
|
||||||
|
case LUA_TTHREAD:
|
||||||
|
if (luaL_getmetafield (L, idx, "__gen_ucl")) {
|
||||||
|
if (lua_isfunction (L, -1)) {
|
||||||
|
lua_settop (L, 3); /* gen, obj, func */
|
||||||
|
lua_insert (L, 1); /* func, gen, obj */
|
||||||
|
lua_insert (L, 2); /* func, obj, gen */
|
||||||
|
lua_call(L, 2, 1);
|
||||||
|
obj = ucl_object_lua_fromelt (L, 1);
|
||||||
|
}
|
||||||
|
lua_pop (L, 2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (type == LUA_TTABLE) {
|
||||||
|
obj = ucl_object_lua_fromtable (L, idx);
|
||||||
|
}
|
||||||
|
else if (type == LUA_TFUNCTION) {
|
||||||
|
fd = malloc (sizeof (*fd));
|
||||||
|
if (fd != NULL) {
|
||||||
|
lua_pushvalue (L, idx);
|
||||||
|
fd->L = L;
|
||||||
|
fd->ret = NULL;
|
||||||
|
fd->idx = luaL_ref (L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
obj = ucl_object_new_userdata (lua_ucl_userdata_dtor,
|
||||||
|
lua_ucl_userdata_emitter);
|
||||||
|
obj->type = UCL_USERDATA;
|
||||||
|
obj->value.ud = (void *)fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function ucl_object_lua_import(L, idx)
|
||||||
|
* Extracts ucl object from lua variable at `idx` position,
|
||||||
|
* @see ucl_object_push_lua for conversion definitions
|
||||||
|
* @param {lua_state} L lua state machine pointer
|
||||||
|
* @param {int} idx index where the source variable is placed
|
||||||
|
* @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
|
||||||
|
* this object thus needs to be unref'ed after usage.
|
||||||
|
*/
|
||||||
|
ucl_object_t *
|
||||||
|
ucl_object_lua_import (lua_State *L, int idx)
|
||||||
|
{
|
||||||
|
ucl_object_t *obj;
|
||||||
|
int t;
|
||||||
|
|
||||||
|
t = lua_type (L, idx);
|
||||||
|
switch (t) {
|
||||||
|
case LUA_TTABLE:
|
||||||
|
obj = ucl_object_lua_fromtable (L, idx);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
obj = ucl_object_lua_fromelt (L, idx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lua_ucl_parser_init (lua_State *L)
|
||||||
|
{
|
||||||
|
struct ucl_parser *parser, **pparser;
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
if (lua_gettop (L) >= 1) {
|
||||||
|
flags = lua_tonumber (L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
parser = ucl_parser_new (flags);
|
||||||
|
if (parser == NULL) {
|
||||||
|
lua_pushnil (L);
|
||||||
|
}
|
||||||
|
|
||||||
|
pparser = lua_newuserdata (L, sizeof (parser));
|
||||||
|
*pparser = parser;
|
||||||
|
luaL_getmetatable (L, PARSER_META);
|
||||||
|
lua_setmetatable (L, -2);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ucl_parser *
|
||||||
|
lua_ucl_parser_get (lua_State *L, int index)
|
||||||
|
{
|
||||||
|
return *((struct ucl_parser **) luaL_checkudata(L, index, PARSER_META));
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @method parser:parse_file(name)
|
||||||
|
* Parse UCL object from file.
|
||||||
|
* @param {string} name filename to parse
|
||||||
|
* @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
|
||||||
|
@example
|
||||||
|
local parser = ucl.parser()
|
||||||
|
local res,err = parser:parse_file('/some/file.conf')
|
||||||
|
|
||||||
|
if not res then
|
||||||
|
print('parser error: ' .. err)
|
||||||
|
else
|
||||||
|
-- Do something with object
|
||||||
|
end
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
lua_ucl_parser_parse_file (lua_State *L)
|
||||||
|
{
|
||||||
|
struct ucl_parser *parser;
|
||||||
|
const char *file;
|
||||||
|
int ret = 2;
|
||||||
|
|
||||||
|
parser = lua_ucl_parser_get (L, 1);
|
||||||
|
file = luaL_checkstring (L, 2);
|
||||||
|
|
||||||
|
if (parser != NULL && file != NULL) {
|
||||||
|
if (ucl_parser_add_file (parser, file)) {
|
||||||
|
lua_pushboolean (L, true);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushboolean (L, false);
|
||||||
|
lua_pushstring (L, ucl_parser_get_error (parser));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushboolean (L, false);
|
||||||
|
lua_pushstring (L, "invalid arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @method parser:parse_string(input)
|
||||||
|
* Parse UCL object from file.
|
||||||
|
* @param {string} input string to parse
|
||||||
|
* @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
lua_ucl_parser_parse_string (lua_State *L)
|
||||||
|
{
|
||||||
|
struct ucl_parser *parser;
|
||||||
|
const char *string;
|
||||||
|
size_t llen;
|
||||||
|
int ret = 2;
|
||||||
|
|
||||||
|
parser = lua_ucl_parser_get (L, 1);
|
||||||
|
string = luaL_checklstring (L, 2, &llen);
|
||||||
|
|
||||||
|
if (parser != NULL && string != NULL) {
|
||||||
|
if (ucl_parser_add_chunk (parser, (const unsigned char *)string, llen)) {
|
||||||
|
lua_pushboolean (L, true);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushboolean (L, false);
|
||||||
|
lua_pushstring (L, ucl_parser_get_error (parser));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushboolean (L, false);
|
||||||
|
lua_pushstring (L, "invalid arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @method parser:get_object()
|
||||||
|
* Get top object from parser and export it to lua representation.
|
||||||
|
* @return {variant or nil} ucl object as lua native variable
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
lua_ucl_parser_get_object (lua_State *L)
|
||||||
|
{
|
||||||
|
struct ucl_parser *parser;
|
||||||
|
ucl_object_t *obj;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
parser = lua_ucl_parser_get (L, 1);
|
||||||
|
obj = ucl_parser_get_object (parser);
|
||||||
|
|
||||||
|
if (obj != NULL) {
|
||||||
|
ret = ucl_object_push_lua (L, obj, false);
|
||||||
|
/* no need to keep reference */
|
||||||
|
ucl_object_unref (obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushnil (L);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lua_ucl_parser_gc (lua_State *L)
|
||||||
|
{
|
||||||
|
struct ucl_parser *parser;
|
||||||
|
|
||||||
|
parser = lua_ucl_parser_get (L, 1);
|
||||||
|
ucl_parser_free (parser);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lua_ucl_parser_mt (lua_State *L)
|
||||||
|
{
|
||||||
|
luaL_newmetatable (L, PARSER_META);
|
||||||
|
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_setfield(L, -2, "__index");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_parser_gc);
|
||||||
|
lua_setfield (L, -2, "__gc");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_parser_parse_file);
|
||||||
|
lua_setfield (L, -2, "parse_file");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_parser_parse_string);
|
||||||
|
lua_setfield (L, -2, "parse_string");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_parser_get_object);
|
||||||
|
lua_setfield (L, -2, "get_object");
|
||||||
|
|
||||||
|
lua_pop (L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type)
|
||||||
|
{
|
||||||
|
unsigned char *result;
|
||||||
|
|
||||||
|
result = ucl_object_emit (obj, type);
|
||||||
|
|
||||||
|
if (result != NULL) {
|
||||||
|
lua_pushstring (L, (const char *)result);
|
||||||
|
free (result);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushnil (L);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lua_ucl_to_json (lua_State *L)
|
||||||
|
{
|
||||||
|
ucl_object_t *obj;
|
||||||
|
int format = UCL_EMIT_JSON;
|
||||||
|
|
||||||
|
if (lua_gettop (L) > 1) {
|
||||||
|
if (lua_toboolean (L, 2)) {
|
||||||
|
format = UCL_EMIT_JSON_COMPACT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = ucl_object_lua_import (L, 1);
|
||||||
|
if (obj != NULL) {
|
||||||
|
lua_ucl_to_string (L, obj, format);
|
||||||
|
ucl_object_unref (obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushnil (L);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lua_ucl_to_config (lua_State *L)
|
||||||
|
{
|
||||||
|
ucl_object_t *obj;
|
||||||
|
|
||||||
|
obj = ucl_object_lua_import (L, 1);
|
||||||
|
if (obj != NULL) {
|
||||||
|
lua_ucl_to_string (L, obj, UCL_EMIT_CONFIG);
|
||||||
|
ucl_object_unref (obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushnil (L);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @function ucl.to_format(var, format)
|
||||||
|
* Converts lua variable `var` to the specified `format`. Formats supported are:
|
||||||
|
*
|
||||||
|
* - `json` - fine printed json
|
||||||
|
* - `json-compact` - compacted json
|
||||||
|
* - `config` - fine printed configuration
|
||||||
|
* - `ucl` - same as `config`
|
||||||
|
* - `yaml` - embedded yaml
|
||||||
|
*
|
||||||
|
* If `var` contains function, they are called during output formatting and if
|
||||||
|
* they return string value, then this value is used for ouptut.
|
||||||
|
* @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
|
||||||
|
* @param {string} format any available format
|
||||||
|
* @return {string} string representation of `var` in the specific `format`.
|
||||||
|
* @example
|
||||||
|
local table = {
|
||||||
|
str = 'value',
|
||||||
|
num = 100500,
|
||||||
|
null = ucl.null,
|
||||||
|
func = function ()
|
||||||
|
return 'huh'
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
print(ucl.to_format(table, 'ucl'))
|
||||||
|
-- Output:
|
||||||
|
--[[
|
||||||
|
num = 100500;
|
||||||
|
str = "value";
|
||||||
|
null = null;
|
||||||
|
func = "huh";
|
||||||
|
--]]
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
lua_ucl_to_format (lua_State *L)
|
||||||
|
{
|
||||||
|
ucl_object_t *obj;
|
||||||
|
int format = UCL_EMIT_JSON;
|
||||||
|
|
||||||
|
if (lua_gettop (L) > 1) {
|
||||||
|
if (lua_type (L, 2) == LUA_TNUMBER) {
|
||||||
|
format = lua_tonumber (L, 2);
|
||||||
|
if (format < 0 || format >= UCL_EMIT_YAML) {
|
||||||
|
lua_pushnil (L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (lua_type (L, 2) == LUA_TSTRING) {
|
||||||
|
const char *strtype = lua_tostring (L, 2);
|
||||||
|
|
||||||
|
if (strcasecmp (strtype, "json") == 0) {
|
||||||
|
format = UCL_EMIT_JSON;
|
||||||
|
}
|
||||||
|
else if (strcasecmp (strtype, "json-compact") == 0) {
|
||||||
|
format = UCL_EMIT_JSON_COMPACT;
|
||||||
|
}
|
||||||
|
else if (strcasecmp (strtype, "yaml") == 0) {
|
||||||
|
format = UCL_EMIT_YAML;
|
||||||
|
}
|
||||||
|
else if (strcasecmp (strtype, "config") == 0 ||
|
||||||
|
strcasecmp (strtype, "ucl") == 0) {
|
||||||
|
format = UCL_EMIT_CONFIG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = ucl_object_lua_import (L, 1);
|
||||||
|
if (obj != NULL) {
|
||||||
|
lua_ucl_to_string (L, obj, format);
|
||||||
|
ucl_object_unref (obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushnil (L);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lua_ucl_null_tostring (lua_State* L)
|
||||||
|
{
|
||||||
|
lua_pushstring (L, "null");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lua_ucl_null_mt (lua_State *L)
|
||||||
|
{
|
||||||
|
luaL_newmetatable (L, NULL_META);
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_null_tostring);
|
||||||
|
lua_setfield (L, -2, "__tostring");
|
||||||
|
|
||||||
|
lua_pop (L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
luaopen_ucl (lua_State *L)
|
||||||
|
{
|
||||||
|
lua_ucl_parser_mt (L);
|
||||||
|
lua_ucl_null_mt (L);
|
||||||
|
|
||||||
|
/* Create the refs weak table: */
|
||||||
|
lua_createtable (L, 0, 2);
|
||||||
|
lua_pushliteral (L, "v"); /* tbl, "v" */
|
||||||
|
lua_setfield (L, -2, "__mode");
|
||||||
|
lua_pushvalue (L, -1); /* tbl, tbl */
|
||||||
|
lua_setmetatable (L, -2); /* tbl */
|
||||||
|
lua_setfield (L, LUA_REGISTRYINDEX, "ucl.refs");
|
||||||
|
|
||||||
|
lua_newtable (L);
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_parser_init);
|
||||||
|
lua_setfield (L, -2, "parser");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_to_json);
|
||||||
|
lua_setfield (L, -2, "to_json");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_to_config);
|
||||||
|
lua_setfield (L, -2, "to_config");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_to_format);
|
||||||
|
lua_setfield (L, -2, "to_format");
|
||||||
|
|
||||||
|
ucl_null = lua_newuserdata (L, 0);
|
||||||
|
luaL_getmetatable (L, NULL_META);
|
||||||
|
lua_setmetatable (L, -2);
|
||||||
|
|
||||||
|
lua_pushvalue (L, -1);
|
||||||
|
lua_setfield (L, LUA_REGISTRYINDEX, "ucl.null");
|
||||||
|
|
||||||
|
lua_setfield (L, -2, "null");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ucl_lua_funcdata*
|
||||||
|
ucl_object_toclosure (const ucl_object_t *obj)
|
||||||
|
{
|
||||||
|
if (obj == NULL || obj->type != UCL_USERDATA) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (struct ucl_lua_funcdata*)obj->value.ud;
|
||||||
|
}
|
48
contrib/libucl/lua/test.lua
Normal file
48
contrib/libucl/lua/test.lua
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
local ucl = require("ucl")
|
||||||
|
|
||||||
|
function test_simple()
|
||||||
|
local expect =
|
||||||
|
'['..
|
||||||
|
'"float",1.5,'..
|
||||||
|
'"integer",5,'..
|
||||||
|
'"true",true,'..
|
||||||
|
'"false",false,'..
|
||||||
|
'"null",null,'..
|
||||||
|
'"string","hello",'..
|
||||||
|
'"array",[1,2],'..
|
||||||
|
'"object",{"key":"value"}'..
|
||||||
|
']'
|
||||||
|
|
||||||
|
-- Input to to_value matches the output of to_string:
|
||||||
|
local parser = ucl.parser()
|
||||||
|
local res,err = parser:parse_string(expect)
|
||||||
|
if not res then
|
||||||
|
print('parser error: ' .. err)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local obj = parser:get_object()
|
||||||
|
local got = ucl.to_json(obj, true)
|
||||||
|
if expect == got then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print(expect .. " == " .. tostring(got))
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test_simple()
|
||||||
|
|
||||||
|
local table = {
|
||||||
|
str = 'value',
|
||||||
|
num = 100500,
|
||||||
|
null = ucl.null,
|
||||||
|
func = function ()
|
||||||
|
return 'huh'
|
||||||
|
end,
|
||||||
|
badfunc = function()
|
||||||
|
print("I'm bad")
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
print(ucl.to_format(table, 'ucl'))
|
4
contrib/libucl/m4/.gitignore
vendored
Normal file
4
contrib/libucl/m4/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Ignore everything in this directory
|
||||||
|
*
|
||||||
|
# Except this file
|
||||||
|
!.gitignore
|
606
contrib/libucl/m4/ax_lua.m4
Normal file
606
contrib/libucl/m4/ax_lua.m4
Normal file
@ -0,0 +1,606 @@
|
|||||||
|
# ===========================================================================
|
||||||
|
# http://www.gnu.org/software/autoconf-archive/ax_lua.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
|
||||||
|
# AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
|
||||||
|
# AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
|
||||||
|
# AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])]
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# Detect a Lua interpreter, optionally specifying a minimum and maximum
|
||||||
|
# version number. Set up important Lua paths, such as the directories in
|
||||||
|
# which to install scripts and modules (shared libraries).
|
||||||
|
#
|
||||||
|
# Also detect Lua headers and libraries. The Lua version contained in the
|
||||||
|
# header is checked to match the Lua interpreter version exactly. When
|
||||||
|
# searching for Lua libraries, the version number is used as a suffix.
|
||||||
|
# This is done with the goal of supporting multiple Lua installs (5.1 and
|
||||||
|
# 5.2 side-by-side).
|
||||||
|
#
|
||||||
|
# A note on compatibility with previous versions: This file has been
|
||||||
|
# mostly rewritten for serial 18. Most developers should be able to use
|
||||||
|
# these macros without needing to modify configure.ac. Care has been taken
|
||||||
|
# to preserve each macro's behavior, but there are some differences:
|
||||||
|
#
|
||||||
|
# 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as
|
||||||
|
# AX_PROG_LUA with no arguments.
|
||||||
|
#
|
||||||
|
# 2) AX_LUA_HEADERS now checks that the version number defined in lua.h
|
||||||
|
# matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore
|
||||||
|
# unnecessary, so it is deprecated and does not expand to anything.
|
||||||
|
#
|
||||||
|
# 3) The configure flag --with-lua-suffix no longer exists; the user
|
||||||
|
# should instead specify the LUA precious variable on the command line.
|
||||||
|
# See the AX_PROG_LUA description for details.
|
||||||
|
#
|
||||||
|
# Please read the macro descriptions below for more information.
|
||||||
|
#
|
||||||
|
# This file was inspired by Andrew Dalke's and James Henstridge's
|
||||||
|
# python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4
|
||||||
|
# (serial 17). Basically, this file is a mash-up of those two files. I
|
||||||
|
# like to think it combines the best of the two!
|
||||||
|
#
|
||||||
|
# AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua
|
||||||
|
# paths. Adds precious variable LUA, which may contain the path of the Lua
|
||||||
|
# interpreter. If LUA is blank, the user's path is searched for an
|
||||||
|
# suitable interpreter.
|
||||||
|
#
|
||||||
|
# If MINIMUM-VERSION is supplied, then only Lua interpreters with a
|
||||||
|
# version number greater or equal to MINIMUM-VERSION will be accepted. If
|
||||||
|
# TOO-BIG- VERSION is also supplied, then only Lua interpreters with a
|
||||||
|
# version number greater or equal to MINIMUM-VERSION and less than
|
||||||
|
# TOO-BIG-VERSION will be accepted.
|
||||||
|
#
|
||||||
|
# The Lua version number, LUA_VERSION, is found from the interpreter, and
|
||||||
|
# substituted. LUA_PLATFORM is also found, but not currently supported (no
|
||||||
|
# standard representation).
|
||||||
|
#
|
||||||
|
# Finally, the macro finds four paths:
|
||||||
|
#
|
||||||
|
# luadir Directory to install Lua scripts.
|
||||||
|
# pkgluadir $luadir/$PACKAGE
|
||||||
|
# luaexecdir Directory to install Lua modules.
|
||||||
|
# pkgluaexecdir $luaexecdir/$PACKAGE
|
||||||
|
#
|
||||||
|
# These paths a found based on $prefix, $exec_prefix, Lua's package.path,
|
||||||
|
# and package.cpath. The first path of package.path beginning with $prefix
|
||||||
|
# is selected as luadir. The first path of package.cpath beginning with
|
||||||
|
# $exec_prefix is used as luaexecdir. This should work on all reasonable
|
||||||
|
# Lua installations. If a path cannot be determined, a default path is
|
||||||
|
# used. Of course, the user can override these later when invoking make.
|
||||||
|
#
|
||||||
|
# luadir Default: $prefix/share/lua/$LUA_VERSION
|
||||||
|
# luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION
|
||||||
|
#
|
||||||
|
# These directories can be used by Automake as install destinations. The
|
||||||
|
# variable name minus 'dir' needs to be used as a prefix to the
|
||||||
|
# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES.
|
||||||
|
#
|
||||||
|
# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is
|
||||||
|
# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT-
|
||||||
|
# FOUND is blank, then it will default to printing an error. To prevent
|
||||||
|
# the default behavior, give ':' as an action.
|
||||||
|
#
|
||||||
|
# AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be
|
||||||
|
# expanded before this macro. Adds precious variable LUA_INCLUDE, which
|
||||||
|
# may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If
|
||||||
|
# LUA_INCLUDE is blank, then this macro will attempt to find suitable
|
||||||
|
# flags.
|
||||||
|
#
|
||||||
|
# LUA_INCLUDE can be used by Automake to compile Lua modules or
|
||||||
|
# executables with embedded interpreters. The *_CPPFLAGS variables should
|
||||||
|
# be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE).
|
||||||
|
#
|
||||||
|
# This macro searches for the header lua.h (and others). The search is
|
||||||
|
# performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE.
|
||||||
|
# If the search is unsuccessful, then some common directories are tried.
|
||||||
|
# If the headers are then found, then LUA_INCLUDE is set accordingly.
|
||||||
|
#
|
||||||
|
# The paths automatically searched are:
|
||||||
|
#
|
||||||
|
# * /usr/include/luaX.Y
|
||||||
|
# * /usr/include/lua/X.Y
|
||||||
|
# * /usr/include/luaXY
|
||||||
|
# * /usr/local/include/luaX.Y
|
||||||
|
# * /usr/local/include/lua-X.Y
|
||||||
|
# * /usr/local/include/lua/X.Y
|
||||||
|
# * /usr/local/include/luaXY
|
||||||
|
#
|
||||||
|
# (Where X.Y is the Lua version number, e.g. 5.1.)
|
||||||
|
#
|
||||||
|
# The Lua version number found in the headers is always checked to match
|
||||||
|
# the Lua interpreter's version number. Lua headers with mismatched
|
||||||
|
# version numbers are not accepted.
|
||||||
|
#
|
||||||
|
# If headers are found, then ACTION-IF-FOUND is performed, otherwise
|
||||||
|
# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then
|
||||||
|
# it will default to printing an error. To prevent the default behavior,
|
||||||
|
# set the action to ':'.
|
||||||
|
#
|
||||||
|
# AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be
|
||||||
|
# expanded before this macro. Adds precious variable LUA_LIB, which may
|
||||||
|
# contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank,
|
||||||
|
# then this macro will attempt to find suitable flags.
|
||||||
|
#
|
||||||
|
# LUA_LIB can be used by Automake to link Lua modules or executables with
|
||||||
|
# embedded interpreters. The *_LIBADD and *_LDADD variables should be used
|
||||||
|
# for this purpose, e.g. mymod_LIBADD = $(LUA_LIB).
|
||||||
|
#
|
||||||
|
# This macro searches for the Lua library. More technically, it searches
|
||||||
|
# for a library containing the function lua_load. The search is performed
|
||||||
|
# with a combination of LIBS, LIBRARY_PATH, and LUA_LIB.
|
||||||
|
#
|
||||||
|
# If the search determines that some linker flags are missing, then those
|
||||||
|
# flags will be added to LUA_LIB.
|
||||||
|
#
|
||||||
|
# If libraries are found, then ACTION-IF-FOUND is performed, otherwise
|
||||||
|
# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then
|
||||||
|
# it will default to printing an error. To prevent the default behavior,
|
||||||
|
# set the action to ':'.
|
||||||
|
#
|
||||||
|
# AX_LUA_READLINE: Search for readline headers and libraries. Requires the
|
||||||
|
# AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the
|
||||||
|
# Autoconf Archive.
|
||||||
|
#
|
||||||
|
# If a readline compatible library is found, then ACTION-IF-FOUND is
|
||||||
|
# performed, otherwise ACTION-IF-NOT-FOUND is performed.
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014 Reuben Thomas <rrt@sc3d.org>
|
||||||
|
# Copyright (c) 2013 Tim Perkins <tprk77@gmail.com>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License as published by the
|
||||||
|
# Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
# Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||||
|
# gives unlimited permission to copy, distribute and modify the configure
|
||||||
|
# scripts that are the output of Autoconf when processing the Macro. You
|
||||||
|
# need not follow the terms of the GNU General Public License when using
|
||||||
|
# or distributing such scripts, even though portions of the text of the
|
||||||
|
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||||
|
# all other use of the material that constitutes the Autoconf Macro.
|
||||||
|
#
|
||||||
|
# This special exception to the GPL applies to versions of the Autoconf
|
||||||
|
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||||
|
# modified version of the Autoconf Macro, you may extend this special
|
||||||
|
# exception to the GPL to apply to your modified version as well.
|
||||||
|
|
||||||
|
#serial 23
|
||||||
|
|
||||||
|
dnl =========================================================================
|
||||||
|
dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION],
|
||||||
|
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||||
|
dnl =========================================================================
|
||||||
|
AC_DEFUN([AX_PROG_LUA],
|
||||||
|
[
|
||||||
|
dnl Make LUA a precious variable.
|
||||||
|
AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1])
|
||||||
|
|
||||||
|
dnl Find a Lua interpreter.
|
||||||
|
m4_define_default([_AX_LUA_INTERPRETER_LIST],
|
||||||
|
[lua lua5.2 lua52 lua5.1 lua51 lua50])
|
||||||
|
|
||||||
|
m4_if([$1], [],
|
||||||
|
[ dnl No version check is needed. Find any Lua interpreter.
|
||||||
|
AS_IF([test "x$LUA" = 'x'],
|
||||||
|
[AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])])
|
||||||
|
ax_display_LUA='lua'
|
||||||
|
|
||||||
|
dnl At least check if this is a Lua interpreter.
|
||||||
|
AC_MSG_CHECKING([if $LUA is a Lua interpreter])
|
||||||
|
_AX_LUA_CHK_IS_INTRP([$LUA],
|
||||||
|
[AC_MSG_RESULT([yes])],
|
||||||
|
[ AC_MSG_RESULT([no])
|
||||||
|
AC_MSG_ERROR([not a Lua interpreter])
|
||||||
|
])
|
||||||
|
],
|
||||||
|
[ dnl A version check is needed.
|
||||||
|
AS_IF([test "x$LUA" != 'x'],
|
||||||
|
[ dnl Check if this is a Lua interpreter.
|
||||||
|
AC_MSG_CHECKING([if $LUA is a Lua interpreter])
|
||||||
|
_AX_LUA_CHK_IS_INTRP([$LUA],
|
||||||
|
[AC_MSG_RESULT([yes])],
|
||||||
|
[ AC_MSG_RESULT([no])
|
||||||
|
AC_MSG_ERROR([not a Lua interpreter])
|
||||||
|
])
|
||||||
|
dnl Check the version.
|
||||||
|
m4_if([$2], [],
|
||||||
|
[_ax_check_text="whether $LUA version >= $1"],
|
||||||
|
[_ax_check_text="whether $LUA version >= $1, < $2"])
|
||||||
|
AC_MSG_CHECKING([$_ax_check_text])
|
||||||
|
_AX_LUA_CHK_VER([$LUA], [$1], [$2],
|
||||||
|
[AC_MSG_RESULT([yes])],
|
||||||
|
[ AC_MSG_RESULT([no])
|
||||||
|
AC_MSG_ERROR([version is out of range for specified LUA])])
|
||||||
|
ax_display_LUA=$LUA
|
||||||
|
],
|
||||||
|
[ dnl Try each interpreter until we find one that satisfies VERSION.
|
||||||
|
m4_if([$2], [],
|
||||||
|
[_ax_check_text="for a Lua interpreter with version >= $1"],
|
||||||
|
[_ax_check_text="for a Lua interpreter with version >= $1, < $2"])
|
||||||
|
AC_CACHE_CHECK([$_ax_check_text],
|
||||||
|
[ax_cv_pathless_LUA],
|
||||||
|
[ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do
|
||||||
|
test "x$ax_cv_pathless_LUA" = 'xnone' && break
|
||||||
|
_AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue])
|
||||||
|
_AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break])
|
||||||
|
done
|
||||||
|
])
|
||||||
|
dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA.
|
||||||
|
AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'],
|
||||||
|
[LUA=':'],
|
||||||
|
[AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])])
|
||||||
|
ax_display_LUA=$ax_cv_pathless_LUA
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
AS_IF([test "x$LUA" = 'x:'],
|
||||||
|
[ dnl Run any user-specified action, or abort.
|
||||||
|
m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])])
|
||||||
|
],
|
||||||
|
[ dnl Query Lua for its version number.
|
||||||
|
AC_CACHE_CHECK([for $ax_display_LUA version], [ax_cv_lua_version],
|
||||||
|
[ ax_cv_lua_version=`$LUA -e 'print(_VERSION:match "(%d+%.%d+)")'` ])
|
||||||
|
AS_IF([test "x$ax_cv_lua_version" = 'x'],
|
||||||
|
[AC_MSG_ERROR([invalid Lua version number])])
|
||||||
|
AC_SUBST([LUA_VERSION], [$ax_cv_lua_version])
|
||||||
|
AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | sed 's|\.||'`])
|
||||||
|
|
||||||
|
dnl The following check is not supported:
|
||||||
|
dnl At times (like when building shared libraries) you may want to know
|
||||||
|
dnl which OS platform Lua thinks this is.
|
||||||
|
AC_CACHE_CHECK([for $ax_display_LUA platform], [ax_cv_lua_platform],
|
||||||
|
[ax_cv_lua_platform=`$LUA -e "print('unknown')"`])
|
||||||
|
AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform])
|
||||||
|
|
||||||
|
dnl Use the values of $prefix and $exec_prefix for the corresponding
|
||||||
|
dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct
|
||||||
|
dnl variables so they can be overridden if need be. However, the general
|
||||||
|
dnl consensus is that you shouldn't need this ability.
|
||||||
|
AC_SUBST([LUA_PREFIX], ['${prefix}'])
|
||||||
|
AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}'])
|
||||||
|
|
||||||
|
dnl Lua provides no way to query the script directory, and instead
|
||||||
|
dnl provides LUA_PATH. However, we should be able to make a safe educated
|
||||||
|
dnl guess. If the built-in search path contains a directory which is
|
||||||
|
dnl prefixed by $prefix, then we can store scripts there. The first
|
||||||
|
dnl matching path will be used.
|
||||||
|
AC_CACHE_CHECK([for $ax_display_LUA script directory],
|
||||||
|
[ax_cv_lua_luadir],
|
||||||
|
[ AS_IF([test "x$prefix" = 'xNONE'],
|
||||||
|
[ax_lua_prefix=$ac_default_prefix],
|
||||||
|
[ax_lua_prefix=$prefix])
|
||||||
|
|
||||||
|
dnl Initialize to the default path.
|
||||||
|
ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION"
|
||||||
|
|
||||||
|
dnl Try to find a path with the prefix.
|
||||||
|
_AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [package.path])
|
||||||
|
AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
|
||||||
|
[ dnl Fix the prefix.
|
||||||
|
_ax_strip_prefix=`echo "$ax_lua_prefix" | sed 's|.|.|g'`
|
||||||
|
ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \
|
||||||
|
sed "s,^$_ax_strip_prefix,$LUA_PREFIX,"`
|
||||||
|
])
|
||||||
|
])
|
||||||
|
AC_SUBST([luadir], [$ax_cv_lua_luadir])
|
||||||
|
AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE])
|
||||||
|
|
||||||
|
dnl Lua provides no way to query the module directory, and instead
|
||||||
|
dnl provides LUA_PATH. However, we should be able to make a safe educated
|
||||||
|
dnl guess. If the built-in search path contains a directory which is
|
||||||
|
dnl prefixed by $exec_prefix, then we can store modules there. The first
|
||||||
|
dnl matching path will be used.
|
||||||
|
AC_CACHE_CHECK([for $ax_display_LUA module directory],
|
||||||
|
[ax_cv_lua_luaexecdir],
|
||||||
|
[ AS_IF([test "x$exec_prefix" = 'xNONE'],
|
||||||
|
[ax_lua_exec_prefix=$ax_lua_prefix],
|
||||||
|
[ax_lua_exec_prefix=$exec_prefix])
|
||||||
|
|
||||||
|
dnl Initialize to the default path.
|
||||||
|
ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION"
|
||||||
|
|
||||||
|
dnl Try to find a path with the prefix.
|
||||||
|
_AX_LUA_FND_PRFX_PTH([$LUA],
|
||||||
|
[$ax_lua_exec_prefix], [package.cpathd])
|
||||||
|
AS_IF([test "x$ax_lua_prefixed_path" != 'x'],
|
||||||
|
[ dnl Fix the prefix.
|
||||||
|
_ax_strip_prefix=`echo "$ax_lua_exec_prefix" | sed 's|.|.|g'`
|
||||||
|
ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \
|
||||||
|
sed "s,^$_ax_strip_prefix,$LUA_EXEC_PREFIX,"`
|
||||||
|
])
|
||||||
|
])
|
||||||
|
AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir])
|
||||||
|
AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE])
|
||||||
|
|
||||||
|
dnl Run any user specified action.
|
||||||
|
$3
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA.
|
||||||
|
AC_DEFUN([AX_WITH_LUA],
|
||||||
|
[
|
||||||
|
AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA]])
|
||||||
|
AX_PROG_LUA
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
dnl =========================================================================
|
||||||
|
dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
|
||||||
|
dnl =========================================================================
|
||||||
|
AC_DEFUN([_AX_LUA_CHK_IS_INTRP],
|
||||||
|
[
|
||||||
|
dnl Just print _VERSION because all Lua interpreters have this global.
|
||||||
|
AS_IF([$1 -e "print('Hello ' .. _VERSION .. '!')" &>/dev/null],
|
||||||
|
[$2], [$3])
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
dnl =========================================================================
|
||||||
|
dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION],
|
||||||
|
dnl [ACTION-IF-TRUE], [ACTION-IF-FALSE])
|
||||||
|
dnl =========================================================================
|
||||||
|
AC_DEFUN([_AX_LUA_CHK_VER],
|
||||||
|
[
|
||||||
|
AS_IF([$1 2>/dev/null -e '
|
||||||
|
function norm (v) i,j=v:match "(%d+)%.(%d+)" return 100 * i + j end
|
||||||
|
v=norm (_VERSION)
|
||||||
|
os.exit ((v >= norm ("$2") and ("$3" == "" or v < norm ("$3"))) and 0 or 1)'],
|
||||||
|
[$4], [$5])
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
dnl =========================================================================
|
||||||
|
dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, LUA-PATH-VARIABLE)
|
||||||
|
dnl =========================================================================
|
||||||
|
AC_DEFUN([_AX_LUA_FND_PRFX_PTH],
|
||||||
|
[
|
||||||
|
dnl Invokes the Lua interpreter PROG to print the path variable
|
||||||
|
dnl LUA-PATH-VARIABLE, usually package.path or package.cpath. Paths are
|
||||||
|
dnl then matched against PREFIX. The first path to begin with PREFIX is set
|
||||||
|
dnl to ax_lua_prefixed_path.
|
||||||
|
|
||||||
|
ax_lua_prefixed_path=''
|
||||||
|
_ax_package_paths=`$1 -e 'print($3)' 2>/dev/null | sed 's|;|\n|g'`
|
||||||
|
dnl Try the paths in order, looking for the prefix.
|
||||||
|
for _ax_package_path in $_ax_package_paths; do
|
||||||
|
dnl Copy the path, up to the use of a Lua wildcard.
|
||||||
|
_ax_path_parts=`echo "$_ax_package_path" | sed 's|/|\n|g'`
|
||||||
|
_ax_reassembled=''
|
||||||
|
for _ax_path_part in $_ax_path_parts; do
|
||||||
|
echo "$_ax_path_part" | grep '\?' >/dev/null && break
|
||||||
|
_ax_reassembled="$_ax_reassembled/$_ax_path_part"
|
||||||
|
done
|
||||||
|
dnl Check the path against the prefix.
|
||||||
|
_ax_package_path=$_ax_reassembled
|
||||||
|
if echo "$_ax_package_path" | grep "^$2" >/dev/null; then
|
||||||
|
dnl Found it.
|
||||||
|
ax_lua_prefixed_path=$_ax_package_path
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
dnl =========================================================================
|
||||||
|
dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||||
|
dnl =========================================================================
|
||||||
|
AC_DEFUN([AX_LUA_HEADERS],
|
||||||
|
[
|
||||||
|
dnl Check for LUA_VERSION.
|
||||||
|
AC_MSG_CHECKING([if LUA_VERSION is defined])
|
||||||
|
AS_IF([test "x$LUA_VERSION" != 'x'],
|
||||||
|
[AC_MSG_RESULT([yes])],
|
||||||
|
[ AC_MSG_RESULT([no])
|
||||||
|
AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION])
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl Make LUA_INCLUDE a precious variable.
|
||||||
|
AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1])
|
||||||
|
|
||||||
|
dnl Some default directories to search.
|
||||||
|
LUA_SHORT_VERSION=`echo "$LUA_VERSION" | sed 's|\.||'`
|
||||||
|
m4_define_default([_AX_LUA_INCLUDE_LIST],
|
||||||
|
[ /usr/include/lua$LUA_VERSION \
|
||||||
|
/usr/include/lua/$LUA_VERSION \
|
||||||
|
/usr/include/lua$LUA_SHORT_VERSION \
|
||||||
|
/usr/local/include/lua$LUA_VERSION \
|
||||||
|
/usr/local/include/lua-$LUA_VERSION \
|
||||||
|
/usr/local/include/lua/$LUA_VERSION \
|
||||||
|
/usr/local/include/lua$LUA_SHORT_VERSION \
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl Try to find the headers.
|
||||||
|
_ax_lua_saved_cppflags=$CPPFLAGS
|
||||||
|
CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
|
||||||
|
AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
|
||||||
|
CPPFLAGS=$_ax_lua_saved_cppflags
|
||||||
|
|
||||||
|
dnl Try some other directories if LUA_INCLUDE was not set.
|
||||||
|
AS_IF([test "x$LUA_INCLUDE" = 'x' &&
|
||||||
|
test "x$ac_cv_header_lua_h" != 'xyes'],
|
||||||
|
[ dnl Try some common include paths.
|
||||||
|
for _ax_include_path in _AX_LUA_INCLUDE_LIST; do
|
||||||
|
test ! -d "$_ax_include_path" && continue
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for Lua headers in])
|
||||||
|
AC_MSG_RESULT([$_ax_include_path])
|
||||||
|
|
||||||
|
AS_UNSET([ac_cv_header_lua_h])
|
||||||
|
AS_UNSET([ac_cv_header_lualib_h])
|
||||||
|
AS_UNSET([ac_cv_header_lauxlib_h])
|
||||||
|
AS_UNSET([ac_cv_header_luaconf_h])
|
||||||
|
|
||||||
|
_ax_lua_saved_cppflags=$CPPFLAGS
|
||||||
|
CPPFLAGS="$CPPFLAGS -I$_ax_include_path"
|
||||||
|
AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h])
|
||||||
|
CPPFLAGS=$_ax_lua_saved_cppflags
|
||||||
|
|
||||||
|
AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
|
||||||
|
[ LUA_INCLUDE="-I$_ax_include_path"
|
||||||
|
break
|
||||||
|
])
|
||||||
|
done
|
||||||
|
])
|
||||||
|
|
||||||
|
AS_IF([test "x$ac_cv_header_lua_h" = 'xyes' && test "x$cross_compiling" != 'xyes'],
|
||||||
|
[ dnl Make a program to print LUA_VERSION defined in the header.
|
||||||
|
dnl TODO This probably shouldn't be a runtime test.
|
||||||
|
|
||||||
|
AC_CACHE_CHECK([for Lua header version],
|
||||||
|
[ax_cv_lua_header_version],
|
||||||
|
[ _ax_lua_saved_cppflags=$CPPFLAGS
|
||||||
|
CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
|
||||||
|
AC_RUN_IFELSE(
|
||||||
|
[ AC_LANG_SOURCE([[
|
||||||
|
#include <lua.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
int main(int argc, char ** argv)
|
||||||
|
{
|
||||||
|
if(argc > 1) printf("%s", LUA_VERSION);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
]])
|
||||||
|
],
|
||||||
|
[ ax_cv_lua_header_version=`./conftest$EXEEXT p | \
|
||||||
|
sed "s|^Lua \(.*\)|\1|" | \
|
||||||
|
grep -o "^@<:@0-9@:>@\+\\.@<:@0-9@:>@\+"`
|
||||||
|
],
|
||||||
|
[ax_cv_lua_header_version='unknown'])
|
||||||
|
CPPFLAGS=$_ax_lua_saved_cppflags
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl Compare this to the previously found LUA_VERSION.
|
||||||
|
AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION])
|
||||||
|
AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"],
|
||||||
|
[ AC_MSG_RESULT([yes])
|
||||||
|
ax_header_version_match='yes'
|
||||||
|
],
|
||||||
|
[ AC_MSG_RESULT([no])
|
||||||
|
ax_header_version_match='no'
|
||||||
|
])
|
||||||
|
],
|
||||||
|
[
|
||||||
|
ax_header_version_match='yes'
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl Was LUA_INCLUDE specified?
|
||||||
|
AS_IF([test "x$ax_header_version_match" != 'xyes' &&
|
||||||
|
test "x$LUA_INCLUDE" != 'x'],
|
||||||
|
[AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])])
|
||||||
|
|
||||||
|
dnl Test the final result and run user code.
|
||||||
|
AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1],
|
||||||
|
[m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])])
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS.
|
||||||
|
AC_DEFUN([AX_LUA_HEADERS_VERSION],
|
||||||
|
[
|
||||||
|
AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS]])
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
dnl =========================================================================
|
||||||
|
dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||||
|
dnl =========================================================================
|
||||||
|
AC_DEFUN([AX_LUA_LIBS],
|
||||||
|
[
|
||||||
|
dnl TODO Should this macro also check various -L flags?
|
||||||
|
|
||||||
|
dnl Check for LUA_VERSION.
|
||||||
|
AC_MSG_CHECKING([if LUA_VERSION is defined])
|
||||||
|
AS_IF([test "x$LUA_VERSION" != 'x'],
|
||||||
|
[AC_MSG_RESULT([yes])],
|
||||||
|
[ AC_MSG_RESULT([no])
|
||||||
|
AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION])
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl Make LUA_LIB a precious variable.
|
||||||
|
AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1])
|
||||||
|
|
||||||
|
AS_IF([test "x$LUA_LIB" != 'x'],
|
||||||
|
[ dnl Check that LUA_LIBS works.
|
||||||
|
_ax_lua_saved_libs=$LIBS
|
||||||
|
LIBS="$LIBS $LUA_LIB"
|
||||||
|
AC_SEARCH_LIBS([lua_load], [],
|
||||||
|
[_ax_found_lua_libs='yes'],
|
||||||
|
[_ax_found_lua_libs='no'])
|
||||||
|
LIBS=$_ax_lua_saved_libs
|
||||||
|
|
||||||
|
dnl Check the result.
|
||||||
|
AS_IF([test "x$_ax_found_lua_libs" != 'xyes'],
|
||||||
|
[AC_MSG_ERROR([cannot find libs for specified LUA_LIB])])
|
||||||
|
],
|
||||||
|
[ dnl First search for extra libs.
|
||||||
|
_ax_lua_extra_libs=''
|
||||||
|
|
||||||
|
_ax_lua_saved_libs=$LIBS
|
||||||
|
LIBS="$LIBS $LUA_LIB"
|
||||||
|
AC_SEARCH_LIBS([exp], [m])
|
||||||
|
AC_SEARCH_LIBS([dlopen], [dl])
|
||||||
|
LIBS=$_ax_lua_saved_libs
|
||||||
|
|
||||||
|
AS_IF([test "x$ac_cv_search_exp" != 'xno' &&
|
||||||
|
test "x$ac_cv_search_exp" != 'xnone required'],
|
||||||
|
[_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"])
|
||||||
|
|
||||||
|
AS_IF([test "x$ac_cv_search_dlopen" != 'xno' &&
|
||||||
|
test "x$ac_cv_search_dlopen" != 'xnone required'],
|
||||||
|
[_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"])
|
||||||
|
|
||||||
|
dnl Try to find the Lua libs.
|
||||||
|
_ax_lua_saved_libs=$LIBS
|
||||||
|
LIBS="$LIBS $LUA_LIB"
|
||||||
|
AC_SEARCH_LIBS([lua_load],
|
||||||
|
[ lua$LUA_VERSION \
|
||||||
|
lua$LUA_SHORT_VERSION \
|
||||||
|
lua-$LUA_VERSION \
|
||||||
|
lua-$LUA_SHORT_VERSION \
|
||||||
|
lua],
|
||||||
|
[_ax_found_lua_libs='yes'],
|
||||||
|
[_ax_found_lua_libs='no'],
|
||||||
|
[$_ax_lua_extra_libs])
|
||||||
|
LIBS=$_ax_lua_saved_libs
|
||||||
|
|
||||||
|
AS_IF([test "x$ac_cv_search_lua_load" != 'xno' &&
|
||||||
|
test "x$ac_cv_search_lua_load" != 'xnone required'],
|
||||||
|
[LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"])
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl Test the result and run user code.
|
||||||
|
AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1],
|
||||||
|
[m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])])
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
dnl =========================================================================
|
||||||
|
dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||||
|
dnl =========================================================================
|
||||||
|
AC_DEFUN([AX_LUA_READLINE],
|
||||||
|
[
|
||||||
|
AX_LIB_READLINE
|
||||||
|
AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' &&
|
||||||
|
test "x$ac_cv_header_readline_history_h" != 'x'],
|
||||||
|
[ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS"
|
||||||
|
$1
|
||||||
|
],
|
||||||
|
[$2])
|
||||||
|
])
|
@ -130,6 +130,19 @@ ucl_emitter_print_key (bool print_key, struct ucl_emitter_context *ctx,
|
|||||||
func->ucl_emitter_append_character (' ', 1, func->ud);
|
func->ucl_emitter_append_character (' ', 1, func->ud);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (ctx->id == UCL_EMIT_YAML) {
|
||||||
|
if (obj->keylen > 0 && (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE)) {
|
||||||
|
ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
|
||||||
|
}
|
||||||
|
else if (obj->keylen > 0) {
|
||||||
|
func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
func->ucl_emitter_append_len ("null", 4, func->ud);
|
||||||
|
}
|
||||||
|
|
||||||
|
func->ucl_emitter_append_len (": ", 2, func->ud);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (obj->keylen > 0) {
|
if (obj->keylen > 0) {
|
||||||
ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
|
ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
|
||||||
@ -182,7 +195,7 @@ ucl_emitter_common_end_object (struct ucl_emitter_context *ctx,
|
|||||||
const struct ucl_emitter_functions *func = ctx->func;
|
const struct ucl_emitter_functions *func = ctx->func;
|
||||||
|
|
||||||
if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
|
if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
|
||||||
ctx->ident --;
|
ctx->indent --;
|
||||||
if (compact) {
|
if (compact) {
|
||||||
func->ucl_emitter_append_character ('}', 1, func->ud);
|
func->ucl_emitter_append_character ('}', 1, func->ud);
|
||||||
}
|
}
|
||||||
@ -191,7 +204,7 @@ ucl_emitter_common_end_object (struct ucl_emitter_context *ctx,
|
|||||||
/* newline is already added for this format */
|
/* newline is already added for this format */
|
||||||
func->ucl_emitter_append_character ('\n', 1, func->ud);
|
func->ucl_emitter_append_character ('\n', 1, func->ud);
|
||||||
}
|
}
|
||||||
ucl_add_tabs (func, ctx->ident, compact);
|
ucl_add_tabs (func, ctx->indent, compact);
|
||||||
func->ucl_emitter_append_character ('}', 1, func->ud);
|
func->ucl_emitter_append_character ('}', 1, func->ud);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,7 +223,7 @@ ucl_emitter_common_end_array (struct ucl_emitter_context *ctx,
|
|||||||
{
|
{
|
||||||
const struct ucl_emitter_functions *func = ctx->func;
|
const struct ucl_emitter_functions *func = ctx->func;
|
||||||
|
|
||||||
ctx->ident --;
|
ctx->indent --;
|
||||||
if (compact) {
|
if (compact) {
|
||||||
func->ucl_emitter_append_character (']', 1, func->ud);
|
func->ucl_emitter_append_character (']', 1, func->ud);
|
||||||
}
|
}
|
||||||
@ -219,7 +232,7 @@ ucl_emitter_common_end_array (struct ucl_emitter_context *ctx,
|
|||||||
/* newline is already added for this format */
|
/* newline is already added for this format */
|
||||||
func->ucl_emitter_append_character ('\n', 1, func->ud);
|
func->ucl_emitter_append_character ('\n', 1, func->ud);
|
||||||
}
|
}
|
||||||
ucl_add_tabs (func, ctx->ident, compact);
|
ucl_add_tabs (func, ctx->indent, compact);
|
||||||
func->ucl_emitter_append_character (']', 1, func->ud);
|
func->ucl_emitter_append_character (']', 1, func->ud);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,7 +262,7 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,
|
|||||||
func->ucl_emitter_append_len ("[\n", 2, func->ud);
|
func->ucl_emitter_append_len ("[\n", 2, func->ud);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->ident ++;
|
ctx->indent ++;
|
||||||
|
|
||||||
if (obj->type == UCL_ARRAY) {
|
if (obj->type == UCL_ARRAY) {
|
||||||
/* explicit array */
|
/* explicit array */
|
||||||
@ -294,7 +307,7 @@ ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,
|
|||||||
else {
|
else {
|
||||||
func->ucl_emitter_append_len ("{\n", 2, func->ud);
|
func->ucl_emitter_append_len ("{\n", 2, func->ud);
|
||||||
}
|
}
|
||||||
ctx->ident ++;
|
ctx->indent ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
|
while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
|
||||||
@ -315,7 +328,7 @@ ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,
|
|||||||
func->ucl_emitter_append_len (",\n", 2, func->ud);
|
func->ucl_emitter_append_len (",\n", 2, func->ud);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ucl_add_tabs (func, ctx->ident, compact);
|
ucl_add_tabs (func, ctx->indent, compact);
|
||||||
ucl_emitter_common_start_array (ctx, cur, true, compact);
|
ucl_emitter_common_start_array (ctx, cur, true, compact);
|
||||||
ucl_emitter_common_end_array (ctx, cur, compact);
|
ucl_emitter_common_end_array (ctx, cur, compact);
|
||||||
}
|
}
|
||||||
@ -342,17 +355,23 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
|
|||||||
{
|
{
|
||||||
const struct ucl_emitter_functions *func = ctx->func;
|
const struct ucl_emitter_functions *func = ctx->func;
|
||||||
bool flag;
|
bool flag;
|
||||||
|
struct ucl_object_userdata *ud;
|
||||||
|
const char *ud_out = "";
|
||||||
|
|
||||||
if (ctx->id != UCL_EMIT_CONFIG && !first) {
|
if (ctx->id != UCL_EMIT_CONFIG && !first) {
|
||||||
if (compact) {
|
if (compact) {
|
||||||
func->ucl_emitter_append_character (',', 1, func->ud);
|
func->ucl_emitter_append_character (',', 1, func->ud);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
func->ucl_emitter_append_len (",\n", 2, func->ud);
|
if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
|
||||||
|
func->ucl_emitter_append_len ("\n", 1, func->ud);
|
||||||
|
} else {
|
||||||
|
func->ucl_emitter_append_len (",\n", 2, func->ud);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ucl_add_tabs (func, ctx->ident, compact);
|
ucl_add_tabs (func, ctx->indent, compact);
|
||||||
|
|
||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
case UCL_INT:
|
case UCL_INT:
|
||||||
@ -379,7 +398,12 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
|
|||||||
break;
|
break;
|
||||||
case UCL_STRING:
|
case UCL_STRING:
|
||||||
ucl_emitter_print_key (print_key, ctx, obj, compact);
|
ucl_emitter_print_key (print_key, ctx, obj, compact);
|
||||||
ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
|
if (ctx->id == UCL_EMIT_CONFIG && ucl_maybe_long_string (obj)) {
|
||||||
|
ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
|
||||||
|
}
|
||||||
ucl_emitter_finish_object (ctx, obj, compact, !print_key);
|
ucl_emitter_finish_object (ctx, obj, compact, !print_key);
|
||||||
break;
|
break;
|
||||||
case UCL_NULL:
|
case UCL_NULL:
|
||||||
@ -396,6 +420,16 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
|
|||||||
ucl_emitter_common_end_array (ctx, obj, compact);
|
ucl_emitter_common_end_array (ctx, obj, compact);
|
||||||
break;
|
break;
|
||||||
case UCL_USERDATA:
|
case UCL_USERDATA:
|
||||||
|
ud = (struct ucl_object_userdata *)obj;
|
||||||
|
ucl_emitter_print_key (print_key, ctx, obj, compact);
|
||||||
|
if (ud->emitter) {
|
||||||
|
ud_out = ud->emitter (obj->value.ud);
|
||||||
|
if (ud_out == NULL) {
|
||||||
|
ud_out = "null";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ucl_elt_string_write_json (ud_out, strlen (ud_out), ctx);
|
||||||
|
ucl_emitter_finish_object (ctx, obj, compact, !print_key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -425,10 +459,10 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
|
|||||||
ucl_emitter_common_end_array (ctx, obj, (compact)); \
|
ucl_emitter_common_end_array (ctx, obj, (compact)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
UCL_EMIT_TYPE_IMPL(json, false);
|
UCL_EMIT_TYPE_IMPL(json, false)
|
||||||
UCL_EMIT_TYPE_IMPL(json_compact, true);
|
UCL_EMIT_TYPE_IMPL(json_compact, true)
|
||||||
UCL_EMIT_TYPE_IMPL(config, false);
|
UCL_EMIT_TYPE_IMPL(config, false)
|
||||||
UCL_EMIT_TYPE_IMPL(yaml, false);
|
UCL_EMIT_TYPE_IMPL(yaml, false)
|
||||||
|
|
||||||
unsigned char *
|
unsigned char *
|
||||||
ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type)
|
ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type)
|
||||||
@ -461,7 +495,7 @@ ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
|
|||||||
if (ctx != NULL) {
|
if (ctx != NULL) {
|
||||||
memcpy (&my_ctx, ctx, sizeof (my_ctx));
|
memcpy (&my_ctx, ctx, sizeof (my_ctx));
|
||||||
my_ctx.func = emitter;
|
my_ctx.func = emitter;
|
||||||
my_ctx.ident = 0;
|
my_ctx.indent = 0;
|
||||||
my_ctx.top = obj;
|
my_ctx.top = obj;
|
||||||
|
|
||||||
my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);
|
my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);
|
||||||
|
@ -108,9 +108,8 @@ ucl_object_emit_streamline_start_container (struct ucl_emitter_context *ctx,
|
|||||||
st->is_array = false;
|
st->is_array = false;
|
||||||
sctx->ops->ucl_emitter_start_object (ctx, obj, print_key);
|
sctx->ops->ucl_emitter_start_object (ctx, obj, print_key);
|
||||||
}
|
}
|
||||||
|
LL_PREPEND (sctx->containers, st);
|
||||||
}
|
}
|
||||||
|
|
||||||
LL_PREPEND (sctx->containers, st);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -93,9 +93,7 @@ ucl_elt_string_write_json (const char *str, size_t size,
|
|||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
const struct ucl_emitter_functions *func = ctx->func;
|
const struct ucl_emitter_functions *func = ctx->func;
|
||||||
|
|
||||||
if (ctx->id != UCL_EMIT_YAML) {
|
func->ucl_emitter_append_character ('"', 1, func->ud);
|
||||||
func->ucl_emitter_append_character ('"', 1, func->ud);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (size) {
|
while (size) {
|
||||||
if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
|
if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
|
||||||
@ -137,9 +135,18 @@ ucl_elt_string_write_json (const char *str, size_t size,
|
|||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
func->ucl_emitter_append_len (c, len, func->ud);
|
func->ucl_emitter_append_len (c, len, func->ud);
|
||||||
}
|
}
|
||||||
if (ctx->id != UCL_EMIT_YAML) {
|
func->ucl_emitter_append_character ('"', 1, func->ud);
|
||||||
func->ucl_emitter_append_character ('"', 1, func->ud);
|
}
|
||||||
}
|
|
||||||
|
void
|
||||||
|
ucl_elt_string_write_multiline (const char *str, size_t size,
|
||||||
|
struct ucl_emitter_context *ctx)
|
||||||
|
{
|
||||||
|
const struct ucl_emitter_functions *func = ctx->func;
|
||||||
|
|
||||||
|
func->ucl_emitter_append_len ("<<EOD\n", sizeof ("<<EOD\n") - 1, func->ud);
|
||||||
|
func->ucl_emitter_append_len (str, size, func->ud);
|
||||||
|
func->ucl_emitter_append_len ("\nEOD", sizeof ("\nEOD") - 1, func->ud);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -154,7 +161,7 @@ ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
|
|||||||
utstring_append_c (buf, c);
|
utstring_append_c (buf, c);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
utstring_reserve (buf, len);
|
utstring_reserve (buf, len + 1);
|
||||||
memset (&buf->d[buf->i], c, len);
|
memset (&buf->d[buf->i], c, len);
|
||||||
buf->i += len;
|
buf->i += len;
|
||||||
buf->d[buf->i] = '\0';
|
buf->d[buf->i] = '\0';
|
||||||
@ -267,19 +274,23 @@ ucl_fd_append_character (unsigned char c, size_t len, void *ud)
|
|||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
|
|
||||||
if (len == 1) {
|
if (len == 1) {
|
||||||
write (fd, &c, 1);
|
return write (fd, &c, 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
buf = malloc (len);
|
buf = malloc (len);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
/* Fallback */
|
/* Fallback */
|
||||||
while (len --) {
|
while (len --) {
|
||||||
write (fd, &c, 1);
|
if (write (fd, &c, 1) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memset (buf, c, len);
|
memset (buf, c, len);
|
||||||
write (fd, buf, len);
|
if (write (fd, buf, len) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
free (buf);
|
free (buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,9 +303,7 @@ ucl_fd_append_len (const unsigned char *str, size_t len, void *ud)
|
|||||||
{
|
{
|
||||||
int fd = *(int *)ud;
|
int fd = *(int *)ud;
|
||||||
|
|
||||||
write (fd, str, len);
|
return write (fd, str, len);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -304,9 +313,7 @@ ucl_fd_append_int (int64_t val, void *ud)
|
|||||||
char intbuf[64];
|
char intbuf[64];
|
||||||
|
|
||||||
snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);
|
snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);
|
||||||
write (fd, intbuf, strlen (intbuf));
|
return write (fd, intbuf, strlen (intbuf));
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -327,9 +334,7 @@ ucl_fd_append_double (double val, void *ud)
|
|||||||
snprintf (nbuf, sizeof (nbuf), "%lf", val);
|
snprintf (nbuf, sizeof (nbuf), "%lf", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
write (fd, nbuf, strlen (nbuf));
|
return write (fd, nbuf, strlen (nbuf));
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ucl_emitter_functions*
|
struct ucl_emitter_functions*
|
||||||
@ -464,3 +469,18 @@ ucl_object_emit_single_json (const ucl_object_t *obj)
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define LONG_STRING_LIMIT 80
|
||||||
|
|
||||||
|
bool
|
||||||
|
ucl_maybe_long_string (const ucl_object_t *obj)
|
||||||
|
{
|
||||||
|
if (obj->len > LONG_STRING_LIMIT || (obj->flags & UCL_OBJECT_MULTILINE)) {
|
||||||
|
/* String is long enough, so search for newline characters in it */
|
||||||
|
if (memchr (obj->value.sv, '\n', obj->len) != NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -66,6 +66,20 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
|
|||||||
HASH_ADD_KEYPTR (hh, hashlin->buckets, key, keylen, node);
|
HASH_ADD_KEYPTR (hh, hashlin->buckets, key, keylen, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,
|
||||||
|
const ucl_object_t *new)
|
||||||
|
{
|
||||||
|
ucl_hash_node_t *node;
|
||||||
|
|
||||||
|
HASH_FIND (hh, hashlin->buckets, old->key, old->keylen, node);
|
||||||
|
if (node != NULL) {
|
||||||
|
/* Direct replacement */
|
||||||
|
node->data = new;
|
||||||
|
node->hh.key = new->key;
|
||||||
|
node->hh.keylen = new->keylen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const void*
|
const void*
|
||||||
ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
|
ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
|
||||||
{
|
{
|
||||||
@ -122,5 +136,6 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
|
|||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
HASH_DELETE (hh, hashlin->buckets, found);
|
HASH_DELETE (hh, hashlin->buckets, found);
|
||||||
|
UCL_FREE (sizeof (ucl_hash_node_t), found);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,12 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func);
|
|||||||
void ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, const char *key,
|
void ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, const char *key,
|
||||||
unsigned keylen);
|
unsigned keylen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace element in the hash
|
||||||
|
*/
|
||||||
|
void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,
|
||||||
|
const ucl_object_t *new);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete an element from the the hashtable.
|
* Delete an element from the the hashtable.
|
||||||
*/
|
*/
|
||||||
|
@ -163,6 +163,7 @@ struct ucl_chunk {
|
|||||||
size_t remain;
|
size_t remain;
|
||||||
unsigned int line;
|
unsigned int line;
|
||||||
unsigned int column;
|
unsigned int column;
|
||||||
|
unsigned priority;
|
||||||
struct ucl_chunk *next;
|
struct ucl_chunk *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -182,7 +183,7 @@ struct ucl_variable {
|
|||||||
char *value;
|
char *value;
|
||||||
size_t var_len;
|
size_t var_len;
|
||||||
size_t value_len;
|
size_t value_len;
|
||||||
struct ucl_variable *next;
|
struct ucl_variable *prev, *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ucl_parser {
|
struct ucl_parser {
|
||||||
@ -192,6 +193,7 @@ struct ucl_parser {
|
|||||||
int flags;
|
int flags;
|
||||||
ucl_object_t *top_obj;
|
ucl_object_t *top_obj;
|
||||||
ucl_object_t *cur_obj;
|
ucl_object_t *cur_obj;
|
||||||
|
char *cur_file;
|
||||||
struct ucl_macro *macroes;
|
struct ucl_macro *macroes;
|
||||||
struct ucl_stack *stack;
|
struct ucl_stack *stack;
|
||||||
struct ucl_chunk *chunks;
|
struct ucl_chunk *chunks;
|
||||||
@ -202,6 +204,12 @@ struct ucl_parser {
|
|||||||
UT_string *err;
|
UT_string *err;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ucl_object_userdata {
|
||||||
|
ucl_object_t obj;
|
||||||
|
ucl_userdata_dtor dtor;
|
||||||
|
ucl_userdata_emitter emitter;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unescape json string inplace
|
* Unescape json string inplace
|
||||||
* @param str
|
* @param str
|
||||||
@ -216,9 +224,11 @@ size_t ucl_unescape_json_string (char *str, size_t len);
|
|||||||
* @param err error ptr
|
* @param err error ptr
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
bool ucl_include_handler (const unsigned char *data, size_t len, void* ud);
|
bool ucl_include_handler (const unsigned char *data, size_t len,
|
||||||
|
const ucl_object_t *args, void* ud);
|
||||||
|
|
||||||
bool ucl_try_include_handler (const unsigned char *data, size_t len, void* ud);
|
bool ucl_try_include_handler (const unsigned char *data, size_t len,
|
||||||
|
const ucl_object_t *args, void* ud);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle includes macro
|
* Handle includes macro
|
||||||
@ -228,7 +238,8 @@ bool ucl_try_include_handler (const unsigned char *data, size_t len, void* ud);
|
|||||||
* @param err error ptr
|
* @param err error ptr
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
bool ucl_includes_handler (const unsigned char *data, size_t len, void* ud);
|
bool ucl_includes_handler (const unsigned char *data, size_t len,
|
||||||
|
const ucl_object_t *args, void* ud);
|
||||||
|
|
||||||
size_t ucl_strlcpy (char *dst, const char *src, size_t siz);
|
size_t ucl_strlcpy (char *dst, const char *src, size_t siz);
|
||||||
size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz);
|
size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz);
|
||||||
@ -264,7 +275,7 @@ ucl_create_err (UT_string **err, const char *fmt, ...)
|
|||||||
static inline bool
|
static inline bool
|
||||||
ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t len)
|
ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t len)
|
||||||
{
|
{
|
||||||
const unsigned char *p = start;
|
const char *p = (const char *)start;
|
||||||
bool ret = false, val = false;
|
bool ret = false, val = false;
|
||||||
|
|
||||||
if (len == 5) {
|
if (len == 5) {
|
||||||
@ -351,13 +362,22 @@ const struct ucl_emitter_context *
|
|||||||
ucl_emit_get_standard_context (enum ucl_emitter emit_type);
|
ucl_emit_get_standard_context (enum ucl_emitter emit_type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialise string
|
* Serialize string as JSON string
|
||||||
* @param str string to emit
|
* @param str string to emit
|
||||||
* @param buf target buffer
|
* @param buf target buffer
|
||||||
*/
|
*/
|
||||||
void ucl_elt_string_write_json (const char *str, size_t size,
|
void ucl_elt_string_write_json (const char *str, size_t size,
|
||||||
struct ucl_emitter_context *ctx);
|
struct ucl_emitter_context *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write multiline string using `EOD` as string terminator
|
||||||
|
* @param str
|
||||||
|
* @param size
|
||||||
|
* @param ctx
|
||||||
|
*/
|
||||||
|
void ucl_elt_string_write_multiline (const char *str, size_t size,
|
||||||
|
struct ucl_emitter_context *ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit a single object to string
|
* Emit a single object to string
|
||||||
* @param obj
|
* @param obj
|
||||||
@ -365,4 +385,12 @@ void ucl_elt_string_write_json (const char *str, size_t size,
|
|||||||
*/
|
*/
|
||||||
unsigned char * ucl_object_emit_single_json (const ucl_object_t *obj);
|
unsigned char * ucl_object_emit_single_json (const ucl_object_t *obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a specified string is long and should be likely printed in
|
||||||
|
* multiline mode
|
||||||
|
* @param obj
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool ucl_maybe_long_string (const ucl_object_t *obj);
|
||||||
|
|
||||||
#endif /* UCL_INTERNAL_H_ */
|
#endif /* UCL_INTERNAL_H_ */
|
||||||
|
@ -26,8 +26,8 @@
|
|||||||
#include "ucl_chartable.h"
|
#include "ucl_chartable.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file rcl_parser.c
|
* @file ucl_parser.c
|
||||||
* The implementation of rcl parser
|
* The implementation of ucl parser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct ucl_parser_saved_state {
|
struct ucl_parser_saved_state {
|
||||||
@ -56,20 +56,33 @@ struct ucl_parser_saved_state {
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err)
|
ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err)
|
||||||
{
|
{
|
||||||
if (chunk->pos < chunk->end) {
|
const char *fmt_string, *filename;
|
||||||
if (isgraph (*chunk->pos)) {
|
struct ucl_chunk *chunk = parser->chunks;
|
||||||
ucl_create_err (err, "error on line %d at column %d: '%s', character: '%c'",
|
|
||||||
chunk->line, chunk->column, str, *chunk->pos);
|
if (parser->cur_file) {
|
||||||
}
|
filename = parser->cur_file;
|
||||||
else {
|
|
||||||
ucl_create_err (err, "error on line %d at column %d: '%s', character: '0x%02x'",
|
|
||||||
chunk->line, chunk->column, str, (int)*chunk->pos);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ucl_create_err (err, "error at the end of chunk: %s", str);
|
filename = "<unknown>";
|
||||||
|
}
|
||||||
|
if (chunk->pos < chunk->end) {
|
||||||
|
if (isgraph (*chunk->pos)) {
|
||||||
|
fmt_string = "error while parsing %s: "
|
||||||
|
"line: %d, column: %d - '%s', character: '%c'";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fmt_string = "error while parsing %s: "
|
||||||
|
"line: %d, column: %d - '%s', character: '0x%02x'";
|
||||||
|
}
|
||||||
|
ucl_create_err (err, fmt_string,
|
||||||
|
filename, chunk->line, chunk->column,
|
||||||
|
str, *chunk->pos);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ucl_create_err (err, "error while parsing %s: at the end of chunk: %s",
|
||||||
|
filename, str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,11 +97,12 @@ ucl_skip_comments (struct ucl_parser *parser)
|
|||||||
struct ucl_chunk *chunk = parser->chunks;
|
struct ucl_chunk *chunk = parser->chunks;
|
||||||
const unsigned char *p;
|
const unsigned char *p;
|
||||||
int comments_nested = 0;
|
int comments_nested = 0;
|
||||||
|
bool quoted = false;
|
||||||
|
|
||||||
p = chunk->pos;
|
p = chunk->pos;
|
||||||
|
|
||||||
start:
|
start:
|
||||||
if (*p == '#') {
|
if (chunk->remain > 0 && *p == '#') {
|
||||||
if (parser->state != UCL_STATE_SCOMMENT &&
|
if (parser->state != UCL_STATE_SCOMMENT &&
|
||||||
parser->state != UCL_STATE_MCOMMENT) {
|
parser->state != UCL_STATE_MCOMMENT) {
|
||||||
while (p < chunk->end) {
|
while (p < chunk->end) {
|
||||||
@ -100,34 +114,41 @@ ucl_skip_comments (struct ucl_parser *parser)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (*p == '/' && chunk->remain >= 2) {
|
else if (chunk->remain >= 2 && *p == '/') {
|
||||||
if (p[1] == '*') {
|
if (p[1] == '*') {
|
||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
comments_nested ++;
|
comments_nested ++;
|
||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
|
||||||
while (p < chunk->end) {
|
while (p < chunk->end) {
|
||||||
if (*p == '*') {
|
if (*p == '"' && *(p - 1) != '\\') {
|
||||||
ucl_chunk_skipc (chunk, p);
|
quoted = !quoted;
|
||||||
if (*p == '/') {
|
|
||||||
comments_nested --;
|
|
||||||
if (comments_nested == 0) {
|
|
||||||
ucl_chunk_skipc (chunk, p);
|
|
||||||
goto start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ucl_chunk_skipc (chunk, p);
|
|
||||||
}
|
}
|
||||||
else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
|
|
||||||
comments_nested ++;
|
if (!quoted) {
|
||||||
ucl_chunk_skipc (chunk, p);
|
if (*p == '*') {
|
||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
continue;
|
if (*p == '/') {
|
||||||
|
comments_nested --;
|
||||||
|
if (comments_nested == 0) {
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
}
|
||||||
|
else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
|
||||||
|
comments_nested ++;
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
}
|
}
|
||||||
if (comments_nested != 0) {
|
if (comments_nested != 0) {
|
||||||
ucl_set_err (chunk, UCL_ENESTED, "unfinished multiline comment", &parser->err);
|
ucl_set_err (parser, UCL_ENESTED,
|
||||||
|
"unfinished multiline comment", &parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -492,7 +513,8 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
|
|||||||
/* Copy string */
|
/* Copy string */
|
||||||
*dst = UCL_ALLOC (in_len + 1);
|
*dst = UCL_ALLOC (in_len + 1);
|
||||||
if (*dst == NULL) {
|
if (*dst == NULL) {
|
||||||
ucl_set_err (parser->chunks, 0, "cannot allocate memory for a string", &parser->err);
|
ucl_set_err (parser, 0, "cannot allocate memory for a string",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (need_lowercase) {
|
if (need_lowercase) {
|
||||||
@ -514,6 +536,10 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
|
|||||||
*dst = tmp;
|
*dst = tmp;
|
||||||
ret = tret;
|
ret = tret;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* Free unexpanded value */
|
||||||
|
UCL_FREE (in_len + 1, tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*dst_const = *dst;
|
*dst_const = *dst;
|
||||||
}
|
}
|
||||||
@ -539,7 +565,7 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
|
|||||||
|
|
||||||
if (!is_array) {
|
if (!is_array) {
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
obj = ucl_object_typed_new (UCL_OBJECT);
|
obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
obj->type = UCL_OBJECT;
|
obj->type = UCL_OBJECT;
|
||||||
@ -549,7 +575,7 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
obj = ucl_object_typed_new (UCL_ARRAY);
|
obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
obj->type = UCL_ARRAY;
|
obj->type = UCL_ARRAY;
|
||||||
@ -559,7 +585,9 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
|
|||||||
|
|
||||||
st = UCL_ALLOC (sizeof (struct ucl_stack));
|
st = UCL_ALLOC (sizeof (struct ucl_stack));
|
||||||
if (st == NULL) {
|
if (st == NULL) {
|
||||||
ucl_set_err (parser->chunks, 0, "cannot allocate memory for an object", &parser->err);
|
ucl_set_err (parser, 0, "cannot allocate memory for an object",
|
||||||
|
&parser->err);
|
||||||
|
ucl_object_unref (obj);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
st->obj = obj;
|
st->obj = obj;
|
||||||
@ -676,8 +704,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now check endptr */
|
/* Now check endptr */
|
||||||
if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0' ||
|
if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
|
||||||
ucl_test_character (*endptr, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
|
|
||||||
p = endptr;
|
p = endptr;
|
||||||
goto set_obj;
|
goto set_obj;
|
||||||
}
|
}
|
||||||
@ -788,8 +815,21 @@ ucl_maybe_parse_number (ucl_object_t *obj,
|
|||||||
goto set_obj;
|
goto set_obj;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case '\t':
|
||||||
|
case ' ':
|
||||||
|
while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (ucl_lex_is_atom_end(*p))
|
||||||
|
goto set_obj;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (endptr == end) {
|
||||||
|
/* Just a number at the end of chunk */
|
||||||
|
p = endptr;
|
||||||
|
goto set_obj;
|
||||||
|
}
|
||||||
|
|
||||||
*pos = c;
|
*pos = c;
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
@ -835,7 +875,7 @@ ucl_lex_number (struct ucl_parser *parser,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (ret == ERANGE) {
|
else if (ret == ERANGE) {
|
||||||
ucl_set_err (chunk, ERANGE, "numeric value out of range", &parser->err);
|
ucl_set_err (parser, ERANGE, "numeric value out of range", &parser->err);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -860,10 +900,12 @@ ucl_lex_json_string (struct ucl_parser *parser,
|
|||||||
if (c < 0x1F) {
|
if (c < 0x1F) {
|
||||||
/* Unmasked control character */
|
/* Unmasked control character */
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline",
|
||||||
|
&parser->err);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character",
|
||||||
|
&parser->err);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -871,7 +913,8 @@ ucl_lex_json_string (struct ucl_parser *parser,
|
|||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
c = *p;
|
c = *p;
|
||||||
if (p >= chunk->end) {
|
if (p >= chunk->end) {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
|
else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
|
||||||
@ -879,13 +922,15 @@ ucl_lex_json_string (struct ucl_parser *parser,
|
|||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
for (i = 0; i < 4 && p < chunk->end; i ++) {
|
for (i = 0; i < 4 && p < chunk->end; i ++) {
|
||||||
if (!isxdigit (*p)) {
|
if (!isxdigit (*p)) {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
}
|
}
|
||||||
if (p >= chunk->end) {
|
if (p >= chunk->end) {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -910,10 +955,42 @@ ucl_lex_json_string (struct ucl_parser *parser,
|
|||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
|
||||||
|
ucl_object_t *top,
|
||||||
|
ucl_object_t *elt)
|
||||||
|
{
|
||||||
|
ucl_object_t *nobj;
|
||||||
|
|
||||||
|
if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) {
|
||||||
|
/* Implicit array */
|
||||||
|
top->flags |= UCL_OBJECT_MULTIVALUE;
|
||||||
|
DL_APPEND (top, elt);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
|
||||||
|
/* Just add to the explicit array */
|
||||||
|
DL_APPEND (top->value.av, elt);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Convert to an array */
|
||||||
|
ucl_hash_delete (cont, top);
|
||||||
|
nobj = ucl_object_typed_new (UCL_ARRAY);
|
||||||
|
nobj->key = top->key;
|
||||||
|
nobj->keylen = top->keylen;
|
||||||
|
nobj->flags |= UCL_OBJECT_MULTIVALUE;
|
||||||
|
DL_APPEND (nobj->value.av, top);
|
||||||
|
DL_APPEND (nobj->value.av, elt);
|
||||||
|
ucl_hash_insert (cont, nobj, nobj->key, nobj->keylen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a key in an object
|
* Parse a key in an object
|
||||||
* @param parser
|
* @param parser
|
||||||
@ -981,7 +1058,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Invalid identifier */
|
/* Invalid identifier */
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -997,7 +1075,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1015,7 +1094,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (p >= chunk->end && got_content) {
|
if (p >= chunk->end && got_content) {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (!got_content) {
|
else if (!got_content) {
|
||||||
@ -1033,7 +1112,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
|||||||
got_eq = true;
|
got_eq = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1043,7 +1123,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
|||||||
got_semicolon = true;
|
got_semicolon = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1061,7 +1142,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (p >= chunk->end && got_content) {
|
if (p >= chunk->end && got_content) {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1096,7 +1177,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Create a new object */
|
/* Create a new object */
|
||||||
nobj = ucl_object_new ();
|
nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
|
||||||
keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
|
keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
|
||||||
&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
|
&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
|
||||||
if (keylen == -1) {
|
if (keylen == -1) {
|
||||||
@ -1104,7 +1185,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (keylen == 0) {
|
else if (keylen == 0) {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
|
||||||
ucl_object_unref (nobj);
|
ucl_object_unref (nobj);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1120,7 +1201,27 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
|||||||
parser->stack->obj->len ++;
|
parser->stack->obj->len ++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DL_APPEND (tobj, nobj);
|
/*
|
||||||
|
* The logic here is the following:
|
||||||
|
*
|
||||||
|
* - if we have two objects with the same priority, then we form an
|
||||||
|
* implicit or explicit array
|
||||||
|
* - if a new object has bigger priority, then we overwrite an old one
|
||||||
|
* - if a new object has lower priority, then we ignore it
|
||||||
|
*/
|
||||||
|
unsigned priold = ucl_object_get_priority (tobj),
|
||||||
|
prinew = ucl_object_get_priority (nobj);
|
||||||
|
if (priold == prinew) {
|
||||||
|
ucl_parser_append_elt (parser, container, tobj, nobj);
|
||||||
|
}
|
||||||
|
else if (priold > prinew) {
|
||||||
|
ucl_object_unref (nobj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ucl_hash_replace (container, tobj, nobj);
|
||||||
|
ucl_object_unref (tobj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ucl_escape) {
|
if (ucl_escape) {
|
||||||
@ -1197,11 +1298,6 @@ ucl_parse_string_value (struct ucl_parser *parser,
|
|||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p >= chunk->end) {
|
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", &parser->err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1219,7 +1315,7 @@ ucl_parse_multiline_string (struct ucl_parser *parser,
|
|||||||
int term_len, unsigned char const **beg,
|
int term_len, unsigned char const **beg,
|
||||||
bool *var_expand)
|
bool *var_expand)
|
||||||
{
|
{
|
||||||
const unsigned char *p, *c;
|
const unsigned char *p, *c, *tend;
|
||||||
bool newline = false;
|
bool newline = false;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
@ -1232,7 +1328,13 @@ ucl_parse_multiline_string (struct ucl_parser *parser,
|
|||||||
if (chunk->end - p < term_len) {
|
if (chunk->end - p < term_len) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (memcmp (p, term, term_len) == 0 && (p[term_len] == '\n' || p[term_len] == '\r')) {
|
else if (memcmp (p, term, term_len) == 0) {
|
||||||
|
tend = p + term_len;
|
||||||
|
if (*tend != '\n' && *tend != ';' && *tend != ',') {
|
||||||
|
/* Incomplete terminator */
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
len = p - c;
|
len = p - c;
|
||||||
chunk->remain -= term_len;
|
chunk->remain -= term_len;
|
||||||
chunk->pos = p + term_len;
|
chunk->pos = p + term_len;
|
||||||
@ -1263,7 +1365,7 @@ ucl_get_value_object (struct ucl_parser *parser)
|
|||||||
|
|
||||||
if (parser->stack->obj->type == UCL_ARRAY) {
|
if (parser->stack->obj->type == UCL_ARRAY) {
|
||||||
/* Object must be allocated */
|
/* Object must be allocated */
|
||||||
obj = ucl_object_new ();
|
obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
|
||||||
t = parser->stack->obj->value.av;
|
t = parser->stack->obj->value.av;
|
||||||
DL_APPEND (t, obj);
|
DL_APPEND (t, obj);
|
||||||
parser->cur_obj = obj;
|
parser->cur_obj = obj;
|
||||||
@ -1378,7 +1480,8 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
chunk->line ++;
|
chunk->line ++;
|
||||||
if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
|
if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
|
||||||
p - c, &c, &var_expand)) == 0) {
|
p - c, &c, &var_expand)) == 0) {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX,
|
||||||
|
"unterminated multiline value", &parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
obj->type = UCL_STRING;
|
obj->type = UCL_STRING;
|
||||||
@ -1423,7 +1526,8 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
}
|
}
|
||||||
str_len = chunk->pos - c - stripped_spaces;
|
str_len = chunk->pos - c - stripped_spaces;
|
||||||
if (str_len <= 0) {
|
if (str_len <= 0) {
|
||||||
ucl_set_err (chunk, 0, "string value must not be empty", &parser->err);
|
ucl_set_err (parser, 0, "string value must not be empty",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
|
else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
|
||||||
@ -1482,7 +1586,9 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
|
else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
|
||||||
if (*p == '}' || *p == ']') {
|
if (*p == '}' || *p == ']') {
|
||||||
if (parser->stack == NULL) {
|
if (parser->stack == NULL) {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "end of array or object detected without corresponding start", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX,
|
||||||
|
"end of array or object detected without corresponding start",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
|
if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
|
||||||
@ -1503,7 +1609,9 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX,
|
||||||
|
"unexpected terminating symbol detected",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1525,7 +1633,8 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
else {
|
else {
|
||||||
/* Anything else */
|
/* Anything else */
|
||||||
if (!got_sep) {
|
if (!got_sep) {
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", &parser->err);
|
ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing",
|
||||||
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -1612,6 +1721,120 @@ ucl_parse_macro_value (struct ucl_parser *parser,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse macro arguments as UCL object
|
||||||
|
* @param parser parser structure
|
||||||
|
* @param chunk the current data chunk
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static ucl_object_t *
|
||||||
|
ucl_parse_macro_arguments (struct ucl_parser *parser,
|
||||||
|
struct ucl_chunk *chunk)
|
||||||
|
{
|
||||||
|
ucl_object_t *res = NULL;
|
||||||
|
struct ucl_parser *params_parser;
|
||||||
|
int obraces = 1, ebraces = 0, state = 0;
|
||||||
|
const unsigned char *p, *c;
|
||||||
|
size_t args_len = 0;
|
||||||
|
struct ucl_parser_saved_state saved;
|
||||||
|
|
||||||
|
saved.column = chunk->column;
|
||||||
|
saved.line = chunk->line;
|
||||||
|
saved.pos = chunk->pos;
|
||||||
|
saved.remain = chunk->remain;
|
||||||
|
p = chunk->pos;
|
||||||
|
|
||||||
|
if (*p != '(' || chunk->remain < 2) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set begin and start */
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
c = p;
|
||||||
|
|
||||||
|
while ((p) < (chunk)->end) {
|
||||||
|
switch (state) {
|
||||||
|
case 0:
|
||||||
|
/* Parse symbols and check for '(', ')' and '"' */
|
||||||
|
if (*p == '(') {
|
||||||
|
obraces ++;
|
||||||
|
}
|
||||||
|
else if (*p == ')') {
|
||||||
|
ebraces ++;
|
||||||
|
}
|
||||||
|
else if (*p == '"') {
|
||||||
|
state = 1;
|
||||||
|
}
|
||||||
|
/* Check pairing */
|
||||||
|
if (obraces == ebraces) {
|
||||||
|
state = 99;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
args_len ++;
|
||||||
|
}
|
||||||
|
/* Check overflow */
|
||||||
|
if (chunk->remain == 0) {
|
||||||
|
goto restore_chunk;
|
||||||
|
}
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* We have quote character, so skip all but quotes */
|
||||||
|
if (*p == '"' && *(p - 1) != '\\') {
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
if (chunk->remain == 0) {
|
||||||
|
goto restore_chunk;
|
||||||
|
}
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
break;
|
||||||
|
case 99:
|
||||||
|
/*
|
||||||
|
* We have read the full body of arguments, so we need to parse and set
|
||||||
|
* object from that
|
||||||
|
*/
|
||||||
|
params_parser = ucl_parser_new (parser->flags);
|
||||||
|
if (!ucl_parser_add_chunk (params_parser, c, args_len)) {
|
||||||
|
ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error",
|
||||||
|
&parser->err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res = ucl_parser_get_object (params_parser);
|
||||||
|
}
|
||||||
|
ucl_parser_free (params_parser);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
restore_chunk:
|
||||||
|
chunk->column = saved.column;
|
||||||
|
chunk->line = saved.line;
|
||||||
|
chunk->pos = saved.pos;
|
||||||
|
chunk->remain = saved.remain;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SKIP_SPACES_COMMENTS(parser, chunk, p) do { \
|
||||||
|
while ((p) < (chunk)->end) { \
|
||||||
|
if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) { \
|
||||||
|
if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) { \
|
||||||
|
if (!ucl_skip_comments (parser)) { \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
p = (chunk)->pos; \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
ucl_chunk_skipc (chunk, p); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the main states of rcl parser
|
* Handle the main states of rcl parser
|
||||||
* @param parser parser structure
|
* @param parser parser structure
|
||||||
@ -1622,13 +1845,13 @@ ucl_parse_macro_value (struct ucl_parser *parser,
|
|||||||
static bool
|
static bool
|
||||||
ucl_state_machine (struct ucl_parser *parser)
|
ucl_state_machine (struct ucl_parser *parser)
|
||||||
{
|
{
|
||||||
ucl_object_t *obj;
|
ucl_object_t *obj, *macro_args;
|
||||||
struct ucl_chunk *chunk = parser->chunks;
|
struct ucl_chunk *chunk = parser->chunks;
|
||||||
const unsigned char *p, *c = NULL, *macro_start = NULL;
|
const unsigned char *p, *c = NULL, *macro_start = NULL;
|
||||||
unsigned char *macro_escaped;
|
unsigned char *macro_escaped;
|
||||||
size_t macro_len = 0;
|
size_t macro_len = 0;
|
||||||
struct ucl_macro *macro = NULL;
|
struct ucl_macro *macro = NULL;
|
||||||
bool next_key = false, end_of_object = false;
|
bool next_key = false, end_of_object = false, ret;
|
||||||
|
|
||||||
if (parser->top_obj == NULL) {
|
if (parser->top_obj == NULL) {
|
||||||
if (*chunk->pos == '[') {
|
if (*chunk->pos == '[') {
|
||||||
@ -1654,7 +1877,6 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
* if we got [ or { correspondingly or can just treat new data as
|
* if we got [ or { correspondingly or can just treat new data as
|
||||||
* a key of newly created object
|
* a key of newly created object
|
||||||
*/
|
*/
|
||||||
obj = parser->cur_obj;
|
|
||||||
if (!ucl_skip_comments (parser)) {
|
if (!ucl_skip_comments (parser)) {
|
||||||
parser->prev_state = parser->state;
|
parser->prev_state = parser->state;
|
||||||
parser->state = UCL_STATE_ERROR;
|
parser->state = UCL_STATE_ERROR;
|
||||||
@ -1691,7 +1913,7 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
}
|
}
|
||||||
if (parser->stack == NULL) {
|
if (parser->stack == NULL) {
|
||||||
/* No objects are on stack, but we want to parse a key */
|
/* No objects are on stack, but we want to parse a key */
|
||||||
ucl_set_err (chunk, UCL_ESYNTAX, "top object is finished but the parser "
|
ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser "
|
||||||
"expects a key", &parser->err);
|
"expects a key", &parser->err);
|
||||||
parser->prev_state = parser->state;
|
parser->prev_state = parser->state;
|
||||||
parser->state = UCL_STATE_ERROR;
|
parser->state = UCL_STATE_ERROR;
|
||||||
@ -1757,7 +1979,8 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
p = chunk->pos;
|
p = chunk->pos;
|
||||||
break;
|
break;
|
||||||
case UCL_STATE_MACRO_NAME:
|
case UCL_STATE_MACRO_NAME:
|
||||||
if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
|
if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
|
||||||
|
*p != '(') {
|
||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
}
|
}
|
||||||
else if (p - c > 0) {
|
else if (p - c > 0) {
|
||||||
@ -1772,48 +1995,51 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* Now we need to skip all spaces */
|
/* Now we need to skip all spaces */
|
||||||
while (p < chunk->end) {
|
SKIP_SPACES_COMMENTS(parser, chunk, p);
|
||||||
if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
|
|
||||||
if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
|
|
||||||
/* Skip comment */
|
|
||||||
if (!ucl_skip_comments (parser)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
p = chunk->pos;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ucl_chunk_skipc (chunk, p);
|
|
||||||
}
|
|
||||||
parser->state = UCL_STATE_MACRO;
|
parser->state = UCL_STATE_MACRO;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case UCL_STATE_MACRO:
|
case UCL_STATE_MACRO:
|
||||||
|
if (*chunk->pos == '(') {
|
||||||
|
macro_args = ucl_parse_macro_arguments (parser, chunk);
|
||||||
|
p = chunk->pos;
|
||||||
|
if (macro_args) {
|
||||||
|
SKIP_SPACES_COMMENTS(parser, chunk, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
macro_args = NULL;
|
||||||
|
}
|
||||||
if (!ucl_parse_macro_value (parser, chunk, macro,
|
if (!ucl_parse_macro_value (parser, chunk, macro,
|
||||||
¯o_start, ¯o_len)) {
|
¯o_start, ¯o_len)) {
|
||||||
parser->prev_state = parser->state;
|
parser->prev_state = parser->state;
|
||||||
parser->state = UCL_STATE_ERROR;
|
parser->state = UCL_STATE_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
macro_len = ucl_expand_variable (parser, ¯o_escaped, macro_start, macro_len);
|
macro_len = ucl_expand_variable (parser, ¯o_escaped,
|
||||||
|
macro_start, macro_len);
|
||||||
parser->state = parser->prev_state;
|
parser->state = parser->prev_state;
|
||||||
if (macro_escaped == NULL) {
|
if (macro_escaped == NULL) {
|
||||||
if (!macro->handler (macro_start, macro_len, macro->ud)) {
|
ret = macro->handler (macro_start, macro_len, macro_args,
|
||||||
return false;
|
macro->ud);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!macro->handler (macro_escaped, macro_len, macro->ud)) {
|
ret = macro->handler (macro_escaped, macro_len, macro_args,
|
||||||
UCL_FREE (macro_len + 1, macro_escaped);
|
macro->ud);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
UCL_FREE (macro_len + 1, macro_escaped);
|
UCL_FREE (macro_len + 1, macro_escaped);
|
||||||
}
|
}
|
||||||
p = chunk->pos;
|
p = chunk->pos;
|
||||||
|
if (macro_args) {
|
||||||
|
ucl_object_unref (macro_args);
|
||||||
|
}
|
||||||
|
if (!ret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* TODO: add all states */
|
/* TODO: add all states */
|
||||||
ucl_set_err (chunk, UCL_EINTERNAL, "internal error: parser is in an unknown state", &parser->err);
|
ucl_set_err (parser, UCL_EINTERNAL,
|
||||||
|
"internal error: parser is in an unknown state", &parser->err);
|
||||||
parser->state = UCL_STATE_ERROR;
|
parser->state = UCL_STATE_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1888,7 +2114,7 @@ ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
|
|||||||
|
|
||||||
if (new != NULL) {
|
if (new != NULL) {
|
||||||
/* Remove variable */
|
/* Remove variable */
|
||||||
LL_DELETE (parser->variables, new);
|
DL_DELETE (parser->variables, new);
|
||||||
free (new->var);
|
free (new->var);
|
||||||
free (new->value);
|
free (new->value);
|
||||||
UCL_FREE (sizeof (struct ucl_variable), new);
|
UCL_FREE (sizeof (struct ucl_variable), new);
|
||||||
@ -1910,7 +2136,7 @@ ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
|
|||||||
new->value = strdup (value);
|
new->value = strdup (value);
|
||||||
new->value_len = strlen (value);
|
new->value_len = strlen (value);
|
||||||
|
|
||||||
LL_PREPEND (parser->variables, new);
|
DL_APPEND (parser->variables, new);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
free (new->value);
|
free (new->value);
|
||||||
@ -1929,15 +2155,19 @@ ucl_parser_set_variables_handler (struct ucl_parser *parser,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
|
ucl_parser_add_chunk_priority (struct ucl_parser *parser, const unsigned char *data,
|
||||||
size_t len)
|
size_t len, unsigned priority)
|
||||||
{
|
{
|
||||||
struct ucl_chunk *chunk;
|
struct ucl_chunk *chunk;
|
||||||
|
|
||||||
if (data == NULL || len == 0) {
|
if (data == NULL) {
|
||||||
ucl_create_err (&parser->err, "invalid chunk added");
|
ucl_create_err (&parser->err, "invalid chunk added");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (len == 0) {
|
||||||
|
parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (parser->state != UCL_STATE_ERROR) {
|
if (parser->state != UCL_STATE_ERROR) {
|
||||||
chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
|
chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
|
||||||
if (chunk == NULL) {
|
if (chunk == NULL) {
|
||||||
@ -1950,6 +2180,7 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
|
|||||||
chunk->end = chunk->begin + len;
|
chunk->end = chunk->begin + len;
|
||||||
chunk->line = 1;
|
chunk->line = 1;
|
||||||
chunk->column = 0;
|
chunk->column = 0;
|
||||||
|
chunk->priority = priority;
|
||||||
LL_PREPEND (parser->chunks, chunk);
|
LL_PREPEND (parser->chunks, chunk);
|
||||||
parser->recursion ++;
|
parser->recursion ++;
|
||||||
if (parser->recursion > UCL_MAX_RECURSION) {
|
if (parser->recursion > UCL_MAX_RECURSION) {
|
||||||
@ -1965,6 +2196,13 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
return ucl_parser_add_chunk_priority (parser, data, len, 0);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ucl_parser_add_string (struct ucl_parser *parser, const char *data,
|
ucl_parser_add_string (struct ucl_parser *parser, const char *data,
|
||||||
size_t len)
|
size_t len)
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include "ucl_internal.h"
|
#include "ucl_internal.h"
|
||||||
#include "ucl_chartable.h"
|
#include "ucl_chartable.h"
|
||||||
|
|
||||||
|
#include <glob.h>
|
||||||
|
|
||||||
#ifdef HAVE_LIBGEN_H
|
#ifdef HAVE_LIBGEN_H
|
||||||
#include <libgen.h> /* For dirname */
|
#include <libgen.h> /* For dirname */
|
||||||
#endif
|
#endif
|
||||||
@ -129,11 +131,6 @@ static char* ucl_realpath(const char *path, char *resolved_path) {
|
|||||||
#define ucl_realpath realpath
|
#define ucl_realpath realpath
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* @file rcl_util.c
|
|
||||||
* Utilities for rcl parsing
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef void (*ucl_object_dtor) (ucl_object_t *obj);
|
typedef void (*ucl_object_dtor) (ucl_object_t *obj);
|
||||||
static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec,
|
static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec,
|
||||||
ucl_object_dtor dtor);
|
ucl_object_dtor dtor);
|
||||||
@ -148,7 +145,19 @@ ucl_object_dtor_free (ucl_object_t *obj)
|
|||||||
if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
|
if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
|
||||||
UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
|
UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
|
||||||
}
|
}
|
||||||
UCL_FREE (sizeof (ucl_object_t), obj);
|
/* Do not free ephemeral objects */
|
||||||
|
if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) {
|
||||||
|
if (obj->type != UCL_USERDATA) {
|
||||||
|
UCL_FREE (sizeof (ucl_object_t), obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj;
|
||||||
|
if (ud->dtor) {
|
||||||
|
ud->dtor (obj->value.ud);
|
||||||
|
}
|
||||||
|
UCL_FREE (sizeof (*ud), obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -423,7 +432,11 @@ ucl_parser_free (struct ucl_parser *parser)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parser->err != NULL) {
|
if (parser->err != NULL) {
|
||||||
utstring_free(parser->err);
|
utstring_free (parser->err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser->cur_file) {
|
||||||
|
free (parser->cur_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
UCL_FREE (sizeof (struct ucl_parser), parser);
|
UCL_FREE (sizeof (struct ucl_parser), parser);
|
||||||
@ -701,7 +714,8 @@ ucl_sig_check (const unsigned char *data, size_t datalen,
|
|||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
ucl_include_url (const unsigned char *data, size_t len,
|
ucl_include_url (const unsigned char *data, size_t len,
|
||||||
struct ucl_parser *parser, bool check_signature, bool must_exist)
|
struct ucl_parser *parser, bool check_signature, bool must_exist,
|
||||||
|
unsigned priority)
|
||||||
{
|
{
|
||||||
|
|
||||||
bool res;
|
bool res;
|
||||||
@ -744,7 +758,7 @@ ucl_include_url (const unsigned char *data, size_t len,
|
|||||||
prev_state = parser->state;
|
prev_state = parser->state;
|
||||||
parser->state = UCL_STATE_INIT;
|
parser->state = UCL_STATE_INIT;
|
||||||
|
|
||||||
res = ucl_parser_add_chunk (parser, buf, buflen);
|
res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority);
|
||||||
if (res == true) {
|
if (res == true) {
|
||||||
/* Remove chunk from the stack */
|
/* Remove chunk from the stack */
|
||||||
chunk = parser->chunks;
|
chunk = parser->chunks;
|
||||||
@ -761,23 +775,30 @@ ucl_include_url (const unsigned char *data, size_t len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Include a file to configuration
|
* Include a single file to the parser
|
||||||
* @param data
|
* @param data
|
||||||
* @param len
|
* @param len
|
||||||
* @param parser
|
* @param parser
|
||||||
* @param err
|
* @param check_signature
|
||||||
|
* @param must_exist
|
||||||
|
* @param allow_glob
|
||||||
|
* @param priority
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
ucl_include_file (const unsigned char *data, size_t len,
|
ucl_include_file_single (const unsigned char *data, size_t len,
|
||||||
struct ucl_parser *parser, bool check_signature, bool must_exist)
|
struct ucl_parser *parser, bool check_signature, bool must_exist,
|
||||||
|
unsigned priority)
|
||||||
{
|
{
|
||||||
bool res;
|
bool res;
|
||||||
struct ucl_chunk *chunk;
|
struct ucl_chunk *chunk;
|
||||||
unsigned char *buf = NULL;
|
unsigned char *buf = NULL;
|
||||||
|
char *old_curfile;
|
||||||
size_t buflen;
|
size_t buflen;
|
||||||
char filebuf[PATH_MAX], realbuf[PATH_MAX];
|
char filebuf[PATH_MAX], realbuf[PATH_MAX];
|
||||||
int prev_state;
|
int prev_state;
|
||||||
|
struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL,
|
||||||
|
*old_filename = NULL;
|
||||||
|
|
||||||
snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
|
snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
|
||||||
if (ucl_realpath (filebuf, realbuf) == NULL) {
|
if (ucl_realpath (filebuf, realbuf) == NULL) {
|
||||||
@ -790,6 +811,13 @@ ucl_include_file (const unsigned char *data, size_t len,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) {
|
||||||
|
/* We are likely including the file itself */
|
||||||
|
ucl_create_err (&parser->err, "trying to include the file %s from itself",
|
||||||
|
realbuf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) {
|
if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) {
|
||||||
return (!must_exist || false);
|
return (!must_exist || false);
|
||||||
}
|
}
|
||||||
@ -818,19 +846,66 @@ ucl_include_file (const unsigned char *data, size_t len,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
old_curfile = parser->cur_file;
|
||||||
|
parser->cur_file = strdup (realbuf);
|
||||||
|
|
||||||
|
/* Store old file vars */
|
||||||
|
DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
|
||||||
|
if (strcmp (cur_var->var, "CURDIR") == 0) {
|
||||||
|
old_curdir = cur_var;
|
||||||
|
DL_DELETE (parser->variables, cur_var);
|
||||||
|
}
|
||||||
|
else if (strcmp (cur_var->var, "FILENAME") == 0) {
|
||||||
|
old_filename = cur_var;
|
||||||
|
DL_DELETE (parser->variables, cur_var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ucl_parser_set_filevars (parser, realbuf, false);
|
ucl_parser_set_filevars (parser, realbuf, false);
|
||||||
|
|
||||||
prev_state = parser->state;
|
prev_state = parser->state;
|
||||||
parser->state = UCL_STATE_INIT;
|
parser->state = UCL_STATE_INIT;
|
||||||
|
|
||||||
res = ucl_parser_add_chunk (parser, buf, buflen);
|
res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority);
|
||||||
if (res == true) {
|
if (!res && !must_exist) {
|
||||||
/* Remove chunk from the stack */
|
/* Free error */
|
||||||
chunk = parser->chunks;
|
utstring_free (parser->err);
|
||||||
if (chunk != NULL) {
|
parser->err = NULL;
|
||||||
parser->chunks = chunk->next;
|
parser->state = UCL_STATE_AFTER_VALUE;
|
||||||
UCL_FREE (sizeof (struct ucl_chunk), chunk);
|
}
|
||||||
|
|
||||||
|
/* Remove chunk from the stack */
|
||||||
|
chunk = parser->chunks;
|
||||||
|
if (chunk != NULL) {
|
||||||
|
parser->chunks = chunk->next;
|
||||||
|
UCL_FREE (sizeof (struct ucl_chunk), chunk);
|
||||||
|
parser->recursion --;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore old file vars */
|
||||||
|
parser->cur_file = old_curfile;
|
||||||
|
DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
|
||||||
|
if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) {
|
||||||
|
DL_DELETE (parser->variables, cur_var);
|
||||||
|
free (cur_var->var);
|
||||||
|
free (cur_var->value);
|
||||||
|
UCL_FREE (sizeof (struct ucl_variable), cur_var);
|
||||||
}
|
}
|
||||||
|
else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) {
|
||||||
|
DL_DELETE (parser->variables, cur_var);
|
||||||
|
free (cur_var->var);
|
||||||
|
free (cur_var->value);
|
||||||
|
UCL_FREE (sizeof (struct ucl_variable), cur_var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (old_filename) {
|
||||||
|
DL_APPEND (parser->variables, old_filename);
|
||||||
|
}
|
||||||
|
if (old_curdir) {
|
||||||
|
DL_APPEND (parser->variables, old_curdir);
|
||||||
|
}
|
||||||
|
if (old_curfile) {
|
||||||
|
free (old_curfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
parser->state = prev_state;
|
parser->state = prev_state;
|
||||||
@ -842,6 +917,138 @@ ucl_include_file (const unsigned char *data, size_t len,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include a file to configuration
|
||||||
|
* @param data
|
||||||
|
* @param len
|
||||||
|
* @param parser
|
||||||
|
* @param err
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ucl_include_file (const unsigned char *data, size_t len,
|
||||||
|
struct ucl_parser *parser, bool check_signature, bool must_exist,
|
||||||
|
bool allow_glob, unsigned priority)
|
||||||
|
{
|
||||||
|
const unsigned char *p = data, *end = data + len;
|
||||||
|
bool need_glob = false;
|
||||||
|
int cnt = 0;
|
||||||
|
glob_t globbuf;
|
||||||
|
char glob_pattern[PATH_MAX];
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!allow_glob) {
|
||||||
|
return ucl_include_file_single (data, len, parser, check_signature,
|
||||||
|
must_exist, priority);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Check for special symbols in a filename */
|
||||||
|
while (p != end) {
|
||||||
|
if (*p == '*' || *p == '?') {
|
||||||
|
need_glob = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p ++;
|
||||||
|
}
|
||||||
|
if (need_glob) {
|
||||||
|
memset (&globbuf, 0, sizeof (globbuf));
|
||||||
|
ucl_strlcpy (glob_pattern, (const char *)data, sizeof (glob_pattern));
|
||||||
|
if (glob (glob_pattern, 0, NULL, &globbuf) != 0) {
|
||||||
|
return (!must_exist || false);
|
||||||
|
}
|
||||||
|
for (i = 0; i < globbuf.gl_pathc; i ++) {
|
||||||
|
if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i],
|
||||||
|
strlen (globbuf.gl_pathv[i]), parser, check_signature,
|
||||||
|
must_exist, priority)) {
|
||||||
|
globfree (&globbuf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cnt ++;
|
||||||
|
}
|
||||||
|
globfree (&globbuf);
|
||||||
|
|
||||||
|
if (cnt == 0 && must_exist) {
|
||||||
|
ucl_create_err (&parser->err, "cannot match any files for pattern %s",
|
||||||
|
glob_pattern);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ucl_include_file_single (data, len, parser, check_signature,
|
||||||
|
must_exist, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common function to handle .*include* macros
|
||||||
|
* @param data
|
||||||
|
* @param len
|
||||||
|
* @param args
|
||||||
|
* @param parser
|
||||||
|
* @param default_try
|
||||||
|
* @param default_sign
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ucl_include_common (const unsigned char *data, size_t len,
|
||||||
|
const ucl_object_t *args, struct ucl_parser *parser,
|
||||||
|
bool default_try,
|
||||||
|
bool default_sign)
|
||||||
|
{
|
||||||
|
bool try_load, allow_glob, allow_url, need_sign;
|
||||||
|
unsigned priority;
|
||||||
|
const ucl_object_t *param;
|
||||||
|
ucl_object_iter_t it = NULL;
|
||||||
|
|
||||||
|
/* Default values */
|
||||||
|
try_load = default_try;
|
||||||
|
allow_glob = false;
|
||||||
|
allow_url = true;
|
||||||
|
need_sign = default_sign;
|
||||||
|
priority = 0;
|
||||||
|
|
||||||
|
/* Process arguments */
|
||||||
|
if (args != NULL && args->type == UCL_OBJECT) {
|
||||||
|
while ((param = ucl_iterate_object (args, &it, true)) != NULL) {
|
||||||
|
if (param->type == UCL_BOOLEAN) {
|
||||||
|
if (strcmp (param->key, "try") == 0) {
|
||||||
|
try_load = ucl_object_toboolean (param);
|
||||||
|
}
|
||||||
|
else if (strcmp (param->key, "sign") == 0) {
|
||||||
|
need_sign = ucl_object_toboolean (param);
|
||||||
|
}
|
||||||
|
else if (strcmp (param->key, "glob") == 0) {
|
||||||
|
allow_glob = ucl_object_toboolean (param);
|
||||||
|
}
|
||||||
|
else if (strcmp (param->key, "url") == 0) {
|
||||||
|
allow_url = ucl_object_toboolean (param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (param->type == UCL_INT) {
|
||||||
|
if (strcmp (param->key, "priority") == 0) {
|
||||||
|
priority = ucl_object_toint (param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*data == '/' || *data == '.') {
|
||||||
|
/* Try to load a file */
|
||||||
|
return ucl_include_file (data, len, parser, need_sign, !try_load,
|
||||||
|
allow_glob, priority);
|
||||||
|
}
|
||||||
|
else if (allow_url) {
|
||||||
|
/* Globbing is not used for URL's */
|
||||||
|
return ucl_include_url (data, len, parser, need_sign, !try_load,
|
||||||
|
priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle include macro
|
* Handle include macro
|
||||||
* @param data include data
|
* @param data include data
|
||||||
@ -851,16 +1058,12 @@ ucl_include_file (const unsigned char *data, size_t len,
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN bool
|
UCL_EXTERN bool
|
||||||
ucl_include_handler (const unsigned char *data, size_t len, void* ud)
|
ucl_include_handler (const unsigned char *data, size_t len,
|
||||||
|
const ucl_object_t *args, void* ud)
|
||||||
{
|
{
|
||||||
struct ucl_parser *parser = ud;
|
struct ucl_parser *parser = ud;
|
||||||
|
|
||||||
if (*data == '/' || *data == '.') {
|
return ucl_include_common (data, len, args, parser, false, false);
|
||||||
/* Try to load a file */
|
|
||||||
return ucl_include_file (data, len, parser, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ucl_include_url (data, len, parser, false, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -872,30 +1075,22 @@ ucl_include_handler (const unsigned char *data, size_t len, void* ud)
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN bool
|
UCL_EXTERN bool
|
||||||
ucl_includes_handler (const unsigned char *data, size_t len, void* ud)
|
ucl_includes_handler (const unsigned char *data, size_t len,
|
||||||
|
const ucl_object_t *args, void* ud)
|
||||||
{
|
{
|
||||||
struct ucl_parser *parser = ud;
|
struct ucl_parser *parser = ud;
|
||||||
|
|
||||||
if (*data == '/' || *data == '.') {
|
return ucl_include_common (data, len, args, parser, false, true);
|
||||||
/* Try to load a file */
|
|
||||||
return ucl_include_file (data, len, parser, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ucl_include_url (data, len, parser, true, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UCL_EXTERN bool
|
UCL_EXTERN bool
|
||||||
ucl_try_include_handler (const unsigned char *data, size_t len, void* ud)
|
ucl_try_include_handler (const unsigned char *data, size_t len,
|
||||||
|
const ucl_object_t *args, void* ud)
|
||||||
{
|
{
|
||||||
struct ucl_parser *parser = ud;
|
struct ucl_parser *parser = ud;
|
||||||
|
|
||||||
if (*data == '/' || *data == '.') {
|
return ucl_include_common (data, len, args, parser, true, false);
|
||||||
/* Try to load a file */
|
|
||||||
return ucl_include_file (data, len, parser, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ucl_include_url (data, len, parser, false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UCL_EXTERN bool
|
UCL_EXTERN bool
|
||||||
@ -947,6 +1142,10 @@ ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parser->cur_file) {
|
||||||
|
free (parser->cur_file);
|
||||||
|
}
|
||||||
|
parser->cur_file = strdup (realbuf);
|
||||||
ucl_parser_set_filevars (parser, realbuf, false);
|
ucl_parser_set_filevars (parser, realbuf, false);
|
||||||
ret = ucl_parser_add_chunk (parser, buf, len);
|
ret = ucl_parser_add_chunk (parser, buf, len);
|
||||||
|
|
||||||
@ -957,6 +1156,39 @@ ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UCL_EXTERN bool
|
||||||
|
ucl_parser_add_fd (struct ucl_parser *parser, int fd)
|
||||||
|
{
|
||||||
|
unsigned char *buf;
|
||||||
|
size_t len;
|
||||||
|
bool ret;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (fstat (fd, &st) == -1) {
|
||||||
|
ucl_create_err (&parser->err, "cannot stat fd %d: %s",
|
||||||
|
fd, strerror (errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
|
||||||
|
ucl_create_err (&parser->err, "cannot mmap fd %d: %s",
|
||||||
|
fd, strerror (errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser->cur_file) {
|
||||||
|
free (parser->cur_file);
|
||||||
|
}
|
||||||
|
parser->cur_file = NULL;
|
||||||
|
len = st.st_size;
|
||||||
|
ret = ucl_parser_add_chunk (parser, buf, len);
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
ucl_munmap (buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ucl_strlcpy (char *dst, const char *src, size_t siz)
|
ucl_strlcpy (char *dst, const char *src, size_t siz)
|
||||||
{
|
{
|
||||||
@ -1176,6 +1408,15 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* workaround for some use cases */
|
||||||
|
if (elt->trash_stack[UCL_TRASH_KEY] != NULL &&
|
||||||
|
key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) {
|
||||||
|
/* Remove copied key */
|
||||||
|
free (elt->trash_stack[UCL_TRASH_KEY]);
|
||||||
|
elt->trash_stack[UCL_TRASH_KEY] = NULL;
|
||||||
|
elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
elt->key = key;
|
elt->key = key;
|
||||||
elt->keylen = keylen;
|
elt->keylen = keylen;
|
||||||
|
|
||||||
@ -1185,9 +1426,8 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
|
|||||||
|
|
||||||
found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));
|
found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));
|
||||||
|
|
||||||
if (!found) {
|
if (found == NULL) {
|
||||||
top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
|
top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
|
||||||
DL_APPEND (found, elt);
|
|
||||||
top->len ++;
|
top->len ++;
|
||||||
if (replace) {
|
if (replace) {
|
||||||
ret = false;
|
ret = false;
|
||||||
@ -1195,11 +1435,8 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (replace) {
|
if (replace) {
|
||||||
ucl_hash_delete (top->value.ov, found);
|
ucl_hash_replace (top->value.ov, found, elt);
|
||||||
ucl_object_unref (found);
|
ucl_object_unref (found);
|
||||||
top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
|
|
||||||
found = NULL;
|
|
||||||
DL_APPEND (found, elt);
|
|
||||||
}
|
}
|
||||||
else if (merge) {
|
else if (merge) {
|
||||||
if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
|
if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
|
||||||
@ -1310,6 +1547,40 @@ ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
|
|||||||
return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
|
return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
|
||||||
|
{
|
||||||
|
ucl_object_t *cur = NULL, *cp = NULL, *found = NULL;
|
||||||
|
ucl_object_iter_t iter = NULL;
|
||||||
|
|
||||||
|
if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mix two hashes */
|
||||||
|
while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) {
|
||||||
|
if (copy) {
|
||||||
|
cp = ucl_object_copy (cur);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cp = ucl_object_ref (cur);
|
||||||
|
}
|
||||||
|
found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen));
|
||||||
|
if (found == NULL) {
|
||||||
|
/* The key does not exist */
|
||||||
|
top->value.ov = ucl_hash_insert_object (top->value.ov, cp);
|
||||||
|
top->len ++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* The key already exists, replace it */
|
||||||
|
ucl_hash_replace (top->value.ov, found, cp);
|
||||||
|
ucl_object_unref (found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const ucl_object_t *
|
const ucl_object_t *
|
||||||
ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen)
|
ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen)
|
||||||
{
|
{
|
||||||
@ -1372,9 +1643,6 @@ ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan
|
|||||||
elt = *iter;
|
elt = *iter;
|
||||||
if (elt == NULL) {
|
if (elt == NULL) {
|
||||||
elt = obj;
|
elt = obj;
|
||||||
if (elt == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (elt == obj) {
|
else if (elt == obj) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1442,29 +1710,59 @@ ucl_lookup_path (const ucl_object_t *top, const char *path_in) {
|
|||||||
ucl_object_t *
|
ucl_object_t *
|
||||||
ucl_object_new (void)
|
ucl_object_new (void)
|
||||||
{
|
{
|
||||||
ucl_object_t *new;
|
return ucl_object_typed_new (UCL_NULL);
|
||||||
new = malloc (sizeof (ucl_object_t));
|
|
||||||
if (new != NULL) {
|
|
||||||
memset (new, 0, sizeof (ucl_object_t));
|
|
||||||
new->ref = 1;
|
|
||||||
new->type = UCL_NULL;
|
|
||||||
}
|
|
||||||
return new;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ucl_object_t *
|
ucl_object_t *
|
||||||
ucl_object_typed_new (ucl_type_t type)
|
ucl_object_typed_new (ucl_type_t type)
|
||||||
|
{
|
||||||
|
return ucl_object_new_full (type, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ucl_object_t *
|
||||||
|
ucl_object_new_full (ucl_type_t type, unsigned priority)
|
||||||
{
|
{
|
||||||
ucl_object_t *new;
|
ucl_object_t *new;
|
||||||
new = malloc (sizeof (ucl_object_t));
|
|
||||||
if (new != NULL) {
|
if (type != UCL_USERDATA) {
|
||||||
memset (new, 0, sizeof (ucl_object_t));
|
new = UCL_ALLOC (sizeof (ucl_object_t));
|
||||||
new->ref = 1;
|
if (new != NULL) {
|
||||||
new->type = (type <= UCL_NULL ? type : UCL_NULL);
|
memset (new, 0, sizeof (ucl_object_t));
|
||||||
|
new->ref = 1;
|
||||||
|
new->type = (type <= UCL_NULL ? type : UCL_NULL);
|
||||||
|
new->next = NULL;
|
||||||
|
new->prev = new;
|
||||||
|
ucl_object_set_priority (new, priority);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
new = ucl_object_new_userdata (NULL, NULL);
|
||||||
|
ucl_object_set_priority (new, priority);
|
||||||
|
}
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ucl_object_t*
|
||||||
|
ucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter)
|
||||||
|
{
|
||||||
|
struct ucl_object_userdata *new;
|
||||||
|
size_t nsize = sizeof (*new);
|
||||||
|
|
||||||
|
new = UCL_ALLOC (nsize);
|
||||||
|
if (new != NULL) {
|
||||||
|
memset (new, 0, nsize);
|
||||||
|
new->obj.ref = 1;
|
||||||
|
new->obj.type = UCL_USERDATA;
|
||||||
|
new->obj.next = NULL;
|
||||||
|
new->obj.prev = (ucl_object_t *)new;
|
||||||
|
new->dtor = dtor;
|
||||||
|
new->emitter = emitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ucl_object_t *)new;
|
||||||
|
}
|
||||||
|
|
||||||
ucl_type_t
|
ucl_type_t
|
||||||
ucl_object_type (const ucl_object_t *obj)
|
ucl_object_type (const ucl_object_t *obj)
|
||||||
{
|
{
|
||||||
@ -1576,6 +1874,30 @@ ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
|
||||||
|
{
|
||||||
|
ucl_object_t *cur, *tmp, *cp;
|
||||||
|
|
||||||
|
if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE (elt->value.av, cur, tmp) {
|
||||||
|
if (copy) {
|
||||||
|
cp = ucl_object_copy (cur);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cp = ucl_object_ref (cur);
|
||||||
|
}
|
||||||
|
if (cp != NULL) {
|
||||||
|
ucl_array_append (top, cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
ucl_object_t *
|
ucl_object_t *
|
||||||
ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
|
ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
|
||||||
{
|
{
|
||||||
@ -1660,6 +1982,28 @@ ucl_array_find_index (const ucl_object_t *top, unsigned int index)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ucl_object_t *
|
||||||
|
ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
|
||||||
|
unsigned int index)
|
||||||
|
{
|
||||||
|
ucl_object_t *cur, *tmp;
|
||||||
|
|
||||||
|
if (top == NULL || top->type != UCL_ARRAY || elt == NULL ||
|
||||||
|
top->len == 0 || (index + 1) > top->len) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DL_FOREACH_SAFE (top->value.av, cur, tmp) {
|
||||||
|
if (index == 0) {
|
||||||
|
DL_REPLACE_ELEM (top->value.av, cur, elt);
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
--index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ucl_object_t *
|
ucl_object_t *
|
||||||
ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
|
ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
|
||||||
{
|
{
|
||||||
@ -1849,16 +2193,99 @@ ucl_object_ref (const ucl_object_t *obj)
|
|||||||
ucl_object_t *res = NULL;
|
ucl_object_t *res = NULL;
|
||||||
|
|
||||||
if (obj != NULL) {
|
if (obj != NULL) {
|
||||||
res = __DECONST (ucl_object_t *, obj);
|
if (obj->flags & UCL_OBJECT_EPHEMERAL) {
|
||||||
|
/*
|
||||||
|
* Use deep copy for ephemeral objects, note that its refcount
|
||||||
|
* is NOT increased, since ephemeral objects does not need refcount
|
||||||
|
* at all
|
||||||
|
*/
|
||||||
|
res = ucl_object_copy (obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res = __DECONST (ucl_object_t *, obj);
|
||||||
#ifdef HAVE_ATOMIC_BUILTINS
|
#ifdef HAVE_ATOMIC_BUILTINS
|
||||||
(void)__sync_add_and_fetch (&res->ref, 1);
|
(void)__sync_add_and_fetch (&res->ref, 1);
|
||||||
#else
|
#else
|
||||||
res->ref ++;
|
res->ref ++;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ucl_object_t *
|
||||||
|
ucl_object_copy_internal (const ucl_object_t *other, bool allow_array)
|
||||||
|
{
|
||||||
|
|
||||||
|
ucl_object_t *new;
|
||||||
|
ucl_object_iter_t it = NULL;
|
||||||
|
const ucl_object_t *cur;
|
||||||
|
|
||||||
|
new = malloc (sizeof (*new));
|
||||||
|
|
||||||
|
if (new != NULL) {
|
||||||
|
memcpy (new, other, sizeof (*new));
|
||||||
|
if (other->flags & UCL_OBJECT_EPHEMERAL) {
|
||||||
|
/* Copied object is always non ephemeral */
|
||||||
|
new->flags &= ~UCL_OBJECT_EPHEMERAL;
|
||||||
|
}
|
||||||
|
new->ref = 1;
|
||||||
|
/* Unlink from others */
|
||||||
|
new->next = NULL;
|
||||||
|
new->prev = new;
|
||||||
|
|
||||||
|
/* deep copy of values stored */
|
||||||
|
if (other->trash_stack[UCL_TRASH_KEY] != NULL) {
|
||||||
|
new->trash_stack[UCL_TRASH_KEY] =
|
||||||
|
strdup (other->trash_stack[UCL_TRASH_KEY]);
|
||||||
|
if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) {
|
||||||
|
new->key = new->trash_stack[UCL_TRASH_KEY];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (other->trash_stack[UCL_TRASH_VALUE] != NULL) {
|
||||||
|
new->trash_stack[UCL_TRASH_VALUE] =
|
||||||
|
strdup (other->trash_stack[UCL_TRASH_VALUE]);
|
||||||
|
if (new->type == UCL_STRING) {
|
||||||
|
new->value.sv = new->trash_stack[UCL_TRASH_VALUE];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) {
|
||||||
|
/* reset old value */
|
||||||
|
memset (&new->value, 0, sizeof (new->value));
|
||||||
|
|
||||||
|
while ((cur = ucl_iterate_object (other, &it, true)) != NULL) {
|
||||||
|
if (other->type == UCL_ARRAY) {
|
||||||
|
ucl_array_append (new, ucl_object_copy_internal (cur, false));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ucl_object_t *cp = ucl_object_copy_internal (cur, true);
|
||||||
|
if (cp != NULL) {
|
||||||
|
ucl_object_insert_key (new, cp, cp->key, cp->keylen,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (allow_array && other->next != NULL) {
|
||||||
|
LL_FOREACH (other->next, cur) {
|
||||||
|
ucl_object_t *cp = ucl_object_copy_internal (cur, false);
|
||||||
|
if (cp != NULL) {
|
||||||
|
DL_APPEND (new, cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
ucl_object_t *
|
||||||
|
ucl_object_copy (const ucl_object_t *other)
|
||||||
|
{
|
||||||
|
return ucl_object_copy_internal (other, true);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ucl_object_unref (ucl_object_t *obj)
|
ucl_object_unref (ucl_object_t *obj)
|
||||||
{
|
{
|
||||||
@ -1956,3 +2383,25 @@ ucl_object_array_sort (ucl_object_t *ar,
|
|||||||
|
|
||||||
DL_SORT (ar->value.av, cmp);
|
DL_SORT (ar->value.av, cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PRIOBITS 4
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
ucl_object_get_priority (const ucl_object_t *obj)
|
||||||
|
{
|
||||||
|
if (obj == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ucl_object_set_priority (ucl_object_t *obj,
|
||||||
|
unsigned int priority)
|
||||||
|
{
|
||||||
|
if (obj != NULL) {
|
||||||
|
priority &= (0x1 << PRIOBITS) - 1;
|
||||||
|
obj->flags |= priority << ((sizeof (obj->flags) * NBBY) - PRIOBITS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
EXTRA_DIST = $(TESTS) basic schema generate.res rcl_test.json.xz
|
EXTRA_DIST = $(TESTS) basic schema generate.res streamline.res rcl_test.json.xz
|
||||||
|
|
||||||
TESTS = basic.test \
|
TESTS = basic.test \
|
||||||
generate.test \
|
generate.test \
|
||||||
|
2
contrib/libucl/tests/basic/12.in
Normal file
2
contrib/libucl/tests/basic/12.in
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
key1: 12 ,
|
||||||
|
key2: 12 value
|
3
contrib/libucl/tests/basic/12.res
Normal file
3
contrib/libucl/tests/basic/12.res
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
key1 = 12;
|
||||||
|
key2 = "12 value";
|
||||||
|
|
9
contrib/libucl/tests/basic/13.in
Normal file
9
contrib/libucl/tests/basic/13.in
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
key = value_orig;
|
||||||
|
|
||||||
|
# test glob
|
||||||
|
.include(glob=true) "${CURDIR}/include_dir/test*.conf"
|
||||||
|
|
||||||
|
.include(priority=1) "${CURDIR}/include_dir/pri1.conf"
|
||||||
|
.include(priority=2) "${CURDIR}/include_dir/pri2.conf"
|
||||||
|
|
||||||
|
.include(try=true) "${CURDIR}/include_dir/invalid.conf"
|
8
contrib/libucl/tests/basic/13.res
Normal file
8
contrib/libucl/tests/basic/13.res
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
key = "value_orig";
|
||||||
|
key = "value1";
|
||||||
|
key = "value2";
|
||||||
|
key = "value3";
|
||||||
|
key_pri = "priority2";
|
||||||
|
key_trace1 = "pri1";
|
||||||
|
key_trace2 = "pri2";
|
||||||
|
|
@ -10,7 +10,14 @@ licenses [
|
|||||||
"BSD",
|
"BSD",
|
||||||
]
|
]
|
||||||
flatsize = 60523;
|
flatsize = 60523;
|
||||||
desc = "pkgconf is a program which helps to configure compiler and linker flags for\ndevelopment frameworks. It is similar to pkg-config, but was written from\nscratch in Summer of 2011 to replace pkg-config, which now needs itself to build\nitself.\n\nWWW: https://github.com/pkgconf/pkgconf";
|
desc = <<EOD
|
||||||
|
pkgconf is a program which helps to configure compiler and linker flags for
|
||||||
|
development frameworks. It is similar to pkg-config, but was written from
|
||||||
|
scratch in Summer of 2011 to replace pkg-config, which now needs itself to build
|
||||||
|
itself.
|
||||||
|
|
||||||
|
WWW: https://github.com/pkgconf/pkgconf
|
||||||
|
EOD;
|
||||||
categories [
|
categories [
|
||||||
"devel",
|
"devel",
|
||||||
]
|
]
|
||||||
@ -31,6 +38,17 @@ scripts {
|
|||||||
pre-deinstall = "cd /usr/local\nn";
|
pre-deinstall = "cd /usr/local\nn";
|
||||||
post-deinstall = "cd /usr/local\nn";
|
post-deinstall = "cd /usr/local\nn";
|
||||||
}
|
}
|
||||||
multiline-key = "test\ntest\ntest\\n\n/* comment like */\n# Some invalid endings\n EOD\nEOD \nEOF\n# Valid ending + empty string\n";
|
multiline-key = <<EOD
|
||||||
|
test
|
||||||
|
test
|
||||||
|
test\n
|
||||||
|
/* comment like */
|
||||||
|
# Some invalid endings
|
||||||
|
EOD
|
||||||
|
EOD
|
||||||
|
EOF
|
||||||
|
# Valid ending + empty string
|
||||||
|
|
||||||
|
EOD;
|
||||||
normal-key = "<<EODnot";
|
normal-key = "<<EODnot";
|
||||||
|
|
||||||
|
25
contrib/libucl/tests/basic/comments.in
Normal file
25
contrib/libucl/tests/basic/comments.in
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# This test is intended to check various comments in ucl
|
||||||
|
|
||||||
|
obj {
|
||||||
|
|
||||||
|
key = value
|
||||||
|
key = "/* value"
|
||||||
|
/*
|
||||||
|
key = value
|
||||||
|
*/
|
||||||
|
# Nested comments
|
||||||
|
key = nested
|
||||||
|
/*
|
||||||
|
adasdasdads
|
||||||
|
/* asdasdasd */asjdasjldaskd
|
||||||
|
/* asdsadasd */
|
||||||
|
/* /* /* /* /* */ */ */ */ */
|
||||||
|
# some
|
||||||
|
*/
|
||||||
|
key = quotes # quoted
|
||||||
|
# Quotes
|
||||||
|
/*
|
||||||
|
key = "/* value"
|
||||||
|
key = "*/value"
|
||||||
|
*/
|
||||||
|
}
|
7
contrib/libucl/tests/basic/comments.res
Normal file
7
contrib/libucl/tests/basic/comments.res
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
obj {
|
||||||
|
key = "value";
|
||||||
|
key = "/* value";
|
||||||
|
key = "nested";
|
||||||
|
key = "quotes";
|
||||||
|
}
|
||||||
|
|
1
contrib/libucl/tests/basic/include_dir/invalid.conf
Normal file
1
contrib/libucl/tests/basic/include_dir/invalid.conf
Normal file
@ -0,0 +1 @@
|
|||||||
|
@@@@ BAD UCL ~~~~
|
2
contrib/libucl/tests/basic/include_dir/pri1.conf
Normal file
2
contrib/libucl/tests/basic/include_dir/pri1.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
key_pri = priority1;
|
||||||
|
key_trace1 = pri1;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user