8275128: Build hsdis using normal build system

Reviewed-by: erikj
This commit is contained in:
Magnus Ihse Bursie 2021-10-12 23:28:53 +00:00
parent 124f82377b
commit 03c2b73e21
8 changed files with 322 additions and 364 deletions

118
make/Hsdis.gmk Normal file
View File

@ -0,0 +1,118 @@
#
# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
default: all
include $(SPEC)
include MakeBase.gmk
include JdkNativeCompilation.gmk
################################################################################
# This makefile compiles and installs the hsdis library
#
################################################################################
HSDIS_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/hsdis
ifeq ($(call isTargetOs, windows), true)
INSTALLED_HSDIS_DIR := $(JDK_OUTPUTDIR)/bin
# On windows, we need to "fake" a completely different toolchain using gcc
# instead of the normal microsoft toolchain. This is quite hacky...
MINGW_BASE := x86_64-w64-mingw32
$(eval $(call DefineNativeToolchain, TOOLCHAIN_MINGW, \
CC := $(MINGW_BASE)-gcc, \
LD := $(MINGW_BASE)-ld, \
OBJCOPY := $(MINGW_BASE)-objcopy, \
RC := $(RC), \
SYSROOT_CFLAGS := --sysroot=/usr/$(MINGW_BASE)/sys-root, \
SYSROOT_LDFLAGS := --sysroot=/usr/$(MINGW_BASE)/sys-root, \
))
TOOLCHAIN_TYPE := gcc
OPENJDK_TARGET_OS := linux
CC_OUT_OPTION := -o$(SPACE)
LD_OUT_OPTION := -o$(SPACE)
GENDEPS_FLAGS := -MMD -MF
CFLAGS_DEBUG_SYMBOLS := -g
DISABLED_WARNINGS :=
DISABLE_WARNING_PREFIX := -Wno-
CFLAGS_WARNINGS_ARE_ERRORS := -Werror
SHARED_LIBRARY_FLAGS := -shared
HSDIS_TOOLCHAIN := TOOLCHAIN_MINGW
HSDIS_TOOLCHAIN_CFLAGS :=
HSDIS_TOOLCHAIN_LDFLAGS := -L/usr/lib/gcc/$(MINGW_BASE)/9.2.0 \
-L/usr/$(MINGW_BASE)/sys-root/mingw/lib
MINGW_DLLCRT := /usr/$(MINGW_BASE)/sys-root/mingw/lib/dllcrt2.o
HSDIS_TOOLCHAIN_LIBS := $(MINGW_DLLCRT) -lmingw32 -lgcc -lgcc_eh -lmoldname \
-lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32
else
INSTALLED_HSDIS_DIR := $(JDK_OUTPUTDIR)/lib
HSDIS_TOOLCHAIN := TOOLCHAIN_DEFAULT
HSDIS_TOOLCHAIN_CFLAGS := $(CFLAGS_JDKLIB)
HSDIS_TOOLCHAIN_LDFLAGS := $(LDFLAGS_JDKLIB)
HSDIS_TOOLCHAIN_LIBS := -ldl
endif
$(eval $(call SetupJdkLibrary, BUILD_HSDIS, \
NAME := hsdis, \
SRC := $(TOPDIR)/src/utils/hsdis, \
TOOLCHAIN := $(HSDIS_TOOLCHAIN), \
OUTPUT_DIR := $(HSDIS_OUTPUT_DIR), \
OBJECT_DIR := $(HSDIS_OUTPUT_DIR), \
DISABLED_WARNINGS_gcc := undef format-nonliteral sign-compare, \
DISABLED_WARNINGS_clang := undef format-nonliteral, \
CFLAGS := $(HSDIS_TOOLCHAIN_CFLAGS) $(HSDIS_CFLAGS), \
LDFLAGS := $(HSDIS_TOOLCHAIN_LDFLAGS) $(SHARED_LIBRARY_FLAGS), \
LIBS := $(HSDIS_LIBS) $(HSDIS_TOOLCHAIN_LIBS), \
))
build: $(BUILD_HSDIS)
TARGETS += build
INSTALLED_HSDIS_NAME := hsdis-$(OPENJDK_TARGET_CPU_LEGACY_LIB)$(SHARED_LIBRARY_SUFFIX)
INSTALLED_HSDIS := $(INSTALLED_HSDIS_DIR)/$(INSTALLED_HSDIS_NAME)
$(INSTALLED_HSDIS): $(BUILD_HSDIS_TARGET)
$(call LogWarn, NOTE: The resulting build might not be redistributable. Seek legal advice before distibuting.)
$(install-file)
install: $(INSTALLED_HSDIS)
TARGETS += install
################################################################################
all: $(TARGETS)
.PHONY: all default build install

