MFHead @ r275232
This commit is contained in:
commit
840e70929b
@ -48,7 +48,6 @@ cd(4) ken Pre-commit review requested.
|
||||
pass(4) ken Pre-commit review requested.
|
||||
ch(4) ken 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.
|
||||
etc/mail gshapiro Pre-commit review requested.
|
||||
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.
|
||||
sbin/routed bms Pre-commit review; notify vendor at rhyolite.com
|
||||
isci(4) jimharris Pre-commit review requested.
|
||||
3dfx cokane Pre-commit review preferred.
|
||||
cmx daniel@roe.ch Pre-commit review preferred.
|
||||
filemon obrien Pre-commit review preferred.
|
||||
sysdoc trhodes Pre-commit review preferred.
|
||||
|
@ -38,6 +38,12 @@
|
||||
# xargs -n1 | sort | uniq -d;
|
||||
# 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
|
||||
OLD_FILES+=etc/rc.d/faith
|
||||
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/keymaps.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/rlstdc.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/man/man3/readline.3.gz
|
||||
# 20140625: csup removal
|
||||
|
@ -40,8 +40,7 @@ MLINKS= csh.1 tcsh.1
|
||||
# utilities of the same name are handled with the associated manpage,
|
||||
# builtin.1 in share/man/man1/.
|
||||
|
||||
DPADD= ${LIBTERMCAPW} ${LIBCRYPT}
|
||||
LDADD= -ltermcapw -lcrypt
|
||||
LIBADD= termcapw crypt
|
||||
|
||||
LINKS= ${BINDIR}/csh ${BINDIR}/tcsh
|
||||
|
||||
|
@ -9,7 +9,6 @@ SRCS= df.c vfslist.c
|
||||
|
||||
CFLAGS+= -I${MOUNT}
|
||||
|
||||
DPADD= ${LIBUTIL} ${LIBXO}
|
||||
LDADD= -lutil -lxo
|
||||
LIBADD= xo util
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -9,8 +9,7 @@ MLINKS= ed.1 red.1
|
||||
|
||||
.if ${MK_OPENSSL} != "no" && ${MK_ED_CRYPTO} != "no"
|
||||
CFLAGS+=-DDES
|
||||
DPADD= ${LIBCRYPTO}
|
||||
LDADD= -lcrypto
|
||||
LIBADD= crypto
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -5,14 +5,12 @@
|
||||
|
||||
PROG= ls
|
||||
SRCS= cmp.c ls.c print.c util.c
|
||||
DPADD= ${LIBUTIL}
|
||||
LDADD= -lutil
|
||||
LIBADD= util
|
||||
|
||||
.if !defined(RELEASE_CRUNCH) && \
|
||||
${MK_LS_COLORS} != no
|
||||
CFLAGS+= -DCOLORLS
|
||||
DPADD+= ${LIBTERMCAPW}
|
||||
LDADD+= -ltermcapw
|
||||
LIBADD+= termcapw
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -5,8 +5,7 @@
|
||||
|
||||
PROG= pkill
|
||||
|
||||
DPADD= ${LIBKVM}
|
||||
LDADD= -lkvm
|
||||
LIBADD= kvm
|
||||
|
||||
LINKS= ${BINDIR}/pkill ${BINDIR}/pgrep
|
||||
MLINKS= pkill.1 pgrep.1
|
||||
|
@ -11,7 +11,6 @@ SRCS= fmt.c keyword.c nlist.c print.c ps.c
|
||||
# on large systems.
|
||||
#
|
||||
CFLAGS+=-DLAZY_PS
|
||||
DPADD= ${LIBM} ${LIBKVM} ${LIBJAIL}
|
||||
LDADD= -lm -lkvm -ljail
|
||||
LIBADD= m kvm jail
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -14,11 +14,7 @@ MAN= rmail.8
|
||||
WARNS?= 2
|
||||
CFLAGS+=-I${SENDMAIL_DIR}/include -I.
|
||||
|
||||
LIBSMDIR= ${.OBJDIR}/../../lib/libsm
|
||||
LIBSM= ${LIBSMDIR}/libsm.a
|
||||
|
||||
DPADD= ${LIBSM}
|
||||
LDADD= ${LIBSM}
|
||||
LIBADD= sm
|
||||
|
||||
SRCS+= 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,
|
||||
# builtin.1 in share/man/man1/.
|
||||
|
||||
DPADD= ${LIBEDIT} ${LIBTERMCAPW}
|
||||
LDADD= -ledit -ltermcapw
|
||||
LIBADD= edit
|
||||
|
||||
CFLAGS+=-DSHELL -I. -I${.CURDIR}
|
||||
# for debug:
|
||||
|
@ -1211,13 +1211,13 @@ dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat)
|
||||
#if defined(__FreeBSD__)
|
||||
if (sh.sh_size == 0)
|
||||
continue;
|
||||
if (is_elf_obj && (sh.sh_type == SHT_PROGBITS ||
|
||||
sh.sh_type == SHT_NOBITS)) {
|
||||
if (sh.sh_type == SHT_PROGBITS || sh.sh_type == SHT_NOBITS) {
|
||||
alignmask = sh.sh_addralign - 1;
|
||||
mapbase += alignmask;
|
||||
mapbase &= ~alignmask;
|
||||
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;
|
||||
}
|
||||
#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) {
|
||||
if (strcmp(pip->pi_fname, fname) == 0 &&
|
||||
((rname == NULL && pip->pi_rname[0] == '\0') ||
|
||||
(rname != NULL && strcmp(pip->pi_rname, rname)) == 0))
|
||||
((rname == NULL && pip->pi_rname == NULL) ||
|
||||
(rname != NULL && pip->pi_rname != NULL &&
|
||||
strcmp(pip->pi_rname, rname) == 0)))
|
||||
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
|
||||
- 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
|
||||
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_parser.o \
|
||||
$(OBJDIR)/ucl_emitter.o \
|
||||
$(OBJDIR)/ucl_emitter_utils.o \
|
||||
$(OBJDIR)/ucl_schema.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
|
||||
$(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
|
||||
$(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)
|
||||
$(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)
|
||||
@ -61,7 +64,7 @@ $(OBJDIR)/xxhash.o: $(SRCDIR)/xxhash.c $(HDEPS)
|
||||
clean:
|
||||
$(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate
|
||||
$(RMDIR) $(OBJDIR)
|
||||
|
||||
|
||||
# Utils
|
||||
|
||||
chargen: utils/chargen.c $(OBJDIR)/$(SONAME)
|
||||
@ -75,7 +78,7 @@ test: $(OBJDIR) $(OBJDIR)/$(SONAME) $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(
|
||||
|
||||
run-test: test
|
||||
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)
|
||||
$(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)
|
||||
|
@ -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
|
||||
UCL configuration;
|
||||
* `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;
|
||||
* `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).
|
||||
Moreover, each macro can accept an optional list of arguments in braces. These
|
||||
arguments themselves are the UCL object that is parsed and passed to a macro as
|
||||
options:
|
||||
|
||||
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
|
||||
|
||||
@ -317,7 +359,7 @@ ucl: emitted compact json in 0.0991 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
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
PROJECT(libucl C)
|
||||
|
||||
SET(LIBUCL_VERSION_MAJOR 0)
|
||||
SET(LIBUCL_VERSION_MINOR 2)
|
||||
SET(LIBUCL_VERSION_PATCH 9)
|
||||
SET(LIBUCL_VERSION_MINOR 5)
|
||||
SET(LIBUCL_VERSION_PATCH 0)
|
||||
|
||||
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
|
||||
../src/ucl_parser.c
|
||||
../src/ucl_emitter.c
|
||||
../src/ucl_emitter_streamline.c
|
||||
../src/ucl_emitter_utils.c
|
||||
../src/ucl_hash.c
|
||||
../src/ucl_schema.c
|
||||
../src/xxhash.c)
|
||||
@ -98,6 +100,18 @@ ENDIF (BUILD_SHARED_LIBS)
|
||||
ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC})
|
||||
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)
|
||||
TARGET_LINK_LIBRARIES(ucl fetch)
|
||||
ELSE(HAVE_FETCH_H)
|
||||
|
@ -1,12 +1,13 @@
|
||||
m4_define([maj_ver], [0])
|
||||
m4_define([med_ver], [5])
|
||||
m4_define([min_ver], [0])
|
||||
m4_define([so_version], [2:0:0])
|
||||
m4_define([med_ver], [6])
|
||||
m4_define([min_ver], [1])
|
||||
m4_define([so_version], [3:0:1])
|
||||
m4_define([ucl_version], [maj_ver.med_ver.min_ver])
|
||||
|
||||
AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
|
||||
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
|
||||
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],
|
||||
[Enable signatures check (requires openssl) @<:@default=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],
|
||||
AS_HELP_STRING([--enable-utils], [Build and install utils @<:@default=no@:>@]),
|
||||
[case "${enableval}" in
|
||||
@ -99,6 +103,21 @@ AS_IF([test "x$enable_regex" = "xyes"], [
|
||||
])
|
||||
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"], [
|
||||
AC_CHECK_HEADER([fetch.h], [
|
||||
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 \
|
||||
src/Makefile \
|
||||
lua/Makefile
|
||||
tests/Makefile \
|
||||
utils/Makefile \
|
||||
doc/Makefile \
|
||||
lua/libucl.rockspec \
|
||||
libucl.pc)
|
||||
AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h])
|
||||
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 {
|
||||
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_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;
|
||||
|
||||
/**
|
||||
@ -171,9 +172,12 @@ typedef enum ucl_string_flags {
|
||||
* Basic flags for an object
|
||||
*/
|
||||
typedef enum ucl_object_flags {
|
||||
UCL_OBJECT_ALLOCATED_KEY = 1, /**< An object has key allocated internally */
|
||||
UCL_OBJECT_ALLOCATED_VALUE = 2, /**< 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_ALLOCATED_KEY = 0x1, /**< An object has key allocated internally */
|
||||
UCL_OBJECT_ALLOCATED_VALUE = 0x2, /**< An object has a string value allocated internally */
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -195,14 +199,21 @@ typedef struct ucl_object_s {
|
||||
const char *key; /**< Key of an object */
|
||||
struct ucl_object_s *next; /**< Array handle */
|
||||
struct ucl_object_s *prev; /**< Array handle */
|
||||
unsigned char* trash_stack[2]; /**< Pointer to allocated chunks */
|
||||
unsigned keylen; /**< Lenght of a key */
|
||||
unsigned len; /**< Size of an object */
|
||||
enum ucl_type type; /**< Real type */
|
||||
uint16_t ref; /**< Reference count */
|
||||
uint32_t keylen; /**< Lenght of a key */
|
||||
uint32_t len; /**< Size of an object */
|
||||
uint32_t ref; /**< Reference count */
|
||||
uint16_t flags; /**< Object flags */
|
||||
uint16_t type; /**< Real type */
|
||||
unsigned char* trash_stack[2]; /**< Pointer to allocated chunks */
|
||||
} 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;
|
||||
|
||||
/**
|
||||
* 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 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'
|
||||
* @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 key key to associate with this object (either const or preallocated)
|
||||
* @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,
|
||||
* 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 key key to associate with this object (either const or preallocated)
|
||||
* @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,
|
||||
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,
|
||||
* @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
|
||||
* released
|
||||
* Removes `key` from `top` object, 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 object
|
||||
* @param key key to remove
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* Delete key from `top` object returning the object deleted. This object is not
|
||||
* released
|
||||
* Removes `key` from `top` object 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 object
|
||||
* @param key key to remove
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* Insert a object 'elt' to the hash 'top' and associate it with key 'key', if the specified key exist,
|
||||
* try to merge its content
|
||||
* @param top destination object (will be created automatically if top is NULL)
|
||||
* Insert a object 'elt' to the hash 'top' and associate it with key 'key', if
|
||||
* the specified key exist, try to merge its content
|
||||
* @param top destination object (must be of type UCL_OBJECT)
|
||||
* @param elt element to insert (must NOT be NULL)
|
||||
* @param key key to associate with this object (either const or preallocated)
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Append an element to the front of array object
|
||||
* @param top destination object (will be created automatically if top is NULL)
|
||||
* Append an element to the end of array object
|
||||
* @param top destination object (must NOT be NULL)
|
||||
* @param elt element to append (must NOT be NULL)
|
||||
* @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
|
||||
* @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)
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Removes an element `elt` from the array `top`. Caller must unref the returned object when it is not
|
||||
* needed.
|
||||
* Merge all elements of second array into the first array
|
||||
* @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 elt element to remove
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Removes the last element from the array `top`. Caller must unref the returned object when it is not
|
||||
* needed.
|
||||
* Removes the last element 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
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Return object identified by an index of the array `top`
|
||||
* @param obj object to get a key from (must be of type UCL_ARRAY)
|
||||
* @param index 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);
|
||||
|
||||
/**
|
||||
* Removes the first element from the array `top`. Caller must unref the returned object when it is not
|
||||
* needed.
|
||||
* Removes the first element 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
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param head head to append (may be NULL)
|
||||
* @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_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
|
||||
* @param obj object to get a key from (must be of type UCL_OBJECT)
|
||||
* @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,
|
||||
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 key key to search
|
||||
* @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,
|
||||
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
|
||||
* @param obj object to ref
|
||||
* @return the referenced object
|
||||
*/
|
||||
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,
|
||||
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
|
||||
*/
|
||||
@ -640,11 +729,14 @@ UCL_EXTERN const ucl_object_t* ucl_iterate_object (const ucl_object_t *obj,
|
||||
* Macro handler for a parser
|
||||
* @param data the content of macro
|
||||
* @param len the length of content
|
||||
* @param arguments arguments object
|
||||
* @param ud opaque user data
|
||||
* @param err error pointer
|
||||
* @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 */
|
||||
struct ucl_parser;
|
||||
@ -702,12 +794,23 @@ UCL_EXTERN void ucl_parser_set_variables_handler (struct ucl_parser *parser,
|
||||
* @param parser parser structure
|
||||
* @param data the pointer to the beginning 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
|
||||
*/
|
||||
UCL_EXTERN bool ucl_parser_add_chunk (struct ucl_parser *parser,
|
||||
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
|
||||
* @param parser parser structure
|
||||
@ -835,7 +938,7 @@ struct ucl_emitter_context {
|
||||
/** A set of output operations */
|
||||
const struct ucl_emitter_operations *ops;
|
||||
/** Current amount of indent tabs */
|
||||
unsigned int ident;
|
||||
unsigned int indent;
|
||||
/** Top level object */
|
||||
const ucl_object_t *top;
|
||||
/** The rest of context */
|
||||
|
@ -7,5 +7,5 @@ Name: LibUCL
|
||||
Description: Universal configuration library
|
||||
Version: @UCL_VERSION@
|
||||
Libs: -L${libdir} -lucl
|
||||
Libs.private: @LIBS_EXTRA@
|
||||
Libs.private: @LIBS_EXTRA@ @LUA_LIB@
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
if (obj->keylen > 0) {
|
||||
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;
|
||||
|
||||
if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
|
||||
ctx->ident --;
|
||||
ctx->indent --;
|
||||
if (compact) {
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -210,7 +223,7 @@ ucl_emitter_common_end_array (struct ucl_emitter_context *ctx,
|
||||
{
|
||||
const struct ucl_emitter_functions *func = ctx->func;
|
||||
|
||||
ctx->ident --;
|
||||
ctx->indent --;
|
||||
if (compact) {
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
|
||||
@ -249,7 +262,7 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,
|
||||
func->ucl_emitter_append_len ("[\n", 2, func->ud);
|
||||
}
|
||||
|
||||
ctx->ident ++;
|
||||
ctx->indent ++;
|
||||
|
||||
if (obj->type == UCL_ARRAY) {
|
||||
/* explicit array */
|
||||
@ -294,7 +307,7 @@ ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,
|
||||
else {
|
||||
func->ucl_emitter_append_len ("{\n", 2, func->ud);
|
||||
}
|
||||
ctx->ident ++;
|
||||
ctx->indent ++;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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_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;
|
||||
bool flag;
|
||||
struct ucl_object_userdata *ud;
|
||||
const char *ud_out = "";
|
||||
|
||||
if (ctx->id != UCL_EMIT_CONFIG && !first) {
|
||||
if (compact) {
|
||||
func->ucl_emitter_append_character (',', 1, func->ud);
|
||||
}
|
||||
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) {
|
||||
case UCL_INT:
|
||||
@ -379,7 +398,12 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
|
||||
break;
|
||||
case UCL_STRING:
|
||||
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);
|
||||
break;
|
||||
case UCL_NULL:
|
||||
@ -396,6 +420,16 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
|
||||
ucl_emitter_common_end_array (ctx, obj, compact);
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -425,10 +459,10 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
|
||||
ucl_emitter_common_end_array (ctx, obj, (compact)); \
|
||||
}
|
||||
|
||||
UCL_EMIT_TYPE_IMPL(json, false);
|
||||
UCL_EMIT_TYPE_IMPL(json_compact, true);
|
||||
UCL_EMIT_TYPE_IMPL(config, false);
|
||||
UCL_EMIT_TYPE_IMPL(yaml, false);
|
||||
UCL_EMIT_TYPE_IMPL(json, false)
|
||||
UCL_EMIT_TYPE_IMPL(json_compact, true)
|
||||
UCL_EMIT_TYPE_IMPL(config, false)
|
||||
UCL_EMIT_TYPE_IMPL(yaml, false)
|
||||
|
||||
unsigned char *
|
||||
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) {
|
||||
memcpy (&my_ctx, ctx, sizeof (my_ctx));
|
||||
my_ctx.func = emitter;
|
||||
my_ctx.ident = 0;
|
||||
my_ctx.indent = 0;
|
||||
my_ctx.top = obj;
|
||||
|
||||
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;
|
||||
sctx->ops->ucl_emitter_start_object (ctx, obj, print_key);
|
||||
}
|
||||
LL_PREPEND (sctx->containers, st);
|
||||
}
|
||||
|
||||
LL_PREPEND (sctx->containers, st);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -93,9 +93,7 @@ ucl_elt_string_write_json (const char *str, size_t size,
|
||||
size_t len = 0;
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
else {
|
||||
utstring_reserve (buf, len);
|
||||
utstring_reserve (buf, len + 1);
|
||||
memset (&buf->d[buf->i], c, len);
|
||||
buf->i += len;
|
||||
buf->d[buf->i] = '\0';
|
||||
@ -267,19 +274,23 @@ ucl_fd_append_character (unsigned char c, size_t len, void *ud)
|
||||
unsigned char *buf;
|
||||
|
||||
if (len == 1) {
|
||||
write (fd, &c, 1);
|
||||
return write (fd, &c, 1);
|
||||
}
|
||||
else {
|
||||
buf = malloc (len);
|
||||
if (buf == NULL) {
|
||||
/* Fallback */
|
||||
while (len --) {
|
||||
write (fd, &c, 1);
|
||||
if (write (fd, &c, 1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
memset (buf, c, len);
|
||||
write (fd, buf, len);
|
||||
if (write (fd, buf, len) == -1) {
|
||||
return -1;
|
||||
}
|
||||
free (buf);
|
||||
}
|
||||
}
|
||||
@ -292,9 +303,7 @@ ucl_fd_append_len (const unsigned char *str, size_t len, void *ud)
|
||||
{
|
||||
int fd = *(int *)ud;
|
||||
|
||||
write (fd, str, len);
|
||||
|
||||
return 0;
|
||||
return write (fd, str, len);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -304,9 +313,7 @@ ucl_fd_append_int (int64_t val, void *ud)
|
||||
char intbuf[64];
|
||||
|
||||
snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);
|
||||
write (fd, intbuf, strlen (intbuf));
|
||||
|
||||
return 0;
|
||||
return write (fd, intbuf, strlen (intbuf));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -327,9 +334,7 @@ ucl_fd_append_double (double val, void *ud)
|
||||
snprintf (nbuf, sizeof (nbuf), "%lf", val);
|
||||
}
|
||||
|
||||
write (fd, nbuf, strlen (nbuf));
|
||||
|
||||
return 0;
|
||||
return write (fd, nbuf, strlen (nbuf));
|
||||
}
|
||||
|
||||
struct ucl_emitter_functions*
|
||||
@ -464,3 +469,18 @@ ucl_object_emit_single_json (const ucl_object_t *obj)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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*
|
||||
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) {
|
||||
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,
|
||||
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.
|
||||
*/
|
||||
|
@ -163,6 +163,7 @@ struct ucl_chunk {
|
||||
size_t remain;
|
||||
unsigned int line;
|
||||
unsigned int column;
|
||||
unsigned priority;
|
||||
struct ucl_chunk *next;
|
||||
};
|
||||
|
||||
@ -182,7 +183,7 @@ struct ucl_variable {
|
||||
char *value;
|
||||
size_t var_len;
|
||||
size_t value_len;
|
||||
struct ucl_variable *next;
|
||||
struct ucl_variable *prev, *next;
|
||||
};
|
||||
|
||||
struct ucl_parser {
|
||||
@ -192,6 +193,7 @@ struct ucl_parser {
|
||||
int flags;
|
||||
ucl_object_t *top_obj;
|
||||
ucl_object_t *cur_obj;
|
||||
char *cur_file;
|
||||
struct ucl_macro *macroes;
|
||||
struct ucl_stack *stack;
|
||||
struct ucl_chunk *chunks;
|
||||
@ -202,6 +204,12 @@ struct ucl_parser {
|
||||
UT_string *err;
|
||||
};
|
||||
|
||||
struct ucl_object_userdata {
|
||||
ucl_object_t obj;
|
||||
ucl_userdata_dtor dtor;
|
||||
ucl_userdata_emitter emitter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unescape json string inplace
|
||||
* @param str
|
||||
@ -216,9 +224,11 @@ size_t ucl_unescape_json_string (char *str, size_t len);
|
||||
* @param err error ptr
|
||||
* @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
|
||||
@ -228,7 +238,8 @@ bool ucl_try_include_handler (const unsigned char *data, size_t len, void* ud);
|
||||
* @param err error ptr
|
||||
* @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_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
|
||||
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;
|
||||
|
||||
if (len == 5) {
|
||||
@ -351,13 +362,22 @@ const struct ucl_emitter_context *
|
||||
ucl_emit_get_standard_context (enum ucl_emitter emit_type);
|
||||
|
||||
/**
|
||||
* Serialise string
|
||||
* Serialize string as JSON string
|
||||
* @param str string to emit
|
||||
* @param buf target buffer
|
||||
*/
|
||||
void ucl_elt_string_write_json (const char *str, size_t size,
|
||||
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
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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_ */
|
||||
|
@ -26,8 +26,8 @@
|
||||
#include "ucl_chartable.h"
|
||||
|
||||
/**
|
||||
* @file rcl_parser.c
|
||||
* The implementation of rcl parser
|
||||
* @file ucl_parser.c
|
||||
* The implementation of ucl parser
|
||||
*/
|
||||
|
||||
struct ucl_parser_saved_state {
|
||||
@ -56,20 +56,33 @@ struct ucl_parser_saved_state {
|
||||
} while (0)
|
||||
|
||||
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) {
|
||||
if (isgraph (*chunk->pos)) {
|
||||
ucl_create_err (err, "error on line %d at column %d: '%s', character: '%c'",
|
||||
chunk->line, chunk->column, str, *chunk->pos);
|
||||
}
|
||||
else {
|
||||
ucl_create_err (err, "error on line %d at column %d: '%s', character: '0x%02x'",
|
||||
chunk->line, chunk->column, str, (int)*chunk->pos);
|
||||
}
|
||||
const char *fmt_string, *filename;
|
||||
struct ucl_chunk *chunk = parser->chunks;
|
||||
|
||||
if (parser->cur_file) {
|
||||
filename = parser->cur_file;
|
||||
}
|
||||
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;
|
||||
const unsigned char *p;
|
||||
int comments_nested = 0;
|
||||
bool quoted = false;
|
||||
|
||||
p = chunk->pos;
|
||||
|
||||
start:
|
||||
if (*p == '#') {
|
||||
if (chunk->remain > 0 && *p == '#') {
|
||||
if (parser->state != UCL_STATE_SCOMMENT &&
|
||||
parser->state != UCL_STATE_MCOMMENT) {
|
||||
while (p < chunk->end) {
|
||||
@ -100,34 +114,41 @@ start:
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (*p == '/' && chunk->remain >= 2) {
|
||||
else if (chunk->remain >= 2 && *p == '/') {
|
||||
if (p[1] == '*') {
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
comments_nested ++;
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
|
||||
while (p < chunk->end) {
|
||||
if (*p == '*') {
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
if (*p == '/') {
|
||||
comments_nested --;
|
||||
if (comments_nested == 0) {
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
goto start;
|
||||
}
|
||||
}
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
if (*p == '"' && *(p - 1) != '\\') {
|
||||
quoted = !quoted;
|
||||
}
|
||||
else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
|
||||
comments_nested ++;
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
continue;
|
||||
|
||||
if (!quoted) {
|
||||
if (*p == '*') {
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -492,7 +513,8 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
|
||||
/* Copy string */
|
||||
*dst = UCL_ALLOC (in_len + 1);
|
||||
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;
|
||||
}
|
||||
if (need_lowercase) {
|
||||
@ -514,6 +536,10 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
|
||||
*dst = tmp;
|
||||
ret = tret;
|
||||
}
|
||||
else {
|
||||
/* Free unexpanded value */
|
||||
UCL_FREE (in_len + 1, tmp);
|
||||
}
|
||||
}
|
||||
*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 (obj == NULL) {
|
||||
obj = ucl_object_typed_new (UCL_OBJECT);
|
||||
obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority);
|
||||
}
|
||||
else {
|
||||
obj->type = UCL_OBJECT;
|
||||
@ -549,7 +575,7 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
|
||||
}
|
||||
else {
|
||||
if (obj == NULL) {
|
||||
obj = ucl_object_typed_new (UCL_ARRAY);
|
||||
obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority);
|
||||
}
|
||||
else {
|
||||
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));
|
||||
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;
|
||||
}
|
||||
st->obj = obj;
|
||||
@ -676,8 +704,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
|
||||
}
|
||||
|
||||
/* Now check endptr */
|
||||
if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0' ||
|
||||
ucl_test_character (*endptr, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
|
||||
if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
|
||||
p = endptr;
|
||||
goto set_obj;
|
||||
}
|
||||
@ -788,8 +815,21 @@ ucl_maybe_parse_number (ucl_object_t *obj,
|
||||
goto set_obj;
|
||||
}
|
||||
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;
|
||||
return EINVAL;
|
||||
@ -835,7 +875,7 @@ ucl_lex_number (struct ucl_parser *parser,
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
@ -860,10 +900,12 @@ ucl_lex_json_string (struct ucl_parser *parser,
|
||||
if (c < 0x1F) {
|
||||
/* Unmasked control character */
|
||||
if (c == '\n') {
|
||||
ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", &parser->err);
|
||||
ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline",
|
||||
&parser->err);
|
||||
}
|
||||
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;
|
||||
}
|
||||
@ -871,7 +913,8 @@ ucl_lex_json_string (struct ucl_parser *parser,
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
c = *p;
|
||||
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;
|
||||
}
|
||||
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);
|
||||
for (i = 0; i < 4 && p < chunk->end; i ++) {
|
||||
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;
|
||||
}
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -910,10 +955,42 @@ ucl_lex_json_string (struct ucl_parser *parser,
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
* @param parser
|
||||
@ -981,7 +1058,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
||||
}
|
||||
else {
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
@ -997,7 +1075,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1015,7 +1094,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
else {
|
||||
ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", &parser->err);
|
||||
ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character",
|
||||
&parser->err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1043,7 +1123,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
||||
got_semicolon = true;
|
||||
}
|
||||
else {
|
||||
ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", &parser->err);
|
||||
ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character",
|
||||
&parser->err);
|
||||
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) {
|
||||
ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
|
||||
ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1096,7 +1177,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
||||
}
|
||||
|
||||
/* 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],
|
||||
&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
|
||||
if (keylen == -1) {
|
||||
@ -1104,7 +1185,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
@ -1120,7 +1201,27 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
||||
parser->stack->obj->len ++;
|
||||
}
|
||||
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) {
|
||||
@ -1197,11 +1298,6 @@ ucl_parse_string_value (struct ucl_parser *parser,
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
}
|
||||
|
||||
if (p >= chunk->end) {
|
||||
ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", &parser->err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1219,7 +1315,7 @@ ucl_parse_multiline_string (struct ucl_parser *parser,
|
||||
int term_len, unsigned char const **beg,
|
||||
bool *var_expand)
|
||||
{
|
||||
const unsigned char *p, *c;
|
||||
const unsigned char *p, *c, *tend;
|
||||
bool newline = false;
|
||||
int len = 0;
|
||||
|
||||
@ -1232,7 +1328,13 @@ ucl_parse_multiline_string (struct ucl_parser *parser,
|
||||
if (chunk->end - p < term_len) {
|
||||
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;
|
||||
chunk->remain -= 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) {
|
||||
/* Object must be allocated */
|
||||
obj = ucl_object_new ();
|
||||
obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
|
||||
t = parser->stack->obj->value.av;
|
||||
DL_APPEND (t, obj);
|
||||
parser->cur_obj = obj;
|
||||
@ -1378,7 +1480,8 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
||||
chunk->line ++;
|
||||
if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
|
||||
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;
|
||||
}
|
||||
obj->type = UCL_STRING;
|
||||
@ -1423,7 +1526,8 @@ parse_string:
|
||||
}
|
||||
str_len = chunk->pos - c - stripped_spaces;
|
||||
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;
|
||||
}
|
||||
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)) {
|
||||
if (*p == '}' || *p == ']') {
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1525,7 +1633,8 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
||||
else {
|
||||
/* Anything else */
|
||||
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 true;
|
||||
@ -1612,6 +1721,120 @@ ucl_parse_macro_value (struct ucl_parser *parser,
|
||||
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
|
||||
* @param parser parser structure
|
||||
@ -1622,13 +1845,13 @@ ucl_parse_macro_value (struct ucl_parser *parser,
|
||||
static bool
|
||||
ucl_state_machine (struct ucl_parser *parser)
|
||||
{
|
||||
ucl_object_t *obj;
|
||||
ucl_object_t *obj, *macro_args;
|
||||
struct ucl_chunk *chunk = parser->chunks;
|
||||
const unsigned char *p, *c = NULL, *macro_start = NULL;
|
||||
unsigned char *macro_escaped;
|
||||
size_t macro_len = 0;
|
||||
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 (*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
|
||||
* a key of newly created object
|
||||
*/
|
||||
obj = parser->cur_obj;
|
||||
if (!ucl_skip_comments (parser)) {
|
||||
parser->prev_state = parser->state;
|
||||
parser->state = UCL_STATE_ERROR;
|
||||
@ -1691,7 +1913,7 @@ ucl_state_machine (struct ucl_parser *parser)
|
||||
}
|
||||
if (parser->stack == NULL) {
|
||||
/* 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);
|
||||
parser->prev_state = parser->state;
|
||||
parser->state = UCL_STATE_ERROR;
|
||||
@ -1757,7 +1979,8 @@ ucl_state_machine (struct ucl_parser *parser)
|
||||
p = chunk->pos;
|
||||
break;
|
||||
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);
|
||||
}
|
||||
else if (p - c > 0) {
|
||||
@ -1772,48 +1995,51 @@ ucl_state_machine (struct ucl_parser *parser)
|
||||
return false;
|
||||
}
|
||||
/* Now we need to skip all spaces */
|
||||
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])) {
|
||||
/* Skip comment */
|
||||
if (!ucl_skip_comments (parser)) {
|
||||
return false;
|
||||
}
|
||||
p = chunk->pos;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
}
|
||||
SKIP_SPACES_COMMENTS(parser, chunk, p);
|
||||
parser->state = UCL_STATE_MACRO;
|
||||
}
|
||||
break;
|
||||
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,
|
||||
¯o_start, ¯o_len)) {
|
||||
parser->prev_state = parser->state;
|
||||
parser->state = UCL_STATE_ERROR;
|
||||
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;
|
||||
if (macro_escaped == NULL) {
|
||||
if (!macro->handler (macro_start, macro_len, macro->ud)) {
|
||||
return false;
|
||||
}
|
||||
ret = macro->handler (macro_start, macro_len, macro_args,
|
||||
macro->ud);
|
||||
}
|
||||
else {
|
||||
if (!macro->handler (macro_escaped, macro_len, macro->ud)) {
|
||||
UCL_FREE (macro_len + 1, macro_escaped);
|
||||
return false;
|
||||
}
|
||||
ret = macro->handler (macro_escaped, macro_len, macro_args,
|
||||
macro->ud);
|
||||
UCL_FREE (macro_len + 1, macro_escaped);
|
||||
}
|
||||
p = chunk->pos;
|
||||
if (macro_args) {
|
||||
ucl_object_unref (macro_args);
|
||||
}
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* 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;
|
||||
return false;
|
||||
}
|
||||
@ -1888,7 +2114,7 @@ ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
|
||||
|
||||
if (new != NULL) {
|
||||
/* Remove variable */
|
||||
LL_DELETE (parser->variables, new);
|
||||
DL_DELETE (parser->variables, new);
|
||||
free (new->var);
|
||||
free (new->value);
|
||||
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_len = strlen (value);
|
||||
|
||||
LL_PREPEND (parser->variables, new);
|
||||
DL_APPEND (parser->variables, new);
|
||||
}
|
||||
else {
|
||||
free (new->value);
|
||||
@ -1929,15 +2155,19 @@ ucl_parser_set_variables_handler (struct ucl_parser *parser,
|
||||
}
|
||||
|
||||
bool
|
||||
ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
|
||||
size_t len)
|
||||
ucl_parser_add_chunk_priority (struct ucl_parser *parser, const unsigned char *data,
|
||||
size_t len, unsigned priority)
|
||||
{
|
||||
struct ucl_chunk *chunk;
|
||||
|
||||
if (data == NULL || len == 0) {
|
||||
if (data == NULL) {
|
||||
ucl_create_err (&parser->err, "invalid chunk added");
|
||||
return false;
|
||||
}
|
||||
if (len == 0) {
|
||||
parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority);
|
||||
return true;
|
||||
}
|
||||
if (parser->state != UCL_STATE_ERROR) {
|
||||
chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
|
||||
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->line = 1;
|
||||
chunk->column = 0;
|
||||
chunk->priority = priority;
|
||||
LL_PREPEND (parser->chunks, chunk);
|
||||
parser->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;
|
||||
}
|
||||
|
||||
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
|
||||
ucl_parser_add_string (struct ucl_parser *parser, const char *data,
|
||||
size_t len)
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "ucl_internal.h"
|
||||
#include "ucl_chartable.h"
|
||||
|
||||
#include <glob.h>
|
||||
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
#include <libgen.h> /* For dirname */
|
||||
#endif
|
||||
@ -129,11 +131,6 @@ static char* ucl_realpath(const char *path, char *resolved_path) {
|
||||
#define ucl_realpath realpath
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file rcl_util.c
|
||||
* Utilities for rcl parsing
|
||||
*/
|
||||
|
||||
typedef void (*ucl_object_dtor) (ucl_object_t *obj);
|
||||
static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec,
|
||||
ucl_object_dtor dtor);
|
||||
@ -148,7 +145,19 @@ ucl_object_dtor_free (ucl_object_t *obj)
|
||||
if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
|
||||
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) {
|
||||
utstring_free(parser->err);
|
||||
utstring_free (parser->err);
|
||||
}
|
||||
|
||||
if (parser->cur_file) {
|
||||
free (parser->cur_file);
|
||||
}
|
||||
|
||||
UCL_FREE (sizeof (struct ucl_parser), parser);
|
||||
@ -701,7 +714,8 @@ ucl_sig_check (const unsigned char *data, size_t datalen,
|
||||
*/
|
||||
static bool
|
||||
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;
|
||||
@ -744,7 +758,7 @@ ucl_include_url (const unsigned char *data, size_t len,
|
||||
prev_state = parser->state;
|
||||
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) {
|
||||
/* Remove chunk from the stack */
|
||||
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 len
|
||||
* @param parser
|
||||
* @param err
|
||||
* @param check_signature
|
||||
* @param must_exist
|
||||
* @param allow_glob
|
||||
* @param priority
|
||||
* @return
|
||||
*/
|
||||
static bool
|
||||
ucl_include_file (const unsigned char *data, size_t len,
|
||||
struct ucl_parser *parser, bool check_signature, bool must_exist)
|
||||
ucl_include_file_single (const unsigned char *data, size_t len,
|
||||
struct ucl_parser *parser, bool check_signature, bool must_exist,
|
||||
unsigned priority)
|
||||
{
|
||||
bool res;
|
||||
struct ucl_chunk *chunk;
|
||||
unsigned char *buf = NULL;
|
||||
char *old_curfile;
|
||||
size_t buflen;
|
||||
char filebuf[PATH_MAX], realbuf[PATH_MAX];
|
||||
int prev_state;
|
||||
struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL,
|
||||
*old_filename = NULL;
|
||||
|
||||
snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
|
||||
if (ucl_realpath (filebuf, realbuf) == NULL) {
|
||||
@ -790,6 +811,13 @@ ucl_include_file (const unsigned char *data, size_t len,
|
||||
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)) {
|
||||
return (!must_exist || false);
|
||||
}
|
||||
@ -818,19 +846,66 @@ ucl_include_file (const unsigned char *data, size_t len,
|
||||
#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);
|
||||
|
||||
prev_state = parser->state;
|
||||
parser->state = UCL_STATE_INIT;
|
||||
|
||||
res = ucl_parser_add_chunk (parser, buf, buflen);
|
||||
if (res == true) {
|
||||
/* Remove chunk from the stack */
|
||||
chunk = parser->chunks;
|
||||
if (chunk != NULL) {
|
||||
parser->chunks = chunk->next;
|
||||
UCL_FREE (sizeof (struct ucl_chunk), chunk);
|
||||
res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority);
|
||||
if (!res && !must_exist) {
|
||||
/* Free error */
|
||||
utstring_free (parser->err);
|
||||
parser->err = NULL;
|
||||
parser->state = UCL_STATE_AFTER_VALUE;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@ -842,6 +917,138 @@ ucl_include_file (const unsigned char *data, size_t len,
|
||||
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
|
||||
* @param data include data
|
||||
@ -851,16 +1058,12 @@ ucl_include_file (const unsigned char *data, size_t len,
|
||||
* @return
|
||||
*/
|
||||
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;
|
||||
|
||||
if (*data == '/' || *data == '.') {
|
||||
/* Try to load a file */
|
||||
return ucl_include_file (data, len, parser, false, true);
|
||||
}
|
||||
|
||||
return ucl_include_url (data, len, parser, false, true);
|
||||
return ucl_include_common (data, len, args, parser, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -872,30 +1075,22 @@ ucl_include_handler (const unsigned char *data, size_t len, void* ud)
|
||||
* @return
|
||||
*/
|
||||
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;
|
||||
|
||||
if (*data == '/' || *data == '.') {
|
||||
/* Try to load a file */
|
||||
return ucl_include_file (data, len, parser, true, true);
|
||||
}
|
||||
|
||||
return ucl_include_url (data, len, parser, true, true);
|
||||
return ucl_include_common (data, len, args, parser, false, true);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
if (*data == '/' || *data == '.') {
|
||||
/* Try to load a file */
|
||||
return ucl_include_file (data, len, parser, false, false);
|
||||
}
|
||||
|
||||
return ucl_include_url (data, len, parser, false, false);
|
||||
return ucl_include_common (data, len, args, parser, true, false);
|
||||
}
|
||||
|
||||
UCL_EXTERN bool
|
||||
@ -947,6 +1142,10 @@ ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parser->cur_file) {
|
||||
free (parser->cur_file);
|
||||
}
|
||||
parser->cur_file = strdup (realbuf);
|
||||
ucl_parser_set_filevars (parser, realbuf, false);
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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->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));
|
||||
|
||||
if (!found) {
|
||||
if (found == NULL) {
|
||||
top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
|
||||
DL_APPEND (found, elt);
|
||||
top->len ++;
|
||||
if (replace) {
|
||||
ret = false;
|
||||
@ -1195,11 +1435,8 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
|
||||
}
|
||||
else {
|
||||
if (replace) {
|
||||
ucl_hash_delete (top->value.ov, found);
|
||||
ucl_hash_replace (top->value.ov, found, elt);
|
||||
ucl_object_unref (found);
|
||||
top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
|
||||
found = NULL;
|
||||
DL_APPEND (found, elt);
|
||||
}
|
||||
else if (merge) {
|
||||
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);
|
||||
}
|
||||
|
||||
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 *
|
||||
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;
|
||||
if (elt == NULL) {
|
||||
elt = obj;
|
||||
if (elt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (elt == obj) {
|
||||
return NULL;
|
||||
@ -1442,29 +1710,59 @@ ucl_lookup_path (const ucl_object_t *top, const char *path_in) {
|
||||
ucl_object_t *
|
||||
ucl_object_new (void)
|
||||
{
|
||||
ucl_object_t *new;
|
||||
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;
|
||||
return ucl_object_typed_new (UCL_NULL);
|
||||
}
|
||||
|
||||
ucl_object_t *
|
||||
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;
|
||||
new = malloc (sizeof (ucl_object_t));
|
||||
if (new != NULL) {
|
||||
memset (new, 0, sizeof (ucl_object_t));
|
||||
new->ref = 1;
|
||||
new->type = (type <= UCL_NULL ? type : UCL_NULL);
|
||||
|
||||
if (type != UCL_USERDATA) {
|
||||
new = UCL_ALLOC (sizeof (ucl_object_t));
|
||||
if (new != 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;
|
||||
}
|
||||
|
||||
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_object_type (const ucl_object_t *obj)
|
||||
{
|
||||
@ -1576,6 +1874,30 @@ ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
|
||||
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_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;
|
||||
}
|
||||
|
||||
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_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;
|
||||
|
||||
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
|
||||
(void)__sync_add_and_fetch (&res->ref, 1);
|
||||
(void)__sync_add_and_fetch (&res->ref, 1);
|
||||
#else
|
||||
res->ref ++;
|
||||
res->ref ++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
#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 \
|
||||
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",
|
||||
]
|
||||
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 [
|
||||
"devel",
|
||||
]
|
||||
@ -31,6 +38,17 @@ scripts {
|
||||
pre-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";
|
||||
|
||||
|
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…
x
Reference in New Issue
Block a user