Introduce asinfo tool

The main purpose of this query tool is to present all information concluded
at sysent.h files in a convenient way.
The asinfo tool has the following staged architecture:
(command dispatcher)->(architecture dispatcher)->
(abi dispatcher)->(system call dispatcher).
Each dispatcher accepts proccesed data from previous one.

This point can be illustrated by the following example:
$ asinfo --get-arch --get-sname write
Firstly, arch_dispatcher will return the current architecture, based on
uname return value, after that in case of no options for abi_dispatcher,
it perceives empty parameter as get-abi parameter and returns ABI mode set at
compile time of strace package. Therefore, syscall_dispatcher accepts this
architecture/ABI and works with specific set of system calls. It is worth
mentioning that it supports all architectures/ABIs supported by strace.
Also, tool can work in multi-arch mode. for instance:
$ ./tools/asinfo/asinfo --set-arch mips64,mips --set-abi n64,all
--get-snum 100,8,%ipc
For more info, use asinfo -h.

* Makefile.am (SUBDIRS): Add tools directory.
* configure.ac (AC_CONFIG_FILES): Add Makefiles.
* tools/Makefile.am: New file.
* tools/asinfo/Makefile.am: New file.
* tools/asinfo/dispatchers.h: New file. Prototype abi_dispatcher,
arch_dispatcher, and syscall_dispatcher.
* tools/asinfo/dispatchers.c: New file. Implement them.
* tools/asinfo/error_interface.h: New file. Introduce error_service to
improve informativeness of output errors. Prototype methods to work with
error_service.
* tools/asinfo/error_interface.c: New file. Implement it.
* tools/asinfo/arch_interface.h: New file. Introduce struct
arch_descriptor. Introduce arch_service. Prototype methods to simplify
work with the arch_service.
* tools/asinfo/arch_interface.c: New file. Implement it.
* tools/asinfo/syscall_interface.h: New file. Introduce syscall_service.
Prototype methods to simplify work with syscall_service.
* tools/asinfo/syscall_interface.c: New file. Implement it.
* tools/asinfo/request_msgs.h: New file. Introduce main requests.
* tools/asinfo/asinfo.c: New file. Implement support of all options.
Implement usage. Implement version.
* tools/asinfo/arch_definitions.h: New file. Introduce useful storage
for architectures.

* tools/asinfo/gen_asinfo_files.sh: New file.
* bootstrap: Add it.
* tools/asinfo/Makefile.am: Include Makemodule.am.
(asinfo_SOURCES): Add $(ARCH_AUX_FILES).
* tools/asinfo/README-arch: New README explaining how to add new
architecture/ABI to asinfo tool.

* configure.ac (AC_CONFIG_FILES): Add asinfo.1.
(asinfo_manpage_date): New m4 define.
(ASINFO_MANPAGE_DATE): New define/subst.
* tools/asinfo/asinfo.1.in: New file.
* tools/asinfo/gen_asinfo_files.sh: Add asinfo.1 to .gitignore
generation.

* debian/control (strace): Add asinfo description.
* debian/strace.install: Add path to asinfo binary.
* debian/strace.manpages: Add path to asinfo manual page.
* strace.spec.in (%files): Add asinfo binary.

Update NEWS

This set of tests cover all possible cases in asinfo tool. However,
as asinfo uses some libraries provided by strace (such as basic_filters)
there is no need to test them again in asinfo context.
Also, the set of syscalls for specific architecture (hence, its number) might
be expanded in the future, so to overcome this obstacle and avoid duplication
of the same strings reference output ptintings are stored in
ref_asinfo_output.h file.
As for syscall-related checks, tests use old syscalls as samples, so their
numbers and names can't be changed.

* configure.ac (AC_CONFIG_FILES): Add tests Makefile to be generated.
* tools/asinfo/Makefile.am (SUBDIRS): Add tests dir.
* tools/asinfo/tests/Makefile.m: New file.
* tools/asinfo/tests/init.sh: New file. Main subroutines for tests.
* tools/asinfo/tests/ref_asinfo_output.h: New file.
* tools/asinfo/tests/com_disp_wrong_keys.c: Likewise.
* tools/asinfo/tests/com_disp_wrong_keys.test: Likewise.
* tools/asinfo/tests/format_output.c: Likewise.
* tools/asinfo/tests/format_output.test: Likewise.
* tools/asinfo/tests/get_arch_abi.c: Likewise.
* tools/asinfo/tests/get_arch_abi.test: Likewise.
* tools/asinfo/tests/get_sname.c: Likewise.
* tools/asinfo/tests/get_sname.test: Likewise.
* tools/asinfo/tests/get_snum.c: Likewise.
* tools/asinfo/tests/get_snum.test: Likewise.
* tools/asinfo/tests/list_arch.c: Likewise.
* tools/asinfo/tests/list_arch.test: Likewise.
* tools/asinfo/tests/multiarch_get_sname.c: Likewise.
* tools/asinfo/tests/multiarch_get_sname.test: Likewise.
* tools/asinfo/tests/multiarch_get_snum.c: Likewise.
* tools/asinfo/tests/multiarch_get_snum.test: Likewise.
* tools/asinfo/tests/set_abi.c: Likewise.
* tools/asinfo/tests/set_abi.test: Likewise.
* tools/asinfo/tests/set_arch.c: Likewise.
* tools/asinfo/tests/set_arch.test: Likewise.
* tools/asinfo/tests/set_mult_abi.c: Likewise.
* tools/asinfo/tests/set_mult_abi.test: Likewise.
* tools/asinfo/tests/set_mult_arch.c: Likewise.
* tools/asinfo/tests/set_mult_arch.test: Likewise.

Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
Adjusted-and-rebased-by: Dmitry V. Levin <ldv@altlinux.org>
This commit is contained in:
Edgar Kaziakhmedov 2017-06-15 14:47:40 +03:00 committed by Dmitry V. Levin
parent bc87159e49
commit 2c877a5df6
51 changed files with 3720 additions and 2 deletions

View File

@ -15,7 +15,7 @@ endif
if HAVE_MX32_RUNTIME
TESTS_MX32 = tests-mx32
endif
SUBDIRS = . tests $(TESTS_M32) $(TESTS_MX32)
SUBDIRS = . tests $(TESTS_M32) $(TESTS_MX32) tools
bin_PROGRAMS = strace
man_MANS = strace.1 strace-log-merge.1

4
NEWS
View File

@ -1,6 +1,10 @@
Noteworthy changes in release ?.?? (????-??-??)
===============================================
* New tools
* Added asinfo tool that is purposed to provide information about
system calls and architectures.
* Improvements
* Updated lists of BPF_*, BTRFS_*, FAN_*, IFLA_*, KERN_*, KVM_CAP_*, NDA_*,
NETNSA_*, NT_*, PR_*, REL_*, SECCOMP_*, SCTP_*, UDP_*, V4L2_*, and *_MAGIC

View File

@ -10,6 +10,7 @@
./xlat/gen.sh
./tests/gen_pure_executables.sh
./tests/gen_tests.sh
./tools/asinfo/gen_asinfo_files.sh
for m in m32 mx32; do
tests=tests-$m

View File