View File

@ -526,6 +526,18 @@ $(eval $(call SetupTarget, update-x11wrappers, \
DEPS := java.base-copy buildtools-jdk, \
))
ifneq ($(HSDIS_BACKEND), none)
$(eval $(call SetupTarget, build-hsdis, \
MAKEFILE := Hsdis, \
TARGET := build, \
))
$(eval $(call SetupTarget, install-hsdis, \
MAKEFILE := Hsdis, \
TARGET := install, \
))
endif
################################################################################
# Cross compilation support

View File

@ -249,6 +249,7 @@ JDKOPT_EXCLUDE_TRANSLATIONS
JDKOPT_ENABLE_DISABLE_MANPAGES
JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE
JDKOPT_ENABLE_DISABLE_COMPATIBLE_CDS_ALIGNMENT
JDKOPT_SETUP_HSDIS
###############################################################################
#

View File

@ -80,6 +80,14 @@ cygwin_help() {
PKGHANDLER_COMMAND="( cd <location of cygwin setup.exe> && cmd /c setup -q -P make )"
HELP_MSG="You might be able to fix this by running '$PKGHANDLER_COMMAND'."
;;
i686-w64-mingw32-gcc)
PKGHANDLER_COMMAND="( cd <location of cygwin setup.exe> && cmd /c setup -q -P gcc-core i686-w64-mingw32-gcc-core mingw64-i686-glib2.0 )"
HELP_MSG="You might be able to fix this by running '$PKGHANDLER_COMMAND'."
;;
x86_64-w64-mingw32-gcc)
PKGHANDLER_COMMAND="( cd <location of cygwin setup.exe> && cmd /c setup -q -P gcc-core x86_64-w64-mingw32-gcc-core mingw64-x86_64-glib2.0 )"
HELP_MSG="You might be able to fix this by running '$PKGHANDLER_COMMAND'."
;;
esac
}

View File

