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:
parent
bc87159e49
commit
2c877a5df6
@ -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
4
NEWS
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
3
debian/control
vendored
@ -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
|
||||
|
1
debian/strace.install
vendored
1
debian/strace.install
vendored
@ -1,2 +1,3 @@
|
||||
build/strace usr/bin
|
||||
strace-log-merge usr/bin
|
||||
build/tools/asinfo/asinfo usr/bin
|
||||
|
1
debian/strace.manpages
vendored
1
debian/strace.manpages
vendored
@ -1,2 +1,3 @@
|
||||
build/strace.1
|
||||
build/strace-log-merge.1
|
||||
build/tools/asinfo/asinfo.1
|
||||
|
@ -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
9
tools/Makefile.am
Normal 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
56
tools/asinfo/Makefile.am
Normal 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
37
tools/asinfo/README-arch
Normal 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.
|
66
tools/asinfo/arch_definitions.h
Normal file
66
tools/asinfo/arch_definitions.h
Normal 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({}) )
|
635
tools/asinfo/arch_interface.c
Normal file
635
tools/asinfo/arch_interface.c
Normal 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);
|
||||
}
|
143
tools/asinfo/arch_interface.h
Normal file
143
tools/asinfo/arch_interface.h
Normal 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
264
tools/asinfo/asinfo.1.in
Normal 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
312
tools/asinfo/asinfo.c
Normal 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
225
tools/asinfo/dispatchers.c
Normal 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;
|
||||
}
|
29
tools/asinfo/dispatchers.h
Normal file
29
tools/asinfo/dispatchers.h
Normal 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 */
|
91
tools/asinfo/error_interface.c
Normal file
91
tools/asinfo/error_interface.c
Normal 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);
|
||||
}
|
76
tools/asinfo/error_interface.h
Normal file
76
tools/asinfo/error_interface.h
Normal 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
152
tools/asinfo/gen_asinfo_files.sh
Executable 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 "$@"
|
74
tools/asinfo/request_msgs.h
Normal file
74
tools/asinfo/request_msgs.h
Normal 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 */
|
672
tools/asinfo/syscall_interface.c
Normal file
672
tools/asinfo/syscall_interface.c
Normal 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);
|
||||
}
|
123
tools/asinfo/syscall_interface.h
Normal file
123
tools/asinfo/syscall_interface.h
Normal 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 */
|
45
tools/asinfo/tests/Makefile.am
Normal file
45
tools/asinfo/tests/Makefile.am
Normal 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)
|
42
tools/asinfo/tests/com_disp_wrong_keys.c
Normal file
42
tools/asinfo/tests/com_disp_wrong_keys.c
Normal 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;
|
||||
}
|
32
tools/asinfo/tests/com_disp_wrong_keys.test
Executable file
32
tools/asinfo/tests/com_disp_wrong_keys.test
Executable 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"
|
17
tools/asinfo/tests/format_output.c
Normal file
17
tools/asinfo/tests/format_output.c
Normal 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;
|
||||
}
|
8
tools/asinfo/tests/format_output.test
Executable file
8
tools/asinfo/tests/format_output.test
Executable 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"
|
172
tools/asinfo/tests/get_arch_abi.c
Normal file
172
tools/asinfo/tests/get_arch_abi.c
Normal 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;
|
||||
}
|
7
tools/asinfo/tests/get_arch_abi.test
Executable file
7
tools/asinfo/tests/get_arch_abi.test
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "${srcdir=.}/init.sh"
|
||||
|
||||
run_prog > $EXP
|
||||
run_asinfo --get-arch --raw > "$LOG"
|
||||
match_diff "$LOG" "$EXP"
|
26
tools/asinfo/tests/get_sname.c
Normal file
26
tools/asinfo/tests/get_sname.c
Normal 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;
|
||||
}
|
12
tools/asinfo/tests/get_sname.test
Executable file
12
tools/asinfo/tests/get_sname.test
Executable 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"
|
26
tools/asinfo/tests/get_snum.c
Normal file
26
tools/asinfo/tests/get_snum.c
Normal 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;
|
||||
}
|
12
tools/asinfo/tests/get_snum.test
Executable file
12
tools/asinfo/tests/get_snum.test
Executable 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"
|
75
tools/asinfo/tests/init.sh
Normal file
75
tools/asinfo/tests/init.sh
Normal 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
|
47
tools/asinfo/tests/list_arch.c
Normal file
47
tools/asinfo/tests/list_arch.c
Normal 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;
|
||||
}
|
7
tools/asinfo/tests/list_arch.test
Executable file
7
tools/asinfo/tests/list_arch.test
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "${srcdir=.}/init.sh"
|
||||
|
||||
run_prog > $EXP
|
||||
run_asinfo --list-arch --raw > $LOG
|
||||
match_diff "$LOG" "$EXP"
|
31
tools/asinfo/tests/multiarch_get_sname.c
Normal file
31
tools/asinfo/tests/multiarch_get_sname.c
Normal 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;
|
||||
}
|
12
tools/asinfo/tests/multiarch_get_sname.test
Executable file
12
tools/asinfo/tests/multiarch_get_sname.test
Executable 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"
|
39
tools/asinfo/tests/multiarch_get_snum.c
Normal file
39
tools/asinfo/tests/multiarch_get_snum.c
Normal 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;
|
||||
}
|
12
tools/asinfo/tests/multiarch_get_snum.test
Executable file
12
tools/asinfo/tests/multiarch_get_snum.test
Executable 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"
|
40
tools/asinfo/tests/ref_asinfo_output.h
Normal file
40
tools/asinfo/tests/ref_asinfo_output.h
Normal 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;"
|
9
tools/asinfo/tests/set_abi.c
Normal file
9
tools/asinfo/tests/set_abi.c
Normal 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;
|
||||
}
|
7
tools/asinfo/tests/set_abi.test
Executable file
7
tools/asinfo/tests/set_abi.test
Executable 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"
|
11
tools/asinfo/tests/set_arch.c
Normal file
11
tools/asinfo/tests/set_arch.c
Normal 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;
|
||||
}
|
7
tools/asinfo/tests/set_arch.test
Executable file
7
tools/asinfo/tests/set_arch.test
Executable 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"
|
11
tools/asinfo/tests/set_mult_abi.c
Normal file
11
tools/asinfo/tests/set_mult_abi.c
Normal 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;
|
||||
}
|
7
tools/asinfo/tests/set_mult_abi.test
Executable file
7
tools/asinfo/tests/set_mult_abi.test
Executable 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"
|
12
tools/asinfo/tests/set_mult_arch.c
Normal file
12
tools/asinfo/tests/set_mult_arch.c
Normal 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;
|
||||
}
|
7
tools/asinfo/tests/set_mult_arch.test
Executable file
7
tools/asinfo/tests/set_mult_arch.test
Executable 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"
|
Loading…
Reference in New Issue
Block a user