@ -18,6 +18,7 @@ AC_INIT([strace],
[https://strace.io])
m4_define([copyright_year], m4_esyscmd([./copyright-year-gen .year]))
m4_define([manpage_date], m4_esyscmd([./file-date-gen strace.1.in]))
m4_define([asinfo_manpage_date], m4_esyscmd([./file-date-gen tools/asinfo/asinfo.1.in]))
AC_COPYRIGHT([Copyright (c) 1999-]copyright_year[ The strace developers.])
AC_CONFIG_SRCDIR([strace.c])
AC_CONFIG_AUX_DIR([.])
@ -48,6 +49,9 @@ AC_SUBST([COPYRIGHT_YEAR], [copyright_year])
AC_DEFINE([MANPAGE_DATE], "[manpage_date]", [Date])
AC_SUBST([MANPAGE_DATE], [manpage_date])
AC_DEFINE([ASINFO_MANPAGE_DATE], "[asinfo_manpage_date]", [Date])
AC_SUBST([ASINFO_MANPAGE_DATE], [asinfo_manpage_date])
AC_MSG_CHECKING([for supported architecture])
arch_m32=
arch_mx32=
@ -922,6 +926,10 @@ AC_CONFIG_FILES([Makefile
tests-mx32/Makefile
strace.1
strace-log-merge.1
tools/asinfo/asinfo.1
tools/Makefile
tools/asinfo/Makefile
tools/asinfo/tests/Makefile
strace.spec
debian/changelog])
AC_OUTPUT

3
debian/control vendored
View File

@ -20,6 +20,9 @@ Description: System call tracer
System calls and signals are events that happen at the user/kernel
interface. A close examination of this boundary is very useful for bug
isolation, sanity checking and attempting to capture race conditions.
.
This package also contains an advanced system call information tool
(asinfo) which provides information about system calls and architectures.
Package: strace64
Architecture: i386 powerpc s390 sparc

View File

@ -1,2 +1,3 @@
build/strace usr/bin
strace-log-merge usr/bin
build/tools/asinfo/asinfo usr/bin

View File

@ -1,2 +1,3 @@
build/strace.1
build/strace-log-merge.1
build/tools/asinfo/asinfo.1

View File

@ -33,7 +33,9 @@ The strace program intercepts and records the system calls called and
received by a running process. Strace can print a record of each
system call, its arguments and its return value. Strace is useful for
diagnosing problems and debugging, as well as for instructional
purposes.
purposes. Also this package contains an advanced system call
information tool (asinfo) which provides information about system calls
and architectures.
Install strace if you need a tool to track the system calls made and
received by a process.
@ -86,6 +88,7 @@ echo 'END OF TEST SUITE INFORMATION'
%doc CREDITS ChangeLog.gz ChangeLog-CVS.gz COPYING NEWS README
%{_bindir}/strace
%{_bindir}/strace-log-merge
%{_bindir}/asinfo
%{_mandir}/man1/*
%changelog

9
tools/Makefile.am Normal file
View File

@ -0,0 +1,9 @@
# Automake input for strace tools.
#
# Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
# Copyright (c) 2017-2018 The strace developers.
# All rights reserved.
#
# SPDX-License-Identifier: GPL-2.0-or-later
SUBDIRS = asinfo

56
tools/asinfo/Makefile.am Normal file
View File

@ -0,0 +1,56 @@
# Automake input for asinfo.
#
# Copyright (c) 2017 Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
# Copyright (c) 2017-2018 The strace developers.
# All rights reserved.
#
# SPDX-License-Identifier: GPL-2.0-or-later
SUBDIRS = . tests
bin_PROGRAMS = asinfo
man_MANS = asinfo.1
OS = linux
AUTOMAKE_OPTIONS = subdir-objects
AM_CFLAGS = $(WARN_CFLAGS)
AM_CPPFLAGS = -I$(builddir) \
-I$(top_builddir)/$(OS) \
-I$(top_srcdir)/$(OS) \
-I$(top_builddir) \
-I$(top_srcdir)
include Makemodule.am
asinfo_CPPFLAGS = $(AM_CPPFLAGS)
asinfo_CFLAGS = $(AM_CFLAGS)
asinfo_SOURCES = \
arch_definitions.h \
arch_interface.c \
$(ARCH_AUX_FILES) \
arch_interface.h \
asinfo.c \
../../basic_filters.c \
dispatchers.c \
dispatchers.h \
error_interface.c \
error_interface.h \
../../error_prints.c \
../../error_prints.h \
../../filter.h \
../../macros.h \
../../number_set.c \
../../number_set.h \
request_msgs.h \
../../string_to_uint.h \
../../string_to_uint.c \
syscall_interface.c \
syscall_interface.h \
../../sysent_shorthand_defs.h \
../../sysent_shorthand_undefs.h \
../../xmalloc.c \
../../xmalloc.h \
#end of asinfo_SOURCES

37
tools/asinfo/README-arch Normal file
View File

@ -0,0 +1,37 @@
This file describes the storage format of arch_definitions.h
Storage format:
/* [ARCH_SPECIFIC_DEFINE],[ACONST1,ACONST2] */
ARCH_DESC_DEFINE(ARCH_NAME,ARCH_ABI,PASS({COMPAT_PERS1,COMPAT_PERS2,...}),\
PASS({ALIAS1,ALIAS2,...}))
ARCH_SPECIFIC_DEFINE:
One syscallent.h header can contain several set of system calls for each
compatible mode. And specific set can be switched by passing particular
definition.
So ARCH_SPECIFIC_DEFINE allows to forward a given definition, where
!ARCH_SPECIFIC_DEFINE forwards undefined.
If it is not required, left empty.
ACONST1,ACONST2:
It could be used to store architecture specific constants and pass them to code.
If is is not required each one must be set to zero.
ARCH_NAME:
The main name of architecture will be used to generate the personality
constants.
The personality constant is equal to ARCH_+\$ARCH_ABI+_+\$ARCH_NAME.
ARCH_ABI:
Application binary interface for a given architecture, i.e. 32bit, 64bit, oabi,
eabi, o32 etc.
COMPAT_PERS1,COMPAT_PERS2,...:
Compatible mode for a given architecture. It should be one of personality
constants.
If is is not required, left empty.
ALIAS1,ALIAS2,...:
Other name of the same architecture, like x86 and i386. At least one alias
must to be set as it shows the name of architecture while printing.
If current ARCH_NAME is just the compatible ABI mode, left empty.

View File

@ -0,0 +1,66 @@
/* [],[bfin/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(blackfin, 32bit, PASS({}), PASS({"blackfin", "bfin"}) ),
/* [],[ia64/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(ia64, 64bit, PASS({}), PASS({"ia64"}) ),
/* [],[m68k/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(m68k, 32bit, PASS({}), PASS({"m68k"}) ),
/* [],[sparc64/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(sparc64, 64bit, PASS({ARCH_sparc_32bit}), PASS({"sparc64"}) ),
/* [],[sparc/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(sparc, 32bit, PASS({}), PASS({"sparc"}) ),
/* [],[metag/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(metag, 32bit, PASS({}), PASS({"metag"}) ),
/* [LINUX_MIPSN64],[dummy.h,mips/syscallent-compat.h,mips/syscallent-n64.h],[0,0] */
ARCH_DESC_DEFINE(mips64, n64, PASS({ARCH_mips64_n32, ARCH_mips_o32}), PASS({"mips64", "mips64le"}) ),
/* [LINUX_MIPSN32],[dummy.h,mips/syscallent-compat.h,mips/syscallent-n32.h],[0,0] */
ARCH_DESC_DEFINE(mips64, n32, PASS({ARCH_mips_o32}), PASS({}) ),
/* [LINUX_MIPSO32],[dummy.h,mips/syscallent-compat.h,mips/syscallent-o32.h],[0,0] */
ARCH_DESC_DEFINE(mips, o32, PASS({}), PASS({"mips", "mipsle"}) ),
/* [],[alpha/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(alpha, 64bit, PASS({}), PASS({"alpha"}) ),
/* [],[powerpc64/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(ppc64, 64bit, PASS({ARCH_ppc_32bit}), PASS({"ppc64", "ppc64le", "powerpc64"}) ),
/* [],[powerpc/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(ppc, 32bit, PASS({}), PASS({"ppc", "ppcle", "powerpc"}) ),
/* [],[aarch64/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(aarch64, 64bit, PASS({ARCH_arm_eabi}), PASS({"aarch64", "arm64"}) ),
/* [!__ARM_EABI__],[arm/syscallent.h],[ARM_FIRST_SHUFFLED_SYSCALL,ARM_LAST_SPECIAL_SYSCALL] */
ARCH_DESC_DEFINE(arm, oabi, PASS({ARCH_arm_eabi}), PASS({"arm"}) ),
/* [__ARM_EABI__],[arm/syscallent.h],[ARM_FIRST_SHUFFLED_SYSCALL,ARM_LAST_SPECIAL_SYSCALL] */
ARCH_DESC_DEFINE(arm, eabi, PASS({}), PASS({}) ),
/* [],[avr32/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(avr32, 32bit, PASS({}), PASS({"avr32"}) ),
/* [],[arc/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(arc, 32bit, PASS({}), PASS({"arc"}) ),
/* [],[s390x/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(s390x, 64bit, PASS({}), PASS({"s390x"}) ),
/* [],[s390/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(s390, 32bit, PASS({}), PASS({"s390"}) ),
/* [],[hppa/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(hppa, 32bit, PASS({}), PASS({"parisc", "hppa"}) ),
/* [],[sh64/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(sh64, 64bit, PASS({}), PASS({"sh64"}) ),
/* [],[sh/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(sh, 32bit, PASS({}), PASS({"sh"}) ),
/* [],[x86_64/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(x86_64, 64bit, PASS({ARCH_x86_64_x32, ARCH_x86_32bit}), PASS({"x86_64", "amd64", "EM64T"}) ),
/* [],[x86_64/syscallent2.h],[0,0] */
ARCH_DESC_DEFINE(x86_64, x32, PASS({ARCH_x86_32bit}), PASS({}) ),
/* [],[i386/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(x86, 32bit, PASS({}), PASS({"x86", "i386", "i486", "i586", "i686"}) ),
/* [],[tile/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(tile, 64bit, PASS({ARCH_tile_32bit}), PASS({"tile", "tilegx"}) ),
/* [],[tile/syscallent1.h],[0,0] */
ARCH_DESC_DEFINE(tile, 32bit, PASS({}), PASS({"tilepro"}) ),
/* [],[microblaze/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(microblaze, 32bit, PASS({}), PASS({"microblaze"}) ),
/* [],[nios2/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(nios2, 32bit, PASS({}), PASS({"nios2"}) ),
/* [],[or1k/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(openrisc, 32bit, PASS({}), PASS({"openrisc", "or1k"}) ),
/* [],[xtensa/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(xtensa, 32bit, PASS({}), PASS({"xtensa"}) ),
/* [],[riscv/syscallent.h],[0,0] */
ARCH_DESC_DEFINE(riscv, 64bit, PASS({ARCH_riscv_32bit}), PASS({"riscv"}) ),
/* [],[riscv/syscallent1.h],[0,0] */
ARCH_DESC_DEFINE(riscv, 32bit, PASS({}), PASS({}) )

View File

@ -0,0 +1,635 @@
/*
* Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
* Copyright (c) 2017-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "arch_interface.h"
#include "defs.h"
#include "macros.h"
#include "xmalloc.h"
/* Define these shorthand notations to simplify the syscallent files. */
#include "sysent_shorthand_defs.h"
/* For the current functionality there is no need
to use sen and (*sys_func)() fields in sysent struct */
#define SEN(syscall_name) 0, NULL
/* Generated file based on arch_definitions.h */
#include "arch_includes.h"
/* Now undef them since short defines cause wicked namespace pollution. */
#include "sysent_shorthand_undefs.h"
#define PASS(...) __VA_ARGS__
#define ARCH_DESC_DEFINE(arch, mode, comp_pers, arch_aliases) \
[ARCH_##arch##_##mode] = { \
.pers = ARCH_##arch##_##mode, \
.arch_name = arch_aliases, \
.abi_mode = #mode, \
.abi_mode_len = ARRAY_SIZE(#arch) - 1, \
.compat_pers = comp_pers, \
.max_scn = ARRAY_SIZE(arch##_##mode##_sysent), \
.syscall_list = arch##_##mode##_sysent, \
.user_num1 = &arch##_##mode##_usr1, \
.user_num2 = &arch##_##mode##_usr2, \
}
/* Generate array of arch_descriptors for each personality */
const struct arch_descriptor architectures[] = {
#include "arch_definitions.h"
};
#undef ARCH_DESC_DEFINE
#undef PASS
struct arch_service *
al_create(unsigned capacity)
{
ARCH_LIST_DEFINE(as) = NULL;
if (!capacity)
return NULL;
as = xcalloc(sizeof(*as), 1);
as->arch_list = xcalloc(sizeof(*(as->arch_list)), capacity);
as->flag = xcalloc(sizeof(*(as->flag)), capacity);
as->in_aname = xcalloc(sizeof(*(as->in_aname)), capacity);
as->err = es_create();
as->capacity = capacity;
as->next_free = 0;
return as;
}
int
al_push(struct arch_service *m, const struct arch_descriptor *element)
{
if (m->next_free >= m->capacity)
return -1;
m->arch_list[m->next_free] = element;
m->flag[m->next_free] = AD_FLAG_EMPTY;
m->next_free++;
return 0;
}
static inline int
al_is_index_ok(struct arch_service *m, unsigned index)
{
if (index >= m->next_free)
return -1;
return 0;
}
int
al_set_flag(struct arch_service *m, unsigned index, int flag)
{
if (al_is_index_ok(m, index) == 0) {
m->flag[index] = flag;
return 0;
}
return -1;
}
int
al_add_flag(struct arch_service *m, unsigned index, int flag)
{
if (al_is_index_ok(m, index) == 0) {
m->flag[index] = m->flag[index] | flag;
return 0;
}
return -1;
}
int
al_sub_flag(struct arch_service *m, unsigned index, int flag)
{
if (al_is_index_ok(m, index) == 0) {
m->flag[index] = m->flag[index] & ~flag;
return 0;
}
return -1;
}
const struct arch_descriptor *
al_get(struct arch_service *m, unsigned index)
{
if (al_is_index_ok(m, index) != 0)
return NULL;
return m->arch_list[index];
}
unsigned int
al_size(struct arch_service *m)
{
return m->next_free;
}
void
al_free(struct arch_service *m)
{
int i;
int size = al_size(m);
for (i = 0; i < size; i++)
if (al_in_aname(m, i) != NULL)
free(al_in_aname(m, i));
free(m->arch_list);
free(m->flag);
free(m->in_aname);
es_free(m->err);
free(m);
}
struct error_service *al_err(struct arch_service *m)
{
return m->err;
}
enum arch_pers
al_pers(struct arch_service *m, unsigned index)
{
const struct arch_descriptor *elem = al_get(m, index);
return (elem ? elem->pers : ARCH_no_pers);
}
const char **
al_arch_name(struct arch_service *m, unsigned index)
{
const struct arch_descriptor *elem = al_get(m, index);
return (elem ? (const char **)elem->arch_name : NULL);
}
enum arch_pers *
al_cpers(struct arch_service *m, unsigned index)
{
const struct arch_descriptor *elem = al_get(m, index);
return (elem ? (enum arch_pers *)elem->compat_pers : NULL);
}
const char *
al_abi_mode(struct arch_service *m, unsigned index)
{
const struct arch_descriptor *elem = al_get(m, index);
return (elem ? elem->abi_mode : NULL);
}
int
al_abi_mode_len(struct arch_service *m, unsigned index)
{
const struct arch_descriptor *elem = al_get(m, index);
return (elem ? elem->abi_mode_len : -1);
}
int
al_flag(struct arch_service *m, unsigned index)
{
int status = al_is_index_ok(m, index);
return (!status ? m->flag[index] : -1);
}
int
al_set_in_aname(struct arch_service *m, unsigned index, char *aname)
{
int status = al_is_index_ok(m, index);
if (status)
return -1;
m->in_aname[index] = aname;
return 0;
}
char *
al_in_aname(struct arch_service *m, unsigned index)
{
int status = al_is_index_ok(m, index);
return (!status ? m->in_aname[index] : NULL);
}
int
al_psize(struct arch_service *m)
{
int i;
int a_size = al_size(m);
int psize = 0;
for (i = 0; i < a_size; i++)
if (al_flag(m, i) & AD_FLAG_PRINT)
psize++;
return psize;
}
int
al_arch_name_len(struct arch_service *m, unsigned index, int delim_len)
{
const char **arch_name = NULL;
int i;
int final_len = 0;
while (!(al_flag(m, index) & AD_FLAG_MPERS))
index--;
arch_name = al_arch_name(m, index);
for (i = 0; (arch_name[i] != NULL) && (i < MAX_ALIASES); i++) {
final_len += strlen(arch_name[i]);
final_len += delim_len;
}
final_len -= delim_len;
return final_len;
}
int
al_syscall_impl(struct arch_service *m, unsigned index)
{
const struct arch_descriptor *elem = al_get(m, index);
int i = 0;
int count = 0;
if (elem == NULL)
return -1;
for (i = 0; i < elem->max_scn; i++) {
if (elem->syscall_list[i].sys_name &&
!(elem->syscall_list[i].sys_flags &
TRACE_INDIRECT_SUBCALL))
count++;
}
return count;
}
/* This method is purposed to count the supported ABI modes for the given
arch */
int
al_get_abi_modes(struct arch_service *m, unsigned index)
{
const struct arch_descriptor *elem = al_get(m, index);
int i = 0;
int abi_count = 1;
if (!elem)
return -1;
for (i = 0; i < MAX_ALT_ABIS; i++)
if (elem->compat_pers[i] != ARCH_no_pers)
abi_count++;
return abi_count;
}
/* This method is purposed to find next one name of the same architecture.
For instance, x86_64 = amd64 */
const char *
al_next_alias(struct arch_service *m, unsigned index)
{
static int next_alias = -1;
static const char **arch_name = NULL;
static unsigned lindex = 0;
if (lindex != index) {
lindex = index;
next_alias = -1;
}
if (al_pers(m, index) == ARCH_no_pers)
return NULL;
if (next_alias == -1) {
next_alias = 0;
while (!(al_flag(m, index) & AD_FLAG_MPERS))
index--;
arch_name = al_arch_name(m, index);
} else
next_alias++;
if (next_alias >= MAX_ALIASES || arch_name[next_alias] == NULL) {
next_alias = -1;
return NULL;
}
return arch_name[next_alias];
}
/* This method is purposed to return next one compat personality of the
same architecture */
enum arch_pers
al_next_cpers(struct arch_service *m, unsigned index)
{
static int next_pers = -1;
enum arch_pers *a_pers = al_cpers(m, index);
static unsigned lindex = 0;
if (al_pers(m, index) == ARCH_no_pers)
return ARCH_no_pers;
if (lindex != index) {
lindex = index;
next_pers = -1;
}
if (next_pers == -1)
next_pers = 0;
else
next_pers++;
if (next_pers >= MAX_ALT_ABIS ||
a_pers[next_pers] == ARCH_no_pers) {
next_pers = -1;
return ARCH_no_pers;
}
return a_pers[next_pers];
}
enum impl_type
al_ipc_syscall(struct arch_service *m, unsigned index)
{
const struct arch_descriptor *elem = al_get(m, index);
int i;
enum impl_type impl_buf = IMPL_int;
for (i = 0; i < elem->max_scn; i++) {
if (elem->syscall_list[i].sys_name == NULL)
continue;
/* It is enough to find just semop sybcall */
if (!strcmp(elem->syscall_list[i].sys_name, "semop")) {
if (!(elem->syscall_list[i].sys_flags &
TRACE_INDIRECT_SUBCALL))
impl_buf = IMPL_ext;
else if (impl_buf == IMPL_ext)
impl_buf = IMPL_int_ext;
else
impl_buf = IMPL_int;
}
}
return impl_buf;
}
enum impl_type
al_sck_syscall(struct arch_service *m, unsigned index)
{
const struct arch_descriptor *elem = al_get(m, index);
int i;
enum impl_type impl_buf = IMPL_int;
for (i = 0; i < elem->max_scn; i++) {
if (elem->syscall_list[i].sys_name == NULL)
continue;
/* It is enough to find just socket sybcall */
if (!strcmp(elem->syscall_list[i].sys_name, "socket")) {
if (!(elem->syscall_list[i].sys_flags &
TRACE_INDIRECT_SUBCALL))
impl_buf = IMPL_ext;
else if (impl_buf == IMPL_ext)
impl_buf = IMPL_int_ext;
else
impl_buf = IMPL_int;
}
}
return impl_buf;
}
/* This method is purposed to create extended list of architectures */
struct arch_service *
al_create_filled(void)
{
static const int architectures_size = ARRAY_SIZE(architectures) - 1;
ARCH_LIST_DEFINE(as) = al_create(architectures_size);
ARCH_LIST_DEFINE(f_as);
enum arch_pers cpers;
int esize = 0;
const char **arch_name = NULL;
int i;
/* Push and calculate size of extended table */
for (i = 0; i < architectures_size; i++) {
al_push(as, &(architectures[i + 1]));
arch_name = al_arch_name(as, i);
if (arch_name[0] != NULL)
esize += al_get_abi_modes(as, i);
}
f_as = al_create(esize);
/* Fill extended teble */
for (i = 0; i < architectures_size; i++) {
arch_name = al_arch_name(as, i);
if (arch_name[0] == NULL)
continue;
al_push(f_as, al_get(as, i));
al_add_flag(f_as, al_size(f_as) - 1, AD_FLAG_MPERS);
while ((cpers = al_next_cpers(as, i)) != ARCH_no_pers)
al_push(f_as, &(architectures[cpers]));
}
free(as);
return f_as;
}
/* To look up arch in arch_descriptor array */
int
al_mark_matches(struct arch_service *m, char *arch_str)
{
int arch_match = -1;
char *match_pointer = NULL;
const char *a_name = NULL;
int al_size_full = al_size(m);
unsigned prev_arch_len = 0;
int i;
int a_abi;
char *in_aname;
if (arch_str == NULL)
return -1;
/* Here we find the best match for arch_str in architecture list.
Best match means here that we have to find the longest name of
architecture in a_full_list with arch_str substring, beginning
from the first letter */
for (i = 0; i < al_size_full; i++) {
if (!(al_flag(m, i) & AD_FLAG_MPERS))
continue;
while ((a_name = al_next_alias(m, i)) != NULL) {
match_pointer = strstr(arch_str, a_name);
if (match_pointer == NULL || match_pointer != arch_str)
continue;
if (arch_match == -1 ||
strlen(a_name) > prev_arch_len) {
prev_arch_len = strlen(a_name);
arch_match = i;
}
}
}
if (arch_match == -1)
return -1;
/* Now we find all ABI modes related to the architecture */
if ((a_abi = al_get_abi_modes(m, arch_match)) == -1)
return -1;
for (i = arch_match; i < (arch_match + a_abi); i++) {
al_add_flag(m, i, AD_FLAG_PRINT);
in_aname = xcalloc(sizeof(*in_aname), strlen(arch_str) + 1);
strcpy(in_aname, arch_str);
al_set_in_aname(m, i, in_aname);
}
return 0;
}
/* Join all architectures from 'f' and architectures with AD_FLAG_PRINT
from 's' arch_service structures */
struct arch_service *
al_join_print(struct arch_service *f, struct arch_service *s)
{
int size1 = (f ? al_size(f) : 0);
int psize2 = al_psize(s);
int size2 = al_size(s);
int i;
int start_point = 0;
ARCH_LIST_DEFINE(final) = al_create(size1 + psize2);
for (i = 0; i < size2; i++)
if (al_flag(s, i) & AD_FLAG_PRINT) {
start_point = i;
break;
}
for (i = 0; i < size1; i++) {
al_push(final, al_get(f, i));
al_set_flag(final, i, al_flag(f, i));
al_set_in_aname(final, i, al_in_aname(f, i));
al_set_in_aname(f, i, NULL);
}
for (i = 0; i < psize2; i++) {
al_push(final, al_get(s, start_point + i));
al_set_flag(final, size1 + i , al_flag(s, start_point + i));
al_set_in_aname(final, size1 + i,
al_in_aname(s, start_point + i));
al_set_in_aname(s, start_point + i, NULL);
al_sub_flag(s, start_point + i, AD_FLAG_PRINT);
}
if (f)
al_free(f);
return final;
}
/* To avoid duplication of for(;;) construction */
void
al_unmark_all(struct arch_service *m, int flag)
{
int a_size = al_size(m);
int i;
for (i = 0; i < a_size; i++)
al_sub_flag(m, i, flag);
}
/* Select one compatible personality in range of one architecture */
int
al_mark_pers4arch(struct arch_service *m, unsigned index, const char *abi_mode)
{
unsigned i = index;
while (!(al_flag(m, i) & AD_FLAG_MPERS) || (i == index)) {
if (strcmp(abi_mode, "all") == 0) {
al_add_flag(m, i, AD_FLAG_PRINT);
i++;
if ((al_is_index_ok(m, i)) ||
(al_flag(m, i) & AD_FLAG_MPERS))
return 0;
else
continue;
}
if (strcmp(al_abi_mode(m, i), abi_mode) == 0) {
al_add_flag(m, i, AD_FLAG_PRINT);
return 0;
}
i++;
}
return -1;
}
void
al_dump(struct arch_service *m, int is_raw)
{
static const char *title[] = {
"N",
"Architecture name",
"ABI mode",
/* Implemented syscalls */
"IMPL syscalls",
/* IPC implementation */
"IPC IMPL",
/* SOCKET implementation */
"SOCKET IMPL"
};
int title_len[] = {
0,
strlen(title[1]),
strlen(title[2]),
strlen(title[3]),
strlen(title[4]),
strlen(title[5]),
};
static const char *impl_st[] = {
"external",
"internal",
"int/ext"
};
static const char *delim = "/";
int i = 0;
int N = 0;
int temp_len = 0;
int arch_size = al_size(m);
int arch_psize = al_psize(m);
const char *next_alias = NULL;
char *whole_arch_name;
/* Calculate length of the column with the number of architectures */
for (i = 1; arch_psize/i != 0; i *= 10)
title_len[0]++;
for (i = 0; i < arch_size; i++) {
if (!(al_flag(m, i) & AD_FLAG_PRINT))
continue;
/* Calculate length of the column with the
architectures name */
temp_len = al_arch_name_len(m, i, strlen(delim));
if (temp_len > title_len[1])
title_len[1] = temp_len;
/* Calculate length of the column with the ABI mode */
if (al_abi_mode_len(m, i) > title_len[2])
title_len[2] = al_abi_mode_len(m, i);
}
whole_arch_name = xcalloc(title_len[1] + 1, sizeof(*whole_arch_name));
/* Output title */
if (!is_raw)
printf("| %*s | %*s | %*s | %*s | %*s | %*s |\n",
title_len[0], title[0], title_len[1], title[1],
title_len[2], title[2], title_len[3], title[3],
title_len[4], title[4], title_len[5], title[5]);
/* Output architectures */
for (i = 0; i < arch_size; i++) {
if (!(al_flag(m, i) & AD_FLAG_PRINT))
continue;
N++;
memset(whole_arch_name, 0, title_len[1]);
/* Put all the same arch back together */
next_alias = al_next_alias(m, i);
strcat(whole_arch_name, next_alias);
while ((next_alias = al_next_alias(m, i)) != NULL) {
strcat(whole_arch_name, delim);
strcat(whole_arch_name, next_alias);
}
if (is_raw) {
printf("%u;%s;%s;%d;%s;%s;\n", N, whole_arch_name,
al_abi_mode(m, i), al_syscall_impl(m, i),
impl_st[al_ipc_syscall(m, i)],
impl_st[al_ipc_syscall(m, i)]);
continue;
}
printf("| %*u | ", title_len[0], N);
printf("%*s | ", title_len[1], whole_arch_name);
printf("%*s | ", title_len[2], al_abi_mode(m, i));
printf("%*d | ", title_len[3], al_syscall_impl(m, i));
printf("%*s | ", title_len[4], impl_st[al_ipc_syscall(m, i)]);
printf("%*s |\n", title_len[5], impl_st[al_sck_syscall(m, i)]);
}
free(whole_arch_name);
}

View File

@ -0,0 +1,143 @@
/*
* The arch_interface.h is purposed to interact with the basic data structure
* based on arch_descriptor struct. Mainly this set of methods are used by
* arch_dispatcher.
*
* Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedv@virtuozzo.com>
* Copyright (c) 2017-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ASINFO_ARCH_INTERFACE_H
#define ASINFO_ARCH_INTERFACE_H
#include "error_interface.h"
#include "sysent.h"
/* Type implementaion of syscall, internal means as a subcall,
external means a separate syscall, this enum is purposed for
well-known ipc and socket subcall group */
enum impl_type {
IMPL_ext,
IMPL_int,
IMPL_int_ext
};
/* Names of personalities
* arch_pers = ARCH_ + kernel_kernel/other_name + abi_mode */
enum arch_pers {
#include "arch_personalities.h"
};
#define MAX_ALIASES 6
#define MAX_ALT_ABIS 3
struct arch_descriptor {
enum arch_pers pers;
const char *arch_name[MAX_ALIASES];
const char *abi_mode;
const int abi_mode_len;
enum arch_pers compat_pers[MAX_ALT_ABIS];
const int max_scn;
const struct_sysent *syscall_list;
/* In the most cases these fields are purposed to store specific for
given arch constants, for instance, ARM_FIRST_SHUFFLED_SYSCALL */
const int *user_num1;
const int *user_num2;
};
#define AD_FLAG_EMPTY 0
/* to hide some abi modes belonging to one architecture */
#define AD_FLAG_PRINT (1 << 0)
/* main personality, like x86_64 64bit */
#define AD_FLAG_MPERS (1 << 1)
/* To provide push-back interface with arch_list */
struct arch_service {
/* immutable field */
const struct arch_descriptor **arch_list;
/* User flags for each arch_descriptor */
int *flag;
/* To support conformity between ABI and ARCH */
char **in_aname;
struct error_service *err;
unsigned capacity;
unsigned next_free;
};
#define ARCH_LIST_DEFINE(name) \
struct arch_service *(name)
/* Push-back interface is purposed to simplify interaction with
arch_service struct
NOTE: al - architecture list */
/* base methods */
struct arch_service *al_create(unsigned capacity);
int al_push(struct arch_service *m, const struct arch_descriptor *element);
int al_set_flag(struct arch_service *m, unsigned index, int flag);
int al_add_flag(struct arch_service *m, unsigned index, int flag);
int al_sub_flag(struct arch_service *m, unsigned index, int flag);
const struct arch_descriptor *al_get(struct arch_service *m, unsigned index);
unsigned int al_size(struct arch_service *m);
void al_free(struct arch_service *m);
struct error_service *al_err(struct arch_service *m);
/* methods returning fields with error check */
enum arch_pers al_pers(struct arch_service *m, unsigned index);
const char **al_arch_name(struct arch_service *m, unsigned index);
enum arch_pers *al_cpers(struct arch_service *m, unsigned index);
const char *al_abi_mode(struct arch_service *m, unsigned index);
int al_abi_mode_len(struct arch_service *m, unsigned index);
int al_flag(struct arch_service *m, unsigned index);
int al_set_in_aname(struct arch_service *m, unsigned index, char *aname);
char *al_in_aname(struct arch_service *m, unsigned index);
/* calculating methods */
int al_psize(struct arch_service *m);
int al_arch_name_len(struct arch_service *m, unsigned index, int delim_len);
int al_syscall_impl(struct arch_service *m, unsigned index);
int al_get_abi_modes(struct arch_service *m, unsigned index);
const char *al_next_alias(struct arch_service *m, unsigned index);
enum arch_pers al_next_cpers(struct arch_service *m, unsigned index);
enum impl_type al_ipc_syscall(struct arch_service *m, unsigned index);
enum impl_type al_sck_syscall(struct arch_service *m, unsigned index);
struct arch_service *al_create_filled(void);
int al_mark_matches(struct arch_service *m, char *arch_str);
struct arch_service *al_join_print(struct arch_service *f,
struct arch_service *s);
void al_unmark_all(struct arch_service *m, int flag);
int al_mark_pers4arch(struct arch_service *m, unsigned index,
const char *abi_mode);
void al_dump(struct arch_service *m, int is_raw);
#endif /* !ASINFO_ARCH_INTERFACE_H */

264
tools/asinfo/asinfo.1.in Normal file
View File

@ -0,0 +1,264 @@
.\" Copyright (c) 2017 Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
.\" Copyright (c) 1996-2018 The strace developers.
.\" All rights reserved.
.\"
.\" SPDX-License-Identifier: GPL-2.0-or-later
.\" Required option.
.de OR
. ie \\n(.$-1 \
. RI "\fB\\$1\fP" "\ \\$2"
. el \
. BR "\\$1"
..
.TH ASINFO 1 "@ASINFO_MANPAGE_DATE@" "strace package @VERSION@"
.SH NAME
asinfo \- Advanced System call INFOrmation tool
.SH SYNOPSIS
.SY asinfo
.BR "" \fR[{
.OR \-\-set\-arch arch
.BR "" |
.OR \-\-get\-arch
.BR "" }
.OR \fR[\fP\-\-set\-abi abi
.BR "" |
.OR \-\-list\-abi\fR]\fR]
.BR "" {
.BR "" {
.OR \-\-get\-sname expr
.BR "" |
.OR \-\-get\-snum expr
.BR "" }
.OP \-\-nargs
.BR "" }
.OP "\-\-raw"
.YS
.SY asinfo
.BR "" {
.OR \-\-set\-arch arch
.BR "" |
.OR \-\-get\-arch
.BR "" |
.OR \-\-list\-arch
.BR "" }
.BD "" [
.OR \fR[\fP\-\-set\-abi abi
.BR "" |
.OR \-\-list\-abi\fR]
.OP "\-\-raw"
.SH DESCRIPTION
.B asinfo
provides information about various aspects of system calls across architectures
using
.B strace
knowledge base.
In the simplest
case it provides mapping from system call name to number and reverse.
The main advantage of tool is it can work in single/multi arch modes with
the opportunity to show discrepancies in system call characteristics.
Also, the single arch mode allows program to take a guess about the
current architecture and ABI, if they are not specified. Furthermore,
.B asinfo
provides convenient filtering for selecting system calls.
.SH OPTIONS
.SS "Architecture parameters"
.TP 7
.BI "\-\-set\-arch " arch
Specify architecture/architectures manually. The format of the
.I arch
expression is:
.RS 9
.IP
\fIarch1\/\fR[\fB,\fIarch2\/\fR]...
.RE
.IP
.TP
.B \-\-get\-arch
Select achitecture based on the current machine.
.TP
.B \-\-list-arch
Print out all supported architectures.
Combined use with any ABI option is permitted.
.SS "ABI parameters"
.TP 7
.BI "\-\-set\-abi " abi
Specify ABI/ABIs manually. The format of the experession is:
.RS 9
.IP
\fIabi1\/\fR[\fB,\fIabi2\/\fR]...
.RE
.IP
.IP
Note that ABI should be selected for each corresponding architecture.
In addition, the special value
.B all
allows to choose all ABIs for the respective architecture.
.TP
.B "\-\-list\-abi "
Select all ABIs for the chosen architecture/architectures.
.IP
If ABI parameters are not used and only single architecture is selected, tool
will take a guess about ABI based on the strace package build.
.SS "System call parameters"
.TP 7
.BI "\-\-get\-sname " expr
Select system calls that satisfy a filtering expression
.I
expr
and print out name of system calls and numbers for each architecture/ABI.
.TP
.BI "\-\-get\-snum " expr
Select system calls that satisfy a filtering expression
.I
expr
and print out number of system calls and names for each architecture/ABI.
.TP
.B \-\-nargs
Switch the second output system call characteristic to number of arguments.
.SS Output formatting
.TP 7
.B "\-\-raw"
Reset alignment and remove titles, use ';' as a delimiter.
.SS Miscellaneous
.TP 7
.B \-h
Print the help summary.
.TP
.B \-v
Print the version number.
.SH "FILTERING EXPRESSION"
A filtering expression is a pattern that describes a set of syscall names,
syscall numbers, and syscall group. The format of the expression is:
.RS 2
.IP
[\fB!\fR][\fB?\fR]\,\fIvalue1\/\fR[\fB,\fR[\fB?\fR]\,\fIvalue2\/\fR]...
.RE
.LP
where
.I value
is a symbol or number. Using an exclamation mark negates the set of values.
For example,
.BR \fIvalue\fR = write
means print strictly the write system call. By contrast,
.BR \fIvalue\fR = !write
means to dump every system call except write. Question mark before the
syscall qualification allows suppression of error in case no syscalls matched
the qualification provided, that can be particularly useful in multiarch mode,
when system call is not presented in all selected architectures. In addition,
the special values
.B all
and
.B none
have the obvious meanings.
.LP
Note that some shells use the exclamation point for history
expansion even inside quoted arguments. If so, you must escape
the exclamation point with a backslash.
.SS "Strict match"
.TP 7
.B \fIvalue\fR=\,\fIset\fR
Print out only the specified set of system calls. For example,
.BR \fIvalue\fR = open,close,read,write
means to only show those four system calls.
.SS "Regex match"
.TP 7
.B \fIvalue\fR=/\,\fIregex\fR
Show only those system calls that match the
.IR regex .
You can use
.B POSIX
Extended Regular Expression syntax (see
.BR regex (7)).
.SS "Class match"
.TP 7
.BR \fIvalue\fR = %file
.TQ
.BR \fIvalue\fR = file " (deprecated)"
Show all system calls which take a file name as an argument. You
can think of this as an abbreviation for
.BR \fIvalue\fR = open,stat,chmod,unlink,...
Furthermore, using the abbreviation will ensure that you don't
accidentally forget to include a call like
.B lstat
in the list.
.PP
.BR \fIvalue\fR = %process
.TQ
.BR \fIvalue\fR = process " (deprecated)"
Show all system calls which involve process management.
.PP
.BR \fIvalue\fR = %network
.TQ
.BR \fIvalue\fR = network " (deprecated)"
Show all the network related system calls.
.PP
.BR \fIvalue\fR = %signal
.TQ
.BR \fIvalue\fR = signal " (deprecated)"
Show all signal related system calls.
.PP
.BR \fIvalue\fR = %ipc
.TQ
.BR \fIvalue\fR = ipc " (deprecated)"
Show all IPC related system calls.
.PP
.BR \fIvalue\fR = %desc
.TQ
.BR \fIvalue\fR = desc " (deprecated)"
Show all file descriptor related system calls.
.PP
.BR \fIvalue\fR = %memory
.TQ
.BR \fIvalue\fR = memory " (deprecated)"
Show all memory mapping related system calls.
.TP
.BR \fIvalue\fR = %stat
Show stat syscall variants.
.TP
.BR \fIvalue\fR = %lstat
Show lstat syscall variants.
.TP
.BR \fIvalue\fR = %fstat
Show fstat and fstatat syscall variants.
.TP
.BR \fIvalue\fR = %%stat
Show syscalls used for requesting file status (stat, lstat, fstat, fstatat,
statx, and their variants).
.TP
.BR \fIvalue\fR = %statfs
Show statfs, statfs64, statvfs, osf_statfs, and osf_statfs64 system calls.
The same effect can be achieved with
.BR \fIvalue\fR = /^(.*_)?statv?fs
regular expression.
.TP
.BR \fIvalue\fR = %fstatfs
Show fstatfs, fstatfs64, fstatvfs, osf_fstatfs, and osf_fstatfs64 system calls.
The same effect can be achieved with
.BR \fIvalue\fR = /fstatv?fs
regular expression.
.TP
.BR \fIvalue\fR = %%statfs
Show syscalls related to file system statistics (statfs-like, fstatfs-like,
and ustat). The same effect can be achieved with
.BR \fIvalue\fR = /statv?fs|fsstat|ustat
regular expression.
.SH "EXIT STATUS"
On success,
.B asinfo
returns 0. Otherwise, in case of wrong input or no matches found, 1.
.SH "REPORTING BUGS"
Problems with
.B asinfo
should be reported to the
.B strace
mailing list at <strace-devel@lists.sourceforge.net>.
.SH "SEE ALSO"
.BR strace (1)

312
tools/asinfo/asinfo.c Normal file
View File

@ -0,0 +1,312 @@
/*
* The asinfo main source. The asinfo tool is purposed to operate
* with system calls and provide information about it.
*
* Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
* Copyright (c) 2017-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "arch_interface.h"
#include "dispatchers.h"
#include "error_interface.h"
#include "error_prints.h"
#include "macros.h"
#include "request_msgs.h"
#include "syscall_interface.h"
#include "xmalloc.h"
#ifndef HAVE_PROGRAM_INVOCATION_NAME
char *program_invocation_name;
#endif
static void
usage(void)
{
puts(
"usage: asinfo (--set-arch arch | --get-arch | --list-arch)\n"
" [--set-abi abi | --list-abi] [--raw]\n"
" or: asinfo [(--set-arch arch | --get-arch) [--set-abi abi | --list-abi]]\n"
" ((--get-sname expr | --get-snum expr) [--nargs]) [--raw]\n"
"\n"
"Architecture:\n"
" --set-arch arch use architecture ARCH for further work\n"
" argument format: arch1,arch2,...\n"
" --get-arch use architecture returned by uname for further work\n"
" --list-arch print out all architectures supported by strace\n"
" (combined use list-arch and any ABI option is permitted)\n"
"\n"
"ABI:\n"
" --set-abi abi use application binary interface ABI for further work\n"
" ('all' can be used as ABI to use all compatible personalities\n"
" for corresponding architecture)\n"
" argument format: abi1,abi2,...\n"
" --list-abi use all ABIs for specified architecture\n"
"\n"
"System call:\n"
" --get-sname expr print all system calls that satisfy a filtering expression:\n"
" [!]all or [!][?]val1[,[?]val2]...\n"
" with the following format:\n"
" | N | syscall name | snum1 | snum2 | ...\n"
" --get-snum expr print all system calls that satisfy a filtering expression:\n"
" [!]all or [!][?]val1[,[?]val2]...\n"
" with the following format:\n"
" | N | syscall number | sname1 | sname2 | ...\n"
" --nargs change output format as follows:\n"
" | N | syscall name or number | nargs1 | sname2 | ...\n"
"\n"
"Output formatting:\n"
" --raw reset alignment and remove titles, use ';' as a delimiter\n"
"\n"
"Miscellaneous:\n"
" -h print help message\n"
" -v print version");
exit(0);
}
static void
print_version(void)
{
printf("asinfo (%s package) -- version %s\n"
"Copyright (c) 1991-%s The strace developers <%s>.\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
PACKAGE_NAME, PACKAGE_VERSION, COPYRIGHT_YEAR, PACKAGE_URL);
exit(0);
}
void
die(void)
{
exit(1);
}
static int
is_more1bit(unsigned int num)
{
return !(num & (num - 1));
}
static unsigned
strpar2req(char *option)
{
/* Convertion table to store string with options */
static const char *options[] = {
[SD_REQ_GET_SNAME_BIT] = "--get-sname",
[SD_REQ_GET_SNUM_BIT] = "--get-snum",
[SD_REQ_NARGS_BIT] = "--nargs",
[AD_REQ_SET_ARCH_BIT] = "--set-arch",
[AD_REQ_GET_ARCH_BIT] = "--get-arch",
[AD_REQ_LIST_ARCH_BIT] = "--list-arch",
[ABD_REQ_SET_ABI_BIT] = "--set-abi",
[ABD_REQ_LIST_ABI_BIT] = "--list-abi",
[SERV_REQ_RAW_BIT] = "--raw",
[SERV_REQ_HELP_BIT] = "-h",
[SERV_REQ_VERSION_BIT] = "-v"
};
unsigned i;
for (i = 0; i < ARRAY_SIZE(options); i++) {
if (options[i] && strcmp(option, options[i]) == 0)
return i;
}
return SERV_REQ_ERROR_BIT;
}
static char **
arg2list(char *argument)
{
int i;
int len = strlen(argument);
int occur = 1;
char **arg_list;
for (i = 0; i < len; i++) {
if (argument[i] == ',') {
if (i == 0 || i == len - 1 || argument[i + 1] == ',')
return NULL;
occur++;
}
}
arg_list = xcalloc(sizeof(*arg_list), occur + 1);
for (i = 0; i < occur; i++) {
arg_list[i] = argument;
argument = strchr(argument, ',');
if (argument) {
*argument = '\0';
argument++;
}
}
return arg_list;
}
/* The purpose of this function is to convert input parameters to number with
set bits, where each bit means specific work mode. Moreover, it checks input
for correctness and outputs error messages in case of wrong input */
static unsigned
command_dispatcher(int argc, char *argv[], char **args[])
{
int i;
unsigned final_req = 0;
unsigned temp_req = 0;
int mult_arch = 0;
int mult_abi = 0;
unsigned non_req_arg = AD_REQ_GET_ARCH | AD_REQ_LIST_ARCH |
ABD_REQ_LIST_ABI | SD_REQ_NARGS |
SERV_REQ_RAW;
if (!program_invocation_name || !*program_invocation_name) {
static char name[] = "asinfo";
program_invocation_name =
(argv[0] && *argv[0]) ? argv[0] : name;
}
/* Try to find help or version parameter first */
for (i = 1; i < argc; i++) {
if (strpar2req(argv[i]) == SERV_REQ_HELP_BIT)
usage();
if (strpar2req(argv[i]) == SERV_REQ_VERSION_BIT)
print_version();
}
/* For now, is is necessary to convert string parameter to number of
request and make basic check */
for (i = 1; i < argc; i++) {
if ((temp_req = strpar2req(argv[i])) == SERV_REQ_ERROR_BIT)
error_msg_and_help("unrecognized option '%s'",
argv[i]);
if (final_req & 1 << temp_req)
error_msg_and_help("parameter '%s' has been used "
"more than once", argv[i]);
if (!((1 << temp_req) & non_req_arg) &&
(i + 1 >= argc || strlen(argv[i + 1]) == 0 ||
strpar2req(argv[i + 1]) != SERV_REQ_ERROR_BIT))
error_msg_and_help("parameter '%s' requires "
"argument", argv[i]);
final_req |= 1 << temp_req;
if (!((1 << temp_req) & non_req_arg)) {
if ((1 << temp_req) & SD_REQ_MASK) {
args[temp_req] = &argv[i + 1];
i++;
continue;
}
if ((args[temp_req] = arg2list(argv[i + 1])) != NULL) {
i++;
continue;
}
error_msg_and_help("argument '%s' of '%s' parameter "
"has a wrong format",
argv[i + 1], argv[i]);
}
}
/* Count our multuarchness */
if (args[AD_REQ_SET_ARCH_BIT])
while (args[AD_REQ_SET_ARCH_BIT][mult_arch] != NULL)
mult_arch++;
if (args[ABD_REQ_SET_ABI_BIT])
while (args[ABD_REQ_SET_ABI_BIT][mult_abi] != NULL)
mult_abi++;
/* final_req should be logically checked */
/* More than one option from one request group couldn't be set */
if ((is_more1bit(final_req & SD_REQ_MASK & ~SD_REQ_NARGS) == 0) ||
(is_more1bit(final_req & AD_REQ_MASK) == 0) ||
(is_more1bit(final_req & ABD_REQ_MASK) == 0))
error_msg_and_help("exclusive parameters");
/* Check on mutually exclusive options chain */
/* If at least one syscall option has been typed, therefore
arch_options couldn't be list-arch and
abi_option couldn't be list-abi */
if ((final_req & SD_REQ_MASK) &&
(((final_req & AD_REQ_MASK) && (final_req & AD_REQ_LIST_ARCH))))
error_msg_and_help("wrong parameters");
/* list-arch couldn't be used with any abi options */
if ((final_req & AD_REQ_LIST_ARCH) &&
(final_req & ABD_REQ_MASK))
error_msg_and_help("'--list-arch' cannot be used with any "
"ABI parameters");
/* ABI requests could be used just in a combination with arch
requests */
if ((final_req & ABD_REQ_MASK) &&
!(final_req & AD_REQ_MASK))
error_msg_and_help("ABI parameters could be used only with "
"architecture parameter");
/* set-abi must be used in case of multiple arch */
if ((mult_arch > 1) && !(final_req & ABD_REQ_MASK))
error_msg_and_help("ABI modes cannot be automatically "
"detected for multiple "
"architectures");
/* set-abi and set-arch have to take the same number of args */
if ((final_req & AD_REQ_SET_ARCH) && (final_req & ABD_REQ_SET_ABI) &&
(mult_arch != mult_abi))
error_msg_and_help("each architecture needs respective "
"ABI mode, and vice versa");
/* --nargs cannot be used alone */
if ((final_req & SD_REQ_NARGS) &&
!(final_req & SD_REQ_MASK & ~SD_REQ_NARGS))
error_msg_and_help("first set main output syscall "
"characteristics");
/* raw should not be single */
if (final_req == SERV_REQ_RAW)
error_msg_and_help("raw data implies existing data");
return final_req;
}
static char *
seek_sc_arg(char **input_args[])
{
int i;
for (i = SD_REQ_GET_SNAME_BIT; i < SYSCALL_REQ_BIT_LAST; i++)
if (input_args[i] != NULL)
return input_args[i][0];
return NULL;
}
int
main(int argc, char *argv[])
{
ARCH_LIST_DEFINE(arch_list);
SYSCALL_LIST_DEFINE(sc_list);
/* This array is purposed to store arguments for options in the
most convenient way */
char ***in_args = xcalloc(sizeof(*in_args), REQ_LAST_BIT);
unsigned reqs;
/* command_dispatcher turn */
reqs = command_dispatcher(argc, argv, in_args);
if (reqs == 0)
error_msg_and_help("must have OPTIONS");
/* arch_dispatcher turn */
arch_list = arch_dispatcher(reqs, in_args[AD_REQ_SET_ARCH_BIT]);
if (es_error(al_err(arch_list)))
perror_msg_and_die("%s", es_get_serror(al_err(arch_list)));
/* abi_dispatcher turn */
abi_dispatcher(arch_list, reqs, in_args[ABD_REQ_SET_ABI_BIT]);
if (es_error(al_err(arch_list)))
perror_msg_and_die("%s", es_get_serror(al_err(arch_list)));
/* syscall_dispatcher turn */
sc_list = syscall_dispatcher(arch_list, reqs, seek_sc_arg(in_args));
if (es_error(ss_err(sc_list)))
perror_msg_and_die("%s", es_get_serror(ss_err(sc_list)));
/* If we want to get info about only architectures thus we print out
architectures, otherwise system calls */
if (!(reqs & SD_REQ_MASK))
al_dump(arch_list, reqs & SERV_REQ_RAW);
else
ss_dump(sc_list, reqs & SERV_REQ_RAW);
return 0;
}

225
tools/asinfo/dispatchers.c Normal file
View File

@ -0,0 +1,225 @@
/*
* Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
* Copyright (c) 2017-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/utsname.h>
#include "arch_interface.h"
#include "dispatchers.h"
#include "macros.h"
#include "request_msgs.h"
#include "syscall_interface.h"
#include "sysent.h"
#include "xmalloc.h"
struct arch_service *
arch_dispatcher(unsigned request_type, char *arch[])
{
struct utsname info_uname;
int i;
ARCH_LIST_DEFINE(arch_list) = al_create_filled();
ARCH_LIST_DEFINE(arch_final) = NULL;
/* If user don't type any option in ARCH_REQ group, it means
get current arch */
if ((request_type & AD_REQ_GET_ARCH) ||
(!(request_type & AD_REQ_MASK))) {
uname(&info_uname);
if (al_mark_matches(arch_list, info_uname.machine) == -1) {
es_set_error(al_err(arch_list), AD_UNSUP_ARCH);
es_set_option(al_err(arch_list), info_uname.machine,
NULL, NULL);
goto fail;
}
/* Cut off useless archs */
arch_final = al_join_print(arch_final, arch_list);
al_unmark_all(arch_final, AD_FLAG_PRINT);
free(arch_list);
goto done;
}
if (request_type & AD_REQ_SET_ARCH) {
for (i = 0; arch[i] != NULL; i++) {
if (al_mark_matches(arch_list, arch[i]) == -1) {
es_set_error(al_err(arch_list), AD_UNSUP_ARCH);
es_set_option(al_err(arch_list), arch[i],
NULL, NULL);
goto fail;
}
arch_final = al_join_print(arch_final, arch_list);
}
al_unmark_all(arch_final, AD_FLAG_PRINT);
al_free(arch_list);
goto done;
}
if ((request_type & AD_REQ_LIST_ARCH)) {
int a_size = al_size(arch_list);
for (i = 0; i < a_size; i++) {
al_add_flag(arch_list, i, AD_FLAG_PRINT);
}
arch_final = arch_list;
goto done;
}
fail:
return arch_list;
done:
return arch_final;
}
int
abi_dispatcher(struct arch_service *a_serv, unsigned request_type,
char *abi[])
{
int i = 0;
enum arch_pers pers;
int arch_size = 0;
int a_pos = 0;
arch_size = al_size(a_serv);
/* The strace package could be compiled as 32bit app on 64bit
architecture, therefore asinfo has to detect it and print out
corresponding personality. Frankly speaking, it is necessary to
detect strace package personality when it is possible */
if (!(request_type & ABD_REQ_MASK) &&
!(request_type & AD_REQ_LIST_ARCH)) {
pers = al_pers(a_serv, a_pos);
switch (pers) {
#if defined(MIPS)
case ARCH_mips_o32:
case ARCH_mips64_n64:
al_mark_pers4arch(a_serv, a_pos,
#if defined(LINUX_MIPSO32)
"o32"
#elif defined(LINUX_MIPSN32)
"n32"
#elif defined(LINUX_MIPSN64)
"n64"
#endif
);
break;
#endif
#if defined(ARM)
case ARCH_arm_oabi:
al_mark_pers4arch(a_serv, a_pos,
#if defined(__ARM_EABI__) || !defined(ENABLE_ARM_OABI)
"eabi"
#else
"oabi"
#endif
);
break;
#endif
#if defined(AARCH64)
case ARCH_aarch64_64bit:
al_mark_pers4arch(a_serv, a_pos,
#if defined(__ARM_EABI__)
"eabi"
#else
"64bit"
#endif
);
break;
#endif
#if defined(X86_64) || defined(X32)
case ARCH_x86_64_64bit:
al_mark_pers4arch(a_serv, a_pos,
#if defined(X86_64)
"64bit"
#elif defined(X32)
"x32"
#endif
);
break;
#endif
/* Especially for x86_64 32bit ABI, because configure.ac defines it
as I386 arch */
#if defined(I386)
case ARCH_x86_64_64bit:
al_mark_pers4arch(a_serv, a_pos, "32bit");
break;
#endif
#if defined(TILE)
case ARCH_tile_64bit:
al_mark_pers4arch(a_serv, a_pos,
#if defined(__tilepro__)
"32bit"
#else
"64bit"
#endif
);
break;
#endif
default:
if (arch_size == 1) {
al_add_flag(a_serv, a_pos, AD_FLAG_PRINT);
goto done;
}
es_set_error(al_err(a_serv), ABI_CANNOT_DETECT);
es_set_option(al_err(a_serv),
al_in_aname(a_serv, a_pos), NULL, NULL);
}
goto done;
}
if (request_type & ABD_REQ_LIST_ABI) {
while (a_pos != arch_size) {
if (!al_mark_pers4arch(a_serv, a_pos, "all")) {
a_pos += al_get_abi_modes(a_serv, a_pos);
continue;
}
break;
}
goto done;
}
if (request_type & ABD_REQ_SET_ABI) {
for (i = 0; abi[i] != NULL; i++) {
if (!al_mark_pers4arch(a_serv, a_pos, abi[i])) {
a_pos += al_get_abi_modes(a_serv, a_pos);
continue;
}
es_set_error(al_err(a_serv), ABI_WRONG4ARCH);
es_set_option(al_err(a_serv),
al_in_aname(a_serv, a_pos),
abi[i], NULL);
break;
}
}
done:
return 0;
}
struct syscall_service *
syscall_dispatcher(struct arch_service *arch, int request_type, char *sysc)
{
SYSCALL_LIST_DEFINE(sysc_serv) = ss_create(arch, request_type);
int narch = ss_size(sysc_serv);
int i = 0;
int ret = 0;
int count = 0;
if (request_type & SD_REQ_MASK) {
for (i = 0; i < narch; i++) {
ss_update_sc_num(sysc_serv, i);
ret = ss_mark_matches(sysc_serv, i, sysc);
if (ret == SD_NO_MATCHES_FND)
count++;
}
}
/* Clear error if we are in multiarch mode */
if (count != narch && narch != 1)
es_set_error(ss_err(sysc_serv), NO_ERROR);
return sysc_serv;
}

View File

@ -0,0 +1,29 @@
/*
* The dispatchers.h contains all necessary functions to perform main
* work in the asinfo tool.
*
* Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
* Copyright (c) 2017-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ASINFO_DISPATCHERS_H
#define ASINFO_DISPATCHERS_H
#include "arch_interface.h"
#include "syscall_interface.h"
/* The function is purposed to provide correct list of architectures */
struct arch_service *arch_dispatcher(unsigned request_type, char *arch[]);
/* Final arch filtering based on personality */
int abi_dispatcher(struct arch_service *a_serv, unsigned request_type,
char *abi[]);
/* The last stage of main filtering */
struct syscall_service *syscall_dispatcher(struct arch_service *arch,
int request_type, char *sysc);
#endif /* !ASINFO_DISPATCHERS_H */

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
* Copyright (c) 2017-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "error_interface.h"
#include "xmalloc.h"
static const char *errors[] = {
[AD_UNSUP_ARCH_BIT] = "architecture '%s' is unsupported",
[ABI_CANNOT_DETECT_BIT] = "ABI mode cannot be automatically "
"detected for non-target architecture '%s'",
[ABI_WRONG4ARCH_BIT] = "architecture '%s' does not have ABI mode "
"'%s'",
[SD_NO_MATCHES_FND_BIT] = "no matches found",
};
struct error_service *
es_create(void)
{
struct error_service *err = xcalloc(sizeof(*err), 1);
return err;
}
enum common_error
es_error(struct error_service *e)
{
return e->last_error;
}
void
es_set_error(struct error_service *e, enum common_error error)
{
e->last_error = error;
}
void
es_set_option(struct error_service *e, char *arch, char *abi, char *sc)
{
if (arch) {
if (e->last_arch)
free(e->last_arch);
e->last_arch = xcalloc(sizeof(*(e->last_arch)),
strlen(arch) + 1);
strcpy(e->last_arch, arch);
}
if (abi) {
if (e->last_abi)
free(e->last_abi);
e->last_abi = xcalloc(sizeof(*(e->last_abi)), strlen(abi) + 1);
strcpy(e->last_abi, abi);
}
if (sc) {
if (e->last_sc)
free(e->last_sc);
e->last_sc = xcalloc(sizeof(*(e->last_sc)), strlen(sc) + 1);
strcpy(e->last_sc, sc);
}
}
const char *
es_get_serror(struct error_service *e)
{
int err = 1 << e->last_error;
if (err & ERROR_ARCH_MASK)
sprintf(e->string, errors[e->last_error], e->last_arch);
else if (err & ERROR_NO_ARG_MASK)
sprintf(e->string, "%s", errors[e->last_error]);
else if (err & ERROR_ARCH_ABI_MASK)
sprintf(e->string, errors[e->last_error], e->last_arch,
e->last_abi);
return (const char *)(e->string);
}
void
es_free(struct error_service *e)
{
free(e);
}

View File

@ -0,0 +1,76 @@
/*
* As each dispatcher has a wide range of possible errors, there is need
* use separate and basic error interface.
*
* Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
* Copyright (c) 2017-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ASINFO_ERROR_INTERFACE_H
#define ASINFO_ERROR_INTERFACE_H
/* errors which using last_arch */
enum error_arch {
NO_ERROR_BIT,
AD_UNSUP_ARCH_BIT = 1,
ABI_CANNOT_DETECT_BIT,
ERROR_ARCH_LAST
};
enum error_no_arg {
SD_NO_MATCHES_FND_BIT = ERROR_ARCH_LAST,
ERROR_NO_ARG_LAST
};
enum error_arch_abi {
ABI_WRONG4ARCH_BIT = ERROR_NO_ARG_LAST,
ERROR_ARCH_ABI_LAST
};
#define ENUM_FLAG(name) name = name##_BIT
enum common_error {
ENUM_FLAG(NO_ERROR),
/* arch dispatcher range */
ENUM_FLAG(AD_UNSUP_ARCH),
/* abi dipatcher range */
ENUM_FLAG(ABI_CANNOT_DETECT),
ENUM_FLAG(ABI_WRONG4ARCH),
/* syscall dispatcher range */
ENUM_FLAG(SD_NO_MATCHES_FND)
};
#undef ENUM_FLAG
#define BITMASK(hi, lo) ((1 << (hi)) - (1 << (lo)))
#define ERROR_ARCH_MASK BITMASK(ERROR_ARCH_LAST, 0)
#define ERROR_NO_ARG_MASK BITMASK(ERROR_NO_ARG_LAST, ERROR_ARCH_LAST)
#define ERROR_ARCH_ABI_MASK BITMASK(ERROR_ARCH_ABI_LAST, ERROR_NO_ARG_LAST)
#define ERROR_MSG_MAX_LEN 255
struct error_service {
char string[ERROR_MSG_MAX_LEN];
enum common_error last_error;
char *last_arch;
char *last_abi;
char *last_sc;
};
struct error_service *es_create(void);
enum common_error es_error(struct error_service *s);
void es_set_error(struct error_service *s, enum common_error se);
void es_set_option(struct error_service *e, char *arch, char *abi, char *sc);
const char *es_get_serror(struct error_service *e);
void es_free(struct error_service *e);
#endif /* !ASINFO_ERROR_INTERFACE_H */

152
tools/asinfo/gen_asinfo_files.sh Executable file
View File

@ -0,0 +1,152 @@
#!/bin/sh
#
# Code generator simplifies addition of new architecture to asinfo tool
#
# Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
# Copyright (c) 2017-2018 The strace developers.
# All rights reserved.
#
# SPDX-License-Identifier: GPL-2.0-or-later
cur_pers=""
gen_pers_line()
{
local out_file="$1"
local line="$2"
local arch_abi=""
LC_COLLATE=C
arch_abi="$(printf %s "${line}" |
sed 's/ARCH_DESC_DEFINE(//' | cut -d, -f 1,2 |
sed 's/,/_/g')"
cur_pers="${arch_abi}"
echo "ARCH_${arch_abi}," >> "${out_file}"
}
gen_includes_block()
{
local out_file="$1"
local line="$2"
local def is_def includes include nums num count
(
LC_COLLATE=C
echo "/* ${cur_pers} */"
def="$(printf %s "${line#*\*}" | cut -d] -f 1 | sed 's/.*[][]//g')"
#Generate define construction
if [ "${def#!}" != "" ] && [ $(printf %.1s "${def}") = "!" ]; then
cat <<-EOF
#ifdef ${def#!}
# undef ${def#!}
# define ${def#!}_DUMMY_UNDEFINE
#endif
EOF
is_def="def"
else if [ "${def#!}" != "" ]; then
cat <<-EOF
#ifndef ${def}
# define ${def}
# define ${def}_DUMMY_DEFINE
#endif
EOF
is_def="undef"
fi
fi
#Generate includes
includes="$(printf %s "${line#*\*}" | cut -d] -f 2 | sed 's/.*[][]//g')"
echo "static const struct_sysent ${cur_pers}_sysent[] = {"
for include in $(echo "${includes}" | sed "s/,/ /g")
do
echo " #include \"${include}\""
done
echo "};"
#Undefine definitions, if it is required
if [ "${is_def}" = "def" ]; then
cat <<-EOF
#ifdef ${def#!}_DUMMY_UNDEFINE
# define ${def#!} 1
# undef ${def#!}_DUMMY_UNDEFINE
#endif
EOF
else if [ "${is_def}" = "undef" ]; then
cat <<-EOF
#ifdef ${def#!}_DUMMY_DEFINE
# undef ${def#!}
# undef ${def#!}_DUMMY_DEFINE
#endif
EOF
fi
fi
#Generate arch specific numbers
nums="$(printf %s "${line#*\*}" | cut -d] -f 3 | sed 's/.*[][]//g')"
count=1
for num in $(echo "${nums}" | sed "s/,/ /g")
do
echo "static const int ${cur_pers}_usr${count} = ${num};"
count=$((count+1))
case "${num}" in
*[A-Za-z_]*) echo "#undef ${num}" ;;
*) ;;
esac
done
if [ $count -eq 1 ]; then
echo "static const int ${cur_pers}_usr${count} = 0;"
fi
echo "#undef SYS_socket_subcall"
) >> "${out_file}"
echo "${def}" >> "${out_file}"
}
main()
{
set -- "${0%/*}" "${0%/*}"
local input="$1"
local output="$2"
local defs_file="arch_definitions.h"
local pers_file="arch_personalities.h"
local includes_file="arch_includes.h"
local pline=""
echo "ARCH_no_pers," > "${output}/${pers_file}"
echo -n > "${output}/${includes_file}"
#Main work
while read line; do
line="$(printf %s "${line}" | sed 's/[[:space:]]//g')"
if $(printf %s "${line}" |
grep -F "ARCH_DESC_DEFINE" > /dev/null); then
gen_pers_line "${output}/${pers_file}" "${line}"
fi
if $(printf %s "${pline}" | grep -F "/*" > /dev/null); then
gen_includes_block "${output}/${includes_file}"\
"${pline}"
fi
pline="${line}"
done < "${input}/${defs_file}"
#Makemodule.am
(
printf \
"ARCH_AUX_FILES = ${includes_file} ${pers_file}\n\
\$(top_srcdir)/tools/asinfo/${includes_file}: \
\$(top_srcdir)/tools/asinfo/${defs_file} \
\$(top_srcdir)/tools/asinfo/gen_asinfo_files.sh\n\
\$(AM_V_GEN)\$(top_srcdir)/tools/asinfo/gen_asinfo_files.sh\n\
\$(top_srcdir)/tools/asinfo/${pers_file}: \
\$(top_srcdir)/tools/asinfo/${defs_file} \
\$(top_srcdir)/tools/asinfo/gen_asinfo_files.sh\n\
\$(AM_V_GEN)\$(top_srcdir)/tools/asinfo/gen_asinfo_files.sh"
) > "${output}/Makemodule.am"
#.gitignore
(
printf \
"/${includes_file}\n\
/${pers_file}\n\
/Makemodule.am\n\
/.gitignore\n\
/asinfo.1"
) > "${output}/.gitignore"
}
main "$@"

View File

@ -0,0 +1,74 @@
/*
* The request_msgs are purposed to set the general mode of work, in
* particular, the work of main dispatchers.
*
* Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
* Copyright (c) 2017-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ASINFO_REQUEST_MSGS_H
#define ASINFO_REQUEST_MSGS_H
/* Request types for syscall_dispatcher,
* arch_dispatcher, which, in turn, could be combined
*/
enum syscall_req_bit {
SD_REQ_GET_SNAME_BIT,
SD_REQ_GET_SNUM_BIT,
SD_REQ_NARGS_BIT,
SYSCALL_REQ_BIT_LAST
};
enum arch_req_bit {
AD_REQ_SET_ARCH_BIT = SYSCALL_REQ_BIT_LAST,
AD_REQ_GET_ARCH_BIT,
AD_REQ_LIST_ARCH_BIT,
ARCH_REQ_BIT_LAST
};
enum abi_req_bit {
ABD_REQ_SET_ABI_BIT = ARCH_REQ_BIT_LAST,
ABD_REQ_LIST_ABI_BIT,
ABD_REQ_BIT_LAST
};
enum serv_req_bit {
SERV_REQ_HELP_BIT = ABD_REQ_BIT_LAST,
SERV_REQ_VERSION_BIT,
SERV_REQ_ERROR_BIT,
SERV_REQ_RAW_BIT,
SERV_REQ_BIT_LAST
};
#define ENUM_FLAG(name) name = 1 << name##_BIT
enum req_type {
ENUM_FLAG(SD_REQ_GET_SNAME),
ENUM_FLAG(SD_REQ_GET_SNUM),
ENUM_FLAG(SD_REQ_NARGS),
ENUM_FLAG(AD_REQ_SET_ARCH),
ENUM_FLAG(AD_REQ_GET_ARCH),
ENUM_FLAG(AD_REQ_LIST_ARCH),
ENUM_FLAG(ABD_REQ_SET_ABI),
ENUM_FLAG(ABD_REQ_LIST_ABI),
ENUM_FLAG(SERV_REQ_HELP),
ENUM_FLAG(SERV_REQ_VERSION),
ENUM_FLAG(SERV_REQ_ERROR),
ENUM_FLAG(SERV_REQ_RAW)
};
#undef ENUM_FLAG
#define BITMASK(hi, lo) ((1 << (hi)) - (1 << (lo)))
#define REQ_LAST_BIT SERV_REQ_BIT_LAST
#define SD_REQ_MASK BITMASK(SYSCALL_REQ_BIT_LAST, 0)
#define AD_REQ_MASK BITMASK(ARCH_REQ_BIT_LAST, SYSCALL_REQ_BIT_LAST)
#define ABD_REQ_MASK BITMASK(ABD_REQ_BIT_LAST, ARCH_REQ_BIT_LAST)
#define SERV_REQ_MASK BITMASK(SERV_REQ_BIT_LAST, ABD_REQ_BIT_LAST)
#endif /* !ASINFO_REQUEST_MSGS_H */

View File

@ -0,0 +1,672 @@
/*
* Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedv@virtuozzo.com>
* Copyright (c) 2017-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "macros.h"
#include "arch_interface.h"
#include "error_interface.h"
#include "filter.h"
#include "number_set.h"
#include "arch_defs.h"
#include "syscall_interface.h"
#include "sysent.h"
#include "request_msgs.h"
#include "xmalloc.h"
/* We shouldn't include defs.h here, because the following definitions
cannot be with const qualifier */
const struct_sysent *sysent_vec[SUPPORTED_PERSONALITIES] = {NULL};
unsigned int nsyscall_vec[SUPPORTED_PERSONALITIES] = {0};
const char *const personality_designators[] =
# if defined X86_64
{ "64", "32", "x32" }
# elif defined X32
{ "x32", "32" }
# elif SUPPORTED_PERSONALITIES == 2
{ "64", "32" }
# else
{ STRINGIFY_VAL(__WORDSIZE) }
# endif
;
struct syscall_service *
ss_create(struct arch_service *m, int request_type)
{
int i;
int ss_count = 0;
int ssize = al_psize(m);
int asize = al_size(m);
struct syscall_service *ss = NULL;
int scn = 0;
ss = xcalloc(sizeof(*ss), 1);
ss->err = al_err(m);
/* If we are in arch/abi mode, but we need syscall_service to pass
check for errors */
if (!(request_type & SD_REQ_MASK) || ssize == 0)
return ss;
ss->aws = xcalloc(sizeof(*(ss->aws)), ssize);
ss->narch = ssize;
for (i = 0; i < asize; i++)
if (al_flag(m, i) & AD_FLAG_PRINT) {
ss->aws[ss_count].arch = al_get(m, i);
scn = ss->aws[ss_count].arch->max_scn;
ss->aws[ss_count].flag = xcalloc(sizeof(int), scn);
ss->aws[ss_count].real_snum = xcalloc(sizeof(int), scn);
ss->aws[ss_count].a_name = al_in_aname(m, i);
al_set_in_aname(m, i, NULL);
ss_count++;
}
ss->request_type = request_type;
return ss;
}
int
ssa_is_ok(struct syscall_service *s, int arch, int num)
{
if (s == NULL || arch > s->narch || arch < 0 || num < 0 ||
num >= s->aws[arch].arch->max_scn)
return 0;
return 1;
}
struct error_service *
ss_err(struct syscall_service *s)
{
return s->err;
}
int
ss_size(struct syscall_service *s)
{
return s->narch;
}
int
ssa_max_scn(struct syscall_service *s, int arch)
{
if (!ssa_is_ok(s, arch, 0))
return -1;
return s->aws[arch].arch->max_scn;
}
const struct_sysent *
ssa_sysc_list(struct syscall_service *s, int arch)
{
if (!ssa_is_ok(s, arch, 0))
return NULL;
return s->aws[arch].arch->syscall_list;
}
int
ssa_flag(struct syscall_service *s, int arch, int num)
{
if (!ssa_is_ok(s, arch, num))
return -1;
return s->aws[arch].flag[num];
}
int
ssa_set_flag(struct syscall_service *s, int arch, int num, int flag)
{
if (!ssa_is_ok(s, arch, num))
return -1;
s->aws[arch].flag[num] = flag;
return 0;
}
int
ssa_real_num(struct syscall_service *s, int arch, int num)
{
if (!ssa_is_ok(s, arch, num))
return -1;
return s->aws[arch].real_snum[num];
}
int
ssa_set_real_num(struct syscall_service *s, int arch, int num, int real_num)
{
if (!ssa_is_ok(s, arch, num))
return -1;
s->aws[arch].real_snum[num] = real_num;
return 0;
}
const char *
ssa_syscall_name(struct syscall_service *s, int arch, int num)
{
if (!ssa_is_ok(s, arch, num))
return NULL;
return s->aws[arch].arch->syscall_list[num].sys_name;
}
int
ssa_syscall_flag(struct syscall_service *s, int arch, int num)
{
if (!ssa_is_ok(s, arch, num))
return -1;
return s->aws[arch].arch->syscall_list[num].sys_flags;
}
int
ssa_syscall_nargs(struct syscall_service *s, int arch, int num)
{
if (!ssa_is_ok(s, arch, num))
return -1;
return (int)s->aws[arch].arch->syscall_list[num].nargs;
}
int
ssa_user_num1(struct syscall_service *s, int arch)
{
if (!ssa_is_ok(s, arch, 0))
return -1;
return *(s->aws[arch].arch->user_num1);
}
int
ssa_user_num2(struct syscall_service *s, int arch)
{
if (!ssa_is_ok(s, arch, 0))
return -1;
return *(s->aws[arch].arch->user_num2);
}
void
ss_free(struct syscall_service *s)
{
int i;
es_free(ss_err(s));
for (i = 0; i < s->narch; i++ ) {
free(s->aws[i].flag);
free(s->aws[i].real_snum);
if (s->aws[i].a_name)
free(s->aws[i].a_name);
}
free(s);
}
int
ssa_print_size(struct syscall_service *s, int arch)
{
int i;
int max_scn = ssa_max_scn(s, arch);
int psize = 0;
for (i = 0; i < max_scn; i++)
if (ssa_flag(s, arch, i) & SS_FLAG_PRINT)
psize++;
return psize;
}
int
ssa_is_syscall_valid(struct syscall_service *s, int arch, int num)
{
if (!ssa_is_ok(s, arch, num))
return 0;
return ssa_syscall_name(s, arch, num) &&
!(ssa_syscall_flag(s, arch, num) & TRACE_INDIRECT_SUBCALL);
}
int
ss_mark_matches(struct syscall_service *s, int arch, char *arg)
{
int i = 0;
int scount = 0;
int max_scn = ssa_max_scn(s, arch);
struct number_set *trace_set;
/* Init global variables */
nsyscall_vec[0] = ssa_max_scn(s, arch);
sysent_vec[0] = ssa_sysc_list(s, arch);
trace_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
qualify_syscall_tokens(arg, trace_set);
for (i = 0; i < max_scn; i++)
if (ssa_is_syscall_valid(s, arch, i) &&
ssa_real_num(s, arch, i) != HIDDEN_SYSC &&
is_number_in_set_array(i, trace_set, 0)) {
ssa_set_flag(s, arch, i, SS_FLAG_PRINT);
scount++;
}
if (scount == 0) {
es_set_error(ss_err(s), SD_NO_MATCHES_FND);
return SD_NO_MATCHES_FND;
}
return 0;
}
int
ss_update_sc_num(struct syscall_service *s, int arch)
{
int i = 0;
int max_scn = ssa_max_scn(s, arch);
int usr1n = ssa_user_num1(s, arch);
int usr2n = ssa_user_num2(s, arch);
for (i = 0; i < max_scn; i++) {
if (!ssa_is_syscall_valid(s, arch, i)) {
ssa_set_real_num(s, arch, i, HIDDEN_SYSC);
continue;
}
switch (s->aws[arch].arch->pers) {
case ARCH_x86_64_x32:
/* Pure x32 specific syscalls without X32_SYSCALL_BIT */
if (strstr(ssa_syscall_name(s, arch, i), "64:"))
ssa_set_real_num(s, arch, i, HIDDEN_SYSC);
else
ssa_set_real_num(s, arch, i, i);
break;
case ARCH_arm_oabi:
case ARCH_arm_eabi:
/* Do not deal with private ARM syscalls */
if (i == usr1n)
ssa_set_real_num(s, arch, i, HIDDEN_SYSC);
if ((i >= usr1n + 1) && (i <= usr1n + usr2n + 1))
ssa_set_real_num(s, arch, i, HIDDEN_SYSC);
if (i < usr1n)
ssa_set_real_num(s, arch, i, i);
break;
case ARCH_sh64_64bit:
ssa_set_real_num(s, arch, i, i & 0xffff);
break;
default:
ssa_set_real_num(s, arch, i, i);
}
}
return 0;
}
static int
sysccmp(const void *arg1, const void *arg2)
{
const char *str1 = ((struct in_sysc *)arg1)->sys_name;
const char *str2 = ((struct in_sysc *)arg2)->sys_name;
return strcmp(str1, str2);
}
static struct sysc_meta *
ss_make_union(struct syscall_service *s,
void* (save)(struct syscall_service *, int, int))
{
struct in_sysc **sysc;
struct out_sysc *sysc_l, *sysc_r, *sysc_to, *sysc_fr;
struct sysc_meta *sm = xcalloc(sizeof(*sm), 1);
int size = ss_size(s);
int max_scn;
int psize;
int out_size = 0;
int i, j, k, l;
int c = 0;
int res = 0;
int eff_size = 1;
/* Preparation */
sysc = xcalloc(sizeof(*sysc), size);
for (i = 0; i < size; i++) {
max_scn = ssa_max_scn(s, i);
psize = ssa_print_size(s, i);
sysc[i] = xcalloc(sizeof(**sysc), psize + 1);
c = 0;
for (j = 0; j < max_scn; j++) {
if (!(ssa_flag(s, i, j) & SS_FLAG_PRINT))
continue;
sysc[i][c].sys_name = ssa_syscall_name(s, i, j);
sysc[i][c].data = save(s, i, j);
c++;
}
qsort(sysc[i], psize, sizeof(struct in_sysc), &sysccmp);
out_size += psize;
}
/* Allocation */
sysc_l = xcalloc(sizeof(*sysc_l), out_size);
sysc_r = xcalloc(sizeof(*sysc_r), out_size);
for (i = 0; i < out_size; i++) {
sysc_r[i].data = xcalloc(sizeof(void *), size);
sysc_l[i].data = xcalloc(sizeof(void *), size);
}
/* Set with first arch in sysc */
for (i = 0; sysc[0][i].sys_name != NULL; i++) {
sysc_r[i].sys_name = sysc[0][i].sys_name;
sysc_r[i].data[0] = sysc[0][i].data;
}
/* Union
Main idea is simple:
[sysc_to]<->[sysc_fr]<------[sysc1][sysc2][sysc3]...
1) [sysc_fr] = [sysc1]
2) [sysc_to] = [sysc_fr] | [sysc2]
3) [sysc_to] <-> [sysc_fr]
4) [sysc_to] = [sysc_fr] | [sysc3]
etc. */
sysc_to = sysc_r;
sysc_fr = sysc_l;
for (i = 1; i < size; i++) {
l = 0; j = 0; k = 0;
if (sysc[i][j].sys_name != NULL || i == 1) {
sysc_fr = (eff_size % 2) ? sysc_r : sysc_l;
sysc_to = (eff_size % 2) ? sysc_l : sysc_r;
eff_size++;
}
while (sysc[i][j].sys_name != NULL && k < out_size) {
memset(sysc_to[l].data, 0, sizeof(void *) * size);
if (!sysc_fr[k].sys_name)
res = -1;
else
res = strcmp(sysc[i][j].sys_name,
sysc_fr[k].sys_name);
if (res < 0) {
sysc_to[l].sys_name = sysc[i][j].sys_name;
sysc_to[l].data[i] = sysc[i][j].data;
j++;
} else if (res > 0) {
sysc_to[l].sys_name = sysc_fr[k].sys_name;
memcpy(sysc_to[l].data, sysc_fr[k].data,
sizeof(void *) * size);
k++;
} else {
sysc_to[l].sys_name = sysc[i][j].sys_name;
memcpy(sysc_to[l].data, sysc_fr[k].data,
sizeof(void *) * size);
sysc_to[l].data[i] = sysc[i][j].data;
k++;
j++;
}
l++;
}
while (k < out_size && l < out_size) {
sysc_to[l].sys_name = sysc_fr[k].sys_name;
memcpy(sysc_to[l].data, sysc_fr[k].data,
sizeof(void *) * size);
k++;
l++;
}
}
/* Free */
for (i = 0; i < out_size; i++)
free(sysc_fr[i].data);
free(sysc_fr);
for (i = 0; i < size; i++)
free(sysc[i]);
free(sysc);
sm->sysc_list = sysc_to;
sm->size = out_size;
return sm;
}
static struct sysc_meta *
ss_make_enumeration(struct syscall_service *s,
void* (save)(struct syscall_service *, int, int))
{
struct out_sysc *sysc_out;
struct sysc_meta *sm = xcalloc(sizeof(*sm), 1);
int size = ss_size(s);
int max_scn = 0;
int i, j, k;
int flag;
bool clear = true;
for (i = 0; i < size; i++)
if (max_scn < ssa_max_scn(s, i))
max_scn = ssa_max_scn(s, i);
sysc_out = xcalloc(sizeof(*sysc_out), max_scn);
for (i = 0; i < max_scn; i++)
sysc_out[i].data = xcalloc(sizeof(void *), size);
for (i = 0; i < size; i++)
for (j = 0; j < max_scn; j++) {
clear = true;
flag = ssa_flag(s, i, j);
if ((flag != -1) && (flag & SS_FLAG_PRINT)) {
sysc_out[j].sys_num = j;
sysc_out[j].data[i] = save(s, i, j);
}
for (k = 0; k <= i; k++)
if (sysc_out[j].data[k])
clear = 0;
if (clear)
sysc_out[j].sys_num = -1;
}
sm->sysc_list = sysc_out;
sm->size = max_scn;
return sm;
}
static void *
ssa_save_snum(struct syscall_service *s, int arch, int snum)
{
return (void *)&(s->aws[arch].real_snum[snum]);
}
static void *
ssa_save_nargs(struct syscall_service *s, int arch, int snum)
{
return (void *)&(s->aws[arch].arch->syscall_list[snum].nargs);
}
static void *
ssa_save_sname(struct syscall_service *s, int arch, int snum)
{
return (void *)(s->aws[arch].arch->syscall_list[snum].sys_name);
}
static unsigned
fast_len(int num)
{
int i;
unsigned count = 0;
for (i = 1; num/i != 0; i *= 10)
count++;
return count;
}
static unsigned *
ss_get_width_sname(struct syscall_service *s, struct sysc_meta *sm, int narch)
{
/* '2' hereinafter takes into account first two default columns */
unsigned *width = xcalloc(sizeof(*width), narch + 2);
int i, j;
unsigned len;
unsigned max;
int N = 1;
struct out_sysc *psysc = sm->sysc_list;
/* Calculate length of 'N' and sname columns */
for (i = 0; i < sm->size; i++) {
if (!psysc[i].sys_name)
continue;
len = strlen(psysc[i].sys_name);
if (len > width[1])
width[1] = len;
N++;
}
width[0] = fast_len(N);
for (i = 0; i < narch; i++) {
for (j = 0; j < sm->size; j++) {
if (!psysc[j].data[i])
continue;
max = *((int *)(psysc[j].data[i]));
if (max > width[i + 2])
width[i + 2] = max;
}
width[i + 2] = fast_len(width[i + 2]);
max = 0;
}
return width;
}
static unsigned *
ss_get_width_snum(struct syscall_service *s, struct sysc_meta *sm, int narch)
{
unsigned *width = xcalloc(sizeof(*width), narch + 2);
int i, j;
unsigned len;
unsigned max;
int N = 1;
struct out_sysc *psysc = sm->sysc_list;
/* Calculate length of 'N' and snum columns */
for (i = 0; i < sm->size; i++) {
if (psysc[i].sys_num == -1)
continue;
max = fast_len(psysc[i].sys_num);
if (max > width[1])
width[1] = max;
N++;
}
width[1] = fast_len(width[1]);
width[0] = fast_len(N);
for (i = 0; i < narch; i++) {
for (j = 0; j < sm->size; j++) {
if (!psysc[j].data[i])
continue;
if (s->request_type & SD_REQ_NARGS)
len = *((int *)(psysc[j].data[i]));
else
len = strlen((char *)(psysc[j].data[i]));
if (len > width[i + 2])
width[i + 2] = len;
}
if (s->request_type & SD_REQ_NARGS)
width[i + 2] = fast_len(width[i + 2]);
len = 0;
}
return width;
}
void
ss_dump(struct syscall_service *s, int is_raw)
{
static const char *title[] = {
"N",
"Syscall name",
"Snum",
};
struct sysc_meta *sm;
struct out_sysc *psysc;
int ncolumn = ss_size(s);
unsigned *title_len;
int N = 1;
int i, j;
/* Main work */
if (s->request_type & SD_REQ_GET_SNAME) {
if (s->request_type & SD_REQ_NARGS)
sm = ss_make_union(s, ssa_save_nargs);
else
sm = ss_make_union(s, ssa_save_snum);
title_len = ss_get_width_sname(s, sm, ncolumn);
if (strlen(title[1]) > title_len[1])
title_len[1] = strlen(title[1]);
} else {
if (s->request_type & SD_REQ_NARGS)
sm = ss_make_enumeration(s, ssa_save_nargs);
else
sm = ss_make_enumeration(s, ssa_save_sname);
title_len = ss_get_width_snum(s, sm, ncolumn);
if (strlen(title[2]) > title_len[1])
title_len[1] = strlen(title[2]);
}
psysc = sm->sysc_list;
if (is_raw)
goto skip_format;
/* Adjust width */
for (i = 0; i < ncolumn; i++) {
if (strlen(s->aws[i].a_name) > title_len[i + 2])
title_len[i + 2] = strlen(s->aws[i].a_name);
if (strlen(s->aws[i].arch->abi_mode) > title_len[i + 2])
title_len[i + 2] = strlen(s->aws[i].arch->abi_mode);
}
/* Print out title */
printf("| %*s | %*s |", title_len[0], "", title_len[1], "");
for (i = 0; i < ncolumn; i++)
printf(" %*s |", title_len[i + 2], s->aws[i].a_name);
puts("");
printf("| %*s |", title_len[0], title[0]);
if (s->request_type & SD_REQ_GET_SNAME)
printf(" %*s |", title_len[1], title[1]);
else
printf(" %*s |", title_len[1], title[2]);
for (i = 0; i < ncolumn; i++)
printf(" %*s |", title_len[i + 2], s->aws[i].arch->abi_mode);
puts("");
/* Syscalls */
for (i = 0; i < sm->size; i++) {
if (s->request_type & SD_REQ_GET_SNAME) {
if (psysc[i].sys_name == NULL)
continue;
printf("| %*d |", title_len[0], N);
printf(" %*s |", title_len[1], psysc[i].sys_name);
} else {
if (psysc[i].sys_num == -1)
continue;
printf("| %*d |", title_len[0], N);
printf(" %*d |", title_len[1], psysc[i].sys_num);
}
for (j = 0; j < ncolumn; j++) {
if (!psysc[i].data[j]) {
printf(" %*s |", title_len[j + 2], "-");
continue;
}
if (s->request_type & SD_REQ_GET_SNAME ||
s->request_type & SD_REQ_NARGS)
printf(" %*d |", title_len[j + 2],
*((int *)(psysc[i].data[j])));
else
printf(" %*s |", title_len[j + 2],
(char *)(psysc[i].data[j]));
}
puts("");
N++;
}
goto out;
skip_format:
for (i = 0; i < sm->size; i++) {
if (s->request_type & SD_REQ_GET_SNAME) {
if (psysc[i].sys_name == NULL)
continue;
printf("%d;%s;", N, psysc[i].sys_name);
} else {
if (psysc[i].sys_num == -1)
continue;
printf("%d;%d;", N, psysc[i].sys_num);
}
for (j = 0; j < ncolumn; j++) {
if (!psysc[i].data[j]) {
printf("%c;", '-');
continue;
}
if (s->request_type & SD_REQ_GET_SNAME ||
s->request_type & SD_REQ_NARGS)
printf("%d;", *((int *)(psysc[i].data[j])));
else
printf("%s;", (char *)(psysc[i].data[j]));
}
puts("");
N++;
}
out:
/* free, exit */
for (i = 0; i < sm->size; i++) {
free(psysc[i].data);
}
free(psysc);
free(sm);
free(title_len);
}

View File

@ -0,0 +1,123 @@
/*
* The syscall_interface.h is purposed to interact with the basic data
* structure based on arch_descriptor struct. Mainly this set of methods are
* used by syscall_dispatcher.
*
* Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhmedv@virtuozzo.com>
* Copyright (c) 2017-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ASINFO_SYSCALL_INTERFACE_H
#define ASINFO_SYSCALL_INTERFACE_H
#include <limits.h>
#include <stdbool.h>
#include "arch_interface.h"
#include "error_interface.h"
#include "sysent.h"
#define SS_FLAG_EMPTY 0
#define SS_FLAG_PRINT 1
#define HIDDEN_SYSC INT_MIN
/* Complete element type struct number_set */
typedef unsigned int number_slot_t;
struct number_set {
number_slot_t *vec;
unsigned int nslots;
bool not;
};
/* To avoid include defs.h */
extern bool is_number_in_set(unsigned int number, const struct number_set *);
struct arch_wrapper {
const struct arch_descriptor *arch;
/* Mutable user flags for each syscall */
int *flag;
int *real_snum;
char *a_name;
};
struct syscall_service {
struct arch_wrapper *aws;
int narch;
/* To choose the format while dumping */
int request_type;
struct error_service *err;
};
/* These structures are purposed to make union and enumeration with
syscall list */
struct out_sysc {
const char *sys_name;
int sys_num;
void **data;
};
struct sysc_meta {
struct out_sysc *sysc_list;
int size;
};
struct in_sysc {
const char *sys_name;
void *data;
};
#define SYSCALL_LIST_DEFINE(name) \
struct syscall_service *(name)
/* base methods
ss is related to syscall_service
ssa is related to arch_wrapper */
struct syscall_service *ss_create(struct arch_service *m, int request_type);
int ssa_is_ok(struct syscall_service *s, int arch, int num);
struct error_service *ss_err(struct syscall_service *s);
int ss_size(struct syscall_service *m);
int ssa_max_scn(struct syscall_service *s, int arch);
const struct_sysent *ssa_sysc_list(struct syscall_service *s, int arch);
int ssa_flag(struct syscall_service *s, int arch, int num);
int ssa_set_flag(struct syscall_service *s, int arch, int num, int flag);
int ssa_real_num(struct syscall_service *s, int arch, int num);
int ssa_set_real_num(struct syscall_service *s, int arch, int num,
int real_num);
const char *ssa_syscall_name(struct syscall_service *s, int arch, int num);
int ssa_syscall_flag(struct syscall_service *s, int arch, int num);
int ssa_syscall_nargs(struct syscall_service *s, int arch, int num);
int ssa_user_num1(struct syscall_service *s, int arch);
int ssa_user_num2(struct syscall_service *s, int arch);
void ss_free(struct syscall_service *s);
/* calculating methods */
int ssa_print_size(struct syscall_service *s, int arch);
int ssa_find_snum(struct syscall_service *s, int arch, int real_num);
int ss_mark_matches(struct syscall_service *s, int arch, char *arg);
int ss_update_sc_num(struct syscall_service *s, int arch);
void ss_dump(struct syscall_service *s, int is_raw);
#endif /* !ASINFO_SYSCALL_INTERFACE_H */

View File

@ -0,0 +1,45 @@
# Automake input for asinfo tests.
#
# Copyright (c) 2017 Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.com>
# Copyright (c) 2017-2018 The strace developers.
# All rights reserved.
#
# SPDX-License-Identifier: GPL-2.0-or-later
OS = linux
AM_COLOR_TESTS = always
AM_CFLAGS = $(WARN_CFLAGS)
AM_CPPFLAGS = $(ARCH_MFLAGS) \
-I$(builddir) \
-I$(builddir)/.. \
-I$(top_builddir) \
-I$(top_srcdir)
AM_LDFLAGS = $(ARCH_MFLAGS)
check_PROGRAMS = set_arch set_mult_arch list_arch set_abi set_mult_abi \
get_arch_abi get_sname get_snum com_disp_wrong_keys \
multiarch_get_sname multiarch_get_snum format_output
TESTS = set_arch.test set_mult_arch.test list_arch.test set_abi.test \
set_mult_abi.test get_arch_abi.test get_sname.test get_snum.test \
com_disp_wrong_keys.test multiarch_get_sname.test \
multiarch_get_snum.test format_output.test
set_arch_SOURCES = set_arch.c
set_mult_arch_SOURCES = set_mult_arch.c
list_arch_SOURCES = list_arch.c
set_abi_SOURCES = set_abi.c
set_mult_abi_SOURCES = set_mult_abi.c
get_arch_abi_SOURCES = get_arch_abi.c
get_sname_SOURCES = get_sname.c
get_snum_SOURCES = get_snum.c
com_disp_wrong_keys_SOURCES = com_disp_wrong_keys.c
multiarch_get_sname_SOURCES = multiarch_get_sname.c
multiarch_get_snum_SOURCES = multiarch_get_snum.c
format_output_SOURCES = format_output.c
EXTRA_DIST = $(TESTS) init.sh ref_asinfo_output.h
clean-local: clean-local-check
.PHONY: clean-local-check
clean-local-check:
-rm -rf -- $(TESTS:.test=.dir)

View File

@ -0,0 +1,42 @@
#include <stdio.h>
#include "ref_asinfo_output.h"
#define TRY_HELP "Try \'../../asinfo -h\' for more information."
int
main(int argc, char *argv[])
{
puts("../../asinfo: unrecognized option \'--set-ar\'\n"
TRY_HELP "\n"
"../../asinfo: parameter \'--get-arch\' has been used more than "
"once\n"
TRY_HELP "\n"
"../../asinfo: parameter \'--set-arch\' requires argument\n"
TRY_HELP "\n"
"../../asinfo: argument \'aarch64,\' of \'--set-arch\' parameter "
"has a wrong format\n"
TRY_HELP "\n"
"../../asinfo: exclusive parameters\n"
TRY_HELP "\n"
"../../asinfo: wrong parameters\n"
TRY_HELP "\n"
"../../asinfo: \'--list-arch\' cannot be used with any ABI "
"parameters\n"
TRY_HELP "\n"
"../../asinfo: ABI parameters could be used only with "
"architecture parameter\n"
TRY_HELP "\n"
"../../asinfo: ABI modes cannot be automatically detected for "
"multiple architectures\n"
TRY_HELP "\n"
"../../asinfo: each architecture needs respective ABI mode, "
"and vice versa\n"
TRY_HELP "\n"
"../../asinfo: first set main output syscall characteristics\n"
TRY_HELP "\n"
"../../asinfo: raw data implies existing data\n"
TRY_HELP "\n"
"../../asinfo: must have OPTIONS\n"
TRY_HELP);
return 0;
}

View File

@ -0,0 +1,32 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
#Unrecognized option
run_asinfo --set-ar > $LOG
#More than once param
run_asinfo --get-arch --get-arch >> $LOG
#Requiring argument
run_asinfo --set-arch >> $LOG
#Wrong format
run_asinfo --set-arch aarch64, >> $LOG
#More than one option in one group
run_asinfo --get-arch --set-arch arm >> $LOG
#syscall and list-arch
run_asinfo --list-arch --get-sname all >> $LOG
#list-arch and abi params
run_asinfo --list-arch --list-abi >> $LOG
#abi params without arch params
run_asinfo --list-abi >> $LOG
#auto abi for multiple archs
run_asinfo --set-arch aarch64,arm >> $LOG
#auto abi for multiple archs
run_asinfo --set-arch aarch64,arm --set-abi all,all,all >> $LOG
#nargs should be used together with other options from syscall group
run_asinfo --set-arch x86_64 --set-abi x32 --nargs >> $LOG
#raw check
run_asinfo --raw >> $LOG
#empty input
run_asinfo >> $LOG
match_diff "$LOG" "$EXP"

View File

@ -0,0 +1,17 @@
#include <stdio.h>
#include "ref_asinfo_output.h"
int
main(int argc, char *argv[])
{
puts(
"| N | Architecture name | ABI mode | IMPL syscalls | IPC IMPL | SOCKET IMPL |\n"
"| 1 | avr32 | 32bit | 329 | external | external |"
);
puts(
"| | | x86_64 | x86_64 | x86_64 |\n"
"| N | Snum | 64bit | x32 | 32bit |\n"
"| 1 | 1 | write | write | - |\n"
"| 2 | 4 | - | - | write |");
return 0;
}

View File

@ -0,0 +1,8 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
run_asinfo --set-arch avr32 --list-abi > $LOG
run_asinfo --set-arch x86_64 --list-abi --get-snum write >> $LOG
match_diff "$LOG" "$EXP"

View File

@ -0,0 +1,172 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <sys/utsname.h>
#include "ref_asinfo_output.h"
static inline void
print_cannot_detect(char *arch_name)
{
printf("../../asinfo: ABI mode cannot be automatically detected for "
"non-target architecture \'%s\'\n", arch_name);
}
int
main(int argc, char *argv[])
{
struct utsname buf;
uname(&buf);
#if defined(bfin)
puts("1" BFIN_32bit_STR);
return 0;
#endif
#if defined(IA64)
puts("1" IA64_64bit_STR);
return 0;
#endif
#if defined(M68K)
puts("1" M68K_32bit_STR);
#endif
#if defined(SPARC64)
print_cannot_detect(buf.machine);
return 0;
#endif
#if defined(SPARC)
puts("1" SPARC_32bit_STR);
return 0;
#endif
#if defined(METAG)
puts("1" METAG_32bit_STR);
return 0;
#endif
#if defined(MIPS)
if (strstr(buf.machine, "mips64")) {
puts(
#if defined(LINUX_MIPSO32)
"1" MIPS64_O32_STR
#elif defined(LINUX_MIPSN32)
"1" MIPS64_N32_STR
#elif defined(LINUX_MIPSN64)
"1" MIPS64_N64_STR
#endif
);
return 0;
}
if (strstr(buf.machine, "mips")) {
puts("1" MIPS_O32_STR);
return 0;
}
#endif
#if defined(ALPHA)
puts("1" ALPHA_64bit_STR);
return 0;
#endif
#if defined(POWERPC64)
print_cannot_detect(buf.machine);
return 0;
#endif
#if defined(POWERPC)
puts("1" PPC_32bit_STR);
return 0;
#endif
#if defined(ARM)
if (strstr(buf.machine, "arm")) {
puts(
#if defined(__ARM_EABI__) || !defined(ENABLE_ARM_OABI)
"1" ARM_eabi_STR
#else
"1" ARM_oabi_STR
#endif
);
return 0;
}
#endif
#if defined(AARCH64)
puts(
#if defined(__ARM_EABI__)
"1" AARCH64_eabi_STR
#else
"1" AARCH64_64bit_STR
#endif
);
return 0;
#endif
#if defined(AVR32)
puts("1" AVR32_32bit_STR);
return 0;
#endif
#if defined(ARC)
puts("1" ARC_32bit_STR);
return 0;
#endif
#if defined(S390)
puts("1" S390_32bit_STR);
return 0;
#endif
#if defined(S390X)
puts("1" S390X_64bit_STR);
return 0;
#endif
#if defined(HPPA)
puts("1" PARISC_32bit_STR);
return 0;
#endif
#if defined(SH64)
puts("1" SH64_64bit_STR);
return 0;
#endif
#if defined(SH)
puts("1" SH_32bit_STR);
return 0;
#endif
#if defined(X86_64) || defined(X32)
puts(
#if defined(X86_64)
"1" X86_64_64bit_STR
#elif defined(X32)
"1" X86_64_X32_STR
#endif
);
return 0;
#endif
#if defined(I386)
if (strstr(buf.machine, "64"))
puts("1" X86_64_32bit_STR);
else
puts("1" X86_32bit_STR);
return 0;
#endif
#if defined(TILE)
puts(
#if defined(__tilepro__)
"1" TILE_64bit_STR
#else
"1" TILE_32bit_STR
#endif
);
#endif
#if defined(MICROBLAZE)
puts("1" MICROBLAZE_32bit_STR);
return 0;
#endif
#if defined(NIOS2)
puts("1" NIOS2_32bit_STR);
return 0;
#endif
#if defined(OR1K)
puts("1" OR1K_32bit_STR);
return 0;
#endif
#if defined(XTENSA)
puts("1" XTENSA_32bit_STR);
return 0;
#endif
#if defined(RISCV)
print_cannot_detect(buf.machine);
return 0;
#endif
printf("../../asinfo: architecture \'%s\' is unsupported\n",
buf.machine);
return 0;
}

View File

@ -0,0 +1,7 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
run_asinfo --get-arch --raw > "$LOG"
match_diff "$LOG" "$EXP"

View File

@ -0,0 +1,26 @@
#include <stdio.h>
#include "ref_asinfo_output.h"
int
main(int argc, char *argv[])
{
//--get-sname write
puts("1;write;1;\n"
//--get-sname /write
"1;process_vm_writev;311;\n"
"2;pwrite64;18;\n"
"3;pwritev;296;\n"
"4;pwritev2;328;\n"
"5;write;1;\n"
"6;writev;20;\n"
//--get-sname write,read
"1;read;0;\n"
"2;write;1;\n"
//--get-sname 1
"1;write;1;\n"
//--get-sname 1000
"../../asinfo: invalid system call \'1000\'\n"
//--get-sname helloworld
"../../asinfo: invalid system call \'helloworld\'");
return 0;
}

View File

@ -0,0 +1,12 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
run_asinfo --set-arch x86_64 --set-abi 64bit --get-sname write --raw > $LOG
run_asinfo --set-arch x86_64 --set-abi 64bit --get-sname /write --raw >> $LOG
run_asinfo --set-arch x86_64 --set-abi 64bit --get-sname write,read --raw >> $LOG
run_asinfo --set-arch x86_64 --set-abi 64bit --get-sname 1 --raw >> $LOG
run_asinfo --set-arch x86_64 --set-abi 64bit --get-sname 1000 --raw >> $LOG
run_asinfo --set-arch x86_64 --set-abi 64bit --get-sname helloworld --raw >> $LOG
match_diff "$LOG" "$EXP"

View File

@ -0,0 +1,26 @@
#include <stdio.h>
#include "ref_asinfo_output.h"
int
main(int argc, char *argv[])
{
//--get-snum write
puts("1;1;write;\n"
//--get-snum /write
"1;1;write;\n"
"2;18;pwrite64;\n"
"3;20;writev;\n"
"4;296;pwritev;\n"
"5;311;process_vm_writev;\n"
"6;328;pwritev2;\n"
//--get-snum write,read
"1;0;read;\n"
"2;1;write;\n"
//--get-snum 1
"1;1;write;\n"
//--get-snum 1000
"../../asinfo: invalid system call \'1000\'\n"
//--get-snum helloworld
"../../asinfo: invalid system call \'helloworld\'");
return 0;
}

View File

@ -0,0 +1,12 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
run_asinfo --set-arch x86_64 --set-abi 64bit --get-snum write --raw > $LOG
run_asinfo --set-arch x86_64 --set-abi 64bit --get-snum /write --raw >> $LOG
run_asinfo --set-arch x86_64 --set-abi 64bit --get-snum write,read --raw >> $LOG
run_asinfo --set-arch x86_64 --set-abi 64bit --get-snum 1 --raw >> $LOG
run_asinfo --set-arch x86_64 --set-abi 64bit --get-snum 1000 --raw >> $LOG
run_asinfo --set-arch x86_64 --set-abi 64bit --get-snum helloworld --raw >> $LOG
match_diff "$LOG" "$EXP"

View File

@ -0,0 +1,75 @@
#!/bin/sh
#
# Copyright (c) 2011-2018 The strace developers.
# All rights reserved.
#
# SPDX-License-Identifier: GPL-2.0-or-later
ME_="${0##*/}"
LOG="log"
OUT="out"
EXP="exp"
ASINFO="../../asinfo"
fail_() { warn_ "$ME_: failed test: $*"; exit 1; }
warn_() { printf >&2 '%s\n' "$*"; }
run_prog()
{
if [ $# -eq 0 ]; then
set -- "../$NAME"
fi
args="$*"
"$@" || {
rc=$?
if [ $rc != 0 ]; then
fail_ "$args failed with code $rc"
fi
}
}
dump_log_and_fail_with()
{
cat < "$LOG" >&2
fail_ "$*"
}
run_asinfo()
{
args="$*"
$ASINFO "$@" 2>&1
}
match_diff()
{
local output expected error
if [ $# -eq 0 ]; then
output="$LOG"
else
output="$1"; shift
fi
if [ $# -eq 0 ]; then
expected="$srcdir/$NAME.expected"
else
expected="$1"; shift
fi
if [ $# -eq 0 ]; then
error="$STRACE $args output mismatch"
else
error="$1"; shift
fi
diff -u -- "$expected" "$output" ||
fail_ "$error"
}
NAME="${ME_%.test}"
TESTDIR="$NAME.dir"
rm -rf -- "$TESTDIR"
mkdir -- "$TESTDIR"
cd "$TESTDIR"
case "$srcdir" in
/*) ;;
*) srcdir="../$srcdir" ;;
esac

View File

@ -0,0 +1,47 @@
#include <stdio.h>
#include "ref_asinfo_output.h"
int
main(int argc, char *argv[])
{
puts("1" BFIN_32bit_STR"\n"
"2" IA64_64bit_STR"\n"
"3" M68K_32bit_STR"\n"
"4" SPARC64_64bit_STR"\n"
"5" SPARC64_32bit_STR"\n"
"6" SPARC_32bit_STR"\n"
"7" METAG_32bit_STR"\n"
"8" MIPS64_N64_STR"\n"
"9" MIPS64_N32_STR"\n"
"10" MIPS64_O32_STR"\n"
"11" MIPS_O32_STR"\n"
"12" ALPHA_64bit_STR"\n"
"13" PPC64_64bit_STR"\n"
"14" PPC64_32bit_STR"\n"
"15" PPC_32bit_STR"\n"
"16" AARCH64_64bit_STR"\n"
"17" AARCH64_eabi_STR"\n"
"18" ARM_oabi_STR"\n"
"19" ARM_eabi_STR"\n"
"20" AVR32_32bit_STR"\n"
"21" ARC_32bit_STR"\n"
"22" S390X_64bit_STR"\n"
"23" S390_32bit_STR"\n"
"24" PARISC_32bit_STR"\n"
"25" SH64_64bit_STR"\n"
"26" SH_32bit_STR"\n"
"27" X86_64_64bit_STR"\n"
"28" X86_64_X32_STR"\n"
"29" X86_64_32bit_STR"\n"
"30" X86_32bit_STR"\n"
"31" TILE_64bit_STR"\n"
"32" TILE_32bit_STR"\n"
"33" TILEPRO_32bit_STR"\n"
"34" MICROBLAZE_32bit_STR"\n"
"35" NIOS2_32bit_STR"\n"
"36" OR1K_32bit_STR"\n"
"37" XTENSA_32bit_STR"\n"
"38" RISCV_64bit_STR"\n"
"39" RISCV_32bit_STR);
return 0;
}

View File

@ -0,0 +1,7 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
run_asinfo --list-arch --raw > $LOG
match_diff "$LOG" "$EXP"

View File

@ -0,0 +1,31 @@
#include <stdio.h>
#include "ref_asinfo_output.h"
int
main(int argc, char *argv[])
{
//--get-sname write
puts("1;write;1;1;4;4;\n"
//--get-sname /write
"1;process_vm_writev;311;540;348;348;\n"
"2;process_vm_writev#64;-;311;-;-;\n"
"3;pwrite64;18;18;181;181;\n"
"4;pwritev;296;535;334;334;\n"
"5;pwritev#64;-;296;-;-;\n"
"6;pwritev2;328;547;379;379;\n"
"7;pwritev2#64;-;328;-;-;\n"
"8;write;1;1;4;4;\n"
"9;writev;20;516;146;146;\n"
"10;writev#64;-;20;-;-;\n"
//--get-sname write,read
"1;read;0;0;3;3;\n"
"2;write;1;1;4;4;\n"
//--get-sname 1
"1;exit;-;-;1;1;\n"
"2;write;1;1;-;-;\n"
//--get-sname 1000
"../../asinfo: invalid system call \'1000\'\n"
//--get-sname helloworld
"../../asinfo: invalid system call \'helloworld\'");
return 0;
}

View File

@ -0,0 +1,12 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
run_asinfo --set-arch x86_64,x86 --list-abi --get-sname write --raw > $LOG
run_asinfo --set-arch x86_64,x86 --list-abi --get-sname /write --raw >> $LOG
run_asinfo --set-arch x86_64,x86 --list-abi --get-sname write,read --raw >> $LOG
run_asinfo --set-arch x86_64,x86 --list-abi --get-sname 1 --raw >> $LOG
run_asinfo --set-arch x86_64,x86 --list-abi --get-sname 1000 --raw >> $LOG
run_asinfo --set-arch x86_64,x86 --list-abi --get-sname helloworld --raw >> $LOG
match_diff "$LOG" "$EXP"

View File

@ -0,0 +1,39 @@
#include <stdio.h>
#include "ref_asinfo_output.h"
int
main(int argc, char *argv[])
{
//--get-snum write
puts("1;1;write;write;-;-;\n"
"2;4;-;-;write;write;\n"
//--get-snum /write
"1;1;write;write;-;-;\n"
"2;4;-;-;write;write;\n"
"3;18;pwrite64;pwrite64;-;-;\n"
"4;20;writev;writev#64;-;-;\n"
"5;146;-;-;writev;writev;\n"
"6;181;-;-;pwrite64;pwrite64;\n"
"7;296;pwritev;pwritev#64;-;-;\n"
"8;311;process_vm_writev;process_vm_writev#64;-;-;\n"
"9;328;pwritev2;pwritev2#64;-;-;\n"
"10;334;-;-;pwritev;pwritev;\n"
"11;348;-;-;process_vm_writev;process_vm_writev;\n"
"12;379;-;-;pwritev2;pwritev2;\n"
"13;516;-;writev;-;-;\n"
"14;535;-;pwritev;-;-;\n"
"15;540;-;process_vm_writev;-;-;\n"
"16;547;-;pwritev2;-;-;\n"
//--get-snum write,read
"1;0;read;read;-;-;\n"
"2;1;write;write;-;-;\n"
"3;3;-;-;read;read;\n"
"4;4;-;-;write;write;\n"
//--get-snum 1
"1;1;write;write;exit;exit;\n"
//--get-snum 1000
"../../asinfo: invalid system call \'1000\'\n"
//--get-snum helloworld
"../../asinfo: invalid system call \'helloworld\'");
return 0;
}

View File

@ -0,0 +1,12 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
run_asinfo --set-arch x86_64,x86 --list-abi --get-snum write --raw > $LOG
run_asinfo --set-arch x86_64,x86 --list-abi --get-snum /write --raw >> $LOG
run_asinfo --set-arch x86_64,x86 --list-abi --get-snum write,read --raw >> $LOG
run_asinfo --set-arch x86_64,x86 --list-abi --get-snum 1 --raw >> $LOG
run_asinfo --set-arch x86_64,x86 --list-abi --get-snum 1000 --raw >> $LOG
run_asinfo --set-arch x86_64,x86 --list-abi --get-snum helloworld --raw >> $LOG
match_diff "$LOG" "$EXP"

View File

@ -0,0 +1,40 @@
/* Reference output strings for asinfo tool which are necessary for tests */
#define BFIN_32bit_STR ";blackfin/bfin;32bit;391;external;external;"
#define IA64_64bit_STR ";ia64;64bit;326;external;external;"
#define M68K_32bit_STR ";m68k;32bit;378;internal;internal;"
#define SPARC64_64bit_STR ";sparc64;64bit;341;internal;internal;"
#define SPARC64_32bit_STR ";sparc64;32bit;359;internal;internal;"
#define SPARC_32bit_STR ";sparc;32bit;359;internal;internal;"
#define METAG_32bit_STR ";metag;32bit;281;external;external;"
#define MIPS64_N64_STR ";mips64/mips64le;n64;1002;int/ext;int/ext;"
#define MIPS64_N32_STR ";mips64/mips64le;n32;1006;int/ext;int/ext;"
#define MIPS64_O32_STR ";mips64/mips64le;o32;1042;internal;internal;"
#define MIPS_O32_STR ";mips/mipsle;o32;1042;internal;internal;"
#define ALPHA_64bit_STR ";alpha;64bit;442;external;external;"
#define PPC64_64bit_STR ";ppc64/ppc64le/powerpc64;64bit;379;int/ext;int/ext;"
#define PPC64_32bit_STR ";ppc64/ppc64le/powerpc64;32bit;388;int/ext;int/ext;"
#define PPC_32bit_STR ";ppc/ppcle/powerpc;32bit;388;int/ext;int/ext;"
#define AARCH64_64bit_STR ";aarch64/arm64;64bit;333;external;external;"
#define AARCH64_eabi_STR ";aarch64/arm64;eabi;403;external;external;"
#define ARM_oabi_STR ";arm;oabi;403;int/ext;int/ext;"
#define ARM_eabi_STR ";arm;eabi;403;external;external;"
#define AVR32_32bit_STR ";avr32;32bit;329;external;external;"
#define ARC_32bit_STR ";arc;32bit;282;external;external;"
#define S390X_64bit_STR ";s390x;64bit;330;internal;internal;"
#define S390_32bit_STR ";s390;32bit;363;internal;internal;"
#define PARISC_32bit_STR ";parisc/hppa;32bit;350;external;external;"
#define SH64_64bit_STR ";sh64;64bit;382;int/ext;int/ext;"
#define SH_32bit_STR ";sh;32bit;374;internal;internal;"
#define X86_64_64bit_STR ";x86_64/amd64/EM64T;64bit;335;external;external;"
#define X86_64_X32_STR ";x86_64/amd64/EM64T;x32;371;external;external;"
#define X86_64_32bit_STR ";x86_64/amd64/EM64T;32bit;383;internal;internal;"
#define X86_32bit_STR ";x86/i386/i486/i586/i686;32bit;383;internal;internal;"
#define TILE_64bit_STR ";tile/tilegx;64bit;279;external;external;"
#define TILE_32bit_STR ";tile/tilegx;32bit;279;external;external;"
#define TILEPRO_32bit_STR ";tilepro;32bit;279;external;external;"
#define MICROBLAZE_32bit_STR ";microblaze;32bit;397;external;external;"
#define NIOS2_32bit_STR ";nios2;32bit;278;external;external;"
#define OR1K_32bit_STR ";openrisc/or1k;32bit;278;external;external;"
#define XTENSA_32bit_STR ";xtensa;32bit;326;external;external;"
#define RISCV_64bit_STR ";riscv;64bit;278;external;external;"
#define RISCV_32bit_STR ";riscv;32bit;277;external;external;"

View File

@ -0,0 +1,9 @@
#include <stdio.h>
#include "ref_asinfo_output.h"
int
main(int argc, char *argv[])
{
puts("1" X86_64_64bit_STR);
return 0;
}

View File

@ -0,0 +1,7 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
run_asinfo --set-arch x86_64 --set-abi 64bit --raw > $LOG
match_diff "$LOG" "$EXP"

View File

@ -0,0 +1,11 @@
#include <stdio.h>
#include "ref_asinfo_output.h"
int
main(int argc, char *argv[])
{
puts("1" X86_64_64bit_STR "\n"
"2" X86_64_X32_STR "\n"
"3" X86_64_32bit_STR);
return 0;
}

View File

@ -0,0 +1,7 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
run_asinfo --set-arch x86_64 --list-abi --raw > $LOG
match_diff "$LOG" "$EXP"

View File

@ -0,0 +1,11 @@
#include <stdio.h>
#include "ref_asinfo_output.h"
int
main(int argc, char *argv[])
{
puts("1" X86_64_64bit_STR "\n"
"2" AARCH64_64bit_STR "\n"
"3" AARCH64_eabi_STR );
return 0;
}

View File

@ -0,0 +1,7 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
run_asinfo --set-arch x86_64,aarch64 --set-abi 64bit,all --raw >> $LOG
match_diff "$LOG" "$EXP"

View File

@ -0,0 +1,12 @@
#include <stdio.h>
#include "ref_asinfo_output.h"
int
main(int argc, char *argv[])
{
puts("1" AARCH64_64bit_STR "\n"
"2" AARCH64_eabi_STR "\n"
"3" ARM_oabi_STR "\n"
"4" ARM_eabi_STR );
return 0;
}

View File

@ -0,0 +1,7 @@
#!/bin/sh
. "${srcdir=.}/init.sh"
run_prog > $EXP
run_asinfo --set-arch aarch64,arm --list-abi --raw >> $LOG
match_diff "$LOG" "$EXP"