@ -704,3 +704,145 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_REPRODUCIBLE_BUILD],
AC_SUBST(SOURCE_DATE)
AC_SUBST(ENABLE_REPRODUCIBLE_BUILD)
])
################################################################################
#
# Helper function to build binutils from source.
#
AC_DEFUN([JDKOPT_BUILD_BINUTILS],
[
BINUTILS_SRC="$with_binutils_src"
UTIL_FIXUP_PATH(BINUTILS_SRC)
if ! test -d $BINUTILS_SRC; then
AC_MSG_ERROR([--with-binutils-src is not pointing to a directory])
fi
if ! test -x $BINUTILS_SRC/configure; then
AC_MSG_ERROR([--with-binutils-src does not look like a binutils source directory])
fi
if test -e $BINUTILS_SRC/bfd/libbfd.a && \
test -e $BINUTILS_SRC/opcodes/libopcodes.a && \
test -e $BINUTILS_SRC/libiberty/libiberty.a && \
test -e $BINUTILS_SRC/zlib/libz.a; then
AC_MSG_NOTICE([Found binutils binaries in binutils source directory -- not building])
else
# On Windows, we cannot build with the normal Microsoft CL, but must instead use
# a separate mingw toolchain.
if test "x$OPENJDK_BUILD_OS" = xwindows; then
if test "x$OPENJDK_TARGET_CPU" = "xx86"; then
target_base="i686-w64-mingw32"
else
target_base="$OPENJDK_TARGET_CPU-w64-mingw32"
fi
binutils_cc="$target_base-gcc"
binutils_target="--host=$target_base --target=$target_base"
# Somehow the uint typedef is not included when building with mingw
binutils_cflags="-Duint=unsigned"
compiler_version=`$binutils_cc --version 2>&1`
if ! [ [[ "$compiler_version" =~ GCC ]] ]; then
AC_MSG_NOTICE([Could not find correct mingw compiler $binutils_cc.])
HELP_MSG_MISSING_DEPENDENCY([$binutils_cc])
AC_MSG_ERROR([Cannot continue. $HELP_MSG])
else
AC_MSG_NOTICE([Using compiler $binutils_cc with version $compiler_version])
fi
elif test "x$OPENJDK_BUILD_OS" = xmacosx; then
if test "x$OPENJDK_TARGET_CPU" = "xaarch64"; then
binutils_target="--enable-targets=aarch64-darwin"
else
binutils_target=""
fi
else
binutils_cc="$CC $SYSROOT_CFLAGS"
binutils_target=""
fi
binutils_cflags="$binutils_cflags $MACHINE_FLAG $JVM_PICFLAG $C_O_FLAG_NORM"
AC_MSG_NOTICE([Running binutils configure])
AC_MSG_NOTICE([configure command line: ./configure --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" $binutils_target])
saved_dir=`pwd`
cd "$BINUTILS_SRC"
./configure --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" $binutils_target
if test $? -ne 0 || ! test -e $BINUTILS_SRC/Makefile; then
AC_MSG_NOTICE([Automatic building of binutils failed on configure. Try building it manually])
AC_MSG_ERROR([Cannot continue])
fi
AC_MSG_NOTICE([Running binutils make])
$MAKE all-opcodes
if test $? -ne 0; then
AC_MSG_NOTICE([Automatic building of binutils failed on make. Try building it manually])
AC_MSG_ERROR([Cannot continue])
fi
cd $saved_dir
AC_MSG_NOTICE([Building of binutils done])
fi
BINUTILS_DIR="$BINUTILS_SRC"
])
################################################################################
#
# Determine if hsdis should be built, and if so, with which backend.
#
AC_DEFUN_ONCE([JDKOPT_SETUP_HSDIS],
[
AC_ARG_WITH([hsdis], [AS_HELP_STRING([--with-hsdis],
[what hsdis backend to use ('none', 'binutils') @<:@none@:>@])])
AC_ARG_WITH([binutils], [AS_HELP_STRING([--with-binutils],
[where to find the binutils files needed for hsdis/binutils])])
AC_ARG_WITH([binutils-src], [AS_HELP_STRING([--with-binutils-src],
[where to find the binutils source for building])])
AC_MSG_CHECKING([what hsdis backend to use])
if test "x$with_hsdis" = xyes; then
AC_MSG_ERROR([--with-hsdis must have a value])
elif test "x$with_hsdis" = xnone || test "x$with_hsdis" = xno || test "x$with_hsdis" = x; then
HSDIS_BACKEND=none
AC_MSG_RESULT(['none', hsdis will not be built])
elif test "x$with_hsdis" = xbinutils; then
HSDIS_BACKEND=binutils
AC_MSG_RESULT(['binutils'])
# We need the binutils static libs and includes.
if test "x$with_binutils_src" != x; then
# Try building the source first. If it succeeds, it sets $BINUTILS_DIR.
JDKOPT_BUILD_BINUTILS
fi
if test "x$with_binutils" != x; then
BINUTILS_DIR="$with_binutils"
fi
AC_MSG_CHECKING([for binutils to use with hsdis])
if test "x$BINUTILS_DIR" != x; then
if test -e $BINUTILS_DIR/bfd/libbfd.a && \
test -e $BINUTILS_DIR/opcodes/libopcodes.a && \
test -e $BINUTILS_DIR/libiberty/libiberty.a; then
AC_MSG_RESULT([$BINUTILS_DIR])
HSDIS_CFLAGS="-I$BINUTILS_DIR/include -I$BINUTILS_DIR/bfd -DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB"
HSDIS_LIBS="$BINUTILS_DIR/bfd/libbfd.a $BINUTILS_DIR/opcodes/libopcodes.a $BINUTILS_DIR/libiberty/libiberty.a $BINUTILS_DIR/zlib/libz.a"
else
AC_MSG_RESULT([invalid])
AC_MSG_ERROR([$BINUTILS_DIR does not contain a proper binutils installation])
fi
else
AC_MSG_RESULT([missing])
AC_MSG_NOTICE([--with-hsdis=binutils requires specifying a binutils installation.])
AC_MSG_NOTICE([Download binutils from https://www.gnu.org/software/binutils and unpack it,])
AC_MSG_NOTICE([and point --with-binutils-src to the resulting directory, or use])
AC_MSG_NOTICE([--with-binutils to point to a pre-built binutils installation.])
AC_MSG_ERROR([Cannot continue])
fi
else
AC_MSG_RESULT([invalid])
AC_MSG_ERROR([Incorrect hsdis backend "$with_hsdis"])
fi
AC_SUBST(HSDIS_BACKEND)
AC_SUBST(HSDIS_CFLAGS)
AC_SUBST(HSDIS_LIBS)
])

View File

@ -359,6 +359,10 @@ ENABLE_COMPATIBLE_CDS_ALIGNMENT := @ENABLE_COMPATIBLE_CDS_ALIGNMENT@
ALLOW_ABSOLUTE_PATHS_IN_OUTPUT := @ALLOW_ABSOLUTE_PATHS_IN_OUTPUT@
HSDIS_BACKEND := @HSDIS_BACKEND@
HSDIS_CFLAGS := @HSDIS_CFLAGS@
HSDIS_LIBS := @HSDIS_LIBS@
# The boot jdk to use. This is overridden in bootcycle-spec.gmk. Make sure to keep
# it in sync.
BOOT_JDK:=@BOOT_JDK@

View File

@ -1,4 +1,4 @@
Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
The Universal Permissive License (UPL), Version 1.0
@ -43,102 +43,56 @@ questions.
________________________________________________________________________
'hsdis': A HotSpot plugin for disassembling dynamically generated code.
'hsdis': A HotSpot plugin for disassembling dynamically generated code.
The files in this directory (Makefile, hsdis.[ch], hsdis-demo.c)
are built independently of the HotSpot JVM.
To use the plugin with a JVM, you need a new version that can load it.
If the product mode of your JVM does not accept -XX:+PrintAssembly,
you do not have a version that is new enough.
The files in this directory are built independently of the HotSpot JVM.
* Building
To build this project you need a copy of GNU binutils to build against.
It is known to work with binutils 2.29.1, 2.30, and 2.31.1. Building
against versions older than 2.29 is no longer supported. Download a
copy of the software from http://directory.fsf.org/project/binutils or
one of its mirrors. Builds targetting windows currently require the
use of a cross compiler.
To build this project you need a copy of GNU binutils to build against. It is
known to work with binutils 2.37. Building against versions older than 2.29 is
not supported. Download a copy of the software from
http://directory.fsf.org/project/binutils or one of its mirrors.
Binutils should be configured with the '--disable-nls' flag to disable
Native Language Support, otherwise you might get an "undefined
reference to `libintl_gettext'" if you try to load hsdis.so on systems
which don't have NLS by default. It also avoids build problems on
other configurations that don't include the full NLS support.
To build this library, you must enable building in configure by "bash configure
--with-hsdis=binutils".
The makefile looks for the sources in build/binutils or you can
specify its location to the makefile using BINUTILS=path. It will
configure binutils and build it first and then build and link the
disassembly adapter. Make all will build the default target for your
platform. If your platform supports both 32 and 64 simultaneously then
"make both" will build them both at once. "make all64" will
explicitly build the 64 bit version. By default this will build the
disassembler library only. If you build demo it will build a demo
program that attempts to exercise the library.
You must also specify where binutils is located. To facilitate building, you can
point to a place where the (unpacked) binutils sources are located using
"--with-binutils-src=<location>", and configure will build binutils for you. On
repeated runs, you can keep this command line option, since configure will
figure out that the binutils binaries are already present and skip building, or
you can replace it with "--with-binutils=<location>".
With recent version of binutils (i.e. binutils-2.23.2) you may get the
following build error:
If you have pre-built binutils binaries, you can point to them directly using
"--with-binutils=<location>".
WARNING: `makeinfo' is missing on your system. You should only need it if
you modified a `.texi' or `.texinfo' file, or any other file
...
When you have created a proper configuration, you can then build the hsdis
library using "make build-hsdis".
This is because of "Bug 15345 - binutils-2.23.2 tarball doesn't build
without makeinfo" [2]. The easiest way to work around this problem is
by doing a "touch $BINUTILS/bfd/doc/bfd.info".
* Building on Windows
Windows
In theory this should be buildable on Windows but getting a working
GNU build environment on Windows has proven difficult. MINGW should
be able to do it but at the time of this writing I was unable to get
this working. Instead you can use the mingw cross compiler on linux
to produce the windows binaries. For 32-bit windows you can install
mingw32 using your package manager and it will be added to your path
automatically. For 64-bit you need to download the 64 bit mingw from
http://sourceforge.net/projects/mingw-w64. Grab a copy of the
complete toolchain and unpack it somewhere. Put the bin directory of
the toolchain in your path. The mingw installs contain cross compile
versions of gcc that are named with a prefix to indicate what they are
targeting and you must tell the Makefile which one to use. This
should either be i586-mingw32msvc or x86_64-pc-mingw32 depending on
which one you are targeting and there should be a version of gcc in
your path named i586-mingw32msvc-gcc or x86_64-pc-mingw32-gcc. Tell
the makefile what prefix to use to find the mingw tools by using
MINGW=. For example:
make MINGW=i586-mingw32msvc BINUTILS=build/binutils-2.31.1
will build the Win32 cross compiled version of hsdis based on 2.31.1.
On Windows, the normal Microsoft Visual Studio toolchain cannot build binutils.
Instead we need to use the mingw compiler. This is available as a cygwin
package. You need to install the "gcc-core" and "mingw64-x86_64-gcc-core"
packages (or "mingw64-i686-gcc-core", if you want the 32-bit version) and
"mingw64-x86_64-glib2.0".
* Installing
Products are named like build/$OS-$LIBARCH/hsdis-$LIBARCH.so. You can
install them next to your libjvm.so inside your JRE/JDK or alternatively
put it anywhere on your LD_LIBRARY_PATH. The search path in the JVM is:
To build the hsdis library, run "make build-hsdis". This will build the library
in a separate directory, but not make it available to the JDK in the
configuration. To actually install it in the JDK, run "make install-hsdis".
1. <home>/lib/<vm>/libhsdis-<arch>.so
2. <home>/lib/<vm>/hsdis-<arch>.so
3. <home>/lib/hsdis-<arch>.so
4. hsdis-<arch>.so (using LD_LIBRARY_PATH)
Note: The resulting build may not be distributable. Please get legal advice if
you intend to distribute the result of your build.
Now test:
* Using the library
export LD_LIBRARY_PATH .../hsdis/build/$OS-$LIBARCH:$LD_LIBRARY_PATH
dargs='-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly'
dargs=$dargs' -XX:PrintAssemblyOptions=hsdis-print-bytes'
java $dargs -Xbatch CompileCommand=print,*String.hashCode HelloWorld
The hsdis library will be automatically loaded by Hotspot when you use the
diagnostic option "-XX:+PrintAssembly". Note that since this is a diagnostic
option, you need to unlock these first, so in practice you activate it using
"-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly".
If the product mode of the JVM does not accept -XX:+PrintAssembly,
you do not have a version new enough to use the hsdis plugin.
* Wiki
More information can be found in the OpenJDK HotSpot Wiki [1].
Resources:
[1] https://wiki.openjdk.java.net/display/HotSpot/PrintAssembly
[2] http://sourceware.org/bugzilla/show_bug.cgi?id=15345
More information is available at the wiki
[https://wiki.openjdk.java.net/display/HotSpot/PrintAssembly].

View File

@ -1,281 +0,0 @@
/*
* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to
* any person obtaining a copy of this software, associated documentation
* and/or data (collectively the "Software"), free of charge and under any
* and all copyright rights in the Software, and any and all patent rights
* owned or freely licensable by each licensor hereunder covering either (i)
* the unmodified Software as contributed to or provided by such licensor,
* or (ii) the Larger Works (as defined below), to deal in both
*
* (a) the Software, and
*
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file
* if one is included with the Software (each a "Larger Work" to which the
* Software is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy,
* create derivative works of, display, perform, and distribute the Software
* and make, use, sell, offer for sale, import, export, have made, and have
* sold the Software and the Larger Work(s), and to sublicense the foregoing
* rights on either these or other terms.
*
* This license is subject to the following condition:
*
* The above copyright notice and either this complete permission notice or
* at a minimum a reference to the UPL must be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/* hsdis-demo.c -- dump a range of addresses as native instructions
This demonstrates the protocol required by the HotSpot PrintAssembly option.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "hsdis.h"
void greet(const char*);
void disassemble(uintptr_t, uintptr_t);
void end_of_file();
const char* options = NULL;
int raw = 0;
int xml = 0;
int main(int ac, char** av) {
int greeted = 0;
int i;
for (i = 1; i < ac; i++) {
const char* arg = av[i];
if (arg[0] == '-') {
if (!strcmp(arg, "-xml"))
xml ^= 1;
else if (!strcmp(arg, "-raw"))
raw ^= 1;
else if (!strncmp(arg, "-options=", 9))
options = arg+9;
else
{ printf("Usage: %s [-xml] [name...]\n", av[0]); exit(2); }
continue;
}
greet(arg);
greeted = 1;
}
if (!greeted)
greet("world");
printf("...And now for something completely different:\n");
void *start = (void*) &main;
void *end = (void*) &end_of_file;
#if defined(__ia64) || (defined(__powerpc__) && !defined(ABI_ELFv2))
/* On IA64 and PPC function pointers are pointers to function descriptors */
start = *((void**)start);
end = *((void**)end);
#endif
disassemble(start, (end > start) ? end : start + 64);
printf("Cheers!\n");
}
void greet(const char* whom) {
printf("Hello, %s!\n", whom);
}
void end_of_file() { }
/* don't disassemble after this point... */
#include "dlfcn.h"
#define DECODE_INSTRUCTIONS_VIRTUAL_NAME "decode_instructions_virtual"
#define DECODE_INSTRUCTIONS_NAME "decode_instructions"
#define HSDIS_NAME "hsdis"
static void* decode_instructions_pv = 0;
static void* decode_instructions_sv = 0;
static const char* hsdis_path[] = {
HSDIS_NAME"-"LIBARCH LIB_EXT,
"./" HSDIS_NAME"-"LIBARCH LIB_EXT,
#ifdef TARGET_DIR
TARGET_DIR"/"HSDIS_NAME"-"LIBARCH LIB_EXT,
#endif
NULL
};
static const char* load_decode_instructions() {
void* dllib = NULL;
const char* *next_in_path = hsdis_path;
while (1) {
decode_instructions_pv = dlsym(dllib, DECODE_INSTRUCTIONS_VIRTUAL_NAME);
decode_instructions_sv = dlsym(dllib, DECODE_INSTRUCTIONS_NAME);
if (decode_instructions_pv != NULL || decode_instructions_sv != NULL)
return NULL;
if (dllib != NULL)
return "plugin does not defined "DECODE_INSTRUCTIONS_VIRTUAL_NAME" and "DECODE_INSTRUCTIONS_NAME;
for (dllib = NULL; dllib == NULL; ) {
const char* next_lib = (*next_in_path++);
if (next_lib == NULL)
return "cannot find plugin "HSDIS_NAME LIB_EXT;
dllib = dlopen(next_lib, RTLD_LAZY);
}
}
}
static const char* lookup(void* addr) {
#if defined(__ia64) || defined(__powerpc__)
/* On IA64 and PPC function pointers are pointers to function descriptors */
#define CHECK_NAME(fn) \
if (addr == *((void**) &fn)) return #fn;
#else
#define CHECK_NAME(fn) \
if (addr == (void*) &fn) return #fn;
#endif
CHECK_NAME(main);
CHECK_NAME(greet);
return NULL;
}
/* does the event match the tag, followed by a null, space, or slash? */
#define MATCH(event, tag) \
(!strncmp(event, tag, sizeof(tag)-1) && \
(!event[sizeof(tag)-1] || strchr(" /", event[sizeof(tag)-1])))
static const char event_cookie[] = "event_cookie"; /* demo placeholder */
static void* simple_handle_event(void* cookie, const char* event, void* arg) {
if (MATCH(event, "/insn")) {
// follow each complete insn by a nice newline
printf("\n");
}
return NULL;
}
static void* handle_event(void* cookie, const char* event, void* arg) {
#define NS_DEMO "demo:"
if (cookie != event_cookie)
printf("*** bad event cookie %p != %p\n", cookie, event_cookie);
if (xml) {
/* We could almost do a printf(event, arg),
but for the sake of a better demo,
we dress the result up as valid XML.
*/
const char* fmt = strchr(event, ' ');
int evlen = (fmt ? fmt - event : strlen(event));
if (!fmt) {
if (event[0] != '/') {
printf("<"NS_DEMO"%.*s>", evlen, event);
} else {
printf("</"NS_DEMO"%.*s>", evlen-1, event+1);
}
} else {
if (event[0] != '/') {
printf("<"NS_DEMO"%.*s", evlen, event);
printf(fmt, arg);
printf(">");
} else {
printf("<"NS_DEMO"%.*s_done", evlen-1, event+1);
printf(fmt, arg);
printf("/></"NS_DEMO"%.*s>", evlen-1, event+1);
}
}
}
if (MATCH(event, "insn")) {
const char* name = lookup(arg);
if (name) printf("%s:\n", name);
/* basic action for <insn>: */
printf(" %p\t", arg);
} else if (MATCH(event, "/insn")) {
// follow each complete insn by a nice newline
printf("\n");
} else if (MATCH(event, "mach")) {
printf("Decoding for CPU '%s'\n", (char*) arg);
} else if (MATCH(event, "addr")) {
/* basic action for <addr/>: */
const char* name = lookup(arg);
if (name) {
printf("&%s (%p)", name, arg);
/* return non-null to notify hsdis not to print the addr */
return arg;
}
}
/* null return is always safe; can mean "I ignored it" */
return NULL;
}
#define fprintf_callback \
(decode_instructions_printf_callback_ftype)&fprintf
void disassemble(uintptr_t from, uintptr_t to) {
const char* err = load_decode_instructions();
if (err != NULL) {
printf("%s: %s\n", err, dlerror());
exit(1);
}
decode_func_vtype decode_instructions_v
= (decode_func_vtype) decode_instructions_pv;
decode_func_stype decode_instructions_s
= (decode_func_stype) decode_instructions_sv;
void* res;
if (decode_instructions_pv != NULL) {
printf("\nDecoding from %p to %p...with %s\n", from, to, DECODE_INSTRUCTIONS_VIRTUAL_NAME);
if (raw) {
res = (*decode_instructions_v)(from, to,
(unsigned char*)from, to - from,
simple_handle_event, stdout,
NULL, stdout,
options, 0);
} else {
res = (*decode_instructions_v)(from, to,
(unsigned char*)from, to - from,
handle_event, (void*) event_cookie,
fprintf_callback, stdout,
options, 0);
}
if (res != (void*)to)
printf("*** Result was %p!\n", res);
}
void* sres;
if (decode_instructions_sv != NULL) {
printf("\nDecoding from %p to %p...with old decode_instructions\n", from, to, DECODE_INSTRUCTIONS_NAME);
if (raw) {
sres = (*decode_instructions_s)(from, to,
simple_handle_event, stdout,
NULL, stdout,
options);
} else {
sres = (*decode_instructions_s)(from, to,
handle_event, (void*) event_cookie,
fprintf_callback, stdout,
options);
}
if (sres != (void *)to)
printf("*** Result of decode_instructions %p!\n", sres);
}
}