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 the previous one.
This point can be illustrated by the following example: $ asinfo --get-arch --get-sname write First of all, 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: Likewise. * 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/arch_includes.h: New file. * tools/asinfo/personalities.h: Likewise. * tools/asinfo/.gitignore: Likewise. Signed-off-by: Edgar Kaziakhmedov <edgar.kaziakhme...@virtuozzo.com> --- Makefile.am | 2 +- configure.ac | 2 + tools/Makefile.am | 28 ++ tools/asinfo/.gitignore | 2 + tools/asinfo/Makefile.am | 62 ++++ tools/asinfo/arch_definitions.h | 70 ++++ tools/asinfo/arch_includes.h | 272 +++++++++++++++ tools/asinfo/arch_interface.c | 654 ++++++++++++++++++++++++++++++++++++ tools/asinfo/arch_interface.h | 162 +++++++++ tools/asinfo/arch_personalities.h | 36 ++ tools/asinfo/asinfo.c | 331 ++++++++++++++++++ tools/asinfo/dispatchers.c | 244 ++++++++++++++ tools/asinfo/dispatchers.h | 48 +++ tools/asinfo/error_interface.c | 110 ++++++ tools/asinfo/error_interface.h | 95 ++++++ tools/asinfo/request_msgs.h | 93 ++++++ tools/asinfo/syscall_interface.c | 684 ++++++++++++++++++++++++++++++++++++++ tools/asinfo/syscall_interface.h | 142 ++++++++ 18 files changed, 3036 insertions(+), 1 deletion(-) create mode 100644 tools/Makefile.am create mode 100644 tools/asinfo/.gitignore create mode 100644 tools/asinfo/Makefile.am create mode 100644 tools/asinfo/arch_definitions.h create mode 100644 tools/asinfo/arch_includes.h create mode 100644 tools/asinfo/arch_interface.c create mode 100644 tools/asinfo/arch_interface.h create mode 100644 tools/asinfo/arch_personalities.h create mode 100644 tools/asinfo/asinfo.c create mode 100644 tools/asinfo/dispatchers.c create mode 100644 tools/asinfo/dispatchers.h create mode 100644 tools/asinfo/error_interface.c create mode 100644 tools/asinfo/error_interface.h create mode 100644 tools/asinfo/request_msgs.h create mode 100644 tools/asinfo/syscall_interface.c create mode 100644 tools/asinfo/syscall_interface.h diff --git a/Makefile.am b/Makefile.am index e90c7809..1c9c3dac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,7 +35,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 diff --git a/configure.ac b/configure.ac index 729ef3f7..0492bd8b 100644 --- a/configure.ac +++ b/configure.ac @@ -904,6 +904,8 @@ AC_CONFIG_FILES([Makefile tests-mx32/Makefile strace.1 strace-log-merge.1 + tools/Makefile + tools/asinfo/Makefile strace.spec debian/changelog]) AC_OUTPUT diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 00000000..f1c75cfb --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,28 @@ +# Automake input for strace tools. +# +# Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhme...@virtuozzo.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +SUBDIRS = asinfo diff --git a/tools/asinfo/.gitignore b/tools/asinfo/.gitignore new file mode 100644 index 00000000..09400c47 --- /dev/null +++ b/tools/asinfo/.gitignore @@ -0,0 +1,2 @@ +asinfo +asinfo.1 diff --git a/tools/asinfo/Makefile.am b/tools/asinfo/Makefile.am new file mode 100644 index 00000000..5051766e --- /dev/null +++ b/tools/asinfo/Makefile.am @@ -0,0 +1,62 @@ +# Automake input for asinfo. +# +# Copyright (c) 2017 Edgar Kaziakhmedov <edgar.kaziakhme...@virtuozzo.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +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) +asinfo_CPPFLAGS = $(AM_CPPFLAGS) +asinfo_CFLAGS = $(AM_CFLAGS) +asinfo_LDFLAGS = +asinfo_LDADD = -L$(top_srcdir) \ + -L$(top_builddir) \ + -lcommon + +asinfo_SOURCES = \ + arch_definitions.h \ + arch_includes.h \ + arch_interface.c \ + arch_interface.h \ + arch_personalities.h \ + asinfo.c \ + dispatchers.c \ + dispatchers.h \ + error_interface.c \ + error_interface.h \ + request_msgs.h \ + syscall_interface.c \ + syscall_interface.h \ + #end of asinfo_SOURCES diff --git a/tools/asinfo/arch_definitions.h b/tools/asinfo/arch_definitions.h new file mode 100644 index 00000000..37103160 --- /dev/null +++ b/tools/asinfo/arch_definitions.h @@ -0,0 +1,70 @@ +/* [],[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"}) ), +/* [],[crisv10/syscallent.h],[0,0] */ +ARCH_DESC_DEFINE(cris, 32bit, PASS({}), PASS({"cris", "crisv10"}) ), +/* [],[crisv32/syscallent.h],[0,0] */ +ARCH_DESC_DEFINE(crisv32, 32bit, PASS({}), PASS({"crisv32"}) ), +/* [],[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({}) ) diff --git a/tools/asinfo/arch_includes.h b/tools/asinfo/arch_includes.h new file mode 100644 index 00000000..e73a8328 --- /dev/null +++ b/tools/asinfo/arch_includes.h @@ -0,0 +1,272 @@ +/* ARCH_blackfin */ +static const struct_sysent blackfin_32bit_sysent[] = { + #include "bfin/syscallent.h" +}; +static const int blackfin_32bit_usr1 = 0; +const int blackfin_32bit_usr2 = 0; +/* ARCH_ia64 */ +struct_sysent ia64_64bit_sysent[] = { + #include "ia64/syscallent.h" +}; +static const int ia64_64bit_usr1 = 0; +static const int ia64_64bit_usr2 = 0; +#undef SYS_socket_subcall +/* ARCH_m68k */ +static const struct_sysent m68k_32bit_sysent[] = { + #include "m68k/syscallent.h" +}; +static const int m68k_32bit_usr1 = 0; +static const int m68k_32bit_usr2 = 0; +/* ARCH_sparc64 64bit ABI */ +static const struct_sysent sparc64_64bit_sysent[] = { + #include "sparc64/syscallent.h" +}; +static const int sparc64_64bit_usr1 = 0; +static const int sparc64_64bit_usr2 = 0; +/* ARCH_sparc and 32bit ABI */ +static const struct_sysent sparc_32bit_sysent[] = { + #include "sparc/syscallent.h" +}; +static const int sparc_32bit_usr1 = 0; +static const int sparc_32bit_usr2 = 0; +#undef SYS_socket_subcall +/* ARCH_metag */ +static const struct_sysent metag_32bit_sysent[] = { + #include "metag/syscallent.h" +}; +static const int metag_32bit_usr1 = 0; +static const int metag_32bit_usr2 = 0; +/* ARCH_mips n64 ABI */ +#ifndef LINUX_MIPSN64 +# define LINUX_MIPSN64 1 +# define NOW_DEFINED 1 +#endif +static const struct_sysent mips64_n64_sysent[] = { + #include "dummy.h" + #include "mips/syscallent-compat.h" + #include "mips/syscallent-n64.h" +}; +#ifdef NOW_DEFINED +# undef LINUX_MIPSN32 +# undef NOW_DEFINED +#endif +static const int mips64_n64_usr1 = 0; +static const int mips64_n64_usr2 = 0; +#undef SYS_socket_subcall +/* ARCH_mips n32 ABI */ +#ifndef LINUX_MIPSN32 +# define LINUX_MIPSN32 1 +# define NOW_DEFINED 1 +#endif +static const struct_sysent mips64_n32_sysent[] = { + #include "dummy.h" + #include "mips/syscallent-compat.h" + #include "mips/syscallent-n32.h" +}; +#ifdef NOW_DEFINED +# undef LINUX_MIPSN32 +# undef NOW_DEFINED +#endif +static const int mips64_n32_usr1 = 0; +static const int mips64_n32_usr2 = 0; +#undef SYS_socket_subcall +/* ARCH_mips o32 ABI */ +#ifndef LINUX_MIPSO32 +# define LINUX_MIPSO32 1 +# define NOW_DEFINED 1 +#endif +static const struct_sysent mips_o32_sysent[] = { + #include "dummy.h" + #include "mips/syscallent-compat.h" + #include "mips/syscallent-o32.h" +}; +#ifdef NOW_DEFINED +# undef LINUX_MIPSO32 +# undef NOW_DEFINED +#endif +static const int mips_o32_usr1 = 0; +static const int mips_o32_usr2 = 0; +#undef SYS_socket_subcall +/* ARCH_alpha */ +static const struct_sysent alpha_64bit_sysent[] = { + #include "alpha/syscallent.h" +}; +static const int alpha_64bit_usr1 = 0; +static const int alpha_64bit_usr2 = 0; +/* ARCH_ppc64 64bit ABI */ +static const struct_sysent ppc64_64bit_sysent[] = { + #include "powerpc64/syscallent.h" +}; +static const int ppc64_64bit_usr1 = 0; +static const int ppc64_64bit_usr2 = 0; +#undef SYS_socket_subcall +/* ARCH_ppc and 32bit */ +static const struct_sysent ppc_32bit_sysent[] = { + #include "powerpc/syscallent.h" +}; +static const int ppc_32bit_usr1 = 0; +static const int ppc_32bit_usr2 = 0; +#undef SYS_socket_subcall +/* ARCH_aarch64 64bit ABI */ +static const struct_sysent aarch64_64bit_sysent[] = { + #include "aarch64/syscallent.h" +}; +static const int aarch64_64bit_usr1 = 0; +static const int aarch64_64bit_usr2 = 0; +/* ARCH_arm OABI*/ +#ifdef __ARM_EABI__ +# undef __ARM_EABI__ +# define NOW_UNDEFINED 1 +#endif +static const struct_sysent arm_oabi_sysent[] = { + #include "arm/syscallent.h" +}; +static const int arm_oabi_usr1 = ARM_FIRST_SHUFFLED_SYSCALL; +static const int arm_oabi_usr2 = ARM_LAST_SPECIAL_SYSCALL; +#undef ARM_FIRST_SHUFFLED_SYSCALL +#undef ARM_LAST_SPECIAL_SYSCALL +#undef SYS_socket_subcall +#ifdef NOW_UNDEFINED +# define __ARM_EABI__ 1 +# undef NOW_UNDEFINED +#endif +/* ARCH_arm EABI*/ +#ifndef __ARM_EABI__ +# define __ARM_EABI__ 1 +# define NOW_DEFINED 1 +#endif +static const struct_sysent arm_eabi_sysent[] = { + #include "arm/syscallent.h" +}; +static const int arm_eabi_usr1 = ARM_FIRST_SHUFFLED_SYSCALL; +static const int arm_eabi_usr2 = ARM_LAST_SPECIAL_SYSCALL; +#undef ARM_FIRST_SHUFFLED_SYSCALL +#undef ARM_LAST_SPECIAL_SYSCALL +#ifdef NOW_DEFINED +# undef __ARM_EABI__ +# undef NOW_DEFINED +#endif +/* ARCH_avr32 */ +static const struct_sysent avr32_32bit_sysent[] = { + #include "avr32/syscallent.h" +}; +static const int avr32_32bit_usr1 = 0; +static const int avr32_32bit_usr2 = 0; +/* ARCH_arc */ +static const struct_sysent arc_32bit_sysent[] = { + #include "arc/syscallent.h" +}; +static const int arc_32bit_usr1 = 0; +static const int arc_32bit_usr2 = 0; +/* ARCH_s390x */ +static const struct_sysent s390x_64bit_sysent[] = { + #include "s390x/syscallent.h" +}; +static const int s390x_64bit_usr1 = 0; +static const int s390x_64bit_usr2 = 0; +#undef SYS_socket_subcall +/* ARCH_s390 */ +static const struct_sysent s390_32bit_sysent[] = { + #include "s390/syscallent.h" +}; +static const int s390_32bit_usr1 = 0; +static const int s390_32bit_usr2 = 0; +#undef SYS_socket_subcall +/* ARCH_hppa */ +static const struct_sysent hppa_32bit_sysent[] = { + #include "hppa/syscallent.h" +}; +static const int hppa_32bit_usr1 = 0; +static const int hppa_32bit_usr2 = 0; +/* ARCH_sh64 */ +static const struct_sysent sh64_64bit_sysent[] = { + #include "sh64/syscallent.h" +}; +static const int sh64_64bit_usr1 = 0; +static const int sh64_64bit_usr2 = 0; +#undef SYS_socket_subcall +/* ARCH_sh */ +static const struct_sysent sh_32bit_sysent[] = { + #include "sh/syscallent.h" +}; +static const int sh_32bit_usr1 = 0; +static const int sh_32bit_usr2 = 0; +/* ARCH_x86_64 64bit ABI mode */ +static const struct_sysent x86_64_64bit_sysent[] = { + #include "x86_64/syscallent.h" +}; +static const int x86_64_64bit_usr1 = 0; +static const int x86_64_64bit_usr2 = 0; +/* ARCH_x86_64 x32 ABI mode */ +static const struct_sysent x86_64_x32_sysent[] = { + #include "x86_64/syscallent2.h" +}; +static const int x86_64_x32_usr1 = 0; +static const int x86_64_x32_usr2 = 0; +/* ARCH_x86 */ +static const struct_sysent x86_32bit_sysent[] = { + #include "i386/syscallent.h" +}; +static const int x86_32bit_usr1 = 0; +static const int x86_32bit_usr2 = 0; +/* ARCH_cris */ +static struct_sysent cris_32bit_sysent[] = { + #include "crisv10/syscallent.h" +}; +static const int cris_32bit_usr1 = 0; +static const int cris_32bit_usr2 = 0; +/* ARCH_crisv32 */ +static const struct_sysent crisv32_32bit_sysent[] = { + #include "crisv32/syscallent.h" +}; +static const int crisv32_32bit_usr1 = 0; +static const int crisv32_32bit_usr2 = 0; +#undef SYS_socket_subcall +/* ARCH_tile 64bit ABI mode */ +static const struct_sysent tile_64bit_sysent[] = { + #include "tile/syscallent.h" +}; +static const int tile_64bit_usr1 = 0; +static const int tile_64bit_usr2 = 0; +/* ARCH_tile 32bit ABI mode */ +static const struct_sysent tile_32bit_sysent[] = { + #include "tile/syscallent1.h" +}; +static const int tile_32bit_usr1 = 0; +static const int tile_32bit_usr2 = 0; +/* ARCH_microblaze */ +static const struct_sysent microblaze_32bit_sysent[] = { + #include "microblaze/syscallent.h" +}; +static const int microblaze_32bit_usr1 = 0; +static const int microblaze_32bit_usr2 = 0; +/* ARCH_nios2 */ +static const struct_sysent nios2_32bit_sysent[] = { + #include "nios2/syscallent.h" +}; +static const int nios2_32bit_usr1 = 0; +static const int nios2_32bit_usr2 = 0; +/* ARCH_openrisc */ +struct_sysent openrisc_32bit_sysent[] = { + #include "or1k/syscallent.h" +}; +static const int openrisc_32bit_usr1 = 0; +static const int openrisc_32bit_usr2 = 0; +/* ARCH_xtensa */ +static const struct_sysent xtensa_32bit_sysent[] = { + #include "xtensa/syscallent.h" +}; +static const int xtensa_32bit_usr1 = 0; +static const int xtensa_32bit_usr2 = 0; +/* ARCH_riscv 64bit ABI mode */ +static const struct_sysent riscv_64bit_sysent[] = { + #include "riscv/syscallent.h" +}; +static const int riscv_64bit_usr1 = 0; +static const int riscv_64bit_usr2 = 0; +/* ARCH_riscv 32bit ABI mode */ +static const struct_sysent riscv_32bit_sysent[] = { + #include "riscv/syscallent1.h" +}; +static const int riscv_32bit_usr1 = 0; +static const int riscv_32bit_usr2 = 0; diff --git a/tools/asinfo/arch_interface.c b/tools/asinfo/arch_interface.c new file mode 100644 index 00000000..8e02ffd0 --- /dev/null +++ b/tools/asinfo/arch_interface.c @@ -0,0 +1,654 @@ +/* + * Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhme...@virtuozzo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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], 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); +} diff --git a/tools/asinfo/arch_interface.h b/tools/asinfo/arch_interface.h new file mode 100644 index 00000000..1e7123fc --- /dev/null +++ b/tools/asinfo/arch_interface.h @@ -0,0 +1,162 @@ +/* + * 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.kaziakhm...@virtuozzo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#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 */ diff --git a/tools/asinfo/arch_personalities.h b/tools/asinfo/arch_personalities.h new file mode 100644 index 00000000..9499c5aa --- /dev/null +++ b/tools/asinfo/arch_personalities.h @@ -0,0 +1,36 @@ +ARCH_no_pers, +ARCH_blackfin_32bit, +ARCH_ia64_64bit, +ARCH_m68k_32bit, +ARCH_sparc64_64bit, +ARCH_sparc_32bit, +ARCH_metag_32bit, +ARCH_mips64_n64, +ARCH_mips64_n32, +ARCH_mips_o32, +ARCH_alpha_64bit, +ARCH_ppc64_64bit, +ARCH_ppc_32bit, +ARCH_aarch64_64bit, +ARCH_arm_oabi, +ARCH_arm_eabi, +ARCH_avr32_32bit, +ARCH_arc_32bit, +ARCH_s390x_64bit, +ARCH_s390_32bit, +ARCH_hppa_32bit, +ARCH_sh64_64bit, +ARCH_sh_32bit, +ARCH_x86_64_64bit, +ARCH_x86_64_x32, +ARCH_x86_32bit, +ARCH_cris_32bit, +ARCH_crisv32_32bit, +ARCH_tile_64bit, +ARCH_tile_32bit, +ARCH_microblaze_32bit, +ARCH_nios2_32bit, +ARCH_openrisc_32bit, +ARCH_xtensa_32bit, +ARCH_riscv_64bit, +ARCH_riscv_32bit diff --git a/tools/asinfo/asinfo.c b/tools/asinfo/asinfo.c new file mode 100644 index 00000000..9b1ac9e5 --- /dev/null +++ b/tools/asinfo/asinfo.c @@ -0,0 +1,331 @@ +/* + * 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.kaziakhme...@virtuozzo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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; +} diff --git a/tools/asinfo/dispatchers.c b/tools/asinfo/dispatchers.c new file mode 100644 index 00000000..ec0f20f9 --- /dev/null +++ b/tools/asinfo/dispatchers.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhme...@virtuozzo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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; +} diff --git a/tools/asinfo/dispatchers.h b/tools/asinfo/dispatchers.h new file mode 100644 index 00000000..778b0344 --- /dev/null +++ b/tools/asinfo/dispatchers.h @@ -0,0 +1,48 @@ +/* + * The dispatchers.h contains all necessary functions to perform main + * work in the asinfo tool. + * + * Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhme...@virtuozzo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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 */ diff --git a/tools/asinfo/error_interface.c b/tools/asinfo/error_interface.c new file mode 100644 index 00000000..2b519a90 --- /dev/null +++ b/tools/asinfo/error_interface.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhme...@virtuozzo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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); +} diff --git a/tools/asinfo/error_interface.h b/tools/asinfo/error_interface.h new file mode 100644 index 00000000..048d2778 --- /dev/null +++ b/tools/asinfo/error_interface.h @@ -0,0 +1,95 @@ +/* + * 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.kaziakhme...@virtuozzo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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 */ diff --git a/tools/asinfo/request_msgs.h b/tools/asinfo/request_msgs.h new file mode 100644 index 00000000..d358798e --- /dev/null +++ b/tools/asinfo/request_msgs.h @@ -0,0 +1,93 @@ +/* + * 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.kaziakhme...@virtuozzo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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 */ diff --git a/tools/asinfo/syscall_interface.c b/tools/asinfo/syscall_interface.c new file mode 100644 index 00000000..e41a8397 --- /dev/null +++ b/tools/asinfo/syscall_interface.c @@ -0,0 +1,684 @@ +/* + * Copyright (c) 2017 Edgar A. Kaziakhmedov <edgar.kaziakhm...@virtuozzo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "arch_interface.h" +#include "error_interface.h" +#include "filter.h" +#include "number_set.h" +#include "supported_personalities.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}; + +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; + static const char *error_format = {"system call(%s/%s)"}; + char *out_error = xcalloc(sizeof(char *), strlen(error_format) + + strlen(s->aws[arch].a_name) + + strlen(s->aws[arch].arch->abi_mode)); + + sprintf(out_error, error_format, s->aws[arch].a_name, + s->aws[arch].arch->abi_mode); + /* 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, out_error); + 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++; + } + free(out_error); + 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); + 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); +} diff --git a/tools/asinfo/syscall_interface.h b/tools/asinfo/syscall_interface.h new file mode 100644 index 00000000..917330cd --- /dev/null +++ b/tools/asinfo/syscall_interface.h @@ -0,0 +1,142 @@ +/* + * 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.kaziakhm...@virtuozzo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#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 */ -- 2.11.0 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel