mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Remove old JIT implementation (#12498)
* Remove old JIT implementation * Remove ext/opcache/jit/zend_jit_vtune.c
This commit is contained in:
parent
e58af7c160
commit
be275433d9
55 changed files with 21 additions and 69086 deletions
|
@ -119,9 +119,6 @@ clean:
|
|||
find . -name \*.so | xargs rm -f
|
||||
find . -name .libs -a -type d|xargs rm -rf
|
||||
rm -f libphp.la $(SAPI_CLI_PATH) $(SAPI_CGI_PATH) $(SAPI_LITESPEED_PATH) $(SAPI_FPM_PATH) $(OVERALL_TARGET) modules/* libs/*
|
||||
rm -f ext/opcache/jit/zend_jit_x86.c
|
||||
rm -f ext/opcache/jit/zend_jit_arm64.c
|
||||
rm -f ext/opcache/minilua
|
||||
rm -f ext/opcache/jit/ir/gen_ir_fold_hash
|
||||
rm -f ext/opcache/jit/ir/minilua
|
||||
rm -f ext/opcache/jit/ir/ir_fold_hash.h
|
||||
|
|
|
@ -24,13 +24,6 @@ PHP_ARG_WITH([capstone],,
|
|||
[no],
|
||||
[no])
|
||||
|
||||
PHP_ARG_ENABLE([opcache-jit-ir],
|
||||
[whether to enable JIT based on IR framework],
|
||||
[AS_HELP_STRING([--disable-opcache-jit-ir],
|
||||
[Disable JIT based on IR framework (use old JIT)])],
|
||||
[yes],
|
||||
[no])
|
||||
|
||||
if test "$PHP_OPCACHE" != "no"; then
|
||||
|
||||
dnl Always build as shared extension
|
||||
|
@ -51,52 +44,7 @@ if test "$PHP_OPCACHE" != "no"; then
|
|||
esac
|
||||
fi
|
||||
|
||||
if test "$PHP_OPCACHE_JIT" = "yes" -a "$PHP_OPCACHE_JIT_IR" = "no" ; then
|
||||
AC_DEFINE(HAVE_JIT, 1, [Define to enable JIT])
|
||||
ZEND_JIT_SRC="jit/zend_jit.c jit/zend_jit_gdb.c jit/zend_jit_vm_helpers.c"
|
||||
|
||||
dnl Find out which ABI we are using.
|
||||
case $host_alias in
|
||||
x86_64-*-darwin*)
|
||||
DASM_FLAGS="-D X64APPLE=1 -D X64=1"
|
||||
DASM_ARCH="x86"
|
||||
;;
|
||||
x86_64*)
|
||||
DASM_FLAGS="-D X64=1"
|
||||
DASM_ARCH="x86"
|
||||
;;
|
||||
i[[34567]]86*)
|
||||
DASM_ARCH="x86"
|
||||
;;
|
||||
x86*)
|
||||
DASM_ARCH="x86"
|
||||
;;
|
||||
aarch64*)
|
||||
DASM_FLAGS="-D ARM64=1"
|
||||
DASM_ARCH="arm64"
|
||||
;;
|
||||
esac
|
||||
|
||||
if test "$PHP_THREAD_SAFETY" = "yes"; then
|
||||
DASM_FLAGS="$DASM_FLAGS -D ZTS=1"
|
||||
fi
|
||||
|
||||
AS_IF([test x"$with_capstone" = "xyes"],[
|
||||
PKG_CHECK_MODULES([CAPSTONE],[capstone >= 3.0.0],[
|
||||
AC_DEFINE([HAVE_CAPSTONE], [1], [Capstone is available])
|
||||
PHP_EVAL_LIBLINE($CAPSTONE_LIBS, OPCACHE_SHARED_LIBADD)
|
||||
PHP_EVAL_INCLINE($CAPSTONE_CFLAGS)
|
||||
],[
|
||||
AC_MSG_ERROR([capstone >= 3.0 required but not found])
|
||||
])
|
||||
])
|
||||
|
||||
PHP_SUBST(DASM_FLAGS)
|
||||
PHP_SUBST(DASM_ARCH)
|
||||
|
||||
JIT_CFLAGS=
|
||||
|
||||
elif test "$PHP_OPCACHE_JIT" = "yes" -a "$PHP_OPCACHE_JIT_IR" = "yes"; then
|
||||
if test "$PHP_OPCACHE_JIT" = "yes" ; then
|
||||
AC_DEFINE(HAVE_JIT, 1, [Define to enable JIT])
|
||||
AC_DEFINE(ZEND_JIT_IR, 1, [Use JIT IR framework])
|
||||
ZEND_JIT_SRC="jit/zend_jit.c jit/zend_jit_vm_helpers.c jit/ir/ir.c jit/ir/ir_strtab.c \
|
||||
|
@ -383,9 +331,7 @@ int main(void) {
|
|||
|
||||
if test "$PHP_OPCACHE_JIT" = "yes"; then
|
||||
PHP_ADD_BUILD_DIR([$ext_builddir/jit], 1)
|
||||
if test "$PHP_OPCACHE_JIT_IR" = "yes"; then
|
||||
PHP_ADD_BUILD_DIR([$ext_builddir/jit/ir], 1)
|
||||
fi
|
||||
PHP_ADD_MAKEFILE_FRAGMENT($ext_srcdir/jit/Makefile.frag)
|
||||
fi
|
||||
PHP_SUBST(OPCACHE_SHARED_LIBADD)
|
||||
|
|
|
@ -5,8 +5,6 @@ if (PHP_OPCACHE != "no") {
|
|||
|
||||
ARG_ENABLE("opcache-jit", "whether to enable JIT", "yes");
|
||||
|
||||
ARG_ENABLE("opcache-jit-ir", "whether to enable JIT based on IR framework", "yes");
|
||||
|
||||
ZEND_EXTENSION('opcache', "\
|
||||
ZendAccelerator.c \
|
||||
zend_accelerator_blacklist.c \
|
||||
|
@ -20,26 +18,7 @@ if (PHP_OPCACHE != "no") {
|
|||
zend_shared_alloc.c \
|
||||
shared_alloc_win32.c", true, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
||||
|
||||
if (PHP_OPCACHE_JIT == "yes" && PHP_OPCACHE_JIT_IR == "no") {
|
||||
if (CHECK_HEADER_ADD_INCLUDE("dynasm/dasm_x86.h", "CFLAGS_OPCACHE", PHP_OPCACHE + ";ext\\opcache\\jit")) {
|
||||
var dasm_flags = (X64 ? "-D X64=1" : "") + (X64 ? " -D X64WIN=1" : "") + " -D WIN=1";
|
||||
if (PHP_ZTS == "yes") {
|
||||
dasm_flags += " -D ZTS=1";
|
||||
}
|
||||
DEFINE("DASM_FLAGS", dasm_flags);
|
||||
DEFINE("DASM_ARCH", "x86");
|
||||
|
||||
AC_DEFINE('HAVE_JIT', 1, 'Define to enable JIT');
|
||||
/* XXX read this dynamically */
|
||||
/*ADD_FLAG("CFLAGS_OPCACHE", "/D DASM_VERSION=10400");*/
|
||||
|
||||
ADD_MAKEFILE_FRAGMENT(configure_module_dirname + "\\jit\\Makefile.frag.w32");
|
||||
|
||||
ADD_SOURCES(configure_module_dirname + "\\jit", "zend_jit.c zend_jit_vm_helpers.c", "opcache", "ext\\opcache\\jit");
|
||||
} else {
|
||||
WARNING("JIT not enabled, headers not found");
|
||||
}
|
||||
} else if (PHP_OPCACHE_JIT == "yes" && PHP_OPCACHE_JIT_IR == "yes") {
|
||||
if (PHP_OPCACHE_JIT == "yes") {
|
||||
if (CHECK_HEADER_ADD_INCLUDE("ir/ir.h", "CFLAGS_OPCACHE", PHP_OPCACHE + ";ext\\opcache\\jit")) {
|
||||
var dasm_flags = (X64 ? "-D X64=1" : "") + (X64 ? " -D X64WIN=1" : "") + " -D WIN=1";
|
||||
var ir_target = (X64 ? "IR_TARGET_X64" : "IR_TARGET_X86");
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
ifdef IR_TARGET
|
||||
# New IR based JIT
|
||||
$(builddir)/jit/ir/minilua: $(srcdir)/jit/ir/dynasm/minilua.c
|
||||
$(BUILD_CC) $(srcdir)/jit/ir/dynasm/minilua.c -lm -o $@
|
||||
|
||||
|
@ -22,26 +20,6 @@ $(builddir)/jit/zend_jit.lo: \
|
|||
$(srcdir)/jit/zend_jit_helpers.c \
|
||||
$(srcdir)/jit/zend_jit_ir.c
|
||||
|
||||
else
|
||||
# Old DynAsm based JIT
|
||||
$(builddir)/minilua: $(srcdir)/jit/dynasm/minilua.c
|
||||
$(BUILD_CC) $(srcdir)/jit/dynasm/minilua.c -lm -o $@
|
||||
|
||||
$(builddir)/jit/zend_jit_$(DASM_ARCH).c: $(srcdir)/jit/zend_jit_$(DASM_ARCH).dasc $(srcdir)/jit/dynasm/*.lua $(builddir)/minilua
|
||||
$(builddir)/minilua $(srcdir)/jit/dynasm/dynasm.lua $(DASM_FLAGS) -o $@ $(srcdir)/jit/zend_jit_$(DASM_ARCH).dasc
|
||||
|
||||
$(builddir)/jit/zend_jit.lo: \
|
||||
$(builddir)/jit/zend_jit_$(DASM_ARCH).c \
|
||||
$(srcdir)/jit/zend_jit_helpers.c \
|
||||
$(srcdir)/jit/zend_jit_disasm.c \
|
||||
$(srcdir)/jit/zend_jit_gdb.c \
|
||||
$(srcdir)/jit/zend_jit_perf_dump.c \
|
||||
$(srcdir)/jit/zend_jit_vtune.c \
|
||||
$(srcdir)/jit/zend_jit_trace.c \
|
||||
$(srcdir)/jit/zend_elf.c
|
||||
|
||||
endif
|
||||
|
||||
# For non-GNU make, jit/zend_jit.lo and ./jit/zend_jit.lo are considered distinct targets.
|
||||
# Use this workaround to allow building from inside ext/opcache.
|
||||
jit/zend_jit.lo: $(builddir)/jit/zend_jit.lo
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
!if "$(IR_TARGET)" != ""
|
||||
# New IR based JIT
|
||||
|
||||
$(BUILD_DIR)\\minilua.exe: ext\opcache\jit\ir\dynasm\minilua.c
|
||||
@if exist $(BUILD_DIR)\\minilua.exe del $(BUILD_DIR)\\minilua.exe
|
||||
$(PHP_CL) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\minilua.exe ext\opcache\jit\ir\dynasm\minilua.c
|
||||
|
@ -39,24 +36,3 @@ $(BUILD_DIR)\ext\opcache\jit\zend_jit.obj: \
|
|||
ext\opcache\jit\zend_jit_helpers.c \
|
||||
ext\opcache\jit\ir\ir.h \
|
||||
ext\opcache\jit\ir\ir_builder.h
|
||||
|
||||
!else
|
||||
# Old DynAsm based JIT
|
||||
|
||||
$(BUILD_DIR)\\minilua.exe: ext\opcache\jit\dynasm\minilua.c
|
||||
@if exist $(BUILD_DIR)\\minilua.exe del $(BUILD_DIR)\\minilua.exe
|
||||
$(PHP_CL) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\minilua.exe ext\opcache\jit\dynasm\minilua.c
|
||||
|
||||
ext\opcache\jit\zend_jit_x86.c: ext\opcache\jit\zend_jit_x86.dasc $(BUILD_DIR)\\minilua.exe
|
||||
@if exist ext\opcache\jit\zend_jit_x86.c del ext\opcache\jit\zend_jit_x86.c
|
||||
$(BUILD_DIR)\\minilua.exe ext/opcache/jit/dynasm/dynasm.lua $(DASM_FLAGS) -o $@ ext/opcache/jit/zend_jit_x86.dasc
|
||||
|
||||
$(BUILD_DIR)\ext\opcache\jit\zend_jit.obj: \
|
||||
ext/opcache/jit/zend_jit_x86.c \
|
||||
ext/opcache/jit/zend_jit_helpers.c \
|
||||
ext/opcache/jit/zend_jit_disasm.c \
|
||||
ext/opcache/jit/zend_jit_gdb.c \
|
||||
ext/opcache/jit/zend_jit_perf_dump.c \
|
||||
ext/opcache/jit/zend_jit_trace.c \
|
||||
ext/opcache/jit/zend_jit_vtune.c
|
||||
!endif
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
New JIT implementation
|
||||
======================
|
||||
|
||||
This branch provides a new JIT implementation based on [IR - Lightweight
|
||||
JIT Compilation Framework](https://github.com/dstogov/ir).
|
||||
|
||||
As opposed to the PHP 8.* JIT approach that generates native code directly from
|
||||
PHP byte-code, this implementation generates intermediate representation (IR)
|
||||
and delegates all lower-level tasks to the IR Framework. IR for JIT is like an
|
||||
AST for compiler.
|
||||
|
||||
Key benefits of the new JIT implementation:
|
||||
- Usage of IR opens possibilities for better optimization and register
|
||||
allocation (the resulting native code is more efficient)
|
||||
- PHP doesn't have to care about most low-level details (different CPUs,
|
||||
calling conventions, TLS details, etc)
|
||||
- it's much easier to implement support for new targets (e.g. RISCV)
|
||||
- IR framework is going to be developed separately from PHP and may accept
|
||||
contributions from other projects (new optimizations, improvements, bug fixes)
|
||||
|
||||
Disadvantages:
|
||||
- JIT compilation becomes slower (this is almost invisible for tracing
|
||||
JIT, but function JIT compilation of Wordpress becomes 4 times slower)
|
||||
|
||||
The necessary part of the IR Framework is embedded into php-src. So, the PR
|
||||
doesn't introduce new dependencies.
|
||||
|
||||
The new JIT implementation successfully passes all CI workflows, but it's still
|
||||
not mature and may cause failures. To reduce risks, this patch doesn't remove
|
||||
the old JIT implementation (that is the same as PHP-8.3 JIT). It's possible
|
||||
to build PHP with the old JIT by configuring with **--disable-opcache-jit-ir**.
|
||||
In the future the old implementation should be removed.
|
|
@ -2,33 +2,10 @@ Opcache JIT
|
|||
===========
|
||||
|
||||
This is the implementation of Opcache's JIT (Just-In-Time compiler),
|
||||
This converts the PHP Virtual Machine's opcodes into x64/x86 assembly,
|
||||
on POSIX platforms and Windows.
|
||||
|
||||
It generates native code directly from PHP byte-code and information collected
|
||||
by the SSA static analysis framework (a part of the opcache optimizer).
|
||||
Code is usually generated separately for each PHP byte-code instruction. Only
|
||||
a few combinations are considered together (e.g. compare + conditional jump).
|
||||
|
||||
See [the JIT RFC](https://wiki.php.net/rfc/jit) for more details.
|
||||
|
||||
DynAsm
|
||||
------
|
||||
|
||||
This uses [DynAsm](https://luajit.org/dynasm.html) (developed for LuaJIT project)
|
||||
for the generation of native code. It's a very lightweight and advanced tool,
|
||||
but does assume good, and very low-level development knowledge of target
|
||||
assembler languages. In the past we tried LLVM, but its code generation speed
|
||||
was almost 100 times slower, making it prohibitively expensive to use.
|
||||
|
||||
[The unofficial DynASM Documentation](https://corsix.github.io/dynasm-doc/tutorial.html)
|
||||
has a tutorial, reference, and instruction listing.
|
||||
|
||||
In x86 builds, `zend_jit_x86.dasc` gets automatically converted to `zend_jit_x86.c` by the bundled
|
||||
`dynasm` during `make`.
|
||||
|
||||
In arm64 builds, `zend_jit_arm64.dasc` gets automatically converted to `zend_jit_arm64.c` by the bundled
|
||||
`dynasm` during `make`.
|
||||
This converts the PHP Virtual Machine's opcodes into Intermediate
|
||||
Representation and uses [IR - Lightweight JIT Compilation Framework](https://github.com/dstogov/ir)
|
||||
to produce optimized native code. The necessary part of the IR
|
||||
Framework is embedded into php-src.
|
||||
|
||||
Running tests of the JIT
|
||||
------------------------
|
||||
|
@ -62,17 +39,6 @@ Note that the JIT supports 3 different architectures: `X86_64`, `i386`, and `arm
|
|||
Miscellaneous
|
||||
-------------
|
||||
|
||||
### Checking dasc files for in a different architecture
|
||||
|
||||
The following command can be run to manually check if the modified `.dasc code` is at least transpilable
|
||||
for an architecture you're not using, e.g.:
|
||||
|
||||
For arm64: `ext/opcache/minilua ext/opcache/jit/dynasm/dynasm.lua -D ARM64=1 -o ext/opcache/jit/zend_jit_arm64.ignored.c ext/opcache/jit/zend_jit_arm64.dasc`
|
||||
|
||||
For x86_64: `ext/opcache/minilua ext/opcache/jit/dynasm/dynasm.lua -D X64=1 -o ext/opcache/jit/zend_jit_x86.ignored.c ext/opcache/jit/zend_jit_x86.dasc`
|
||||
|
||||
For i386 (i.e. 32-bit): `ext/opcache/minilua ext/opcache/jit/dynasm/dynasm.lua -o ext/opcache/jit/zend_jit_x86.ignored.c ext/opcache/jit/zend_jit_x86.dasc`
|
||||
|
||||
### How to build 32-bit builds on x86_64 environments
|
||||
|
||||
Refer to [../../../.github/workflows/push.yml](../../../.github/workflows/push.yml) for examples of
|
||||
|
|
|
@ -1,461 +0,0 @@
|
|||
/*
|
||||
** DynASM ARM encoding engine.
|
||||
** Copyright (C) 2005-2021 Mike Pall. All rights reserved.
|
||||
** Released under the MIT license. See dynasm.lua for full copyright notice.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DASM_ARCH "arm"
|
||||
|
||||
#ifndef DASM_EXTERN
|
||||
#define DASM_EXTERN(a,b,c,d) 0
|
||||
#endif
|
||||
|
||||
/* Action definitions. */
|
||||
enum {
|
||||
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
|
||||
/* The following actions need a buffer position. */
|
||||
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
|
||||
/* The following actions also have an argument. */
|
||||
DASM_REL_PC, DASM_LABEL_PC,
|
||||
DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8,
|
||||
DASM__MAX
|
||||
};
|
||||
|
||||
/* Maximum number of section buffer positions for a single dasm_put() call. */
|
||||
#define DASM_MAXSECPOS 25
|
||||
|
||||
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
|
||||
#define DASM_S_OK 0x00000000
|
||||
#define DASM_S_NOMEM 0x01000000
|
||||
#define DASM_S_PHASE 0x02000000
|
||||
#define DASM_S_MATCH_SEC 0x03000000
|
||||
#define DASM_S_RANGE_I 0x11000000
|
||||
#define DASM_S_RANGE_SEC 0x12000000
|
||||
#define DASM_S_RANGE_LG 0x13000000
|
||||
#define DASM_S_RANGE_PC 0x14000000
|
||||
#define DASM_S_RANGE_REL 0x15000000
|
||||
#define DASM_S_UNDEF_LG 0x21000000
|
||||
#define DASM_S_UNDEF_PC 0x22000000
|
||||
|
||||
/* Macros to convert positions (8 bit section + 24 bit index). */
|
||||
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
|
||||
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
|
||||
#define DASM_SEC2POS(sec) ((sec)<<24)
|
||||
#define DASM_POS2SEC(pos) ((pos)>>24)
|
||||
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
|
||||
|
||||
/* Action list type. */
|
||||
typedef const unsigned int *dasm_ActList;
|
||||
|
||||
/* Per-section structure. */
|
||||
typedef struct dasm_Section {
|
||||
int *rbuf; /* Biased buffer pointer (negative section bias). */
|
||||
int *buf; /* True buffer pointer. */
|
||||
size_t bsize; /* Buffer size in bytes. */
|
||||
int pos; /* Biased buffer position. */
|
||||
int epos; /* End of biased buffer position - max single put. */
|
||||
int ofs; /* Byte offset into section. */
|
||||
} dasm_Section;
|
||||
|
||||
/* Core structure holding the DynASM encoding state. */
|
||||
struct dasm_State {
|
||||
size_t psize; /* Allocated size of this structure. */
|
||||
dasm_ActList actionlist; /* Current actionlist pointer. */
|
||||
int *lglabels; /* Local/global chain/pos ptrs. */
|
||||
size_t lgsize;
|
||||
int *pclabels; /* PC label chains/pos ptrs. */
|
||||
size_t pcsize;
|
||||
void **globals; /* Array of globals (bias -10). */
|
||||
dasm_Section *section; /* Pointer to active section. */
|
||||
size_t codesize; /* Total size of all code sections. */
|
||||
int maxsection; /* 0 <= sectionidx < maxsection. */
|
||||
int status; /* Status code. */
|
||||
dasm_Section sections[1]; /* All sections. Alloc-extended. */
|
||||
};
|
||||
|
||||
/* The size of the core structure depends on the max. number of sections. */
|
||||
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
|
||||
|
||||
|
||||
/* Initialize DynASM state. */
|
||||
void dasm_init(Dst_DECL, int maxsection)
|
||||
{
|
||||
dasm_State *D;
|
||||
size_t psz = 0;
|
||||
int i;
|
||||
Dst_REF = NULL;
|
||||
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
|
||||
D = Dst_REF;
|
||||
D->psize = psz;
|
||||
D->lglabels = NULL;
|
||||
D->lgsize = 0;
|
||||
D->pclabels = NULL;
|
||||
D->pcsize = 0;
|
||||
D->globals = NULL;
|
||||
D->maxsection = maxsection;
|
||||
for (i = 0; i < maxsection; i++) {
|
||||
D->sections[i].buf = NULL; /* Need this for pass3. */
|
||||
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
|
||||
D->sections[i].bsize = 0;
|
||||
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Free DynASM state. */
|
||||
void dasm_free(Dst_DECL)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int i;
|
||||
for (i = 0; i < D->maxsection; i++)
|
||||
if (D->sections[i].buf)
|
||||
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
|
||||
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
|
||||
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
|
||||
DASM_M_FREE(Dst, D, D->psize);
|
||||
}
|
||||
|
||||
/* Setup global label array. Must be called before dasm_setup(). */
|
||||
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
D->globals = gl - 10; /* Negative bias to compensate for locals. */
|
||||
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
|
||||
}
|
||||
|
||||
/* Grow PC label array. Can be called after dasm_setup(), too. */
|
||||
void dasm_growpc(Dst_DECL, unsigned int maxpc)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
size_t osz = D->pcsize;
|
||||
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
|
||||
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
|
||||
}
|
||||
|
||||
/* Setup encoder. */
|
||||
void dasm_setup(Dst_DECL, const void *actionlist)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int i;
|
||||
D->actionlist = (dasm_ActList)actionlist;
|
||||
D->status = DASM_S_OK;
|
||||
D->section = &D->sections[0];
|
||||
memset((void *)D->lglabels, 0, D->lgsize);
|
||||
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
|
||||
for (i = 0; i < D->maxsection; i++) {
|
||||
D->sections[i].pos = DASM_SEC2POS(i);
|
||||
D->sections[i].ofs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
#define CK(x, st) \
|
||||
do { if (!(x)) { \
|
||||
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
|
||||
#define CKPL(kind, st) \
|
||||
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
|
||||
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
|
||||
#else
|
||||
#define CK(x, st) ((void)0)
|
||||
#define CKPL(kind, st) ((void)0)
|
||||
#endif
|
||||
|
||||
static int dasm_imm12(unsigned int n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30))
|
||||
if (n <= 255) return (int)(n + (i << 8));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
|
||||
void dasm_put(Dst_DECL, int start, ...)
|
||||
{
|
||||
va_list ap;
|
||||
dasm_State *D = Dst_REF;
|
||||
dasm_ActList p = D->actionlist + start;
|
||||
dasm_Section *sec = D->section;
|
||||
int pos = sec->pos, ofs = sec->ofs;
|
||||
int *b;
|
||||
|
||||
if (pos >= sec->epos) {
|
||||
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
|
||||
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
|
||||
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
|
||||
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
|
||||
}
|
||||
|
||||
b = sec->rbuf;
|
||||
b[pos++] = start;
|
||||
|
||||
va_start(ap, start);
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16);
|
||||
if (action >= DASM__MAX) {
|
||||
ofs += 4;
|
||||
} else {
|
||||
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
|
||||
switch (action) {
|
||||
case DASM_STOP: goto stop;
|
||||
case DASM_SECTION:
|
||||
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
|
||||
D->section = &D->sections[n]; goto stop;
|
||||
case DASM_ESC: p++; ofs += 4; break;
|
||||
case DASM_REL_EXT: break;
|
||||
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
|
||||
case DASM_REL_LG:
|
||||
n = (ins & 2047) - 10; pl = D->lglabels + n;
|
||||
/* Bkwd rel or global. */
|
||||
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
|
||||
pl += 10; n = *pl;
|
||||
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
|
||||
goto linkrel;
|
||||
case DASM_REL_PC:
|
||||
pl = D->pclabels + n; CKPL(pc, PC);
|
||||
putrel:
|
||||
n = *pl;
|
||||
if (n < 0) { /* Label exists. Get label pos and store it. */
|
||||
b[pos] = -n;
|
||||
} else {
|
||||
linkrel:
|
||||
b[pos] = n; /* Else link to rel chain, anchored at label. */
|
||||
*pl = pos;
|
||||
}
|
||||
pos++;
|
||||
break;
|
||||
case DASM_LABEL_LG:
|
||||
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
|
||||
case DASM_LABEL_PC:
|
||||
pl = D->pclabels + n; CKPL(pc, PC);
|
||||
putlabel:
|
||||
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
|
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
|
||||
}
|
||||
*pl = -pos; /* Label exists now. */
|
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */
|
||||
break;
|
||||
case DASM_IMM:
|
||||
case DASM_IMM16:
|
||||
#ifdef DASM_CHECKS
|
||||
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
|
||||
if ((ins & 0x8000))
|
||||
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
|
||||
else
|
||||
CK((n>>((ins>>5)&31)) == 0, RANGE_I);
|
||||
#endif
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_IMMV8:
|
||||
CK((n & 3) == 0, RANGE_I);
|
||||
n >>= 2;
|
||||
/* fallthrough */
|
||||
case DASM_IMML8:
|
||||
case DASM_IMML12:
|
||||
CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) :
|
||||
(((-n)>>((ins>>5)&31)) == 0), RANGE_I);
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_IMM12:
|
||||
CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
|
||||
b[pos++] = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
stop:
|
||||
va_end(ap);
|
||||
sec->pos = pos;
|
||||
sec->ofs = ofs;
|
||||
}
|
||||
#undef CK
|
||||
|
||||
/* Pass 2: Link sections, shrink aligns, fix label offsets. */
|
||||
int dasm_link(Dst_DECL, size_t *szp)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int secnum;
|
||||
int ofs = 0;
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
*szp = 0;
|
||||
if (D->status != DASM_S_OK) return D->status;
|
||||
{
|
||||
int pc;
|
||||
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
|
||||
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
|
||||
}
|
||||
#endif
|
||||
|
||||
{ /* Handle globals not defined in this translation unit. */
|
||||
int idx;
|
||||
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
|
||||
int n = D->lglabels[idx];
|
||||
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
|
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Combine all code sections. No support for data sections (yet). */
|
||||
for (secnum = 0; secnum < D->maxsection; secnum++) {
|
||||
dasm_Section *sec = D->sections + secnum;
|
||||
int *b = sec->rbuf;
|
||||
int pos = DASM_SEC2POS(secnum);
|
||||
int lastpos = sec->pos;
|
||||
|
||||
while (pos != lastpos) {
|
||||
dasm_ActList p = D->actionlist + b[pos++];
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16);
|
||||
switch (action) {
|
||||
case DASM_STOP: case DASM_SECTION: goto stop;
|
||||
case DASM_ESC: p++; break;
|
||||
case DASM_REL_EXT: break;
|
||||
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
|
||||
case DASM_REL_LG: case DASM_REL_PC: pos++; break;
|
||||
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
|
||||
case DASM_IMM: case DASM_IMM12: case DASM_IMM16:
|
||||
case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break;
|
||||
}
|
||||
}
|
||||
stop: (void)0;
|
||||
}
|
||||
ofs += sec->ofs; /* Next section starts right after current section. */
|
||||
}
|
||||
|
||||
D->codesize = ofs; /* Total size of all code sections */
|
||||
*szp = ofs;
|
||||
return DASM_S_OK;
|
||||
}
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
#define CK(x, st) \
|
||||
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
|
||||
#else
|
||||
#define CK(x, st) ((void)0)
|
||||
#endif
|
||||
|
||||
/* Pass 3: Encode sections. */
|
||||
int dasm_encode(Dst_DECL, void *buffer)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
char *base = (char *)buffer;
|
||||
unsigned int *cp = (unsigned int *)buffer;
|
||||
int secnum;
|
||||
|
||||
/* Encode all code sections. No support for data sections (yet). */
|
||||
for (secnum = 0; secnum < D->maxsection; secnum++) {
|
||||
dasm_Section *sec = D->sections + secnum;
|
||||
int *b = sec->buf;
|
||||
int *endb = sec->rbuf + sec->pos;
|
||||
|
||||
while (b != endb) {
|
||||
dasm_ActList p = D->actionlist + *b++;
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16);
|
||||
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
|
||||
switch (action) {
|
||||
case DASM_STOP: case DASM_SECTION: goto stop;
|
||||
case DASM_ESC: *cp++ = *p++; break;
|
||||
case DASM_REL_EXT:
|
||||
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048));
|
||||
goto patchrel;
|
||||
case DASM_ALIGN:
|
||||
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
|
||||
break;
|
||||
case DASM_REL_LG:
|
||||
if (n < 0) {
|
||||
n = (int)((ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp - 4);
|
||||
goto patchrel;
|
||||
}
|
||||
/* fallthrough */
|
||||
case DASM_REL_PC:
|
||||
CK(n >= 0, UNDEF_PC);
|
||||
n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4;
|
||||
patchrel:
|
||||
if ((ins & 0x800) == 0) {
|
||||
CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL);
|
||||
cp[-1] |= ((n >> 2) & 0x00ffffff);
|
||||
} else if ((ins & 0x1000)) {
|
||||
CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL);
|
||||
goto patchimml8;
|
||||
} else if ((ins & 0x2000) == 0) {
|
||||
CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL);
|
||||
goto patchimml;
|
||||
} else {
|
||||
CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL);
|
||||
n >>= 2;
|
||||
goto patchimml;
|
||||
}
|
||||
break;
|
||||
case DASM_LABEL_LG:
|
||||
ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
|
||||
break;
|
||||
case DASM_LABEL_PC: break;
|
||||
case DASM_IMM:
|
||||
cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31);
|
||||
break;
|
||||
case DASM_IMM12:
|
||||
cp[-1] |= dasm_imm12((unsigned int)n);
|
||||
break;
|
||||
case DASM_IMM16:
|
||||
cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff);
|
||||
break;
|
||||
case DASM_IMML8: patchimml8:
|
||||
cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) :
|
||||
((-n & 0x0f) | ((-n & 0xf0) << 4));
|
||||
break;
|
||||
case DASM_IMML12: case DASM_IMMV8: patchimml:
|
||||
cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n);
|
||||
break;
|
||||
default: *cp++ = ins; break;
|
||||
}
|
||||
}
|
||||
stop: (void)0;
|
||||
}
|
||||
}
|
||||
|
||||
if (base + D->codesize != (char *)cp) /* Check for phase errors. */
|
||||
return DASM_S_PHASE;
|
||||
return DASM_S_OK;
|
||||
}
|
||||
#undef CK
|
||||
|
||||
/* Get PC label offset. */
|
||||
int dasm_getpclabel(Dst_DECL, unsigned int pc)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
if (pc*sizeof(int) < D->pcsize) {
|
||||
int pos = D->pclabels[pc];
|
||||
if (pos < 0) return *DASM_POS2PTR(D, -pos);
|
||||
if (pos > 0) return -1; /* Undefined. */
|
||||
}
|
||||
return -2; /* Unused or out of range. */
|
||||
}
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
/* Optional sanity checker to call between isolated encoding steps. */
|
||||
int dasm_checkstep(Dst_DECL, int secmatch)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
if (D->status == DASM_S_OK) {
|
||||
int i;
|
||||
for (i = 1; i <= 9; i++) {
|
||||
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
|
||||
D->lglabels[i] = 0;
|
||||
}
|
||||
}
|
||||
if (D->status == DASM_S_OK && secmatch >= 0 &&
|
||||
D->section != &D->sections[secmatch])
|
||||
D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
|
||||
return D->status;
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,570 +0,0 @@
|
|||
/*
|
||||
** DynASM ARM64 encoding engine.
|
||||
** Copyright (C) 2005-2021 Mike Pall. All rights reserved.
|
||||
** Released under the MIT license. See dynasm.lua for full copyright notice.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DASM_ARCH "arm64"
|
||||
|
||||
#ifndef DASM_EXTERN
|
||||
#define DASM_EXTERN(a,b,c,d) 0
|
||||
#endif
|
||||
|
||||
/* Action definitions. */
|
||||
enum {
|
||||
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
|
||||
/* The following actions need a buffer position. */
|
||||
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
|
||||
/* The following actions also have an argument. */
|
||||
DASM_REL_PC, DASM_LABEL_PC, DASM_REL_A,
|
||||
DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML,
|
||||
DASM_IMMV, DASM_VREG,
|
||||
DASM__MAX
|
||||
};
|
||||
|
||||
/* Maximum number of section buffer positions for a single dasm_put() call. */
|
||||
#define DASM_MAXSECPOS 25
|
||||
|
||||
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
|
||||
#define DASM_S_OK 0x00000000
|
||||
#define DASM_S_NOMEM 0x01000000
|
||||
#define DASM_S_PHASE 0x02000000
|
||||
#define DASM_S_MATCH_SEC 0x03000000
|
||||
#define DASM_S_RANGE_I 0x11000000
|
||||
#define DASM_S_RANGE_SEC 0x12000000
|
||||
#define DASM_S_RANGE_LG 0x13000000
|
||||
#define DASM_S_RANGE_PC 0x14000000
|
||||
#define DASM_S_RANGE_REL 0x15000000
|
||||
#define DASM_S_RANGE_VREG 0x16000000
|
||||
#define DASM_S_UNDEF_LG 0x21000000
|
||||
#define DASM_S_UNDEF_PC 0x22000000
|
||||
|
||||
/* Macros to convert positions (8 bit section + 24 bit index). */
|
||||
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
|
||||
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
|
||||
#define DASM_SEC2POS(sec) ((sec)<<24)
|
||||
#define DASM_POS2SEC(pos) ((pos)>>24)
|
||||
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
|
||||
|
||||
/* Action list type. */
|
||||
typedef const unsigned int *dasm_ActList;
|
||||
|
||||
/* Per-section structure. */
|
||||
typedef struct dasm_Section {
|
||||
int *rbuf; /* Biased buffer pointer (negative section bias). */
|
||||
int *buf; /* True buffer pointer. */
|
||||
size_t bsize; /* Buffer size in bytes. */
|
||||
int pos; /* Biased buffer position. */
|
||||
int epos; /* End of biased buffer position - max single put. */
|
||||
int ofs; /* Byte offset into section. */
|
||||
} dasm_Section;
|
||||
|
||||
/* Core structure holding the DynASM encoding state. */
|
||||
struct dasm_State {
|
||||
size_t psize; /* Allocated size of this structure. */
|
||||
dasm_ActList actionlist; /* Current actionlist pointer. */
|
||||
int *lglabels; /* Local/global chain/pos ptrs. */
|
||||
size_t lgsize;
|
||||
int *pclabels; /* PC label chains/pos ptrs. */
|
||||
size_t pcsize;
|
||||
void **globals; /* Array of globals (bias -10). */
|
||||
dasm_Section *section; /* Pointer to active section. */
|
||||
size_t codesize; /* Total size of all code sections. */
|
||||
int maxsection; /* 0 <= sectionidx < maxsection. */
|
||||
int status; /* Status code. */
|
||||
dasm_Section sections[1]; /* All sections. Alloc-extended. */
|
||||
};
|
||||
|
||||
/* The size of the core structure depends on the max. number of sections. */
|
||||
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
|
||||
|
||||
|
||||
/* Initialize DynASM state. */
|
||||
void dasm_init(Dst_DECL, int maxsection)
|
||||
{
|
||||
dasm_State *D;
|
||||
size_t psz = 0;
|
||||
int i;
|
||||
Dst_REF = NULL;
|
||||
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
|
||||
D = Dst_REF;
|
||||
D->psize = psz;
|
||||
D->lglabels = NULL;
|
||||
D->lgsize = 0;
|
||||
D->pclabels = NULL;
|
||||
D->pcsize = 0;
|
||||
D->globals = NULL;
|
||||
D->maxsection = maxsection;
|
||||
for (i = 0; i < maxsection; i++) {
|
||||
D->sections[i].buf = NULL; /* Need this for pass3. */
|
||||
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
|
||||
D->sections[i].bsize = 0;
|
||||
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Free DynASM state. */
|
||||
void dasm_free(Dst_DECL)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int i;
|
||||
for (i = 0; i < D->maxsection; i++)
|
||||
if (D->sections[i].buf)
|
||||
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
|
||||
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
|
||||
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
|
||||
DASM_M_FREE(Dst, D, D->psize);
|
||||
}
|
||||
|
||||
/* Setup global label array. Must be called before dasm_setup(). */
|
||||
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
D->globals = gl - 10; /* Negative bias to compensate for locals. */
|
||||
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
|
||||
}
|
||||
|
||||
/* Grow PC label array. Can be called after dasm_setup(), too. */
|
||||
void dasm_growpc(Dst_DECL, unsigned int maxpc)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
size_t osz = D->pcsize;
|
||||
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
|
||||
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
|
||||
}
|
||||
|
||||
/* Setup encoder. */
|
||||
void dasm_setup(Dst_DECL, const void *actionlist)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int i;
|
||||
D->actionlist = (dasm_ActList)actionlist;
|
||||
D->status = DASM_S_OK;
|
||||
D->section = &D->sections[0];
|
||||
memset((void *)D->lglabels, 0, D->lgsize);
|
||||
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
|
||||
for (i = 0; i < D->maxsection; i++) {
|
||||
D->sections[i].pos = DASM_SEC2POS(i);
|
||||
D->sections[i].ofs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
#define CK(x, st) \
|
||||
do { if (!(x)) { \
|
||||
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
|
||||
#define CKPL(kind, st) \
|
||||
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
|
||||
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
|
||||
#else
|
||||
#define CK(x, st) ((void)0)
|
||||
#define CKPL(kind, st) ((void)0)
|
||||
#endif
|
||||
|
||||
static int dasm_imm12(unsigned int n)
|
||||
{
|
||||
if ((n >> 12) == 0)
|
||||
return n;
|
||||
else if ((n & 0xff000fff) == 0)
|
||||
return (n >> 12) | 0x1000;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dasm_ffs(unsigned long long x)
|
||||
{
|
||||
int n = -1;
|
||||
while (x) { x >>= 1; n++; }
|
||||
return n;
|
||||
}
|
||||
|
||||
static int dasm_imm13(int lo, int hi)
|
||||
{
|
||||
int inv = 0, w = 64, s = 0xfff, xa, xb;
|
||||
unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo;
|
||||
unsigned long long m = 1ULL, a, b, c;
|
||||
if (n & 1) { n = ~n; inv = 1; }
|
||||
a = n & -n; b = (n+a)&-(n+a); c = (n+a-b)&-(n+a-b);
|
||||
xa = dasm_ffs(a); xb = dasm_ffs(b);
|
||||
if (c) {
|
||||
w = dasm_ffs(c) - xa;
|
||||
if (w == 32) m = 0x0000000100000001UL;
|
||||
else if (w == 16) m = 0x0001000100010001UL;
|
||||
else if (w == 8) m = 0x0101010101010101UL;
|
||||
else if (w == 4) m = 0x1111111111111111UL;
|
||||
else if (w == 2) m = 0x5555555555555555UL;
|
||||
else return -1;
|
||||
s = (-2*w & 0x3f) - 1;
|
||||
} else if (!a) {
|
||||
return -1;
|
||||
} else if (xb == -1) {
|
||||
xb = 64;
|
||||
}
|
||||
if ((b-a) * m != n) return -1;
|
||||
if (inv) {
|
||||
return ((w - xb) << 6) | (s+w+xa-xb);
|
||||
} else {
|
||||
return ((w - xa) << 6) | (s+xb-xa);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
|
||||
void dasm_put(Dst_DECL, int start, ...)
|
||||
{
|
||||
va_list ap;
|
||||
dasm_State *D = Dst_REF;
|
||||
dasm_ActList p = D->actionlist + start;
|
||||
dasm_Section *sec = D->section;
|
||||
int pos = sec->pos, ofs = sec->ofs;
|
||||
int *b;
|
||||
|
||||
if (pos >= sec->epos) {
|
||||
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
|
||||
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
|
||||
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
|
||||
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
|
||||
}
|
||||
|
||||
b = sec->rbuf;
|
||||
b[pos++] = start;
|
||||
|
||||
va_start(ap, start);
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16);
|
||||
if (action >= DASM__MAX) {
|
||||
ofs += 4;
|
||||
} else {
|
||||
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
|
||||
switch (action) {
|
||||
case DASM_STOP: goto stop;
|
||||
case DASM_SECTION:
|
||||
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
|
||||
D->section = &D->sections[n]; goto stop;
|
||||
case DASM_ESC: p++; ofs += 4; break;
|
||||
case DASM_REL_EXT: if ((ins & 0x8000)) ofs += 8; break;
|
||||
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
|
||||
case DASM_REL_LG:
|
||||
n = (ins & 2047) - 10; pl = D->lglabels + n;
|
||||
/* Bkwd rel or global. */
|
||||
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
|
||||
pl += 10; n = *pl;
|
||||
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
|
||||
goto linkrel;
|
||||
case DASM_REL_PC:
|
||||
pl = D->pclabels + n; CKPL(pc, PC);
|
||||
putrel:
|
||||
n = *pl;
|
||||
if (n < 0) { /* Label exists. Get label pos and store it. */
|
||||
b[pos] = -n;
|
||||
} else {
|
||||
linkrel:
|
||||
b[pos] = n; /* Else link to rel chain, anchored at label. */
|
||||
*pl = pos;
|
||||
}
|
||||
pos++;
|
||||
if ((ins & 0x8000)) ofs += 8;
|
||||
break;
|
||||
case DASM_REL_A:
|
||||
b[pos++] = n;
|
||||
b[pos++] = va_arg(ap, int);
|
||||
break;
|
||||
case DASM_LABEL_LG:
|
||||
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
|
||||
case DASM_LABEL_PC:
|
||||
pl = D->pclabels + n; CKPL(pc, PC);
|
||||
putlabel:
|
||||
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
|
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
|
||||
}
|
||||
*pl = -pos; /* Label exists now. */
|
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */
|
||||
break;
|
||||
case DASM_IMM:
|
||||
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
|
||||
n >>= ((ins>>10)&31);
|
||||
#ifdef DASM_CHECKS
|
||||
if ((ins & 0x8000))
|
||||
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
|
||||
else
|
||||
CK((n>>((ins>>5)&31)) == 0, RANGE_I);
|
||||
#endif
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_IMM6:
|
||||
CK((n >> 6) == 0, RANGE_I);
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_IMM12:
|
||||
CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_IMM13W:
|
||||
CK(dasm_imm13(n, n) != -1, RANGE_I);
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_IMM13X: {
|
||||
int m = va_arg(ap, int);
|
||||
CK(dasm_imm13(n, m) != -1, RANGE_I);
|
||||
b[pos++] = n;
|
||||
b[pos++] = m;
|
||||
break;
|
||||
}
|
||||
case DASM_IMML: {
|
||||
#ifdef DASM_CHECKS
|
||||
int scale = (ins & 3);
|
||||
CK((!(n & ((1<<scale)-1)) && (unsigned int)(n>>scale) < 4096) ||
|
||||
(unsigned int)(n+256) < 512, RANGE_I);
|
||||
#endif
|
||||
b[pos++] = n;
|
||||
break;
|
||||
}
|
||||
case DASM_IMMV:
|
||||
ofs += 4;
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_VREG:
|
||||
CK(n < 32, RANGE_VREG);
|
||||
b[pos++] = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
stop:
|
||||
va_end(ap);
|
||||
sec->pos = pos;
|
||||
sec->ofs = ofs;
|
||||
}
|
||||
#undef CK
|
||||
|
||||
/* Pass 2: Link sections, shrink aligns, fix label offsets. */
|
||||
int dasm_link(Dst_DECL, size_t *szp)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int secnum;
|
||||
int ofs = 0;
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
*szp = 0;
|
||||
if (D->status != DASM_S_OK) return D->status;
|
||||
{
|
||||
int pc;
|
||||
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
|
||||
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
|
||||
}
|
||||
#endif
|
||||
|
||||
{ /* Handle globals not defined in this translation unit. */
|
||||
int idx;
|
||||
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
|
||||
int n = D->lglabels[idx];
|
||||
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
|
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Combine all code sections. No support for data sections (yet). */
|
||||
for (secnum = 0; secnum < D->maxsection; secnum++) {
|
||||
dasm_Section *sec = D->sections + secnum;
|
||||
int *b = sec->rbuf;
|
||||
int pos = DASM_SEC2POS(secnum);
|
||||
int lastpos = sec->pos;
|
||||
|
||||
while (pos != lastpos) {
|
||||
dasm_ActList p = D->actionlist + b[pos++];
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16);
|
||||
switch (action) {
|
||||
case DASM_STOP: case DASM_SECTION: goto stop;
|
||||
case DASM_ESC: p++; break;
|
||||
case DASM_REL_EXT: break;
|
||||
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
|
||||
case DASM_REL_LG: case DASM_REL_PC: pos++; break;
|
||||
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
|
||||
case DASM_IMM: case DASM_IMM6: case DASM_IMM12: case DASM_IMM13W:
|
||||
case DASM_IMML: case DASM_IMMV: case DASM_VREG: pos++; break;
|
||||
case DASM_IMM13X: case DASM_REL_A: pos += 2; break;
|
||||
}
|
||||
}
|
||||
stop: (void)0;
|
||||
}
|
||||
ofs += sec->ofs; /* Next section starts right after current section. */
|
||||
}
|
||||
|
||||
D->codesize = ofs; /* Total size of all code sections */
|
||||
*szp = ofs;
|
||||
return DASM_S_OK;
|
||||
}
|
||||
|
||||
#ifdef DASM_ADD_VENEER
|
||||
#define CK_REL(x, o) \
|
||||
do { if (!(x) && !(n = DASM_ADD_VENEER(D, buffer, ins, b, cp, o))) \
|
||||
return DASM_S_RANGE_REL|(p-D->actionlist-1); \
|
||||
} while (0)
|
||||
#else
|
||||
#define CK_REL(x, o) CK(x, RANGE_REL)
|
||||
#endif
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
#define CK(x, st) \
|
||||
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
|
||||
#else
|
||||
#define CK(x, st) ((void)0)
|
||||
#endif
|
||||
|
||||
/* Pass 3: Encode sections. */
|
||||
int dasm_encode(Dst_DECL, void *buffer)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
char *base = (char *)buffer;
|
||||
unsigned int *cp = (unsigned int *)buffer;
|
||||
int secnum;
|
||||
|
||||
/* Encode all code sections. No support for data sections (yet). */
|
||||
for (secnum = 0; secnum < D->maxsection; secnum++) {
|
||||
dasm_Section *sec = D->sections + secnum;
|
||||
int *b = sec->buf;
|
||||
int *endb = sec->rbuf + sec->pos;
|
||||
|
||||
while (b != endb) {
|
||||
dasm_ActList p = D->actionlist + *b++;
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16);
|
||||
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
|
||||
switch (action) {
|
||||
case DASM_STOP: case DASM_SECTION: goto stop;
|
||||
case DASM_ESC: *cp++ = *p++; break;
|
||||
case DASM_REL_EXT:
|
||||
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048));
|
||||
goto patchrel;
|
||||
case DASM_ALIGN:
|
||||
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
|
||||
break;
|
||||
case DASM_REL_LG:
|
||||
if (n < 0) {
|
||||
ptrdiff_t na = (ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp + 4;
|
||||
n = (int)na;
|
||||
CK_REL((ptrdiff_t)n == na, na);
|
||||
goto patchrel;
|
||||
}
|
||||
/* fallthrough */
|
||||
case DASM_REL_PC:
|
||||
CK(n >= 0, UNDEF_PC);
|
||||
n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) + 4;
|
||||
patchrel:
|
||||
if (!(ins & 0xf800)) { /* B, BL */
|
||||
CK_REL((n & 3) == 0 && ((n+0x08000000) >> 28) == 0, n);
|
||||
cp[-1] |= ((n >> 2) & 0x03ffffff);
|
||||
} else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */
|
||||
CK_REL((n & 3) == 0 && ((n+0x00100000) >> 21) == 0, n);
|
||||
cp[-1] |= ((n << 3) & 0x00ffffe0);
|
||||
} else if ((ins & 0x3000) == 0x2000) { /* ADR */
|
||||
CK_REL(((n+0x00100000) >> 21) == 0, n);
|
||||
cp[-1] |= ((n << 3) & 0x00ffffe0) | ((n & 3) << 29);
|
||||
} else if ((ins & 0x3000) == 0x3000) { /* ADRP */
|
||||
cp[-1] |= ((n >> 9) & 0x00ffffe0) | (((n >> 12) & 3) << 29);
|
||||
} else if ((ins & 0x1000)) { /* TBZ, TBNZ */
|
||||
CK_REL((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, n);
|
||||
cp[-1] |= ((n << 3) & 0x0007ffe0);
|
||||
} else if ((ins & 0x8000)) { /* absolute */
|
||||
cp[0] = (unsigned int)((ptrdiff_t)cp - 4 + n);
|
||||
cp[1] = (unsigned int)(((ptrdiff_t)cp - 4 + n) >> 32);
|
||||
cp += 2;
|
||||
}
|
||||
break;
|
||||
case DASM_REL_A: {
|
||||
ptrdiff_t na = (((ptrdiff_t)(*b++) << 32) | (unsigned int)n);
|
||||
if ((ins & 0x3000) == 0x3000) { /* ADRP */
|
||||
ins &= ~0x1000;
|
||||
na = (na >> 12) - (((ptrdiff_t)cp - 4) >> 12);
|
||||
} else {
|
||||
na = na - (ptrdiff_t)cp + 4;
|
||||
}
|
||||
n = (int)na;
|
||||
CK_REL((ptrdiff_t)n == na, na);
|
||||
goto patchrel;
|
||||
}
|
||||
case DASM_LABEL_LG:
|
||||
ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
|
||||
break;
|
||||
case DASM_LABEL_PC: break;
|
||||
case DASM_IMM:
|
||||
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
|
||||
break;
|
||||
case DASM_IMM6:
|
||||
cp[-1] |= ((n&31) << 19) | ((n&32) << 26);
|
||||
break;
|
||||
case DASM_IMM12:
|
||||
cp[-1] |= (dasm_imm12((unsigned int)n) << 10);
|
||||
break;
|
||||
case DASM_IMM13W:
|
||||
cp[-1] |= (dasm_imm13(n, n) << 10);
|
||||
break;
|
||||
case DASM_IMM13X:
|
||||
cp[-1] |= (dasm_imm13(n, *b++) << 10);
|
||||
break;
|
||||
case DASM_IMML: {
|
||||
int scale = (ins & 3);
|
||||
cp[-1] |= (!(n & ((1<<scale)-1)) && (unsigned int)(n>>scale) < 4096) ?
|
||||
((n << (10-scale)) | 0x01000000) : ((n & 511) << 12);
|
||||
break;
|
||||
}
|
||||
case DASM_IMMV:
|
||||
*cp++ = n;
|
||||
break;
|
||||
case DASM_VREG:
|
||||
cp[-1] |= (n & 0x1f) << (ins & 0x1f);
|
||||
break;
|
||||
default: *cp++ = ins; break;
|
||||
}
|
||||
}
|
||||
stop: (void)0;
|
||||
}
|
||||
}
|
||||
|
||||
if (base + D->codesize != (char *)cp) /* Check for phase errors. */
|
||||
return DASM_S_PHASE;
|
||||
return DASM_S_OK;
|
||||
}
|
||||
#undef CK
|
||||
|
||||
/* Get PC label offset. */
|
||||
int dasm_getpclabel(Dst_DECL, unsigned int pc)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
if (pc*sizeof(int) < D->pcsize) {
|
||||
int pos = D->pclabels[pc];
|
||||
if (pos < 0) return *DASM_POS2PTR(D, -pos);
|
||||
if (pos > 0) return -1; /* Undefined. */
|
||||
}
|
||||
return -2; /* Unused or out of range. */
|
||||
}
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
/* Optional sanity checker to call between isolated encoding steps. */
|
||||
int dasm_checkstep(Dst_DECL, int secmatch)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
if (D->status == DASM_S_OK) {
|
||||
int i;
|
||||
for (i = 1; i <= 9; i++) {
|
||||
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
|
||||
D->lglabels[i] = 0;
|
||||
}
|
||||
}
|
||||
if (D->status == DASM_S_OK && secmatch >= 0 &&
|
||||
D->section != &D->sections[secmatch])
|
||||
D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
|
||||
return D->status;
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,424 +0,0 @@
|
|||
/*
|
||||
** DynASM MIPS encoding engine.
|
||||
** Copyright (C) 2005-2021 Mike Pall. All rights reserved.
|
||||
** Released under the MIT license. See dynasm.lua for full copyright notice.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DASM_ARCH "mips"
|
||||
|
||||
#ifndef DASM_EXTERN
|
||||
#define DASM_EXTERN(a,b,c,d) 0
|
||||
#endif
|
||||
|
||||
/* Action definitions. */
|
||||
enum {
|
||||
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
|
||||
/* The following actions need a buffer position. */
|
||||
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
|
||||
/* The following actions also have an argument. */
|
||||
DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMS,
|
||||
DASM__MAX
|
||||
};
|
||||
|
||||
/* Maximum number of section buffer positions for a single dasm_put() call. */
|
||||
#define DASM_MAXSECPOS 25
|
||||
|
||||
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
|
||||
#define DASM_S_OK 0x00000000
|
||||
#define DASM_S_NOMEM 0x01000000
|
||||
#define DASM_S_PHASE 0x02000000
|
||||
#define DASM_S_MATCH_SEC 0x03000000
|
||||
#define DASM_S_RANGE_I 0x11000000
|
||||
#define DASM_S_RANGE_SEC 0x12000000
|
||||
#define DASM_S_RANGE_LG 0x13000000
|
||||
#define DASM_S_RANGE_PC 0x14000000
|
||||
#define DASM_S_RANGE_REL 0x15000000
|
||||
#define DASM_S_UNDEF_LG 0x21000000
|
||||
#define DASM_S_UNDEF_PC 0x22000000
|
||||
|
||||
/* Macros to convert positions (8 bit section + 24 bit index). */
|
||||
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
|
||||
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
|
||||
#define DASM_SEC2POS(sec) ((sec)<<24)
|
||||
#define DASM_POS2SEC(pos) ((pos)>>24)
|
||||
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
|
||||
|
||||
/* Action list type. */
|
||||
typedef const unsigned int *dasm_ActList;
|
||||
|
||||
/* Per-section structure. */
|
||||
typedef struct dasm_Section {
|
||||
int *rbuf; /* Biased buffer pointer (negative section bias). */
|
||||
int *buf; /* True buffer pointer. */
|
||||
size_t bsize; /* Buffer size in bytes. */
|
||||
int pos; /* Biased buffer position. */
|
||||
int epos; /* End of biased buffer position - max single put. */
|
||||
int ofs; /* Byte offset into section. */
|
||||
} dasm_Section;
|
||||
|
||||
/* Core structure holding the DynASM encoding state. */
|
||||
struct dasm_State {
|
||||
size_t psize; /* Allocated size of this structure. */
|
||||
dasm_ActList actionlist; /* Current actionlist pointer. */
|
||||
int *lglabels; /* Local/global chain/pos ptrs. */
|
||||
size_t lgsize;
|
||||
int *pclabels; /* PC label chains/pos ptrs. */
|
||||
size_t pcsize;
|
||||
void **globals; /* Array of globals (bias -10). */
|
||||
dasm_Section *section; /* Pointer to active section. */
|
||||
size_t codesize; /* Total size of all code sections. */
|
||||
int maxsection; /* 0 <= sectionidx < maxsection. */
|
||||
int status; /* Status code. */
|
||||
dasm_Section sections[1]; /* All sections. Alloc-extended. */
|
||||
};
|
||||
|
||||
/* The size of the core structure depends on the max. number of sections. */
|
||||
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
|
||||
|
||||
|
||||
/* Initialize DynASM state. */
|
||||
void dasm_init(Dst_DECL, int maxsection)
|
||||
{
|
||||
dasm_State *D;
|
||||
size_t psz = 0;
|
||||
int i;
|
||||
Dst_REF = NULL;
|
||||
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
|
||||
D = Dst_REF;
|
||||
D->psize = psz;
|
||||
D->lglabels = NULL;
|
||||
D->lgsize = 0;
|
||||
D->pclabels = NULL;
|
||||
D->pcsize = 0;
|
||||
D->globals = NULL;
|
||||
D->maxsection = maxsection;
|
||||
for (i = 0; i < maxsection; i++) {
|
||||
D->sections[i].buf = NULL; /* Need this for pass3. */
|
||||
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
|
||||
D->sections[i].bsize = 0;
|
||||
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Free DynASM state. */
|
||||
void dasm_free(Dst_DECL)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int i;
|
||||
for (i = 0; i < D->maxsection; i++)
|
||||
if (D->sections[i].buf)
|
||||
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
|
||||
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
|
||||
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
|
||||
DASM_M_FREE(Dst, D, D->psize);
|
||||
}
|
||||
|
||||
/* Setup global label array. Must be called before dasm_setup(). */
|
||||
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
D->globals = gl - 10; /* Negative bias to compensate for locals. */
|
||||
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
|
||||
}
|
||||
|
||||
/* Grow PC label array. Can be called after dasm_setup(), too. */
|
||||
void dasm_growpc(Dst_DECL, unsigned int maxpc)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
size_t osz = D->pcsize;
|
||||
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
|
||||
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
|
||||
}
|
||||
|
||||
/* Setup encoder. */
|
||||
void dasm_setup(Dst_DECL, const void *actionlist)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int i;
|
||||
D->actionlist = (dasm_ActList)actionlist;
|
||||
D->status = DASM_S_OK;
|
||||
D->section = &D->sections[0];
|
||||
memset((void *)D->lglabels, 0, D->lgsize);
|
||||
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
|
||||
for (i = 0; i < D->maxsection; i++) {
|
||||
D->sections[i].pos = DASM_SEC2POS(i);
|
||||
D->sections[i].ofs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
#define CK(x, st) \
|
||||
do { if (!(x)) { \
|
||||
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
|
||||
#define CKPL(kind, st) \
|
||||
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
|
||||
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
|
||||
#else
|
||||
#define CK(x, st) ((void)0)
|
||||
#define CKPL(kind, st) ((void)0)
|
||||
#endif
|
||||
|
||||
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
|
||||
void dasm_put(Dst_DECL, int start, ...)
|
||||
{
|
||||
va_list ap;
|
||||
dasm_State *D = Dst_REF;
|
||||
dasm_ActList p = D->actionlist + start;
|
||||
dasm_Section *sec = D->section;
|
||||
int pos = sec->pos, ofs = sec->ofs;
|
||||
int *b;
|
||||
|
||||
if (pos >= sec->epos) {
|
||||
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
|
||||
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
|
||||
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
|
||||
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
|
||||
}
|
||||
|
||||
b = sec->rbuf;
|
||||
b[pos++] = start;
|
||||
|
||||
va_start(ap, start);
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16) - 0xff00;
|
||||
if (action >= DASM__MAX) {
|
||||
ofs += 4;
|
||||
} else {
|
||||
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
|
||||
switch (action) {
|
||||
case DASM_STOP: goto stop;
|
||||
case DASM_SECTION:
|
||||
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
|
||||
D->section = &D->sections[n]; goto stop;
|
||||
case DASM_ESC: p++; ofs += 4; break;
|
||||
case DASM_REL_EXT: break;
|
||||
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
|
||||
case DASM_REL_LG:
|
||||
n = (ins & 2047) - 10; pl = D->lglabels + n;
|
||||
/* Bkwd rel or global. */
|
||||
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
|
||||
pl += 10; n = *pl;
|
||||
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
|
||||
goto linkrel;
|
||||
case DASM_REL_PC:
|
||||
pl = D->pclabels + n; CKPL(pc, PC);
|
||||
putrel:
|
||||
n = *pl;
|
||||
if (n < 0) { /* Label exists. Get label pos and store it. */
|
||||
b[pos] = -n;
|
||||
} else {
|
||||
linkrel:
|
||||
b[pos] = n; /* Else link to rel chain, anchored at label. */
|
||||
*pl = pos;
|
||||
}
|
||||
pos++;
|
||||
break;
|
||||
case DASM_LABEL_LG:
|
||||
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
|
||||
case DASM_LABEL_PC:
|
||||
pl = D->pclabels + n; CKPL(pc, PC);
|
||||
putlabel:
|
||||
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
|
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
|
||||
}
|
||||
*pl = -pos; /* Label exists now. */
|
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */
|
||||
break;
|
||||
case DASM_IMM: case DASM_IMMS:
|
||||
#ifdef DASM_CHECKS
|
||||
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
|
||||
#endif
|
||||
n >>= ((ins>>10)&31);
|
||||
#ifdef DASM_CHECKS
|
||||
if (ins & 0x8000)
|
||||
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
|
||||
else
|
||||
CK((n>>((ins>>5)&31)) == 0, RANGE_I);
|
||||
#endif
|
||||
b[pos++] = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
stop:
|
||||
va_end(ap);
|
||||
sec->pos = pos;
|
||||
sec->ofs = ofs;
|
||||
}
|
||||
#undef CK
|
||||
|
||||
/* Pass 2: Link sections, shrink aligns, fix label offsets. */
|
||||
int dasm_link(Dst_DECL, size_t *szp)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int secnum;
|
||||
int ofs = 0;
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
*szp = 0;
|
||||
if (D->status != DASM_S_OK) return D->status;
|
||||
{
|
||||
int pc;
|
||||
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
|
||||
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
|
||||
}
|
||||
#endif
|
||||
|
||||
{ /* Handle globals not defined in this translation unit. */
|
||||
int idx;
|
||||
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
|
||||
int n = D->lglabels[idx];
|
||||
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
|
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Combine all code sections. No support for data sections (yet). */
|
||||
for (secnum = 0; secnum < D->maxsection; secnum++) {
|
||||
dasm_Section *sec = D->sections + secnum;
|
||||
int *b = sec->rbuf;
|
||||
int pos = DASM_SEC2POS(secnum);
|
||||
int lastpos = sec->pos;
|
||||
|
||||
while (pos != lastpos) {
|
||||
dasm_ActList p = D->actionlist + b[pos++];
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16) - 0xff00;
|
||||
switch (action) {
|
||||
case DASM_STOP: case DASM_SECTION: goto stop;
|
||||
case DASM_ESC: p++; break;
|
||||
case DASM_REL_EXT: break;
|
||||
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
|
||||
case DASM_REL_LG: case DASM_REL_PC: pos++; break;
|
||||
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
|
||||
case DASM_IMM: case DASM_IMMS: pos++; break;
|
||||
}
|
||||
}
|
||||
stop: (void)0;
|
||||
}
|
||||
ofs += sec->ofs; /* Next section starts right after current section. */
|
||||
}
|
||||
|
||||
D->codesize = ofs; /* Total size of all code sections */
|
||||
*szp = ofs;
|
||||
return DASM_S_OK;
|
||||
}
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
#define CK(x, st) \
|
||||
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
|
||||
#else
|
||||
#define CK(x, st) ((void)0)
|
||||
#endif
|
||||
|
||||
/* Pass 3: Encode sections. */
|
||||
int dasm_encode(Dst_DECL, void *buffer)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
char *base = (char *)buffer;
|
||||
unsigned int *cp = (unsigned int *)buffer;
|
||||
int secnum;
|
||||
|
||||
/* Encode all code sections. No support for data sections (yet). */
|
||||
for (secnum = 0; secnum < D->maxsection; secnum++) {
|
||||
dasm_Section *sec = D->sections + secnum;
|
||||
int *b = sec->buf;
|
||||
int *endb = sec->rbuf + sec->pos;
|
||||
|
||||
while (b != endb) {
|
||||
dasm_ActList p = D->actionlist + *b++;
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16) - 0xff00;
|
||||
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
|
||||
switch (action) {
|
||||
case DASM_STOP: case DASM_SECTION: goto stop;
|
||||
case DASM_ESC: *cp++ = *p++; break;
|
||||
case DASM_REL_EXT:
|
||||
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1);
|
||||
goto patchrel;
|
||||
case DASM_ALIGN:
|
||||
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
|
||||
break;
|
||||
case DASM_REL_LG:
|
||||
if (n < 0) {
|
||||
n = (int)((ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp);
|
||||
goto patchrel;
|
||||
}
|
||||
/* fallthrough */
|
||||
case DASM_REL_PC:
|
||||
CK(n >= 0, UNDEF_PC);
|
||||
n = *DASM_POS2PTR(D, n);
|
||||
if (ins & 2048)
|
||||
n = (n + (int)(size_t)base) & 0x0fffffff;
|
||||
else
|
||||
n = n - (int)((char *)cp - base);
|
||||
patchrel: {
|
||||
unsigned int e = 16 + ((ins >> 12) & 15);
|
||||
CK((n & 3) == 0 &&
|
||||
((n + ((ins & 2048) ? 0 : (1<<(e+1)))) >> (e+2)) == 0, RANGE_REL);
|
||||
cp[-1] |= ((n>>2) & ((1<<e)-1));
|
||||
}
|
||||
break;
|
||||
case DASM_LABEL_LG:
|
||||
ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
|
||||
break;
|
||||
case DASM_LABEL_PC: break;
|
||||
case DASM_IMMS:
|
||||
cp[-1] |= ((n>>3) & 4); n &= 0x1f;
|
||||
/* fallthrough */
|
||||
case DASM_IMM:
|
||||
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
|
||||
break;
|
||||
default: *cp++ = ins; break;
|
||||
}
|
||||
}
|
||||
stop: (void)0;
|
||||
}
|
||||
}
|
||||
|
||||
if (base + D->codesize != (char *)cp) /* Check for phase errors. */
|
||||
return DASM_S_PHASE;
|
||||
return DASM_S_OK;
|
||||
}
|
||||
#undef CK
|
||||
|
||||
/* Get PC label offset. */
|
||||
int dasm_getpclabel(Dst_DECL, unsigned int pc)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
if (pc*sizeof(int) < D->pcsize) {
|
||||
int pos = D->pclabels[pc];
|
||||
if (pos < 0) return *DASM_POS2PTR(D, -pos);
|
||||
if (pos > 0) return -1; /* Undefined. */
|
||||
}
|
||||
return -2; /* Unused or out of range. */
|
||||
}
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
/* Optional sanity checker to call between isolated encoding steps. */
|
||||
int dasm_checkstep(Dst_DECL, int secmatch)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
if (D->status == DASM_S_OK) {
|
||||
int i;
|
||||
for (i = 1; i <= 9; i++) {
|
||||
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
|
||||
D->lglabels[i] = 0;
|
||||
}
|
||||
}
|
||||
if (D->status == DASM_S_OK && secmatch >= 0 &&
|
||||
D->section != &D->sections[secmatch])
|
||||
D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
|
||||
return D->status;
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,12 +0,0 @@
|
|||
------------------------------------------------------------------------------
|
||||
-- DynASM MIPS64 module.
|
||||
--
|
||||
-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
|
||||
-- See dynasm.lua for full copyright notice.
|
||||
------------------------------------------------------------------------------
|
||||
-- This module just sets 64 bit mode for the combined MIPS/MIPS64 module.
|
||||
-- All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
mips64 = true -- Using a global is an ugly, but effective solution.
|
||||
return require("dasm_mips")
|
|
@ -1,423 +0,0 @@
|
|||
/*
|
||||
** DynASM PPC/PPC64 encoding engine.
|
||||
** Copyright (C) 2005-2021 Mike Pall. All rights reserved.
|
||||
** Released under the MIT license. See dynasm.lua for full copyright notice.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DASM_ARCH "ppc"
|
||||
|
||||
#ifndef DASM_EXTERN
|
||||
#define DASM_EXTERN(a,b,c,d) 0
|
||||
#endif
|
||||
|
||||
/* Action definitions. */
|
||||
enum {
|
||||
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
|
||||
/* The following actions need a buffer position. */
|
||||
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
|
||||
/* The following actions also have an argument. */
|
||||
DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMSH,
|
||||
DASM__MAX
|
||||
};
|
||||
|
||||
/* Maximum number of section buffer positions for a single dasm_put() call. */
|
||||
#define DASM_MAXSECPOS 25
|
||||
|
||||
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
|
||||
#define DASM_S_OK 0x00000000
|
||||
#define DASM_S_NOMEM 0x01000000
|
||||
#define DASM_S_PHASE 0x02000000
|
||||
#define DASM_S_MATCH_SEC 0x03000000
|
||||
#define DASM_S_RANGE_I 0x11000000
|
||||
#define DASM_S_RANGE_SEC 0x12000000
|
||||
#define DASM_S_RANGE_LG 0x13000000
|
||||
#define DASM_S_RANGE_PC 0x14000000
|
||||
#define DASM_S_RANGE_REL 0x15000000
|
||||
#define DASM_S_UNDEF_LG 0x21000000
|
||||
#define DASM_S_UNDEF_PC 0x22000000
|
||||
|
||||
/* Macros to convert positions (8 bit section + 24 bit index). */
|
||||
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
|
||||
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
|
||||
#define DASM_SEC2POS(sec) ((sec)<<24)
|
||||
#define DASM_POS2SEC(pos) ((pos)>>24)
|
||||
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
|
||||
|
||||
/* Action list type. */
|
||||
typedef const unsigned int *dasm_ActList;
|
||||
|
||||
/* Per-section structure. */
|
||||
typedef struct dasm_Section {
|
||||
int *rbuf; /* Biased buffer pointer (negative section bias). */
|
||||
int *buf; /* True buffer pointer. */
|
||||
size_t bsize; /* Buffer size in bytes. */
|
||||
int pos; /* Biased buffer position. */
|
||||
int epos; /* End of biased buffer position - max single put. */
|
||||
int ofs; /* Byte offset into section. */
|
||||
} dasm_Section;
|
||||
|
||||
/* Core structure holding the DynASM encoding state. */
|
||||
struct dasm_State {
|
||||
size_t psize; /* Allocated size of this structure. */
|
||||
dasm_ActList actionlist; /* Current actionlist pointer. */
|
||||
int *lglabels; /* Local/global chain/pos ptrs. */
|
||||
size_t lgsize;
|
||||
int *pclabels; /* PC label chains/pos ptrs. */
|
||||
size_t pcsize;
|
||||
void **globals; /* Array of globals (bias -10). */
|
||||
dasm_Section *section; /* Pointer to active section. */
|
||||
size_t codesize; /* Total size of all code sections. */
|
||||
int maxsection; /* 0 <= sectionidx < maxsection. */
|
||||
int status; /* Status code. */
|
||||
dasm_Section sections[1]; /* All sections. Alloc-extended. */
|
||||
};
|
||||
|
||||
/* The size of the core structure depends on the max. number of sections. */
|
||||
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
|
||||
|
||||
|
||||
/* Initialize DynASM state. */
|
||||
void dasm_init(Dst_DECL, int maxsection)
|
||||
{
|
||||
dasm_State *D;
|
||||
size_t psz = 0;
|
||||
int i;
|
||||
Dst_REF = NULL;
|
||||
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
|
||||
D = Dst_REF;
|
||||
D->psize = psz;
|
||||
D->lglabels = NULL;
|
||||
D->lgsize = 0;
|
||||
D->pclabels = NULL;
|
||||
D->pcsize = 0;
|
||||
D->globals = NULL;
|
||||
D->maxsection = maxsection;
|
||||
for (i = 0; i < maxsection; i++) {
|
||||
D->sections[i].buf = NULL; /* Need this for pass3. */
|
||||
D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
|
||||
D->sections[i].bsize = 0;
|
||||
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Free DynASM state. */
|
||||
void dasm_free(Dst_DECL)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int i;
|
||||
for (i = 0; i < D->maxsection; i++)
|
||||
if (D->sections[i].buf)
|
||||
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
|
||||
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
|
||||
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
|
||||
DASM_M_FREE(Dst, D, D->psize);
|
||||
}
|
||||
|
||||
/* Setup global label array. Must be called before dasm_setup(). */
|
||||
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
D->globals = gl - 10; /* Negative bias to compensate for locals. */
|
||||
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
|
||||
}
|
||||
|
||||
/* Grow PC label array. Can be called after dasm_setup(), too. */
|
||||
void dasm_growpc(Dst_DECL, unsigned int maxpc)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
size_t osz = D->pcsize;
|
||||
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
|
||||
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
|
||||
}
|
||||
|
||||
/* Setup encoder. */
|
||||
void dasm_setup(Dst_DECL, const void *actionlist)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int i;
|
||||
D->actionlist = (dasm_ActList)actionlist;
|
||||
D->status = DASM_S_OK;
|
||||
D->section = &D->sections[0];
|
||||
memset((void *)D->lglabels, 0, D->lgsize);
|
||||
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
|
||||
for (i = 0; i < D->maxsection; i++) {
|
||||
D->sections[i].pos = DASM_SEC2POS(i);
|
||||
D->sections[i].ofs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
#define CK(x, st) \
|
||||
do { if (!(x)) { \
|
||||
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
|
||||
#define CKPL(kind, st) \
|
||||
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
|
||||
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
|
||||
#else
|
||||
#define CK(x, st) ((void)0)
|
||||
#define CKPL(kind, st) ((void)0)
|
||||
#endif
|
||||
|
||||
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
|
||||
void dasm_put(Dst_DECL, int start, ...)
|
||||
{
|
||||
va_list ap;
|
||||
dasm_State *D = Dst_REF;
|
||||
dasm_ActList p = D->actionlist + start;
|
||||
dasm_Section *sec = D->section;
|
||||
int pos = sec->pos, ofs = sec->ofs;
|
||||
int *b;
|
||||
|
||||
if (pos >= sec->epos) {
|
||||
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
|
||||
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
|
||||
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
|
||||
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
|
||||
}
|
||||
|
||||
b = sec->rbuf;
|
||||
b[pos++] = start;
|
||||
|
||||
va_start(ap, start);
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16);
|
||||
if (action >= DASM__MAX) {
|
||||
ofs += 4;
|
||||
} else {
|
||||
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
|
||||
switch (action) {
|
||||
case DASM_STOP: goto stop;
|
||||
case DASM_SECTION:
|
||||
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
|
||||
D->section = &D->sections[n]; goto stop;
|
||||
case DASM_ESC: p++; ofs += 4; break;
|
||||
case DASM_REL_EXT: break;
|
||||
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
|
||||
case DASM_REL_LG:
|
||||
n = (ins & 2047) - 10; pl = D->lglabels + n;
|
||||
/* Bkwd rel or global. */
|
||||
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
|
||||
pl += 10; n = *pl;
|
||||
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
|
||||
goto linkrel;
|
||||
case DASM_REL_PC:
|
||||
pl = D->pclabels + n; CKPL(pc, PC);
|
||||
putrel:
|
||||
n = *pl;
|
||||
if (n < 0) { /* Label exists. Get label pos and store it. */
|
||||
b[pos] = -n;
|
||||
} else {
|
||||
linkrel:
|
||||
b[pos] = n; /* Else link to rel chain, anchored at label. */
|
||||
*pl = pos;
|
||||
}
|
||||
pos++;
|
||||
break;
|
||||
case DASM_LABEL_LG:
|
||||
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
|
||||
case DASM_LABEL_PC:
|
||||
pl = D->pclabels + n; CKPL(pc, PC);
|
||||
putlabel:
|
||||
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
|
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
|
||||
}
|
||||
*pl = -pos; /* Label exists now. */
|
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */
|
||||
break;
|
||||
case DASM_IMM:
|
||||
#ifdef DASM_CHECKS
|
||||
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
|
||||
#endif
|
||||
n >>= ((ins>>10)&31);
|
||||
#ifdef DASM_CHECKS
|
||||
if (ins & 0x8000)
|
||||
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
|
||||
else
|
||||
CK((n>>((ins>>5)&31)) == 0, RANGE_I);
|
||||
#endif
|
||||
b[pos++] = n;
|
||||
break;
|
||||
case DASM_IMMSH:
|
||||
CK((n >> 6) == 0, RANGE_I);
|
||||
b[pos++] = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
stop:
|
||||
va_end(ap);
|
||||
sec->pos = pos;
|
||||
sec->ofs = ofs;
|
||||
}
|
||||
#undef CK
|
||||
|
||||
/* Pass 2: Link sections, shrink aligns, fix label offsets. */
|
||||
int dasm_link(Dst_DECL, size_t *szp)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int secnum;
|
||||
int ofs = 0;
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
*szp = 0;
|
||||
if (D->status != DASM_S_OK) return D->status;
|
||||
{
|
||||
int pc;
|
||||
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
|
||||
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
|
||||
}
|
||||
#endif
|
||||
|
||||
{ /* Handle globals not defined in this translation unit. */
|
||||
int idx;
|
||||
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
|
||||
int n = D->lglabels[idx];
|
||||
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
|
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Combine all code sections. No support for data sections (yet). */
|
||||
for (secnum = 0; secnum < D->maxsection; secnum++) {
|
||||
dasm_Section *sec = D->sections + secnum;
|
||||
int *b = sec->rbuf;
|
||||
int pos = DASM_SEC2POS(secnum);
|
||||
int lastpos = sec->pos;
|
||||
|
||||
while (pos != lastpos) {
|
||||
dasm_ActList p = D->actionlist + b[pos++];
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16);
|
||||
switch (action) {
|
||||
case DASM_STOP: case DASM_SECTION: goto stop;
|
||||
case DASM_ESC: p++; break;
|
||||
case DASM_REL_EXT: break;
|
||||
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
|
||||
case DASM_REL_LG: case DASM_REL_PC: pos++; break;
|
||||
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
|
||||
case DASM_IMM: case DASM_IMMSH: pos++; break;
|
||||
}
|
||||
}
|
||||
stop: (void)0;
|
||||
}
|
||||
ofs += sec->ofs; /* Next section starts right after current section. */
|
||||
}
|
||||
|
||||
D->codesize = ofs; /* Total size of all code sections */
|
||||
*szp = ofs;
|
||||
return DASM_S_OK;
|
||||
}
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
#define CK(x, st) \
|
||||
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
|
||||
#else
|
||||
#define CK(x, st) ((void)0)
|
||||
#endif
|
||||
|
||||
/* Pass 3: Encode sections. */
|
||||
int dasm_encode(Dst_DECL, void *buffer)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
char *base = (char *)buffer;
|
||||
unsigned int *cp = (unsigned int *)buffer;
|
||||
int secnum;
|
||||
|
||||
/* Encode all code sections. No support for data sections (yet). */
|
||||
for (secnum = 0; secnum < D->maxsection; secnum++) {
|
||||
dasm_Section *sec = D->sections + secnum;
|
||||
int *b = sec->buf;
|
||||
int *endb = sec->rbuf + sec->pos;
|
||||
|
||||
while (b != endb) {
|
||||
dasm_ActList p = D->actionlist + *b++;
|
||||
while (1) {
|
||||
unsigned int ins = *p++;
|
||||
unsigned int action = (ins >> 16);
|
||||
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
|
||||
switch (action) {
|
||||
case DASM_STOP: case DASM_SECTION: goto stop;
|
||||
case DASM_ESC: *cp++ = *p++; break;
|
||||
case DASM_REL_EXT:
|
||||
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4;
|
||||
goto patchrel;
|
||||
case DASM_ALIGN:
|
||||
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
|
||||
break;
|
||||
case DASM_REL_LG:
|
||||
if (n < 0) {
|
||||
n = (int)((ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp);
|
||||
goto patchrel;
|
||||
}
|
||||
/* fallthrough */
|
||||
case DASM_REL_PC:
|
||||
CK(n >= 0, UNDEF_PC);
|
||||
n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base);
|
||||
patchrel:
|
||||
CK((n & 3) == 0 &&
|
||||
(((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >>
|
||||
((ins & 2048) ? 16 : 26)) == 0, RANGE_REL);
|
||||
cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc));
|
||||
break;
|
||||
case DASM_LABEL_LG:
|
||||
ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
|
||||
break;
|
||||
case DASM_LABEL_PC: break;
|
||||
case DASM_IMM:
|
||||
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
|
||||
break;
|
||||
case DASM_IMMSH:
|
||||
cp[-1] |= (ins & 1) ? ((n&31)<<11)|((n&32)>>4) : ((n&31)<<6)|(n&32);
|
||||
break;
|
||||
default: *cp++ = ins; break;
|
||||
}
|
||||
}
|
||||
stop: (void)0;
|
||||
}
|
||||
}
|
||||
|
||||
if (base + D->codesize != (char *)cp) /* Check for phase errors. */
|
||||
return DASM_S_PHASE;
|
||||
return DASM_S_OK;
|
||||
}
|
||||
#undef CK
|
||||
|
||||
/* Get PC label offset. */
|
||||
int dasm_getpclabel(Dst_DECL, unsigned int pc)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
if (pc*sizeof(int) < D->pcsize) {
|
||||
int pos = D->pclabels[pc];
|
||||
if (pos < 0) return *DASM_POS2PTR(D, -pos);
|
||||
if (pos > 0) return -1; /* Undefined. */
|
||||
}
|
||||
return -2; /* Unused or out of range. */
|
||||
}
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
/* Optional sanity checker to call between isolated encoding steps. */
|
||||
int dasm_checkstep(Dst_DECL, int secmatch)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
if (D->status == DASM_S_OK) {
|
||||
int i;
|
||||
for (i = 1; i <= 9; i++) {
|
||||
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
|
||||
D->lglabels[i] = 0;
|
||||
}
|
||||
}
|
||||
if (D->status == DASM_S_OK && secmatch >= 0 &&
|
||||
D->section != &D->sections[secmatch])
|
||||
D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
|
||||
return D->status;
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
** DynASM encoding engine prototypes.
|
||||
** Copyright (C) 2005-2021 Mike Pall. All rights reserved.
|
||||
** Released under the MIT license. See dynasm.lua for full copyright notice.
|
||||
*/
|
||||
|
||||
#ifndef _DASM_PROTO_H
|
||||
#define _DASM_PROTO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define DASM_IDENT "DynASM 1.5.0"
|
||||
#define DASM_VERSION 10500 /* 1.5.0 */
|
||||
|
||||
#ifndef Dst_DECL
|
||||
#define Dst_DECL dasm_State **Dst
|
||||
#endif
|
||||
|
||||
#ifndef Dst_REF
|
||||
#define Dst_REF (*Dst)
|
||||
#endif
|
||||
|
||||
#ifndef DASM_FDEF
|
||||
#define DASM_FDEF extern
|
||||
#endif
|
||||
|
||||
#ifndef DASM_M_GROW
|
||||
#define DASM_M_GROW(ctx, t, p, sz, need) \
|
||||
do { \
|
||||
size_t _sz = (sz), _need = (need); \
|
||||
if (_sz < _need) { \
|
||||
if (_sz < 16) _sz = 16; \
|
||||
while (_sz < _need) _sz += _sz; \
|
||||
(p) = (t *)realloc((p), _sz); \
|
||||
if ((p) == NULL) exit(1); \
|
||||
(sz) = _sz; \
|
||||
} \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
#ifndef DASM_M_FREE
|
||||
#define DASM_M_FREE(ctx, p, sz) free(p)
|
||||
#endif
|
||||
|
||||
/* Internal DynASM encoder state. */
|
||||
typedef struct dasm_State dasm_State;
|
||||
|
||||
|
||||
/* Initialize and free DynASM state. */
|
||||
DASM_FDEF void dasm_init(Dst_DECL, int maxsection);
|
||||
DASM_FDEF void dasm_free(Dst_DECL);
|
||||
|
||||
/* Setup global array. Must be called before dasm_setup(). */
|
||||
DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl);
|
||||
|
||||
/* Grow PC label array. Can be called after dasm_setup(), too. */
|
||||
DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc);
|
||||
|
||||
/* Setup encoder. */
|
||||
DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist);
|
||||
|
||||
/* Feed encoder with actions. Calls are generated by pre-processor. */
|
||||
DASM_FDEF void dasm_put(Dst_DECL, int start, ...);
|
||||
|
||||
/* Link sections and return the resulting size. */
|
||||
DASM_FDEF int dasm_link(Dst_DECL, size_t *szp);
|
||||
|
||||
/* Encode sections into buffer. */
|
||||
DASM_FDEF int dasm_encode(Dst_DECL, void *buffer);
|
||||
|
||||
/* Get PC label offset. */
|
||||
DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc);
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
/* Optional sanity checker to call between isolated encoding steps. */
|
||||
DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch);
|
||||
#else
|
||||
#define dasm_checkstep(a, b) 0
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _DASM_PROTO_H */
|
|
@ -1,12 +0,0 @@
|
|||
------------------------------------------------------------------------------
|
||||
-- DynASM x64 module.
|
||||
--
|
||||
-- Copyright (C) 2005-2021 Mike Pall. All rights reserved.
|
||||
-- See dynasm.lua for full copyright notice.
|
||||
------------------------------------------------------------------------------
|
||||
-- This module just sets 64 bit mode for the combined x86/x64 module.
|
||||
-- All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
x64 = true -- Using a global is an ugly, but effective solution.
|
||||
return require("dasm_x86")
|
|
@ -1,540 +0,0 @@
|
|||
/*
|
||||
** DynASM x86 encoding engine.
|
||||
** Copyright (C) 2005-2021 Mike Pall. All rights reserved.
|
||||
** Released under the MIT license. See dynasm.lua for full copyright notice.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DASM_ARCH "x86"
|
||||
|
||||
#ifndef DASM_EXTERN
|
||||
#define DASM_EXTERN(a,b,c,d) 0
|
||||
#endif
|
||||
|
||||
/* Action definitions. DASM_STOP must be 255. */
|
||||
enum {
|
||||
DASM_DISP = 233,
|
||||
DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB,
|
||||
DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC,
|
||||
DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN,
|
||||
DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP
|
||||
};
|
||||
|
||||
/* Maximum number of section buffer positions for a single dasm_put() call. */
|
||||
#define DASM_MAXSECPOS 25
|
||||
|
||||
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
|
||||
#define DASM_S_OK 0x00000000
|
||||
#define DASM_S_NOMEM 0x01000000
|
||||
#define DASM_S_PHASE 0x02000000
|
||||
#define DASM_S_MATCH_SEC 0x03000000
|
||||
#define DASM_S_RANGE_I 0x11000000
|
||||
#define DASM_S_RANGE_SEC 0x12000000
|
||||
#define DASM_S_RANGE_LG 0x13000000
|
||||
#define DASM_S_RANGE_PC 0x14000000
|
||||
#define DASM_S_RANGE_VREG 0x15000000
|
||||
#define DASM_S_UNDEF_L 0x21000000
|
||||
#define DASM_S_UNDEF_PC 0x22000000
|
||||
|
||||
/* Macros to convert positions (8 bit section + 24 bit index). */
|
||||
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
|
||||
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
|
||||
#define DASM_SEC2POS(sec) ((sec)<<24)
|
||||
#define DASM_POS2SEC(pos) ((pos)>>24)
|
||||
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
|
||||
|
||||
/* Action list type. */
|
||||
typedef const unsigned char *dasm_ActList;
|
||||
|
||||
/* Per-section structure. */
|
||||
typedef struct dasm_Section {
|
||||
int *rbuf; /* Biased buffer pointer (negative section bias). */
|
||||
int *buf; /* True buffer pointer. */
|
||||
size_t bsize; /* Buffer size in bytes. */
|
||||
int pos; /* Biased buffer position. */
|
||||
int epos; /* End of biased buffer position - max single put. */
|
||||
int ofs; /* Byte offset into section. */
|
||||
} dasm_Section;
|
||||
|
||||
/* Core structure holding the DynASM encoding state. */
|
||||
struct dasm_State {
|
||||
size_t psize; /* Allocated size of this structure. */
|
||||
dasm_ActList actionlist; /* Current actionlist pointer. */
|
||||
int *lglabels; /* Local/global chain/pos ptrs. */
|
||||
size_t lgsize;
|
||||
int *pclabels; /* PC label chains/pos ptrs. */
|
||||
size_t pcsize;
|
||||
void **globals; /* Array of globals (bias -10). */
|
||||
dasm_Section *section; /* Pointer to active section. */
|
||||
size_t codesize; /* Total size of all code sections. */
|
||||
int maxsection; /* 0 <= sectionidx < maxsection. */
|
||||
int status; /* Status code. */
|
||||
dasm_Section sections[1]; /* All sections. Alloc-extended. */
|
||||
};
|
||||
|
||||
/* The size of the core structure depends on the max. number of sections. */
|
||||
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
|
||||
|
||||
/* Perform potentially overflowing pointer operations in a way that avoids UB. */
|
||||
#define DASM_PTR_SUB(p1, off) ((void *) ((uintptr_t) (p1) - sizeof(*p1) * (uintptr_t) (off)))
|
||||
#define DASM_PTR_ADD(p1, off) ((void *) ((uintptr_t) (p1) + sizeof(*p1) * (uintptr_t) (off)))
|
||||
|
||||
/* Initialize DynASM state. */
|
||||
void dasm_init(Dst_DECL, int maxsection)
|
||||
{
|
||||
dasm_State *D;
|
||||
size_t psz = 0;
|
||||
int i;
|
||||
Dst_REF = NULL;
|
||||
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
|
||||
D = Dst_REF;
|
||||
D->psize = psz;
|
||||
D->lglabels = NULL;
|
||||
D->lgsize = 0;
|
||||
D->pclabels = NULL;
|
||||
D->pcsize = 0;
|
||||
D->globals = NULL;
|
||||
D->maxsection = maxsection;
|
||||
for (i = 0; i < maxsection; i++) {
|
||||
D->sections[i].buf = NULL; /* Need this for pass3. */
|
||||
D->sections[i].rbuf = DASM_PTR_SUB(D->sections[i].buf, DASM_SEC2POS(i));
|
||||
D->sections[i].bsize = 0;
|
||||
D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Free DynASM state. */
|
||||
void dasm_free(Dst_DECL)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int i;
|
||||
for (i = 0; i < D->maxsection; i++)
|
||||
if (D->sections[i].buf)
|
||||
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
|
||||
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
|
||||
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
|
||||
DASM_M_FREE(Dst, D, D->psize);
|
||||
}
|
||||
|
||||
/* Setup global label array. Must be called before dasm_setup(). */
|
||||
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#endif
|
||||
D->globals = gl - 10; /* Negative bias to compensate for locals. */
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
|
||||
}
|
||||
|
||||
/* Grow PC label array. Can be called after dasm_setup(), too. */
|
||||
void dasm_growpc(Dst_DECL, unsigned int maxpc)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
size_t osz = D->pcsize;
|
||||
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
|
||||
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
|
||||
}
|
||||
|
||||
/* Setup encoder. */
|
||||
void dasm_setup(Dst_DECL, const void *actionlist)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int i;
|
||||
D->actionlist = (dasm_ActList)actionlist;
|
||||
D->status = DASM_S_OK;
|
||||
D->section = &D->sections[0];
|
||||
memset((void *)D->lglabels, 0, D->lgsize);
|
||||
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
|
||||
for (i = 0; i < D->maxsection; i++) {
|
||||
D->sections[i].pos = DASM_SEC2POS(i);
|
||||
D->sections[i].ofs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
#define CK(x, st) \
|
||||
do { if (!(x)) { \
|
||||
D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0)
|
||||
#define CKPL(kind, st) \
|
||||
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
|
||||
D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0)
|
||||
#else
|
||||
#define CK(x, st) ((void)0)
|
||||
#define CKPL(kind, st) ((void)0)
|
||||
#endif
|
||||
|
||||
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
|
||||
void dasm_put(Dst_DECL, int start, ...)
|
||||
{
|
||||
va_list ap;
|
||||
dasm_State *D = Dst_REF;
|
||||
dasm_ActList p = D->actionlist + start;
|
||||
dasm_Section *sec = D->section;
|
||||
int pos = sec->pos, ofs = sec->ofs, mrm = -1;
|
||||
int *b;
|
||||
|
||||
if (pos >= sec->epos) {
|
||||
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
|
||||
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
|
||||
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
|
||||
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
|
||||
}
|
||||
|
||||
b = sec->rbuf;
|
||||
b[pos++] = start;
|
||||
|
||||
va_start(ap, start);
|
||||
while (1) {
|
||||
int action = *p++;
|
||||
if (action < DASM_DISP) {
|
||||
ofs++;
|
||||
} else if (action <= DASM_REL_A) {
|
||||
int n = va_arg(ap, int);
|
||||
b[pos++] = n;
|
||||
switch (action) {
|
||||
case DASM_DISP:
|
||||
if (n == 0) { if (mrm < 0) mrm = p[-2]; if ((mrm&7) != 5) break; }
|
||||
/* fallthrough */
|
||||
case DASM_IMM_DB: if ((((unsigned)n+128)&-256) == 0) goto ob; /* fallthrough */
|
||||
case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */
|
||||
case DASM_IMM_D: ofs += 4; break;
|
||||
case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob;
|
||||
case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break;
|
||||
case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; /* fallthrough */
|
||||
case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break;
|
||||
case DASM_SPACE: p++; ofs += n; break;
|
||||
case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */
|
||||
case DASM_VREG: CK((n&-16) == 0 && (n != 4 || (*p>>5) != 2), RANGE_VREG);
|
||||
if (*p < 0x40 && p[1] == DASM_DISP) mrm = n;
|
||||
if (*p < 0x20 && (n&7) == 4) ofs++;
|
||||
switch ((*p++ >> 3) & 3) {
|
||||
case 3: n |= b[pos-3]; /* fallthrough */
|
||||
case 2: n |= b[pos-2]; /* fallthrough */
|
||||
case 1: if (n <= 7) { b[pos-1] |= 0x10; ofs--; }
|
||||
}
|
||||
continue;
|
||||
}
|
||||
mrm = -1;
|
||||
} else {
|
||||
int *pl, n;
|
||||
switch (action) {
|
||||
case DASM_REL_LG:
|
||||
case DASM_IMM_LG:
|
||||
n = *p++; pl = D->lglabels + n;
|
||||
/* Bkwd rel or global. */
|
||||
if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
|
||||
pl -= 246; n = *pl;
|
||||
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
|
||||
goto linkrel;
|
||||
case DASM_REL_PC:
|
||||
case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
|
||||
putrel:
|
||||
n = *pl;
|
||||
if (n < 0) { /* Label exists. Get label pos and store it. */
|
||||
b[pos] = -n;
|
||||
} else {
|
||||
linkrel:
|
||||
b[pos] = n; /* Else link to rel chain, anchored at label. */
|
||||
*pl = pos;
|
||||
}
|
||||
pos++;
|
||||
ofs += 4; /* Maximum offset needed. */
|
||||
if (action == DASM_REL_LG || action == DASM_REL_PC) {
|
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */
|
||||
} else if (sizeof(ptrdiff_t) == 8) {
|
||||
ofs += 4;
|
||||
}
|
||||
break;
|
||||
case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel;
|
||||
case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
|
||||
putlabel:
|
||||
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
|
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; }
|
||||
*pl = -pos; /* Label exists now. */
|
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */
|
||||
break;
|
||||
case DASM_ALIGN:
|
||||
ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */
|
||||
b[pos++] = ofs; /* Store pass1 offset estimate. */
|
||||
break;
|
||||
case DASM_EXTERN: p += 2; ofs += 4; break;
|
||||
case DASM_ESC: p++; ofs++; break;
|
||||
case DASM_MARK: mrm = p[-2]; break;
|
||||
case DASM_SECTION:
|
||||
n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n];
|
||||
case DASM_STOP: goto stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
stop:
|
||||
va_end(ap);
|
||||
sec->pos = pos;
|
||||
sec->ofs = ofs;
|
||||
}
|
||||
#undef CK
|
||||
|
||||
/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */
|
||||
int dasm_link(Dst_DECL, size_t *szp)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
int secnum;
|
||||
int ofs = 0;
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
*szp = 0;
|
||||
if (D->status != DASM_S_OK) return D->status;
|
||||
{
|
||||
int pc;
|
||||
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
|
||||
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
|
||||
}
|
||||
#endif
|
||||
|
||||
{ /* Handle globals not defined in this translation unit. */
|
||||
int idx;
|
||||
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
|
||||
int n = D->lglabels[idx];
|
||||
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
|
||||
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Combine all code sections. No support for data sections (yet). */
|
||||
for (secnum = 0; secnum < D->maxsection; secnum++) {
|
||||
dasm_Section *sec = D->sections + secnum;
|
||||
int *b = sec->rbuf;
|
||||
int pos = DASM_SEC2POS(secnum);
|
||||
int lastpos = sec->pos;
|
||||
|
||||
while (pos != lastpos) {
|
||||
dasm_ActList p = D->actionlist + b[pos++];
|
||||
int op = 0;
|
||||
while (1) {
|
||||
int action = *p++;
|
||||
switch (action) {
|
||||
case DASM_REL_LG: p++;
|
||||
/* fallthrough */
|
||||
case DASM_REL_PC: {
|
||||
int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0);
|
||||
if (shrink) { /* Shrinkable branch opcode? */
|
||||
int lofs, lpos = b[pos];
|
||||
if (lpos < 0) goto noshrink; /* Ext global? */
|
||||
lofs = *DASM_POS2PTR(D, lpos);
|
||||
if (lpos > pos) { /* Fwd label: add cumulative section offsets. */
|
||||
int i;
|
||||
for (i = secnum; i < DASM_POS2SEC(lpos); i++)
|
||||
lofs += D->sections[i].ofs;
|
||||
} else {
|
||||
lofs -= ofs; /* Bkwd label: unfix offset. */
|
||||
}
|
||||
lofs -= b[pos+1]; /* Short branch ok? */
|
||||
if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */
|
||||
else { noshrink: shrink = 0; } /* No, cannot shrink op. */
|
||||
}
|
||||
b[pos+1] = shrink;
|
||||
pos += 2;
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++;
|
||||
case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W:
|
||||
case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB:
|
||||
case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break;
|
||||
case DASM_LABEL_LG: p++;
|
||||
/* fallthrough */
|
||||
case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */
|
||||
case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */
|
||||
case DASM_EXTERN: p += 2; break;
|
||||
case DASM_ESC: op = *p++; break;
|
||||
case DASM_MARK: break;
|
||||
case DASM_SECTION: case DASM_STOP: goto stop;
|
||||
default: op = action; break;
|
||||
}
|
||||
}
|
||||
stop: (void)0;
|
||||
}
|
||||
ofs += sec->ofs; /* Next section starts right after current section. */
|
||||
}
|
||||
|
||||
D->codesize = ofs; /* Total size of all code sections */
|
||||
*szp = ofs;
|
||||
return DASM_S_OK;
|
||||
}
|
||||
|
||||
#define dasmb(x) *cp++ = (unsigned char)(x)
|
||||
#ifndef DASM_ALIGNED_WRITES
|
||||
typedef ZEND_SET_ALIGNED(1, unsigned short unaligned_short);
|
||||
typedef ZEND_SET_ALIGNED(1, unsigned int unaligned_int);
|
||||
typedef ZEND_SET_ALIGNED(1, unsigned long long unaligned_long_long);
|
||||
#define dasmw(x) \
|
||||
do { *((unaligned_short *)cp) = (unsigned short)(x); cp+=2; } while (0)
|
||||
#define dasmd(x) \
|
||||
do { *((unaligned_int *)cp) = (unsigned int)(x); cp+=4; } while (0)
|
||||
#define dasmq(x) \
|
||||
do { *((unaligned_long_long *)cp) = (unsigned long long)(x); cp+=8; } while (0)
|
||||
#else
|
||||
#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0)
|
||||
#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0)
|
||||
#define dasmq(x) do { dasmd(x); dasmd((x)>>32); } while (0)
|
||||
#endif
|
||||
static unsigned char *dasma_(unsigned char *cp, ptrdiff_t x)
|
||||
{
|
||||
if (sizeof(ptrdiff_t) == 8)
|
||||
dasmq((unsigned long long)x);
|
||||
else
|
||||
dasmd((unsigned int)x);
|
||||
return cp;
|
||||
}
|
||||
#define dasma(x) (cp = dasma_(cp, (x)))
|
||||
|
||||
/* Pass 3: Encode sections. */
|
||||
int dasm_encode(Dst_DECL, void *buffer)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
unsigned char *base = (unsigned char *)buffer;
|
||||
unsigned char *cp = base;
|
||||
int secnum;
|
||||
|
||||
/* Encode all code sections. No support for data sections (yet). */
|
||||
for (secnum = 0; secnum < D->maxsection; secnum++) {
|
||||
dasm_Section *sec = D->sections + secnum;
|
||||
int *b = sec->buf;
|
||||
int *endb = DASM_PTR_ADD(sec->rbuf, sec->pos);
|
||||
|
||||
while (b != endb) {
|
||||
dasm_ActList p = D->actionlist + *b++;
|
||||
unsigned char *mark = NULL;
|
||||
while (1) {
|
||||
int action = *p++;
|
||||
int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0;
|
||||
switch (action) {
|
||||
case DASM_DISP: if (!mark) mark = cp; {
|
||||
unsigned char *mm = mark;
|
||||
if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL;
|
||||
if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7;
|
||||
if (mrm != 5) { mm[-1] -= 0x80; break; } }
|
||||
if ((((unsigned)n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40;
|
||||
}
|
||||
/* fallthrough */
|
||||
case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break;
|
||||
case DASM_IMM_DB: if ((((unsigned)n+128)&-256) == 0) {
|
||||
db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb;
|
||||
} else mark = NULL;
|
||||
/* fallthrough */
|
||||
case DASM_IMM_D: wd: dasmd(n); break;
|
||||
case DASM_IMM_WB: if ((((unsigned)n+128)&-256) == 0) goto db; else mark = NULL;
|
||||
/* fallthrough */
|
||||
case DASM_IMM_W: dasmw(n); break;
|
||||
case DASM_VREG: {
|
||||
int t = *p++;
|
||||
unsigned char *ex = cp - (t&7);
|
||||
if ((n & 8) && t < 0xa0) {
|
||||
if (*ex & 0x80) ex[1] ^= 0x20 << (t>>6); else *ex ^= 1 << (t>>6);
|
||||
n &= 7;
|
||||
} else if (n & 0x10) {
|
||||
if (*ex & 0x80) {
|
||||
*ex = 0xc5; ex[1] = (ex[1] & 0x80) | ex[2]; ex += 2;
|
||||
}
|
||||
while (++ex < cp) ex[-1] = *ex;
|
||||
if (mark) mark--;
|
||||
cp--;
|
||||
n &= 7;
|
||||
}
|
||||
if (t >= 0xc0) n <<= 4;
|
||||
else if (t >= 0x40) n <<= 3;
|
||||
else if (n == 4 && t < 0x20) { cp[-1] ^= n; *cp++ = 0x20; }
|
||||
cp[-1] ^= n;
|
||||
break;
|
||||
}
|
||||
case DASM_REL_LG: p++; if (n >= 0) goto rel_pc;
|
||||
b++; n = (int)(ptrdiff_t)D->globals[-n];
|
||||
/* fallthrough */
|
||||
case DASM_REL_A: rel_a:
|
||||
n -= (unsigned int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */
|
||||
case DASM_REL_PC: rel_pc: {
|
||||
int shrink = *b++;
|
||||
int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; }
|
||||
n = *pb - ((int)(cp-base) + 4-shrink);
|
||||
if (shrink == 0) goto wd;
|
||||
if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb;
|
||||
goto wb;
|
||||
}
|
||||
case DASM_IMM_LG:
|
||||
p++;
|
||||
if (n < 0) { dasma((ptrdiff_t)D->globals[-n]); break; }
|
||||
/* fallthrough */
|
||||
case DASM_IMM_PC: {
|
||||
int *pb = DASM_POS2PTR(D, n);
|
||||
dasma(*pb < 0 ? (ptrdiff_t)pb[1] : (*pb + (ptrdiff_t)base));
|
||||
break;
|
||||
}
|
||||
case DASM_LABEL_LG: {
|
||||
int idx = *p++;
|
||||
if (idx >= 10)
|
||||
D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n));
|
||||
break;
|
||||
}
|
||||
case DASM_LABEL_PC: case DASM_SETLABEL: break;
|
||||
case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; }
|
||||
case DASM_ALIGN:
|
||||
n = *p++;
|
||||
while (((cp-base) & n)) *cp++ = 0x90; /* nop */
|
||||
break;
|
||||
case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd;
|
||||
case DASM_MARK: mark = cp; break;
|
||||
case DASM_ESC: action = *p++;
|
||||
/* fallthrough */
|
||||
default: *cp++ = action; break;
|
||||
case DASM_SECTION: case DASM_STOP: goto stop;
|
||||
}
|
||||
}
|
||||
stop: (void)0;
|
||||
}
|
||||
}
|
||||
|
||||
if (base + D->codesize != cp) /* Check for phase errors. */
|
||||
return DASM_S_PHASE;
|
||||
return DASM_S_OK;
|
||||
}
|
||||
|
||||
/* Get PC label offset. */
|
||||
int dasm_getpclabel(Dst_DECL, unsigned int pc)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
if (pc*sizeof(int) < D->pcsize) {
|
||||
int pos = D->pclabels[pc];
|
||||
if (pos < 0) return *DASM_POS2PTR(D, -pos);
|
||||
if (pos > 0) return -1; /* Undefined. */
|
||||
}
|
||||
return -2; /* Unused or out of range. */
|
||||
}
|
||||
|
||||
#ifdef DASM_CHECKS
|
||||
/* Optional sanity checker to call between isolated encoding steps. */
|
||||
int dasm_checkstep(Dst_DECL, int secmatch)
|
||||
{
|
||||
dasm_State *D = Dst_REF;
|
||||
if (D->status == DASM_S_OK) {
|
||||
int i;
|
||||
for (i = 1; i <= 9; i++) {
|
||||
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; }
|
||||
D->lglabels[i] = 0;
|
||||
}
|
||||
}
|
||||
if (D->status == DASM_S_OK && secmatch >= 0 &&
|
||||
D->section != &D->sections[secmatch])
|
||||
D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections);
|
||||
return D->status;
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,22 +0,0 @@
|
|||
Copyright (c) 2002-2012, Vivek Thampi <vivek.mt@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
File diff suppressed because it is too large
Load diff
|
@ -1,197 +0,0 @@
|
|||
/* udis86 - libudis86/decode.h
|
||||
*
|
||||
* Copyright (c) 2002-2009 Vivek Thampi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef UD_DECODE_H
|
||||
#define UD_DECODE_H
|
||||
|
||||
#include "types.h"
|
||||
#include "udint.h"
|
||||
#include "itab.h"
|
||||
|
||||
#define MAX_INSN_LENGTH 15
|
||||
|
||||
/* itab prefix bits */
|
||||
#define P_none ( 0 )
|
||||
|
||||
#define P_inv64 ( 1 << 0 )
|
||||
#define P_INV64(n) ( ( n >> 0 ) & 1 )
|
||||
#define P_def64 ( 1 << 1 )
|
||||
#define P_DEF64(n) ( ( n >> 1 ) & 1 )
|
||||
|
||||
#define P_oso ( 1 << 2 )
|
||||
#define P_OSO(n) ( ( n >> 2 ) & 1 )
|
||||
#define P_aso ( 1 << 3 )
|
||||
#define P_ASO(n) ( ( n >> 3 ) & 1 )
|
||||
|
||||
#define P_rexb ( 1 << 4 )
|
||||
#define P_REXB(n) ( ( n >> 4 ) & 1 )
|
||||
#define P_rexw ( 1 << 5 )
|
||||
#define P_REXW(n) ( ( n >> 5 ) & 1 )
|
||||
#define P_rexr ( 1 << 6 )
|
||||
#define P_REXR(n) ( ( n >> 6 ) & 1 )
|
||||
#define P_rexx ( 1 << 7 )
|
||||
#define P_REXX(n) ( ( n >> 7 ) & 1 )
|
||||
|
||||
#define P_seg ( 1 << 8 )
|
||||
#define P_SEG(n) ( ( n >> 8 ) & 1 )
|
||||
|
||||
#define P_vexl ( 1 << 9 )
|
||||
#define P_VEXL(n) ( ( n >> 9 ) & 1 )
|
||||
#define P_vexw ( 1 << 10 )
|
||||
#define P_VEXW(n) ( ( n >> 10 ) & 1 )
|
||||
|
||||
#define P_str ( 1 << 11 )
|
||||
#define P_STR(n) ( ( n >> 11 ) & 1 )
|
||||
#define P_strz ( 1 << 12 )
|
||||
#define P_STR_ZF(n) ( ( n >> 12 ) & 1 )
|
||||
|
||||
/* operand type constants -- order is important! */
|
||||
|
||||
enum ud_operand_code {
|
||||
OP_NONE,
|
||||
|
||||
OP_A, OP_E, OP_M, OP_G,
|
||||
OP_I, OP_F,
|
||||
|
||||
OP_R0, OP_R1, OP_R2, OP_R3,
|
||||
OP_R4, OP_R5, OP_R6, OP_R7,
|
||||
|
||||
OP_AL, OP_CL, OP_DL,
|
||||
OP_AX, OP_CX, OP_DX,
|
||||
OP_eAX, OP_eCX, OP_eDX,
|
||||
OP_rAX, OP_rCX, OP_rDX,
|
||||
|
||||
OP_ES, OP_CS, OP_SS, OP_DS,
|
||||
OP_FS, OP_GS,
|
||||
|
||||
OP_ST0, OP_ST1, OP_ST2, OP_ST3,
|
||||
OP_ST4, OP_ST5, OP_ST6, OP_ST7,
|
||||
|
||||
OP_J, OP_S, OP_O,
|
||||
OP_I1, OP_I3, OP_sI,
|
||||
|
||||
OP_V, OP_W, OP_Q, OP_P,
|
||||
OP_U, OP_N, OP_MU, OP_H,
|
||||
OP_L,
|
||||
|
||||
OP_R, OP_C, OP_D,
|
||||
|
||||
OP_MR
|
||||
} UD_ATTR_PACKED;
|
||||
|
||||
|
||||
/*
|
||||
* Operand size constants
|
||||
*
|
||||
* Symbolic constants for various operand sizes. Some of these constants
|
||||
* are given a value equal to the width of the data (SZ_B == 8), such
|
||||
* that they maybe used interchangeably in the internals. Modifying them
|
||||
* will most certainly break things!
|
||||
*/
|
||||
typedef uint16_t ud_operand_size_t;
|
||||
|
||||
#define SZ_NA 0
|
||||
#define SZ_Z 1
|
||||
#define SZ_V 2
|
||||
#define SZ_Y 3
|
||||
#define SZ_X 4
|
||||
#define SZ_RDQ 7
|
||||
#define SZ_B 8
|
||||
#define SZ_W 16
|
||||
#define SZ_D 32
|
||||
#define SZ_Q 64
|
||||
#define SZ_T 80
|
||||
#define SZ_O 12
|
||||
#define SZ_DQ 128 /* double quad */
|
||||
#define SZ_QQ 256 /* quad quad */
|
||||
|
||||
/*
|
||||
* Complex size types; that encode sizes for operands of type MR (memory or
|
||||
* register); for internal use only. Id space above 256.
|
||||
*/
|
||||
#define SZ_BD ((SZ_B << 8) | SZ_D)
|
||||
#define SZ_BV ((SZ_B << 8) | SZ_V)
|
||||
#define SZ_WD ((SZ_W << 8) | SZ_D)
|
||||
#define SZ_WV ((SZ_W << 8) | SZ_V)
|
||||
#define SZ_WY ((SZ_W << 8) | SZ_Y)
|
||||
#define SZ_DY ((SZ_D << 8) | SZ_Y)
|
||||
#define SZ_WO ((SZ_W << 8) | SZ_O)
|
||||
#define SZ_DO ((SZ_D << 8) | SZ_O)
|
||||
#define SZ_QO ((SZ_Q << 8) | SZ_O)
|
||||
|
||||
|
||||
/* resolve complex size type.
|
||||
*/
|
||||
static UD_INLINE ud_operand_size_t
|
||||
Mx_mem_size(ud_operand_size_t size)
|
||||
{
|
||||
return (size >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static UD_INLINE ud_operand_size_t
|
||||
Mx_reg_size(ud_operand_size_t size)
|
||||
{
|
||||
return size & 0xff;
|
||||
}
|
||||
|
||||
/* A single operand of an entry in the instruction table.
|
||||
* (internal use only)
|
||||
*/
|
||||
struct ud_itab_entry_operand
|
||||
{
|
||||
enum ud_operand_code type;
|
||||
ud_operand_size_t size;
|
||||
};
|
||||
|
||||
|
||||
/* A single entry in an instruction table.
|
||||
*(internal use only)
|
||||
*/
|
||||
struct ud_itab_entry
|
||||
{
|
||||
enum ud_mnemonic_code mnemonic;
|
||||
struct ud_itab_entry_operand operand1;
|
||||
struct ud_itab_entry_operand operand2;
|
||||
struct ud_itab_entry_operand operand3;
|
||||
struct ud_itab_entry_operand operand4;
|
||||
uint32_t prefix;
|
||||
};
|
||||
|
||||
struct ud_lookup_table_list_entry {
|
||||
const uint16_t *table;
|
||||
enum ud_table_type type;
|
||||
const char *meta;
|
||||
};
|
||||
|
||||
extern struct ud_itab_entry ud_itab[];
|
||||
extern struct ud_lookup_table_list_entry ud_lookup_table_list[];
|
||||
|
||||
#endif /* UD_DECODE_H */
|
||||
|
||||
/* vim:cindent
|
||||
* vim:expandtab
|
||||
* vim:ts=4
|
||||
* vim:sw=4
|
||||
*/
|
|
@ -1,113 +0,0 @@
|
|||
/* udis86 - libudis86/extern.h
|
||||
*
|
||||
* Copyright (c) 2002-2009, 2013 Vivek Thampi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef UD_EXTERN_H
|
||||
#define UD_EXTERN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#if defined(_MSC_VER) && defined(_USRDLL)
|
||||
# ifdef LIBUDIS86_EXPORTS
|
||||
# define LIBUDIS86_DLLEXTERN __declspec(dllexport)
|
||||
# else
|
||||
# define LIBUDIS86_DLLEXTERN __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define LIBUDIS86_DLLEXTERN
|
||||
#endif
|
||||
|
||||
/* ============================= PUBLIC API ================================= */
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_init(struct ud*);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_set_mode(struct ud*, uint8_t);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_set_pc(struct ud*, uint64_t);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_set_input_hook(struct ud*, int (*)(struct ud*));
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_set_input_buffer(struct ud*, const uint8_t*, size_t);
|
||||
|
||||
#ifndef __UD_STANDALONE__
|
||||
extern LIBUDIS86_DLLEXTERN void ud_set_input_file(struct ud*, FILE*);
|
||||
#endif /* __UD_STANDALONE__ */
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_set_vendor(struct ud*, unsigned);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_set_syntax(struct ud*, void (*)(struct ud*));
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_input_skip(struct ud*, size_t);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN int ud_input_end(const struct ud*);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN unsigned int ud_decode(struct ud*);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN unsigned int ud_disassemble(struct ud*);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_translate_intel(struct ud*);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_translate_att(struct ud*);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN const char* ud_insn_asm(const struct ud* u);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN const uint8_t* ud_insn_ptr(const struct ud* u);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN uint64_t ud_insn_off(const struct ud*);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN const char* ud_insn_hex(struct ud*);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN unsigned int ud_insn_len(const struct ud* u);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN const struct ud_operand* ud_insn_opr(const struct ud *u, unsigned int n);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN int ud_opr_is_sreg(const struct ud_operand *opr);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN int ud_opr_is_gpr(const struct ud_operand *opr);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN enum ud_mnemonic_code ud_insn_mnemonic(const struct ud *u);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN const char* ud_lookup_mnemonic(enum ud_mnemonic_code c);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_set_user_opaque_data(struct ud*, void*);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void* ud_get_user_opaque_data(const struct ud*);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_set_asm_buffer(struct ud *u, char *buf, size_t size);
|
||||
|
||||
extern LIBUDIS86_DLLEXTERN void ud_set_sym_resolver(struct ud *u,
|
||||
const char* (*resolver)(struct ud*,
|
||||
uint64_t addr,
|
||||
int64_t *offset));
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* UD_EXTERN_H */
|
File diff suppressed because it is too large
Load diff
|
@ -1,939 +0,0 @@
|
|||
#ifndef UD_ITAB_H
|
||||
#define UD_ITAB_H
|
||||
|
||||
/* itab.h -- generated by udis86:scripts/ud_itab.py, do no edit */
|
||||
|
||||
/* ud_table_type -- lookup table types (see decode.c) */
|
||||
enum ud_table_type {
|
||||
UD_TAB__OPC_VEX,
|
||||
UD_TAB__OPC_TABLE,
|
||||
UD_TAB__OPC_X87,
|
||||
UD_TAB__OPC_MOD,
|
||||
UD_TAB__OPC_RM,
|
||||
UD_TAB__OPC_OSIZE,
|
||||
UD_TAB__OPC_MODE,
|
||||
UD_TAB__OPC_VEX_L,
|
||||
UD_TAB__OPC_3DNOW,
|
||||
UD_TAB__OPC_REG,
|
||||
UD_TAB__OPC_ASIZE,
|
||||
UD_TAB__OPC_VEX_W,
|
||||
UD_TAB__OPC_SSE,
|
||||
UD_TAB__OPC_VENDOR
|
||||
};
|
||||
|
||||
/* ud_mnemonic -- mnemonic constants */
|
||||
enum ud_mnemonic_code {
|
||||
UD_Iaaa,
|
||||
UD_Iaad,
|
||||
UD_Iaam,
|
||||
UD_Iaas,
|
||||
UD_Iadc,
|
||||
UD_Iadd,
|
||||
UD_Iaddpd,
|
||||
UD_Iaddps,
|
||||
UD_Iaddsd,
|
||||
UD_Iaddss,
|
||||
UD_Iaddsubpd,
|
||||
UD_Iaddsubps,
|
||||
UD_Iaesdec,
|
||||
UD_Iaesdeclast,
|
||||
UD_Iaesenc,
|
||||
UD_Iaesenclast,
|
||||
UD_Iaesimc,
|
||||
UD_Iaeskeygenassist,
|
||||
UD_Iand,
|
||||
UD_Iandnpd,
|
||||
UD_Iandnps,
|
||||
UD_Iandpd,
|
||||
UD_Iandps,
|
||||
UD_Iarpl,
|
||||
UD_Iblendpd,
|
||||
UD_Iblendps,
|
||||
UD_Iblendvpd,
|
||||
UD_Iblendvps,
|
||||
UD_Ibound,
|
||||
UD_Ibsf,
|
||||
UD_Ibsr,
|
||||
UD_Ibswap,
|
||||
UD_Ibt,
|
||||
UD_Ibtc,
|
||||
UD_Ibtr,
|
||||
UD_Ibts,
|
||||
UD_Icall,
|
||||
UD_Icbw,
|
||||
UD_Icdq,
|
||||
UD_Icdqe,
|
||||
UD_Iclc,
|
||||
UD_Icld,
|
||||
UD_Iclflush,
|
||||
UD_Iclgi,
|
||||
UD_Icli,
|
||||
UD_Iclts,
|
||||
UD_Icmc,
|
||||
UD_Icmova,
|
||||
UD_Icmovae,
|
||||
UD_Icmovb,
|
||||
UD_Icmovbe,
|
||||
UD_Icmovg,
|
||||
UD_Icmovge,
|
||||
UD_Icmovl,
|
||||
UD_Icmovle,
|
||||
UD_Icmovno,
|
||||
UD_Icmovnp,
|
||||
UD_Icmovns,
|
||||
UD_Icmovnz,
|
||||
UD_Icmovo,
|
||||
UD_Icmovp,
|
||||
UD_Icmovs,
|
||||
UD_Icmovz,
|
||||
UD_Icmp,
|
||||
UD_Icmppd,
|
||||
UD_Icmpps,
|
||||
UD_Icmpsb,
|
||||
UD_Icmpsd,
|
||||
UD_Icmpsq,
|
||||
UD_Icmpss,
|
||||
UD_Icmpsw,
|
||||
UD_Icmpxchg,
|
||||
UD_Icmpxchg16b,
|
||||
UD_Icmpxchg8b,
|
||||
UD_Icomisd,
|
||||
UD_Icomiss,
|
||||
UD_Icpuid,
|
||||
UD_Icqo,
|
||||
UD_Icrc32,
|
||||
UD_Icvtdq2pd,
|
||||
UD_Icvtdq2ps,
|
||||
UD_Icvtpd2dq,
|
||||
UD_Icvtpd2pi,
|
||||
UD_Icvtpd2ps,
|
||||
UD_Icvtpi2pd,
|
||||
UD_Icvtpi2ps,
|
||||
UD_Icvtps2dq,
|
||||
UD_Icvtps2pd,
|
||||
UD_Icvtps2pi,
|
||||
UD_Icvtsd2si,
|
||||
UD_Icvtsd2ss,
|
||||
UD_Icvtsi2sd,
|
||||
UD_Icvtsi2ss,
|
||||
UD_Icvtss2sd,
|
||||
UD_Icvtss2si,
|
||||
UD_Icvttpd2dq,
|
||||
UD_Icvttpd2pi,
|
||||
UD_Icvttps2dq,
|
||||
UD_Icvttps2pi,
|
||||
UD_Icvttsd2si,
|
||||
UD_Icvttss2si,
|
||||
UD_Icwd,
|
||||
UD_Icwde,
|
||||
UD_Idaa,
|
||||
UD_Idas,
|
||||
UD_Idec,
|
||||
UD_Idiv,
|
||||
UD_Idivpd,
|
||||
UD_Idivps,
|
||||
UD_Idivsd,
|
||||
UD_Idivss,
|
||||
UD_Idppd,
|
||||
UD_Idpps,
|
||||
UD_Iemms,
|
||||
UD_Ienter,
|
||||
UD_Iextractps,
|
||||
UD_If2xm1,
|
||||
UD_Ifabs,
|
||||
UD_Ifadd,
|
||||
UD_Ifaddp,
|
||||
UD_Ifbld,
|
||||
UD_Ifbstp,
|
||||
UD_Ifchs,
|
||||
UD_Ifclex,
|
||||
UD_Ifcmovb,
|
||||
UD_Ifcmovbe,
|
||||
UD_Ifcmove,
|
||||
UD_Ifcmovnb,
|
||||
UD_Ifcmovnbe,
|
||||
UD_Ifcmovne,
|
||||
UD_Ifcmovnu,
|
||||
UD_Ifcmovu,
|
||||
UD_Ifcom,
|
||||
UD_Ifcom2,
|
||||
UD_Ifcomi,
|
||||
UD_Ifcomip,
|
||||
UD_Ifcomp,
|
||||
UD_Ifcomp3,
|
||||
UD_Ifcomp5,
|
||||
UD_Ifcompp,
|
||||
UD_Ifcos,
|
||||
UD_Ifdecstp,
|
||||
UD_Ifdiv,
|
||||
UD_Ifdivp,
|
||||
UD_Ifdivr,
|
||||
UD_Ifdivrp,
|
||||
UD_Ifemms,
|
||||
UD_Iffree,
|
||||
UD_Iffreep,
|
||||
UD_Ifiadd,
|
||||
UD_Ificom,
|
||||
UD_Ificomp,
|
||||
UD_Ifidiv,
|
||||
UD_Ifidivr,
|
||||
UD_Ifild,
|
||||
UD_Ifimul,
|
||||
UD_Ifincstp,
|
||||
UD_Ifist,
|
||||
UD_Ifistp,
|
||||
UD_Ifisttp,
|
||||
UD_Ifisub,
|
||||
UD_Ifisubr,
|
||||
UD_Ifld,
|
||||
UD_Ifld1,
|
||||
UD_Ifldcw,
|
||||
UD_Ifldenv,
|
||||
UD_Ifldl2e,
|
||||
UD_Ifldl2t,
|
||||
UD_Ifldlg2,
|
||||
UD_Ifldln2,
|
||||
UD_Ifldpi,
|
||||
UD_Ifldz,
|
||||
UD_Ifmul,
|
||||
UD_Ifmulp,
|
||||
UD_Ifndisi,
|
||||
UD_Ifneni,
|
||||
UD_Ifninit,
|
||||
UD_Ifnop,
|
||||
UD_Ifnsave,
|
||||
UD_Ifnsetpm,
|
||||
UD_Ifnstcw,
|
||||
UD_Ifnstenv,
|
||||
UD_Ifnstsw,
|
||||
UD_Ifpatan,
|
||||
UD_Ifprem,
|
||||
UD_Ifprem1,
|
||||
UD_Ifptan,
|
||||
UD_Ifrndint,
|
||||
UD_Ifrstor,
|
||||
UD_Ifrstpm,
|
||||
UD_Ifscale,
|
||||
UD_Ifsin,
|
||||
UD_Ifsincos,
|
||||
UD_Ifsqrt,
|
||||
UD_Ifst,
|
||||
UD_Ifstp,
|
||||
UD_Ifstp1,
|
||||
UD_Ifstp8,
|
||||
UD_Ifstp9,
|
||||
UD_Ifsub,
|
||||
UD_Ifsubp,
|
||||
UD_Ifsubr,
|
||||
UD_Ifsubrp,
|
||||
UD_Iftst,
|
||||
UD_Ifucom,
|
||||
UD_Ifucomi,
|
||||
UD_Ifucomip,
|
||||
UD_Ifucomp,
|
||||
UD_Ifucompp,
|
||||
UD_Ifxam,
|
||||
UD_Ifxch,
|
||||
UD_Ifxch4,
|
||||
UD_Ifxch7,
|
||||
UD_Ifxrstor,
|
||||
UD_Ifxsave,
|
||||
UD_Ifxtract,
|
||||
UD_Ifyl2x,
|
||||
UD_Ifyl2xp1,
|
||||
UD_Igetsec,
|
||||
UD_Ihaddpd,
|
||||
UD_Ihaddps,
|
||||
UD_Ihlt,
|
||||
UD_Ihsubpd,
|
||||
UD_Ihsubps,
|
||||
UD_Iidiv,
|
||||
UD_Iimul,
|
||||
UD_Iin,
|
||||
UD_Iinc,
|
||||
UD_Iinsb,
|
||||
UD_Iinsd,
|
||||
UD_Iinsertps,
|
||||
UD_Iinsw,
|
||||
UD_Iint,
|
||||
UD_Iint1,
|
||||
UD_Iint3,
|
||||
UD_Iinto,
|
||||
UD_Iinvd,
|
||||
UD_Iinvept,
|
||||
UD_Iinvlpg,
|
||||
UD_Iinvlpga,
|
||||
UD_Iinvvpid,
|
||||
UD_Iiretd,
|
||||
UD_Iiretq,
|
||||
UD_Iiretw,
|
||||
UD_Ija,
|
||||
UD_Ijae,
|
||||
UD_Ijb,
|
||||
UD_Ijbe,
|
||||
UD_Ijcxz,
|
||||
UD_Ijecxz,
|
||||
UD_Ijg,
|
||||
UD_Ijge,
|
||||
UD_Ijl,
|
||||
UD_Ijle,
|
||||
UD_Ijmp,
|
||||
UD_Ijno,
|
||||
UD_Ijnp,
|
||||
UD_Ijns,
|
||||
UD_Ijnz,
|
||||
UD_Ijo,
|
||||
UD_Ijp,
|
||||
UD_Ijrcxz,
|
||||
UD_Ijs,
|
||||
UD_Ijz,
|
||||
UD_Ilahf,
|
||||
UD_Ilar,
|
||||
UD_Ilddqu,
|
||||
UD_Ildmxcsr,
|
||||
UD_Ilds,
|
||||
UD_Ilea,
|
||||
UD_Ileave,
|
||||
UD_Iles,
|
||||
UD_Ilfence,
|
||||
UD_Ilfs,
|
||||
UD_Ilgdt,
|
||||
UD_Ilgs,
|
||||
UD_Ilidt,
|
||||
UD_Illdt,
|
||||
UD_Ilmsw,
|
||||
UD_Ilock,
|
||||
UD_Ilodsb,
|
||||
UD_Ilodsd,
|
||||
UD_Ilodsq,
|
||||
UD_Ilodsw,
|
||||
UD_Iloop,
|
||||
UD_Iloope,
|
||||
UD_Iloopne,
|
||||
UD_Ilsl,
|
||||
UD_Ilss,
|
||||
UD_Iltr,
|
||||
UD_Imaskmovdqu,
|
||||
UD_Imaskmovq,
|
||||
UD_Imaxpd,
|
||||
UD_Imaxps,
|
||||
UD_Imaxsd,
|
||||
UD_Imaxss,
|
||||
UD_Imfence,
|
||||
UD_Iminpd,
|
||||
UD_Iminps,
|
||||
UD_Iminsd,
|
||||
UD_Iminss,
|
||||
UD_Imonitor,
|
||||
UD_Imontmul,
|
||||
UD_Imov,
|
||||
UD_Imovapd,
|
||||
UD_Imovaps,
|
||||
UD_Imovbe,
|
||||
UD_Imovd,
|
||||
UD_Imovddup,
|
||||
UD_Imovdq2q,
|
||||
UD_Imovdqa,
|
||||
UD_Imovdqu,
|
||||
UD_Imovhlps,
|
||||
UD_Imovhpd,
|
||||
UD_Imovhps,
|
||||
UD_Imovlhps,
|
||||
UD_Imovlpd,
|
||||
UD_Imovlps,
|
||||
UD_Imovmskpd,
|
||||
UD_Imovmskps,
|
||||
UD_Imovntdq,
|
||||
UD_Imovntdqa,
|
||||
UD_Imovnti,
|
||||
UD_Imovntpd,
|
||||
UD_Imovntps,
|
||||
UD_Imovntq,
|
||||
UD_Imovq,
|
||||
UD_Imovq2dq,
|
||||
UD_Imovsb,
|
||||
UD_Imovsd,
|
||||
UD_Imovshdup,
|
||||
UD_Imovsldup,
|
||||
UD_Imovsq,
|
||||
UD_Imovss,
|
||||
UD_Imovsw,
|
||||
UD_Imovsx,
|
||||
UD_Imovsxd,
|
||||
UD_Imovupd,
|
||||
UD_Imovups,
|
||||
UD_Imovzx,
|
||||
UD_Impsadbw,
|
||||
UD_Imul,
|
||||
UD_Imulpd,
|
||||
UD_Imulps,
|
||||
UD_Imulsd,
|
||||
UD_Imulss,
|
||||
UD_Imwait,
|
||||
UD_Ineg,
|
||||
UD_Inop,
|
||||
UD_Inot,
|
||||
UD_Ior,
|
||||
UD_Iorpd,
|
||||
UD_Iorps,
|
||||
UD_Iout,
|
||||
UD_Ioutsb,
|
||||
UD_Ioutsd,
|
||||
UD_Ioutsw,
|
||||
UD_Ipabsb,
|
||||
UD_Ipabsd,
|
||||
UD_Ipabsw,
|
||||
UD_Ipackssdw,
|
||||
UD_Ipacksswb,
|
||||
UD_Ipackusdw,
|
||||
UD_Ipackuswb,
|
||||
UD_Ipaddb,
|
||||
UD_Ipaddd,
|
||||
UD_Ipaddq,
|
||||
UD_Ipaddsb,
|
||||
UD_Ipaddsw,
|
||||
UD_Ipaddusb,
|
||||
UD_Ipaddusw,
|
||||
UD_Ipaddw,
|
||||
UD_Ipalignr,
|
||||
UD_Ipand,
|
||||
UD_Ipandn,
|
||||
UD_Ipavgb,
|
||||
UD_Ipavgusb,
|
||||
UD_Ipavgw,
|
||||
UD_Ipblendvb,
|
||||
UD_Ipblendw,
|
||||
UD_Ipclmulqdq,
|
||||
UD_Ipcmpeqb,
|
||||
UD_Ipcmpeqd,
|
||||
UD_Ipcmpeqq,
|
||||
UD_Ipcmpeqw,
|
||||
UD_Ipcmpestri,
|
||||
UD_Ipcmpestrm,
|
||||
UD_Ipcmpgtb,
|
||||
UD_Ipcmpgtd,
|
||||
UD_Ipcmpgtq,
|
||||
UD_Ipcmpgtw,
|
||||
UD_Ipcmpistri,
|
||||
UD_Ipcmpistrm,
|
||||
UD_Ipextrb,
|
||||
UD_Ipextrd,
|
||||
UD_Ipextrq,
|
||||
UD_Ipextrw,
|
||||
UD_Ipf2id,
|
||||
UD_Ipf2iw,
|
||||
UD_Ipfacc,
|
||||
UD_Ipfadd,
|
||||
UD_Ipfcmpeq,
|
||||
UD_Ipfcmpge,
|
||||
UD_Ipfcmpgt,
|
||||
UD_Ipfmax,
|
||||
UD_Ipfmin,
|
||||
UD_Ipfmul,
|
||||
UD_Ipfnacc,
|
||||
UD_Ipfpnacc,
|
||||
UD_Ipfrcp,
|
||||
UD_Ipfrcpit1,
|
||||
UD_Ipfrcpit2,
|
||||
UD_Ipfrsqit1,
|
||||
UD_Ipfrsqrt,
|
||||
UD_Ipfsub,
|
||||
UD_Ipfsubr,
|
||||
UD_Iphaddd,
|
||||
UD_Iphaddsw,
|
||||
UD_Iphaddw,
|
||||
UD_Iphminposuw,
|
||||
UD_Iphsubd,
|
||||
UD_Iphsubsw,
|
||||
UD_Iphsubw,
|
||||
UD_Ipi2fd,
|
||||
UD_Ipi2fw,
|
||||
UD_Ipinsrb,
|
||||
UD_Ipinsrd,
|
||||
UD_Ipinsrq,
|
||||
UD_Ipinsrw,
|
||||
UD_Ipmaddubsw,
|
||||
UD_Ipmaddwd,
|
||||
UD_Ipmaxsb,
|
||||
UD_Ipmaxsd,
|
||||
UD_Ipmaxsw,
|
||||
UD_Ipmaxub,
|
||||
UD_Ipmaxud,
|
||||
UD_Ipmaxuw,
|
||||
UD_Ipminsb,
|
||||
UD_Ipminsd,
|
||||
UD_Ipminsw,
|
||||
UD_Ipminub,
|
||||
UD_Ipminud,
|
||||
UD_Ipminuw,
|
||||
UD_Ipmovmskb,
|
||||
UD_Ipmovsxbd,
|
||||
UD_Ipmovsxbq,
|
||||
UD_Ipmovsxbw,
|
||||
UD_Ipmovsxdq,
|
||||
UD_Ipmovsxwd,
|
||||
UD_Ipmovsxwq,
|
||||
UD_Ipmovzxbd,
|
||||
UD_Ipmovzxbq,
|
||||
UD_Ipmovzxbw,
|
||||
UD_Ipmovzxdq,
|
||||
UD_Ipmovzxwd,
|
||||
UD_Ipmovzxwq,
|
||||
UD_Ipmuldq,
|
||||
UD_Ipmulhrsw,
|
||||
UD_Ipmulhrw,
|
||||
UD_Ipmulhuw,
|
||||
UD_Ipmulhw,
|
||||
UD_Ipmulld,
|
||||
UD_Ipmullw,
|
||||
UD_Ipmuludq,
|
||||
UD_Ipop,
|
||||
UD_Ipopa,
|
||||
UD_Ipopad,
|
||||
UD_Ipopcnt,
|
||||
UD_Ipopfd,
|
||||
UD_Ipopfq,
|
||||
UD_Ipopfw,
|
||||
UD_Ipor,
|
||||
UD_Iprefetch,
|
||||
UD_Iprefetchnta,
|
||||
UD_Iprefetcht0,
|
||||
UD_Iprefetcht1,
|
||||
UD_Iprefetcht2,
|
||||
UD_Ipsadbw,
|
||||
UD_Ipshufb,
|
||||
UD_Ipshufd,
|
||||
UD_Ipshufhw,
|
||||
UD_Ipshuflw,
|
||||
UD_Ipshufw,
|
||||
UD_Ipsignb,
|
||||
UD_Ipsignd,
|
||||
UD_Ipsignw,
|
||||
UD_Ipslld,
|
||||
UD_Ipslldq,
|
||||
UD_Ipsllq,
|
||||
UD_Ipsllw,
|
||||
UD_Ipsrad,
|
||||
UD_Ipsraw,
|
||||
UD_Ipsrld,
|
||||
UD_Ipsrldq,
|
||||
UD_Ipsrlq,
|
||||
UD_Ipsrlw,
|
||||
UD_Ipsubb,
|
||||
UD_Ipsubd,
|
||||
UD_Ipsubq,
|
||||
UD_Ipsubsb,
|
||||
UD_Ipsubsw,
|
||||
UD_Ipsubusb,
|
||||
UD_Ipsubusw,
|
||||
UD_Ipsubw,
|
||||
UD_Ipswapd,
|
||||
UD_Iptest,
|
||||
UD_Ipunpckhbw,
|
||||
UD_Ipunpckhdq,
|
||||
UD_Ipunpckhqdq,
|
||||
UD_Ipunpckhwd,
|
||||
UD_Ipunpcklbw,
|
||||
UD_Ipunpckldq,
|
||||
UD_Ipunpcklqdq,
|
||||
UD_Ipunpcklwd,
|
||||
UD_Ipush,
|
||||
UD_Ipusha,
|
||||
UD_Ipushad,
|
||||
UD_Ipushfd,
|
||||
UD_Ipushfq,
|
||||
UD_Ipushfw,
|
||||
UD_Ipxor,
|
||||
UD_Ircl,
|
||||
UD_Ircpps,
|
||||
UD_Ircpss,
|
||||
UD_Ircr,
|
||||
UD_Irdmsr,
|
||||
UD_Irdpmc,
|
||||
UD_Irdrand,
|
||||
UD_Irdtsc,
|
||||
UD_Irdtscp,
|
||||
UD_Irep,
|
||||
UD_Irepne,
|
||||
UD_Iret,
|
||||
UD_Iretf,
|
||||
UD_Irol,
|
||||
UD_Iror,
|
||||
UD_Iroundpd,
|
||||
UD_Iroundps,
|
||||
UD_Iroundsd,
|
||||
UD_Iroundss,
|
||||
UD_Irsm,
|
||||
UD_Irsqrtps,
|
||||
UD_Irsqrtss,
|
||||
UD_Isahf,
|
||||
UD_Isalc,
|
||||
UD_Isar,
|
||||
UD_Isbb,
|
||||
UD_Iscasb,
|
||||
UD_Iscasd,
|
||||
UD_Iscasq,
|
||||
UD_Iscasw,
|
||||
UD_Iseta,
|
||||
UD_Isetae,
|
||||
UD_Isetb,
|
||||
UD_Isetbe,
|
||||
UD_Isetg,
|
||||
UD_Isetge,
|
||||
UD_Isetl,
|
||||
UD_Isetle,
|
||||
UD_Isetno,
|
||||
UD_Isetnp,
|
||||
UD_Isetns,
|
||||
UD_Isetnz,
|
||||
UD_Iseto,
|
||||
UD_Isetp,
|
||||
UD_Isets,
|
||||
UD_Isetz,
|
||||
UD_Isfence,
|
||||
UD_Isgdt,
|
||||
UD_Ishl,
|
||||
UD_Ishld,
|
||||
UD_Ishr,
|
||||
UD_Ishrd,
|
||||
UD_Ishufpd,
|
||||
UD_Ishufps,
|
||||
UD_Isidt,
|
||||
UD_Iskinit,
|
||||
UD_Isldt,
|
||||
UD_Ismsw,
|
||||
UD_Isqrtpd,
|
||||
UD_Isqrtps,
|
||||
UD_Isqrtsd,
|
||||
UD_Isqrtss,
|
||||
UD_Istc,
|
||||
UD_Istd,
|
||||
UD_Istgi,
|
||||
UD_Isti,
|
||||
UD_Istmxcsr,
|
||||
UD_Istosb,
|
||||
UD_Istosd,
|
||||
UD_Istosq,
|
||||
UD_Istosw,
|
||||
UD_Istr,
|
||||
UD_Isub,
|
||||
UD_Isubpd,
|
||||
UD_Isubps,
|
||||
UD_Isubsd,
|
||||
UD_Isubss,
|
||||
UD_Iswapgs,
|
||||
UD_Isyscall,
|
||||
UD_Isysenter,
|
||||
UD_Isysexit,
|
||||
UD_Isysret,
|
||||
UD_Itest,
|
||||
UD_Iucomisd,
|
||||
UD_Iucomiss,
|
||||
UD_Iud2,
|
||||
UD_Iunpckhpd,
|
||||
UD_Iunpckhps,
|
||||
UD_Iunpcklpd,
|
||||
UD_Iunpcklps,
|
||||
UD_Ivaddpd,
|
||||
UD_Ivaddps,
|
||||
UD_Ivaddsd,
|
||||
UD_Ivaddss,
|
||||
UD_Ivaddsubpd,
|
||||
UD_Ivaddsubps,
|
||||
UD_Ivaesdec,
|
||||
UD_Ivaesdeclast,
|
||||
UD_Ivaesenc,
|
||||
UD_Ivaesenclast,
|
||||
UD_Ivaesimc,
|
||||
UD_Ivaeskeygenassist,
|
||||
UD_Ivandnpd,
|
||||
UD_Ivandnps,
|
||||
UD_Ivandpd,
|
||||
UD_Ivandps,
|
||||
UD_Ivblendpd,
|
||||
UD_Ivblendps,
|
||||
UD_Ivblendvpd,
|
||||
UD_Ivblendvps,
|
||||
UD_Ivbroadcastsd,
|
||||
UD_Ivbroadcastss,
|
||||
UD_Ivcmppd,
|
||||
UD_Ivcmpps,
|
||||
UD_Ivcmpsd,
|
||||
UD_Ivcmpss,
|
||||
UD_Ivcomisd,
|
||||
UD_Ivcomiss,
|
||||
UD_Ivcvtdq2pd,
|
||||
UD_Ivcvtdq2ps,
|
||||
UD_Ivcvtpd2dq,
|
||||
UD_Ivcvtpd2ps,
|
||||
UD_Ivcvtps2dq,
|
||||
UD_Ivcvtps2pd,
|
||||
UD_Ivcvtsd2si,
|
||||
UD_Ivcvtsd2ss,
|
||||
UD_Ivcvtsi2sd,
|
||||
UD_Ivcvtsi2ss,
|
||||
UD_Ivcvtss2sd,
|
||||
UD_Ivcvtss2si,
|
||||
UD_Ivcvttpd2dq,
|
||||
UD_Ivcvttps2dq,
|
||||
UD_Ivcvttsd2si,
|
||||
UD_Ivcvttss2si,
|
||||
UD_Ivdivpd,
|
||||
UD_Ivdivps,
|
||||
UD_Ivdivsd,
|
||||
UD_Ivdivss,
|
||||
UD_Ivdppd,
|
||||
UD_Ivdpps,
|
||||
UD_Iverr,
|
||||
UD_Iverw,
|
||||
UD_Ivextractf128,
|
||||
UD_Ivextractps,
|
||||
UD_Ivhaddpd,
|
||||
UD_Ivhaddps,
|
||||
UD_Ivhsubpd,
|
||||
UD_Ivhsubps,
|
||||
UD_Ivinsertf128,
|
||||
UD_Ivinsertps,
|
||||
UD_Ivlddqu,
|
||||
UD_Ivmaskmovdqu,
|
||||
UD_Ivmaskmovpd,
|
||||
UD_Ivmaskmovps,
|
||||
UD_Ivmaxpd,
|
||||
UD_Ivmaxps,
|
||||
UD_Ivmaxsd,
|
||||
UD_Ivmaxss,
|
||||
UD_Ivmcall,
|
||||
UD_Ivmclear,
|
||||
UD_Ivminpd,
|
||||
UD_Ivminps,
|
||||
UD_Ivminsd,
|
||||
UD_Ivminss,
|
||||
UD_Ivmlaunch,
|
||||
UD_Ivmload,
|
||||
UD_Ivmmcall,
|
||||
UD_Ivmovapd,
|
||||
UD_Ivmovaps,
|
||||
UD_Ivmovd,
|
||||
UD_Ivmovddup,
|
||||
UD_Ivmovdqa,
|
||||
UD_Ivmovdqu,
|
||||
UD_Ivmovhlps,
|
||||
UD_Ivmovhpd,
|
||||
UD_Ivmovhps,
|
||||
UD_Ivmovlhps,
|
||||
UD_Ivmovlpd,
|
||||
UD_Ivmovlps,
|
||||
UD_Ivmovmskpd,
|
||||
UD_Ivmovmskps,
|
||||
UD_Ivmovntdq,
|
||||
UD_Ivmovntdqa,
|
||||
UD_Ivmovntpd,
|
||||
UD_Ivmovntps,
|
||||
UD_Ivmovq,
|
||||
UD_Ivmovsd,
|
||||
UD_Ivmovshdup,
|
||||
UD_Ivmovsldup,
|
||||
UD_Ivmovss,
|
||||
UD_Ivmovupd,
|
||||
UD_Ivmovups,
|
||||
UD_Ivmpsadbw,
|
||||
UD_Ivmptrld,
|
||||
UD_Ivmptrst,
|
||||
UD_Ivmread,
|
||||
UD_Ivmresume,
|
||||
UD_Ivmrun,
|
||||
UD_Ivmsave,
|
||||
UD_Ivmulpd,
|
||||
UD_Ivmulps,
|
||||
UD_Ivmulsd,
|
||||
UD_Ivmulss,
|
||||
UD_Ivmwrite,
|
||||
UD_Ivmxoff,
|
||||
UD_Ivmxon,
|
||||
UD_Ivorpd,
|
||||
UD_Ivorps,
|
||||
UD_Ivpabsb,
|
||||
UD_Ivpabsd,
|
||||
UD_Ivpabsw,
|
||||
UD_Ivpackssdw,
|
||||
UD_Ivpacksswb,
|
||||
UD_Ivpackusdw,
|
||||
UD_Ivpackuswb,
|
||||
UD_Ivpaddb,
|
||||
UD_Ivpaddd,
|
||||
UD_Ivpaddq,
|
||||
UD_Ivpaddsb,
|
||||
UD_Ivpaddsw,
|
||||
UD_Ivpaddusb,
|
||||
UD_Ivpaddusw,
|
||||
UD_Ivpaddw,
|
||||
UD_Ivpalignr,
|
||||
UD_Ivpand,
|
||||
UD_Ivpandn,
|
||||
UD_Ivpavgb,
|
||||
UD_Ivpavgw,
|
||||
UD_Ivpblendvb,
|
||||
UD_Ivpblendw,
|
||||
UD_Ivpclmulqdq,
|
||||
UD_Ivpcmpeqb,
|
||||
UD_Ivpcmpeqd,
|
||||
UD_Ivpcmpeqq,
|
||||
UD_Ivpcmpeqw,
|
||||
UD_Ivpcmpestri,
|
||||
UD_Ivpcmpestrm,
|
||||
UD_Ivpcmpgtb,
|
||||
UD_Ivpcmpgtd,
|
||||
UD_Ivpcmpgtq,
|
||||
UD_Ivpcmpgtw,
|
||||
UD_Ivpcmpistri,
|
||||
UD_Ivpcmpistrm,
|
||||
UD_Ivperm2f128,
|
||||
UD_Ivpermilpd,
|
||||
UD_Ivpermilps,
|
||||
UD_Ivpextrb,
|
||||
UD_Ivpextrd,
|
||||
UD_Ivpextrq,
|
||||
UD_Ivpextrw,
|
||||
UD_Ivphaddd,
|
||||
UD_Ivphaddsw,
|
||||
UD_Ivphaddw,
|
||||
UD_Ivphminposuw,
|
||||
UD_Ivphsubd,
|
||||
UD_Ivphsubsw,
|
||||
UD_Ivphsubw,
|
||||
UD_Ivpinsrb,
|
||||
UD_Ivpinsrd,
|
||||
UD_Ivpinsrq,
|
||||
UD_Ivpinsrw,
|
||||
UD_Ivpmaddubsw,
|
||||
UD_Ivpmaddwd,
|
||||
UD_Ivpmaxsb,
|
||||
UD_Ivpmaxsd,
|
||||
UD_Ivpmaxsw,
|
||||
UD_Ivpmaxub,
|
||||
UD_Ivpmaxud,
|
||||
UD_Ivpmaxuw,
|
||||
UD_Ivpminsb,
|
||||
UD_Ivpminsd,
|
||||
UD_Ivpminsw,
|
||||
UD_Ivpminub,
|
||||
UD_Ivpminud,
|
||||
UD_Ivpminuw,
|
||||
UD_Ivpmovmskb,
|
||||
UD_Ivpmovsxbd,
|
||||
UD_Ivpmovsxbq,
|
||||
UD_Ivpmovsxbw,
|
||||
UD_Ivpmovsxwd,
|
||||
UD_Ivpmovsxwq,
|
||||
UD_Ivpmovzxbd,
|
||||
UD_Ivpmovzxbq,
|
||||
UD_Ivpmovzxbw,
|
||||
UD_Ivpmovzxdq,
|
||||
UD_Ivpmovzxwd,
|
||||
UD_Ivpmovzxwq,
|
||||
UD_Ivpmuldq,
|
||||
UD_Ivpmulhrsw,
|
||||
UD_Ivpmulhuw,
|
||||
UD_Ivpmulhw,
|
||||
UD_Ivpmulld,
|
||||
UD_Ivpmullw,
|
||||
UD_Ivpor,
|
||||
UD_Ivpsadbw,
|
||||
UD_Ivpshufb,
|
||||
UD_Ivpshufd,
|
||||
UD_Ivpshufhw,
|
||||
UD_Ivpshuflw,
|
||||
UD_Ivpsignb,
|
||||
UD_Ivpsignd,
|
||||
UD_Ivpsignw,
|
||||
UD_Ivpslld,
|
||||
UD_Ivpslldq,
|
||||
UD_Ivpsllq,
|
||||
UD_Ivpsllw,
|
||||
UD_Ivpsrad,
|
||||
UD_Ivpsraw,
|
||||
UD_Ivpsrld,
|
||||
UD_Ivpsrldq,
|
||||
UD_Ivpsrlq,
|
||||
UD_Ivpsrlw,
|
||||
UD_Ivpsubb,
|
||||
UD_Ivpsubd,
|
||||
UD_Ivpsubq,
|
||||
UD_Ivpsubsb,
|
||||
UD_Ivpsubsw,
|
||||
UD_Ivpsubusb,
|
||||
UD_Ivpsubusw,
|
||||
UD_Ivpsubw,
|
||||
UD_Ivptest,
|
||||
UD_Ivpunpckhbw,
|
||||
UD_Ivpunpckhdq,
|
||||
UD_Ivpunpckhqdq,
|
||||
UD_Ivpunpckhwd,
|
||||
UD_Ivpunpcklbw,
|
||||
UD_Ivpunpckldq,
|
||||
UD_Ivpunpcklqdq,
|
||||
UD_Ivpunpcklwd,
|
||||
UD_Ivpxor,
|
||||
UD_Ivrcpps,
|
||||
UD_Ivrcpss,
|
||||
UD_Ivroundpd,
|
||||
UD_Ivroundps,
|
||||
UD_Ivroundsd,
|
||||
UD_Ivroundss,
|
||||
UD_Ivrsqrtps,
|
||||
UD_Ivrsqrtss,
|
||||
UD_Ivshufpd,
|
||||
UD_Ivshufps,
|
||||
UD_Ivsqrtpd,
|
||||
UD_Ivsqrtps,
|
||||
UD_Ivsqrtsd,
|
||||
UD_Ivsqrtss,
|
||||
UD_Ivstmxcsr,
|
||||
UD_Ivsubpd,
|
||||
UD_Ivsubps,
|
||||
UD_Ivsubsd,
|
||||
UD_Ivsubss,
|
||||
UD_Ivtestpd,
|
||||
UD_Ivtestps,
|
||||
UD_Ivucomisd,
|
||||
UD_Ivucomiss,
|
||||
UD_Ivunpckhpd,
|
||||
UD_Ivunpckhps,
|
||||
UD_Ivunpcklpd,
|
||||
UD_Ivunpcklps,
|
||||
UD_Ivxorpd,
|
||||
UD_Ivxorps,
|
||||
UD_Ivzeroall,
|
||||
UD_Ivzeroupper,
|
||||
UD_Iwait,
|
||||
UD_Iwbinvd,
|
||||
UD_Iwrmsr,
|
||||
UD_Ixadd,
|
||||
UD_Ixchg,
|
||||
UD_Ixcryptcbc,
|
||||
UD_Ixcryptcfb,
|
||||
UD_Ixcryptctr,
|
||||
UD_Ixcryptecb,
|
||||
UD_Ixcryptofb,
|
||||
UD_Ixgetbv,
|
||||
UD_Ixlatb,
|
||||
UD_Ixor,
|
||||
UD_Ixorpd,
|
||||
UD_Ixorps,
|
||||
UD_Ixrstor,
|
||||
UD_Ixsave,
|
||||
UD_Ixsetbv,
|
||||
UD_Ixsha1,
|
||||
UD_Ixsha256,
|
||||
UD_Ixstore,
|
||||
UD_Iinvalid,
|
||||
UD_I3dnow,
|
||||
UD_Inone,
|
||||
UD_Idb,
|
||||
UD_Ipause,
|
||||
UD_MAX_MNEMONIC_CODE
|
||||
};
|
||||
|
||||
extern const char * ud_mnemonics_str[];
|
||||
|
||||
#endif /* UD_ITAB_H */
|
|
@ -1,228 +0,0 @@
|
|||
/* udis86 - libudis86/syn-att.c
|
||||
*
|
||||
* Copyright (c) 2002-2009 Vivek Thampi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "types.h"
|
||||
#include "extern.h"
|
||||
#include "decode.h"
|
||||
#include "itab.h"
|
||||
#include "syn.h"
|
||||
#include "udint.h"
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* opr_cast() - Prints an operand cast.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
opr_cast(struct ud* u, struct ud_operand* op)
|
||||
{
|
||||
switch(op->size) {
|
||||
case 16 : case 32 :
|
||||
ud_asmprintf(u, "*"); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* gen_operand() - Generates assembly output for each operand.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
gen_operand(struct ud* u, struct ud_operand* op)
|
||||
{
|
||||
switch(op->type) {
|
||||
case UD_OP_CONST:
|
||||
ud_asmprintf(u, "$0x%x", op->lval.udword);
|
||||
break;
|
||||
|
||||
case UD_OP_REG:
|
||||
ud_asmprintf(u, "%%%s", ud_reg_tab[op->base - UD_R_AL]);
|
||||
break;
|
||||
|
||||
case UD_OP_MEM:
|
||||
if (u->br_far) {
|
||||
opr_cast(u, op);
|
||||
}
|
||||
if (u->pfx_seg) {
|
||||
ud_asmprintf(u, "%%%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]);
|
||||
}
|
||||
if (op->offset != 0) {
|
||||
ud_syn_print_mem_disp(u, op, 0);
|
||||
}
|
||||
if (op->base) {
|
||||
ud_asmprintf(u, "(%%%s", ud_reg_tab[op->base - UD_R_AL]);
|
||||
}
|
||||
if (op->index) {
|
||||
if (op->base) {
|
||||
ud_asmprintf(u, ",");
|
||||
} else {
|
||||
ud_asmprintf(u, "(");
|
||||
}
|
||||
ud_asmprintf(u, "%%%s", ud_reg_tab[op->index - UD_R_AL]);
|
||||
}
|
||||
if (op->scale) {
|
||||
ud_asmprintf(u, ",%d", op->scale);
|
||||
}
|
||||
if (op->base || op->index) {
|
||||
ud_asmprintf(u, ")");
|
||||
}
|
||||
break;
|
||||
|
||||
case UD_OP_IMM:
|
||||
ud_asmprintf(u, "$");
|
||||
ud_syn_print_imm(u, op);
|
||||
break;
|
||||
|
||||
case UD_OP_JIMM:
|
||||
ud_syn_print_addr(u, ud_syn_rel_target(u, op));
|
||||
break;
|
||||
|
||||
case UD_OP_PTR:
|
||||
switch (op->size) {
|
||||
case 32:
|
||||
ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg,
|
||||
op->lval.ptr.off & 0xFFFF);
|
||||
break;
|
||||
case 48:
|
||||
ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg,
|
||||
op->lval.ptr.off);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
/* =============================================================================
|
||||
* translates to AT&T syntax
|
||||
* =============================================================================
|
||||
*/
|
||||
extern void
|
||||
ud_translate_att(struct ud *u)
|
||||
{
|
||||
int size = 0;
|
||||
int star = 0;
|
||||
|
||||
/* check if P_OSO prefix is used */
|
||||
if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) {
|
||||
switch (u->dis_mode) {
|
||||
case 16:
|
||||
ud_asmprintf(u, "o32 ");
|
||||
break;
|
||||
case 32:
|
||||
case 64:
|
||||
ud_asmprintf(u, "o16 ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if P_ASO prefix was used */
|
||||
if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) {
|
||||
switch (u->dis_mode) {
|
||||
case 16:
|
||||
ud_asmprintf(u, "a32 ");
|
||||
break;
|
||||
case 32:
|
||||
ud_asmprintf(u, "a16 ");
|
||||
break;
|
||||
case 64:
|
||||
ud_asmprintf(u, "a32 ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (u->pfx_lock)
|
||||
ud_asmprintf(u, "lock ");
|
||||
if (u->pfx_rep) {
|
||||
ud_asmprintf(u, "rep ");
|
||||
} else if (u->pfx_repe) {
|
||||
ud_asmprintf(u, "repe ");
|
||||
} else if (u->pfx_repne) {
|
||||
ud_asmprintf(u, "repne ");
|
||||
}
|
||||
|
||||
/* special instructions */
|
||||
switch (u->mnemonic) {
|
||||
case UD_Iretf:
|
||||
ud_asmprintf(u, "lret ");
|
||||
break;
|
||||
case UD_Idb:
|
||||
ud_asmprintf(u, ".byte 0x%x", u->operand[0].lval.ubyte);
|
||||
return;
|
||||
case UD_Ijmp:
|
||||
case UD_Icall:
|
||||
if (u->br_far) ud_asmprintf(u, "l");
|
||||
if (u->operand[0].type == UD_OP_REG) {
|
||||
star = 1;
|
||||
}
|
||||
ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
|
||||
break;
|
||||
case UD_Ibound:
|
||||
case UD_Ienter:
|
||||
if (u->operand[0].type != UD_NONE)
|
||||
gen_operand(u, &u->operand[0]);
|
||||
if (u->operand[1].type != UD_NONE) {
|
||||
ud_asmprintf(u, ",");
|
||||
gen_operand(u, &u->operand[1]);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
|
||||
}
|
||||
|
||||
if (size == 8) {
|
||||
ud_asmprintf(u, "b");
|
||||
} else if (size == 16) {
|
||||
ud_asmprintf(u, "w");
|
||||
} else if (size == 64) {
|
||||
ud_asmprintf(u, "q");
|
||||
}
|
||||
|
||||
if (star) {
|
||||
ud_asmprintf(u, " *");
|
||||
} else {
|
||||
ud_asmprintf(u, " ");
|
||||
}
|
||||
|
||||
if (u->operand[3].type != UD_NONE) {
|
||||
gen_operand(u, &u->operand[3]);
|
||||
ud_asmprintf(u, ", ");
|
||||
}
|
||||
if (u->operand[2].type != UD_NONE) {
|
||||
gen_operand(u, &u->operand[2]);
|
||||
ud_asmprintf(u, ", ");
|
||||
}
|
||||
if (u->operand[1].type != UD_NONE) {
|
||||
gen_operand(u, &u->operand[1]);
|
||||
ud_asmprintf(u, ", ");
|
||||
}
|
||||
if (u->operand[0].type != UD_NONE) {
|
||||
gen_operand(u, &u->operand[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
vim: set ts=2 sw=2 expandtab
|
||||
*/
|
|
@ -1,224 +0,0 @@
|
|||
/* udis86 - libudis86/syn-intel.c
|
||||
*
|
||||
* Copyright (c) 2002-2013 Vivek Thampi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "types.h"
|
||||
#include "extern.h"
|
||||
#include "decode.h"
|
||||
#include "itab.h"
|
||||
#include "syn.h"
|
||||
#include "udint.h"
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* opr_cast() - Prints an operand cast.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
opr_cast(struct ud* u, struct ud_operand* op)
|
||||
{
|
||||
if (u->br_far) {
|
||||
ud_asmprintf(u, "far ");
|
||||
}
|
||||
switch(op->size) {
|
||||
case 8: ud_asmprintf(u, "byte " ); break;
|
||||
case 16: ud_asmprintf(u, "word " ); break;
|
||||
case 32: ud_asmprintf(u, "dword "); break;
|
||||
case 64: ud_asmprintf(u, "qword "); break;
|
||||
case 80: ud_asmprintf(u, "tword "); break;
|
||||
case 128: ud_asmprintf(u, "oword "); break;
|
||||
case 256: ud_asmprintf(u, "yword "); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* gen_operand() - Generates assembly output for each operand.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast)
|
||||
{
|
||||
switch(op->type) {
|
||||
case UD_OP_REG:
|
||||
ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]);
|
||||
break;
|
||||
|
||||
case UD_OP_MEM:
|
||||
if (syn_cast) {
|
||||
opr_cast(u, op);
|
||||
}
|
||||
ud_asmprintf(u, "[");
|
||||
if (u->pfx_seg) {
|
||||
ud_asmprintf(u, "%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]);
|
||||
}
|
||||
if (op->base) {
|
||||
ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]);
|
||||
}
|
||||
if (op->index) {
|
||||
ud_asmprintf(u, "%s%s", op->base != UD_NONE? "+" : "",
|
||||
ud_reg_tab[op->index - UD_R_AL]);
|
||||
if (op->scale) {
|
||||
ud_asmprintf(u, "*%d", op->scale);
|
||||
}
|
||||
}
|
||||
if (op->offset != 0) {
|
||||
ud_syn_print_mem_disp(u, op, (op->base != UD_NONE ||
|
||||
op->index != UD_NONE) ? 1 : 0);
|
||||
}
|
||||
ud_asmprintf(u, "]");
|
||||
break;
|
||||
|
||||
case UD_OP_IMM:
|
||||
ud_syn_print_imm(u, op);
|
||||
break;
|
||||
|
||||
|
||||
case UD_OP_JIMM:
|
||||
ud_syn_print_addr(u, ud_syn_rel_target(u, op));
|
||||
break;
|
||||
|
||||
case UD_OP_PTR:
|
||||
switch (op->size) {
|
||||
case 32:
|
||||
ud_asmprintf(u, "word 0x%x:0x%x", op->lval.ptr.seg,
|
||||
op->lval.ptr.off & 0xFFFF);
|
||||
break;
|
||||
case 48:
|
||||
ud_asmprintf(u, "dword 0x%x:0x%x", op->lval.ptr.seg,
|
||||
op->lval.ptr.off);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case UD_OP_CONST:
|
||||
if (syn_cast) opr_cast(u, op);
|
||||
ud_asmprintf(u, "%d", op->lval.udword);
|
||||
break;
|
||||
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
/* =============================================================================
|
||||
* translates to intel syntax
|
||||
* =============================================================================
|
||||
*/
|
||||
extern void
|
||||
ud_translate_intel(struct ud* u)
|
||||
{
|
||||
/* check if P_OSO prefix is used */
|
||||
if (!P_OSO(u->itab_entry->prefix) && u->pfx_opr) {
|
||||
switch (u->dis_mode) {
|
||||
case 16: ud_asmprintf(u, "o32 "); break;
|
||||
case 32:
|
||||
case 64: ud_asmprintf(u, "o16 "); break;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if P_ASO prefix was used */
|
||||
if (!P_ASO(u->itab_entry->prefix) && u->pfx_adr) {
|
||||
switch (u->dis_mode) {
|
||||
case 16: ud_asmprintf(u, "a32 "); break;
|
||||
case 32: ud_asmprintf(u, "a16 "); break;
|
||||
case 64: ud_asmprintf(u, "a32 "); break;
|
||||
}
|
||||
}
|
||||
|
||||
if (u->pfx_seg &&
|
||||
u->operand[0].type != UD_OP_MEM &&
|
||||
u->operand[1].type != UD_OP_MEM ) {
|
||||
ud_asmprintf(u, "%s ", ud_reg_tab[u->pfx_seg - UD_R_AL]);
|
||||
}
|
||||
|
||||
if (u->pfx_lock) {
|
||||
ud_asmprintf(u, "lock ");
|
||||
}
|
||||
if (u->pfx_rep) {
|
||||
ud_asmprintf(u, "rep ");
|
||||
} else if (u->pfx_repe) {
|
||||
ud_asmprintf(u, "repe ");
|
||||
} else if (u->pfx_repne) {
|
||||
ud_asmprintf(u, "repne ");
|
||||
}
|
||||
|
||||
/* print the instruction mnemonic */
|
||||
ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
|
||||
|
||||
if (u->operand[0].type != UD_NONE) {
|
||||
int cast = 0;
|
||||
ud_asmprintf(u, " ");
|
||||
if (u->operand[0].type == UD_OP_MEM) {
|
||||
if (u->operand[1].type == UD_OP_IMM ||
|
||||
u->operand[1].type == UD_OP_CONST ||
|
||||
u->operand[1].type == UD_NONE ||
|
||||
(u->operand[0].size != u->operand[1].size)) {
|
||||
cast = 1;
|
||||
} else if (u->operand[1].type == UD_OP_REG &&
|
||||
u->operand[1].base == UD_R_CL) {
|
||||
switch (u->mnemonic) {
|
||||
case UD_Ircl:
|
||||
case UD_Irol:
|
||||
case UD_Iror:
|
||||
case UD_Ircr:
|
||||
case UD_Ishl:
|
||||
case UD_Ishr:
|
||||
case UD_Isar:
|
||||
cast = 1;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
gen_operand(u, &u->operand[0], cast);
|
||||
}
|
||||
|
||||
if (u->operand[1].type != UD_NONE) {
|
||||
int cast = 0;
|
||||
ud_asmprintf(u, ", ");
|
||||
if (u->operand[1].type == UD_OP_MEM &&
|
||||
u->operand[0].size != u->operand[1].size &&
|
||||
!ud_opr_is_sreg(&u->operand[0])) {
|
||||
cast = 1;
|
||||
}
|
||||
gen_operand(u, &u->operand[1], cast);
|
||||
}
|
||||
|
||||
if (u->operand[2].type != UD_NONE) {
|
||||
int cast = 0;
|
||||
ud_asmprintf(u, ", ");
|
||||
if (u->operand[2].type == UD_OP_MEM &&
|
||||
u->operand[2].size != u->operand[1].size) {
|
||||
cast = 1;
|
||||
}
|
||||
gen_operand(u, &u->operand[2], cast);
|
||||
}
|
||||
|
||||
if (u->operand[3].type != UD_NONE) {
|
||||
ud_asmprintf(u, ", ");
|
||||
gen_operand(u, &u->operand[3], 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
vim: set ts=2 sw=2 expandtab
|
||||
*/
|
|
@ -1,258 +0,0 @@
|
|||
/* udis86 - libudis86/syn.c
|
||||
*
|
||||
* Copyright (c) 2002-2013 Vivek Thampi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "types.h"
|
||||
#include "decode.h"
|
||||
#include "syn.h"
|
||||
#include "udint.h"
|
||||
|
||||
/*
|
||||
* Register Table - Order Matters (types.h)!
|
||||
*
|
||||
*/
|
||||
const char* ud_reg_tab[] =
|
||||
{
|
||||
"al", "cl", "dl", "bl",
|
||||
"ah", "ch", "dh", "bh",
|
||||
"spl", "bpl", "sil", "dil",
|
||||
"r8b", "r9b", "r10b", "r11b",
|
||||
"r12b", "r13b", "r14b", "r15b",
|
||||
|
||||
"ax", "cx", "dx", "bx",
|
||||
"sp", "bp", "si", "di",
|
||||
"r8w", "r9w", "r10w", "r11w",
|
||||
"r12w", "r13w", "r14w", "r15w",
|
||||
|
||||
"eax", "ecx", "edx", "ebx",
|
||||
"esp", "ebp", "esi", "edi",
|
||||
"r8d", "r9d", "r10d", "r11d",
|
||||
"r12d", "r13d", "r14d", "r15d",
|
||||
|
||||
"rax", "rcx", "rdx", "rbx",
|
||||
"rsp", "rbp", "rsi", "rdi",
|
||||
"r8", "r9", "r10", "r11",
|
||||
"r12", "r13", "r14", "r15",
|
||||
|
||||
"es", "cs", "ss", "ds",
|
||||
"fs", "gs",
|
||||
|
||||
"cr0", "cr1", "cr2", "cr3",
|
||||
"cr4", "cr5", "cr6", "cr7",
|
||||
"cr8", "cr9", "cr10", "cr11",
|
||||
"cr12", "cr13", "cr14", "cr15",
|
||||
|
||||
"dr0", "dr1", "dr2", "dr3",
|
||||
"dr4", "dr5", "dr6", "dr7",
|
||||
"dr8", "dr9", "dr10", "dr11",
|
||||
"dr12", "dr13", "dr14", "dr15",
|
||||
|
||||
"mm0", "mm1", "mm2", "mm3",
|
||||
"mm4", "mm5", "mm6", "mm7",
|
||||
|
||||
"st0", "st1", "st2", "st3",
|
||||
"st4", "st5", "st6", "st7",
|
||||
|
||||
"xmm0", "xmm1", "xmm2", "xmm3",
|
||||
"xmm4", "xmm5", "xmm6", "xmm7",
|
||||
"xmm8", "xmm9", "xmm10", "xmm11",
|
||||
"xmm12", "xmm13", "xmm14", "xmm15",
|
||||
|
||||
"ymm0", "ymm1", "ymm2", "ymm3",
|
||||
"ymm4", "ymm5", "ymm6", "ymm7",
|
||||
"ymm8", "ymm9", "ymm10", "ymm11",
|
||||
"ymm12", "ymm13", "ymm14", "ymm15",
|
||||
|
||||
"rip"
|
||||
};
|
||||
|
||||
|
||||
uint64_t
|
||||
ud_syn_rel_target(struct ud *u, struct ud_operand *opr)
|
||||
{
|
||||
#if 1
|
||||
const uint64_t trunc_mask = 0xffffffffffffffffull >> (64 - u->adr_mode);
|
||||
#else
|
||||
const uint64_t trunc_mask = 0xffffffffffffffffull >> (64 - u->opr_mode);
|
||||
#endif
|
||||
switch (opr->size) {
|
||||
case 8 : return (u->pc + opr->lval.sbyte) & trunc_mask;
|
||||
case 16: return (u->pc + opr->lval.sword) & trunc_mask;
|
||||
case 32: return (u->pc + opr->lval.sdword) & trunc_mask;
|
||||
default: UD_ASSERT(!"invalid relative offset size.");
|
||||
return 0ull;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* asmprintf
|
||||
* Printf style function for printing translated assembly
|
||||
* output. Returns the number of characters written and
|
||||
* moves the buffer pointer forward. On an overflow,
|
||||
* returns a negative number and truncates the output.
|
||||
*/
|
||||
int
|
||||
ud_asmprintf(struct ud *u, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
int avail;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
avail = u->asm_buf_size - u->asm_buf_fill - 1 /* nullchar */;
|
||||
ret = vsnprintf((char*) u->asm_buf + u->asm_buf_fill, avail, fmt, ap);
|
||||
if (ret < 0 || ret > avail) {
|
||||
u->asm_buf_fill = u->asm_buf_size - 1;
|
||||
} else {
|
||||
u->asm_buf_fill += ret;
|
||||
}
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ud_syn_print_addr(struct ud *u, uint64_t addr)
|
||||
{
|
||||
const char *name = NULL;
|
||||
if (u->sym_resolver) {
|
||||
int64_t offset = 0;
|
||||
name = u->sym_resolver(u, addr, &offset);
|
||||
if (name) {
|
||||
if (offset) {
|
||||
ud_asmprintf(u, "%s%+" FMT64 "d", name, offset);
|
||||
} else {
|
||||
ud_asmprintf(u, "%s", name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
ud_asmprintf(u, "0x%" FMT64 "x", addr);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ud_syn_print_imm(struct ud* u, const struct ud_operand *op)
|
||||
{
|
||||
uint64_t v;
|
||||
if (op->_oprcode == OP_sI && op->size != u->opr_mode) {
|
||||
if (op->size == 8) {
|
||||
v = (int64_t)op->lval.sbyte;
|
||||
} else {
|
||||
UD_ASSERT(op->size == 32);
|
||||
v = (int64_t)op->lval.sdword;
|
||||
}
|
||||
if (u->opr_mode < 64) {
|
||||
v = v & ((1ull << u->opr_mode) - 1ull);
|
||||
}
|
||||
} else {
|
||||
switch (op->size) {
|
||||
case 8 : v = op->lval.ubyte; break;
|
||||
case 16: v = op->lval.uword; break;
|
||||
case 32: v = op->lval.udword; break;
|
||||
case 64: v = op->lval.uqword; break;
|
||||
default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
|
||||
}
|
||||
}
|
||||
#if 1
|
||||
if (u->sym_resolver) {
|
||||
int64_t offset = 0;
|
||||
const char *name = u->sym_resolver(u, v, &offset);
|
||||
if (name) {
|
||||
if (offset) {
|
||||
ud_asmprintf(u, "%s%+" FMT64 "d", name, offset);
|
||||
} else {
|
||||
ud_asmprintf(u, "%s", name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ud_asmprintf(u, "0x%" FMT64 "x", v);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *op, int sign)
|
||||
{
|
||||
UD_ASSERT(op->offset != 0);
|
||||
if (op->base == UD_NONE && op->index == UD_NONE) {
|
||||
uint64_t v;
|
||||
UD_ASSERT(op->scale == UD_NONE && op->offset != 8);
|
||||
/* unsigned mem-offset */
|
||||
switch (op->offset) {
|
||||
case 16: v = op->lval.uword; break;
|
||||
case 32: v = op->lval.udword; break;
|
||||
case 64: v = op->lval.uqword; break;
|
||||
default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
|
||||
}
|
||||
#if 1
|
||||
if (u->sym_resolver) {
|
||||
int64_t offset = 0;
|
||||
const char *name = u->sym_resolver(u, v, &offset);
|
||||
if (name) {
|
||||
if (offset) {
|
||||
ud_asmprintf(u, "%s%+" FMT64 "d", name, offset);
|
||||
} else {
|
||||
ud_asmprintf(u, "%s", name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ud_asmprintf(u, "0x%" FMT64 "x", v);
|
||||
} else {
|
||||
int64_t v;
|
||||
UD_ASSERT(op->offset != 64);
|
||||
switch (op->offset) {
|
||||
case 8 : v = op->lval.sbyte; break;
|
||||
case 16: v = op->lval.sword; break;
|
||||
case 32: v = op->lval.sdword; break;
|
||||
default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
|
||||
}
|
||||
#if 1
|
||||
if (u->sym_resolver) {
|
||||
int64_t offset = 0;
|
||||
const char *name = u->sym_resolver(u, v, &offset);
|
||||
if (name) {
|
||||
if (offset) {
|
||||
ud_asmprintf(u, "%s%+" FMT64 "d", name, offset);
|
||||
} else {
|
||||
ud_asmprintf(u, "%s", name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (v < 0) {
|
||||
ud_asmprintf(u, "-0x%" FMT64 "x", -v);
|
||||
} else if (v > 0) {
|
||||
ud_asmprintf(u, "%s0x%" FMT64 "x", sign? "+" : "", v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
vim: set ts=2 sw=2 expandtab
|
||||
*/
|
|
@ -1,53 +0,0 @@
|
|||
/* udis86 - libudis86/syn.h
|
||||
*
|
||||
* Copyright (c) 2002-2009
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef UD_SYN_H
|
||||
#define UD_SYN_H
|
||||
|
||||
#include "types.h"
|
||||
#ifndef __UD_STANDALONE__
|
||||
# include <stdarg.h>
|
||||
#endif /* __UD_STANDALONE__ */
|
||||
|
||||
extern const char* ud_reg_tab[];
|
||||
|
||||
uint64_t ud_syn_rel_target(struct ud*, struct ud_operand*);
|
||||
|
||||
#ifdef __GNUC__
|
||||
int ud_asmprintf(struct ud *u, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
#else
|
||||
int ud_asmprintf(struct ud *u, const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
void ud_syn_print_addr(struct ud *u, uint64_t addr);
|
||||
void ud_syn_print_imm(struct ud* u, const struct ud_operand *op);
|
||||
void ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *, int sign);
|
||||
|
||||
#endif /* UD_SYN_H */
|
||||
|
||||
/*
|
||||
vim: set ts=2 sw=2 expandtab
|
||||
*/
|
|
@ -1,260 +0,0 @@
|
|||
/* udis86 - libudis86/types.h
|
||||
*
|
||||
* Copyright (c) 2002-2013 Vivek Thampi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef UD_TYPES_H
|
||||
#define UD_TYPES_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
/*
|
||||
* -D__KERNEL__ is automatically passed on the command line when
|
||||
* building something as part of the Linux kernel. Assume standalone
|
||||
* mode.
|
||||
*/
|
||||
# include <linux/kernel.h>
|
||||
# include <linux/string.h>
|
||||
# ifndef __UD_STANDALONE__
|
||||
# define __UD_STANDALONE__ 1
|
||||
# endif
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#if !defined(__UD_STANDALONE__)
|
||||
# include <stdint.h>
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
/* gcc specific extensions */
|
||||
#ifdef __GNUC__
|
||||
# define UD_ATTR_PACKED __attribute__((packed))
|
||||
#else
|
||||
# define UD_ATTR_PACKED
|
||||
#endif /* UD_ATTR_PACKED */
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* All possible "types" of objects in udis86. Order is Important!
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
enum ud_type
|
||||
{
|
||||
UD_NONE,
|
||||
|
||||
/* 8 bit GPRs */
|
||||
UD_R_AL, UD_R_CL, UD_R_DL, UD_R_BL,
|
||||
UD_R_AH, UD_R_CH, UD_R_DH, UD_R_BH,
|
||||
UD_R_SPL, UD_R_BPL, UD_R_SIL, UD_R_DIL,
|
||||
UD_R_R8B, UD_R_R9B, UD_R_R10B, UD_R_R11B,
|
||||
UD_R_R12B, UD_R_R13B, UD_R_R14B, UD_R_R15B,
|
||||
|
||||
/* 16 bit GPRs */
|
||||
UD_R_AX, UD_R_CX, UD_R_DX, UD_R_BX,
|
||||
UD_R_SP, UD_R_BP, UD_R_SI, UD_R_DI,
|
||||
UD_R_R8W, UD_R_R9W, UD_R_R10W, UD_R_R11W,
|
||||
UD_R_R12W, UD_R_R13W, UD_R_R14W, UD_R_R15W,
|
||||
|
||||
/* 32 bit GPRs */
|
||||
UD_R_EAX, UD_R_ECX, UD_R_EDX, UD_R_EBX,
|
||||
UD_R_ESP, UD_R_EBP, UD_R_ESI, UD_R_EDI,
|
||||
UD_R_R8D, UD_R_R9D, UD_R_R10D, UD_R_R11D,
|
||||
UD_R_R12D, UD_R_R13D, UD_R_R14D, UD_R_R15D,
|
||||
|
||||
/* 64 bit GPRs */
|
||||
UD_R_RAX, UD_R_RCX, UD_R_RDX, UD_R_RBX,
|
||||
UD_R_RSP, UD_R_RBP, UD_R_RSI, UD_R_RDI,
|
||||
UD_R_R8, UD_R_R9, UD_R_R10, UD_R_R11,
|
||||
UD_R_R12, UD_R_R13, UD_R_R14, UD_R_R15,
|
||||
|
||||
/* segment registers */
|
||||
UD_R_ES, UD_R_CS, UD_R_SS, UD_R_DS,
|
||||
UD_R_FS, UD_R_GS,
|
||||
|
||||
/* control registers*/
|
||||
UD_R_CR0, UD_R_CR1, UD_R_CR2, UD_R_CR3,
|
||||
UD_R_CR4, UD_R_CR5, UD_R_CR6, UD_R_CR7,
|
||||
UD_R_CR8, UD_R_CR9, UD_R_CR10, UD_R_CR11,
|
||||
UD_R_CR12, UD_R_CR13, UD_R_CR14, UD_R_CR15,
|
||||
|
||||
/* debug registers */
|
||||
UD_R_DR0, UD_R_DR1, UD_R_DR2, UD_R_DR3,
|
||||
UD_R_DR4, UD_R_DR5, UD_R_DR6, UD_R_DR7,
|
||||
UD_R_DR8, UD_R_DR9, UD_R_DR10, UD_R_DR11,
|
||||
UD_R_DR12, UD_R_DR13, UD_R_DR14, UD_R_DR15,
|
||||
|
||||
/* mmx registers */
|
||||
UD_R_MM0, UD_R_MM1, UD_R_MM2, UD_R_MM3,
|
||||
UD_R_MM4, UD_R_MM5, UD_R_MM6, UD_R_MM7,
|
||||
|
||||
/* x87 registers */
|
||||
UD_R_ST0, UD_R_ST1, UD_R_ST2, UD_R_ST3,
|
||||
UD_R_ST4, UD_R_ST5, UD_R_ST6, UD_R_ST7,
|
||||
|
||||
/* extended multimedia registers */
|
||||
UD_R_XMM0, UD_R_XMM1, UD_R_XMM2, UD_R_XMM3,
|
||||
UD_R_XMM4, UD_R_XMM5, UD_R_XMM6, UD_R_XMM7,
|
||||
UD_R_XMM8, UD_R_XMM9, UD_R_XMM10, UD_R_XMM11,
|
||||
UD_R_XMM12, UD_R_XMM13, UD_R_XMM14, UD_R_XMM15,
|
||||
|
||||
/* 256B multimedia registers */
|
||||
UD_R_YMM0, UD_R_YMM1, UD_R_YMM2, UD_R_YMM3,
|
||||
UD_R_YMM4, UD_R_YMM5, UD_R_YMM6, UD_R_YMM7,
|
||||
UD_R_YMM8, UD_R_YMM9, UD_R_YMM10, UD_R_YMM11,
|
||||
UD_R_YMM12, UD_R_YMM13, UD_R_YMM14, UD_R_YMM15,
|
||||
|
||||
UD_R_RIP,
|
||||
|
||||
/* Operand Types */
|
||||
UD_OP_REG, UD_OP_MEM, UD_OP_PTR, UD_OP_IMM,
|
||||
UD_OP_JIMM, UD_OP_CONST
|
||||
};
|
||||
|
||||
#include "itab.h"
|
||||
|
||||
union ud_lval {
|
||||
int8_t sbyte;
|
||||
uint8_t ubyte;
|
||||
int16_t sword;
|
||||
uint16_t uword;
|
||||
int32_t sdword;
|
||||
uint32_t udword;
|
||||
int64_t sqword;
|
||||
uint64_t uqword;
|
||||
struct {
|
||||
uint16_t seg;
|
||||
uint32_t off;
|
||||
} ptr;
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* struct ud_operand - Disassembled instruction Operand.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
struct ud_operand {
|
||||
enum ud_type type;
|
||||
uint16_t size;
|
||||
enum ud_type base;
|
||||
enum ud_type index;
|
||||
uint8_t scale;
|
||||
uint8_t offset;
|
||||
union ud_lval lval;
|
||||
/*
|
||||
* internal use only
|
||||
*/
|
||||
uint64_t _legacy; /* this will be removed in 1.8 */
|
||||
uint8_t _oprcode;
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* struct ud - The udis86 object.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
struct ud
|
||||
{
|
||||
/*
|
||||
* input buffering
|
||||
*/
|
||||
int (*inp_hook) (struct ud*);
|
||||
#ifndef __UD_STANDALONE__
|
||||
FILE* inp_file;
|
||||
#endif
|
||||
const uint8_t* inp_buf;
|
||||
size_t inp_buf_size;
|
||||
size_t inp_buf_index;
|
||||
uint8_t inp_curr;
|
||||
size_t inp_ctr;
|
||||
uint8_t inp_sess[64];
|
||||
int inp_end;
|
||||
int inp_peek;
|
||||
|
||||
void (*translator)(struct ud*);
|
||||
uint64_t insn_offset;
|
||||
char insn_hexcode[64];
|
||||
|
||||
/*
|
||||
* Assembly output buffer
|
||||
*/
|
||||
char *asm_buf;
|
||||
size_t asm_buf_size;
|
||||
size_t asm_buf_fill;
|
||||
char asm_buf_int[128];
|
||||
|
||||
/*
|
||||
* Symbol resolver for use in the translation phase.
|
||||
*/
|
||||
const char* (*sym_resolver)(struct ud*, uint64_t addr, int64_t *offset);
|
||||
|
||||
uint8_t dis_mode;
|
||||
uint64_t pc;
|
||||
uint8_t vendor;
|
||||
enum ud_mnemonic_code mnemonic;
|
||||
struct ud_operand operand[4];
|
||||
uint8_t error;
|
||||
uint8_t _rex;
|
||||
uint8_t pfx_rex;
|
||||
uint8_t pfx_seg;
|
||||
uint8_t pfx_opr;
|
||||
uint8_t pfx_adr;
|
||||
uint8_t pfx_lock;
|
||||
uint8_t pfx_str;
|
||||
uint8_t pfx_rep;
|
||||
uint8_t pfx_repe;
|
||||
uint8_t pfx_repne;
|
||||
uint8_t opr_mode;
|
||||
uint8_t adr_mode;
|
||||
uint8_t br_far;
|
||||
uint8_t br_near;
|
||||
uint8_t have_modrm;
|
||||
uint8_t modrm;
|
||||
uint8_t modrm_offset;
|
||||
uint8_t vex_op;
|
||||
uint8_t vex_b1;
|
||||
uint8_t vex_b2;
|
||||
uint8_t primary_opcode;
|
||||
void * user_opaque_data;
|
||||
struct ud_itab_entry * itab_entry;
|
||||
struct ud_lookup_table_list_entry *le;
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Type-definitions
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
typedef enum ud_type ud_type_t;
|
||||
typedef enum ud_mnemonic_code ud_mnemonic_code_t;
|
||||
|
||||
typedef struct ud ud_t;
|
||||
typedef struct ud_operand ud_operand_t;
|
||||
|
||||
#define UD_SYN_INTEL ud_translate_intel
|
||||
#define UD_SYN_ATT ud_translate_att
|
||||
#define UD_EOI (-1)
|
||||
#define UD_INP_CACHE_SZ 32
|
||||
#define UD_VENDOR_AMD 0
|
||||
#define UD_VENDOR_INTEL 1
|
||||
#define UD_VENDOR_ANY 2
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
vim: set ts=2 sw=2 expandtab
|
||||
*/
|
|
@ -1,99 +0,0 @@
|
|||
/* udis86 - libudis86/udint.h -- definitions for internal use only
|
||||
*
|
||||
* Copyright (c) 2002-2009 Vivek Thampi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _UDINT_H_
|
||||
#define _UDINT_H_
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#if defined(UD_DEBUG) && HAVE_ASSERT_H
|
||||
# include <assert.h>
|
||||
# define UD_ASSERT(_x) assert(_x)
|
||||
#else
|
||||
# define UD_ASSERT(_x)
|
||||
#endif /* !HAVE_ASSERT_H */
|
||||
|
||||
#if defined(UD_DEBUG)
|
||||
#define UDERR(u, msg) \
|
||||
do { \
|
||||
(u)->error = 1; \
|
||||
fprintf(stderr, "decode-error: %s:%d: %s", \
|
||||
__FILE__, __LINE__, (msg)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define UDERR(u, m) \
|
||||
do { \
|
||||
(u)->error = 1; \
|
||||
} while (0)
|
||||
#endif /* !LOGERR */
|
||||
|
||||
#define UD_RETURN_ON_ERROR(u) \
|
||||
do { \
|
||||
if ((u)->error != 0) { \
|
||||
return (u)->error; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define UD_RETURN_WITH_ERROR(u, m) \
|
||||
do { \
|
||||
UDERR(u, m); \
|
||||
return (u)->error; \
|
||||
} while (0)
|
||||
|
||||
#ifndef __UD_STANDALONE__
|
||||
# define UD_NON_STANDALONE(x) x
|
||||
#else
|
||||
# define UD_NON_STANDALONE(x)
|
||||
#endif
|
||||
|
||||
/* printf formatting int64 specifier */
|
||||
#ifdef FMT64
|
||||
# undef FMT64
|
||||
#endif
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
# define FMT64 "I64"
|
||||
#else
|
||||
# if defined(__APPLE__) || defined(__OpenBSD__)
|
||||
# define FMT64 "ll"
|
||||
# elif defined(__amd64__) || defined(__x86_64__)
|
||||
# define FMT64 "l"
|
||||
# else
|
||||
# define FMT64 "ll"
|
||||
# endif /* !x64 */
|
||||
#endif
|
||||
|
||||
/* define an inline macro */
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
# define UD_INLINE __inline /* MS Visual Studio requires __inline
|
||||
instead of inline for C code */
|
||||
#else
|
||||
# define UD_INLINE inline
|
||||
#endif
|
||||
|
||||
#endif /* _UDINT_H_ */
|
|
@ -1,458 +0,0 @@
|
|||
/* udis86 - libudis86/udis86.c
|
||||
*
|
||||
* Copyright (c) 2002-2013 Vivek Thampi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "udint.h"
|
||||
#include "extern.h"
|
||||
#include "decode.h"
|
||||
|
||||
#if !defined(__UD_STANDALONE__)
|
||||
# if HAVE_STRING_H
|
||||
# include <string.h>
|
||||
# endif
|
||||
#endif /* !__UD_STANDALONE__ */
|
||||
|
||||
static void ud_inp_init(struct ud *u);
|
||||
|
||||
/* =============================================================================
|
||||
* ud_init
|
||||
* Initializes ud_t object.
|
||||
* =============================================================================
|
||||
*/
|
||||
extern void
|
||||
ud_init(struct ud* u)
|
||||
{
|
||||
memset((void*)u, 0, sizeof(struct ud));
|
||||
ud_set_mode(u, 16);
|
||||
u->mnemonic = UD_Iinvalid;
|
||||
ud_set_pc(u, 0);
|
||||
#ifndef __UD_STANDALONE__
|
||||
ud_set_input_file(u, stdin);
|
||||
#endif /* __UD_STANDALONE__ */
|
||||
|
||||
ud_set_asm_buffer(u, u->asm_buf_int, sizeof(u->asm_buf_int));
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_disassemble
|
||||
* Disassembles one instruction and returns the number of
|
||||
* bytes disassembled. A zero means end of disassembly.
|
||||
* =============================================================================
|
||||
*/
|
||||
extern unsigned int
|
||||
ud_disassemble(struct ud* u)
|
||||
{
|
||||
int len;
|
||||
if (u->inp_end) {
|
||||
return 0;
|
||||
}
|
||||
if ((len = ud_decode(u)) > 0) {
|
||||
if (u->translator != NULL) {
|
||||
u->asm_buf[0] = '\0';
|
||||
u->translator(u);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_set_mode() - Set Disassemly Mode.
|
||||
* =============================================================================
|
||||
*/
|
||||
extern void
|
||||
ud_set_mode(struct ud* u, uint8_t m)
|
||||
{
|
||||
switch(m) {
|
||||
case 16:
|
||||
case 32:
|
||||
case 64: u->dis_mode = m ; return;
|
||||
default: u->dis_mode = 16; return;
|
||||
}
|
||||
}
|
||||
|
||||
/* =============================================================================
|
||||
* ud_set_vendor() - Set vendor.
|
||||
* =============================================================================
|
||||
*/
|
||||
extern void
|
||||
ud_set_vendor(struct ud* u, unsigned v)
|
||||
{
|
||||
switch(v) {
|
||||
case UD_VENDOR_INTEL:
|
||||
u->vendor = v;
|
||||
break;
|
||||
case UD_VENDOR_ANY:
|
||||
u->vendor = v;
|
||||
break;
|
||||
default:
|
||||
u->vendor = UD_VENDOR_AMD;
|
||||
}
|
||||
}
|
||||
|
||||
/* =============================================================================
|
||||
* ud_set_pc() - Sets code origin.
|
||||
* =============================================================================
|
||||
*/
|
||||
extern void
|
||||
ud_set_pc(struct ud* u, uint64_t o)
|
||||
{
|
||||
u->pc = o;
|
||||
}
|
||||
|
||||
/* =============================================================================
|
||||
* ud_set_syntax() - Sets the output syntax.
|
||||
* =============================================================================
|
||||
*/
|
||||
extern void
|
||||
ud_set_syntax(struct ud* u, void (*t)(struct ud*))
|
||||
{
|
||||
u->translator = t;
|
||||
}
|
||||
|
||||
/* =============================================================================
|
||||
* ud_insn() - returns the disassembled instruction
|
||||
* =============================================================================
|
||||
*/
|
||||
const char*
|
||||
ud_insn_asm(const struct ud* u)
|
||||
{
|
||||
return u->asm_buf;
|
||||
}
|
||||
|
||||
/* =============================================================================
|
||||
* ud_insn_offset() - Returns the offset.
|
||||
* =============================================================================
|
||||
*/
|
||||
uint64_t
|
||||
ud_insn_off(const struct ud* u)
|
||||
{
|
||||
return u->insn_offset;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_insn_hex() - Returns hex form of disassembled instruction.
|
||||
* =============================================================================
|
||||
*/
|
||||
const char*
|
||||
ud_insn_hex(struct ud* u)
|
||||
{
|
||||
u->insn_hexcode[0] = 0;
|
||||
if (!u->error) {
|
||||
unsigned int i;
|
||||
const unsigned char *src_ptr = ud_insn_ptr(u);
|
||||
char* src_hex;
|
||||
src_hex = (char*) u->insn_hexcode;
|
||||
/* for each byte used to decode instruction */
|
||||
for (i = 0; i < ud_insn_len(u) && i < sizeof(u->insn_hexcode) / 2;
|
||||
++i, ++src_ptr) {
|
||||
sprintf(src_hex, "%02x", *src_ptr & 0xFF);
|
||||
src_hex += 2;
|
||||
}
|
||||
}
|
||||
return u->insn_hexcode;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_insn_ptr
|
||||
* Returns a pointer to buffer containing the bytes that were
|
||||
* disassembled.
|
||||
* =============================================================================
|
||||
*/
|
||||
extern const uint8_t*
|
||||
ud_insn_ptr(const struct ud* u)
|
||||
{
|
||||
return (u->inp_buf == NULL) ?
|
||||
u->inp_sess : u->inp_buf + (u->inp_buf_index - u->inp_ctr);
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_insn_len
|
||||
* Returns the count of bytes disassembled.
|
||||
* =============================================================================
|
||||
*/
|
||||
extern unsigned int
|
||||
ud_insn_len(const struct ud* u)
|
||||
{
|
||||
return u->inp_ctr;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_insn_get_opr
|
||||
* Return the operand struct representing the nth operand of
|
||||
* the currently disassembled instruction. Returns NULL if
|
||||
* there's no such operand.
|
||||
* =============================================================================
|
||||
*/
|
||||
const struct ud_operand*
|
||||
ud_insn_opr(const struct ud *u, unsigned int n)
|
||||
{
|
||||
if (n > 3 || u->operand[n].type == UD_NONE) {
|
||||
return NULL;
|
||||
} else {
|
||||
return &u->operand[n];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_opr_is_sreg
|
||||
* Returns non-zero if the given operand is of a segment register type.
|
||||
* =============================================================================
|
||||
*/
|
||||
int
|
||||
ud_opr_is_sreg(const struct ud_operand *opr)
|
||||
{
|
||||
return opr->type == UD_OP_REG &&
|
||||
opr->base >= UD_R_ES &&
|
||||
opr->base <= UD_R_GS;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_opr_is_sreg
|
||||
* Returns non-zero if the given operand is of a general purpose
|
||||
* register type.
|
||||
* =============================================================================
|
||||
*/
|
||||
int
|
||||
ud_opr_is_gpr(const struct ud_operand *opr)
|
||||
{
|
||||
return opr->type == UD_OP_REG &&
|
||||
opr->base >= UD_R_AL &&
|
||||
opr->base <= UD_R_R15;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_set_user_opaque_data
|
||||
* ud_get_user_opaque_data
|
||||
* Get/set user opaqute data pointer
|
||||
* =============================================================================
|
||||
*/
|
||||
void
|
||||
ud_set_user_opaque_data(struct ud * u, void* opaque)
|
||||
{
|
||||
u->user_opaque_data = opaque;
|
||||
}
|
||||
|
||||
void*
|
||||
ud_get_user_opaque_data(const struct ud *u)
|
||||
{
|
||||
return u->user_opaque_data;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_set_asm_buffer
|
||||
* Allow the user to set an assembler output buffer. If `buf` is NULL,
|
||||
* we switch back to the internal buffer.
|
||||
* =============================================================================
|
||||
*/
|
||||
void
|
||||
ud_set_asm_buffer(struct ud *u, char *buf, size_t size)
|
||||
{
|
||||
if (buf == NULL) {
|
||||
ud_set_asm_buffer(u, u->asm_buf_int, sizeof(u->asm_buf_int));
|
||||
} else {
|
||||
u->asm_buf = buf;
|
||||
u->asm_buf_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_set_sym_resolver
|
||||
* Set symbol resolver for relative targets used in the translation
|
||||
* phase.
|
||||
*
|
||||
* The resolver is a function that takes a uint64_t address and returns a
|
||||
* symbolic name for the that address. The function also takes a second
|
||||
* argument pointing to an integer that the client can optionally set to a
|
||||
* non-zero value for offsetted targets. (symbol+offset) The function may
|
||||
* also return NULL, in which case the translator only prints the target
|
||||
* address.
|
||||
*
|
||||
* The function pointer maybe NULL which resets symbol resolution.
|
||||
* =============================================================================
|
||||
*/
|
||||
void
|
||||
ud_set_sym_resolver(struct ud *u, const char* (*resolver)(struct ud*,
|
||||
uint64_t addr,
|
||||
int64_t *offset))
|
||||
{
|
||||
u->sym_resolver = resolver;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_insn_mnemonic
|
||||
* Return the current instruction mnemonic.
|
||||
* =============================================================================
|
||||
*/
|
||||
enum ud_mnemonic_code
|
||||
ud_insn_mnemonic(const struct ud *u)
|
||||
{
|
||||
return u->mnemonic;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_lookup_mnemonic
|
||||
* Looks up mnemonic code in the mnemonic string table.
|
||||
* Returns NULL if the mnemonic code is invalid.
|
||||
* =============================================================================
|
||||
*/
|
||||
const char*
|
||||
ud_lookup_mnemonic(enum ud_mnemonic_code c)
|
||||
{
|
||||
if (c < UD_MAX_MNEMONIC_CODE) {
|
||||
return ud_mnemonics_str[c];
|
||||
} else {
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ud_inp_init
|
||||
* Initializes the input system.
|
||||
*/
|
||||
static void
|
||||
ud_inp_init(struct ud *u)
|
||||
{
|
||||
u->inp_hook = NULL;
|
||||
u->inp_buf = NULL;
|
||||
u->inp_buf_size = 0;
|
||||
u->inp_buf_index = 0;
|
||||
u->inp_curr = 0;
|
||||
u->inp_ctr = 0;
|
||||
u->inp_end = 0;
|
||||
u->inp_peek = UD_EOI;
|
||||
UD_NON_STANDALONE(u->inp_file = NULL);
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_inp_set_hook
|
||||
* Sets input hook.
|
||||
* =============================================================================
|
||||
*/
|
||||
void
|
||||
ud_set_input_hook(register struct ud* u, int (*hook)(struct ud*))
|
||||
{
|
||||
ud_inp_init(u);
|
||||
u->inp_hook = hook;
|
||||
}
|
||||
|
||||
/* =============================================================================
|
||||
* ud_inp_set_buffer
|
||||
* Set buffer as input.
|
||||
* =============================================================================
|
||||
*/
|
||||
void
|
||||
ud_set_input_buffer(register struct ud* u, const uint8_t* buf, size_t len)
|
||||
{
|
||||
ud_inp_init(u);
|
||||
u->inp_buf = buf;
|
||||
u->inp_buf_size = len;
|
||||
u->inp_buf_index = 0;
|
||||
}
|
||||
|
||||
|
||||
#ifndef __UD_STANDALONE__
|
||||
/* =============================================================================
|
||||
* ud_input_set_file
|
||||
* Set FILE as input.
|
||||
* =============================================================================
|
||||
*/
|
||||
static int
|
||||
inp_file_hook(struct ud* u)
|
||||
{
|
||||
return fgetc(u->inp_file);
|
||||
}
|
||||
|
||||
void
|
||||
ud_set_input_file(register struct ud* u, FILE* f)
|
||||
{
|
||||
ud_inp_init(u);
|
||||
u->inp_hook = inp_file_hook;
|
||||
u->inp_file = f;
|
||||
}
|
||||
#endif /* __UD_STANDALONE__ */
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_input_skip
|
||||
* Skip n input bytes.
|
||||
* ============================================================================
|
||||
*/
|
||||
void
|
||||
ud_input_skip(struct ud* u, size_t n)
|
||||
{
|
||||
if (u->inp_end) {
|
||||
return;
|
||||
}
|
||||
if (u->inp_buf == NULL) {
|
||||
while (n--) {
|
||||
int c = u->inp_hook(u);
|
||||
if (c == UD_EOI) {
|
||||
goto eoi;
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (n > u->inp_buf_size ||
|
||||
u->inp_buf_index > u->inp_buf_size - n) {
|
||||
u->inp_buf_index = u->inp_buf_size;
|
||||
goto eoi;
|
||||
}
|
||||
u->inp_buf_index += n;
|
||||
return;
|
||||
}
|
||||
eoi:
|
||||
u->inp_end = 1;
|
||||
UDERR(u, "cannot skip, eoi received\b");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================================================
|
||||
* ud_input_end
|
||||
* Returns non-zero on end-of-input.
|
||||
* =============================================================================
|
||||
*/
|
||||
int
|
||||
ud_input_end(const struct ud *u)
|
||||
{
|
||||
return u->inp_end;
|
||||
}
|
||||
|
||||
/* vim:set ts=2 sw=2 expandtab */
|
|
@ -1,596 +0,0 @@
|
|||
/* <copyright>
|
||||
This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
redistributing this file, you may do so under either license.
|
||||
|
||||
GPL LICENSE SUMMARY
|
||||
|
||||
Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of version 2 of the GNU General Public License as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
The full GNU General Public License is included in this distribution
|
||||
in the file called LICENSE.GPL.
|
||||
|
||||
Contact Information:
|
||||
http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
|
||||
|
||||
BSD LICENSE
|
||||
|
||||
Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</copyright> */
|
||||
#ifndef _ITTNOTIFY_CONFIG_H_
|
||||
#define _ITTNOTIFY_CONFIG_H_
|
||||
|
||||
/** @cond exclude_from_documentation */
|
||||
#ifndef ITT_OS_WIN
|
||||
# define ITT_OS_WIN 1
|
||||
#endif /* ITT_OS_WIN */
|
||||
|
||||
#ifndef ITT_OS_LINUX
|
||||
# define ITT_OS_LINUX 2
|
||||
#endif /* ITT_OS_LINUX */
|
||||
|
||||
#ifndef ITT_OS_MAC
|
||||
# define ITT_OS_MAC 3
|
||||
#endif /* ITT_OS_MAC */
|
||||
|
||||
#ifndef ITT_OS_FREEBSD
|
||||
# define ITT_OS_FREEBSD 4
|
||||
#endif /* ITT_OS_FREEBSD */
|
||||
|
||||
#ifndef ITT_OS
|
||||
# if defined WIN32 || defined _WIN32
|
||||
# define ITT_OS ITT_OS_WIN
|
||||
# elif defined( __APPLE__ ) && defined( __MACH__ )
|
||||
# define ITT_OS ITT_OS_MAC
|
||||
# elif defined( __FreeBSD__ )
|
||||
# define ITT_OS ITT_OS_FREEBSD
|
||||
# else
|
||||
# define ITT_OS ITT_OS_LINUX
|
||||
# endif
|
||||
#endif /* ITT_OS */
|
||||
|
||||
#ifndef ITT_PLATFORM_WIN
|
||||
# define ITT_PLATFORM_WIN 1
|
||||
#endif /* ITT_PLATFORM_WIN */
|
||||
|
||||
#ifndef ITT_PLATFORM_POSIX
|
||||
# define ITT_PLATFORM_POSIX 2
|
||||
#endif /* ITT_PLATFORM_POSIX */
|
||||
|
||||
#ifndef ITT_PLATFORM_MAC
|
||||
# define ITT_PLATFORM_MAC 3
|
||||
#endif /* ITT_PLATFORM_MAC */
|
||||
|
||||
#ifndef ITT_PLATFORM_FREEBSD
|
||||
# define ITT_PLATFORM_FREEBSD 4
|
||||
#endif /* ITT_PLATFORM_FREEBSD */
|
||||
|
||||
#ifndef ITT_PLATFORM
|
||||
# if ITT_OS==ITT_OS_WIN
|
||||
# define ITT_PLATFORM ITT_PLATFORM_WIN
|
||||
# elif ITT_OS==ITT_OS_MAC
|
||||
# define ITT_PLATFORM ITT_PLATFORM_MAC
|
||||
# elif ITT_OS==ITT_OS_FREEBSD
|
||||
# define ITT_PLATFORM ITT_PLATFORM_FREEBSD
|
||||
# else
|
||||
# define ITT_PLATFORM ITT_PLATFORM_POSIX
|
||||
# endif
|
||||
#endif /* ITT_PLATFORM */
|
||||
|
||||
#if defined(_UNICODE) && !defined(UNICODE)
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
#include <tchar.h>
|
||||
#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
#include <stdint.h>
|
||||
#if defined(UNICODE) || defined(_UNICODE)
|
||||
#include <wchar.h>
|
||||
#endif /* UNICODE || _UNICODE */
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
|
||||
#ifndef ITTAPI_CDECL
|
||||
# if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
# define ITTAPI_CDECL __cdecl
|
||||
# else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
# if defined _M_IX86 || defined __i386__
|
||||
# define ITTAPI_CDECL __attribute__ ((cdecl))
|
||||
# else /* _M_IX86 || __i386__ */
|
||||
# define ITTAPI_CDECL /* actual only on x86 platform */
|
||||
# endif /* _M_IX86 || __i386__ */
|
||||
# endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
#endif /* ITTAPI_CDECL */
|
||||
|
||||
#ifndef STDCALL
|
||||
# if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
# define STDCALL __stdcall
|
||||
# else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
# if defined _M_IX86 || defined __i386__
|
||||
# define STDCALL __attribute__ ((stdcall))
|
||||
# else /* _M_IX86 || __i386__ */
|
||||
# define STDCALL /* supported only on x86 platform */
|
||||
# endif /* _M_IX86 || __i386__ */
|
||||
# endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
#endif /* STDCALL */
|
||||
|
||||
#define ITTAPI ITTAPI_CDECL
|
||||
#define LIBITTAPI ITTAPI_CDECL
|
||||
|
||||
/* TODO: Temporary for compatibility! */
|
||||
#define ITTAPI_CALL ITTAPI_CDECL
|
||||
#define LIBITTAPI_CALL ITTAPI_CDECL
|
||||
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
/* use __forceinline (VC++ specific) */
|
||||
#define ITT_INLINE __forceinline
|
||||
#define ITT_INLINE_ATTRIBUTE /* nothing */
|
||||
#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
/*
|
||||
* Generally, functions are not inlined unless optimization is specified.
|
||||
* For functions declared inline, this attribute inlines the function even
|
||||
* if no optimization level was specified.
|
||||
*/
|
||||
#ifdef __STRICT_ANSI__
|
||||
#define ITT_INLINE static
|
||||
#define ITT_INLINE_ATTRIBUTE __attribute__((unused))
|
||||
#else /* __STRICT_ANSI__ */
|
||||
#define ITT_INLINE static inline
|
||||
#define ITT_INLINE_ATTRIBUTE __attribute__((always_inline, unused))
|
||||
#endif /* __STRICT_ANSI__ */
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
/** @endcond */
|
||||
|
||||
#ifndef ITT_ARCH_IA32
|
||||
# define ITT_ARCH_IA32 1
|
||||
#endif /* ITT_ARCH_IA32 */
|
||||
|
||||
#ifndef ITT_ARCH_IA32E
|
||||
# define ITT_ARCH_IA32E 2
|
||||
#endif /* ITT_ARCH_IA32E */
|
||||
|
||||
#ifndef ITT_ARCH_ARM
|
||||
# define ITT_ARCH_ARM 4
|
||||
#endif /* ITT_ARCH_ARM */
|
||||
|
||||
#ifndef ITT_ARCH_PPC64
|
||||
# define ITT_ARCH_PPC64 5
|
||||
#endif /* ITT_ARCH_PPC64 */
|
||||
|
||||
#ifndef ITT_ARCH
|
||||
# if defined _M_IX86 || defined __i386__
|
||||
# define ITT_ARCH ITT_ARCH_IA32
|
||||
# elif defined _M_X64 || defined _M_AMD64 || defined __x86_64__
|
||||
# define ITT_ARCH ITT_ARCH_IA32E
|
||||
# elif defined _M_IA64 || defined __ia64__
|
||||
# define ITT_ARCH ITT_ARCH_IA64
|
||||
# elif defined _M_ARM || defined __arm__
|
||||
# define ITT_ARCH ITT_ARCH_ARM
|
||||
# elif defined __powerpc64__
|
||||
# define ITT_ARCH ITT_ARCH_PPC64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
# define ITT_EXTERN_C extern "C"
|
||||
# define ITT_EXTERN_C_BEGIN extern "C" {
|
||||
# define ITT_EXTERN_C_END }
|
||||
#else
|
||||
# define ITT_EXTERN_C /* nothing */
|
||||
# define ITT_EXTERN_C_BEGIN /* nothing */
|
||||
# define ITT_EXTERN_C_END /* nothing */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define ITT_TO_STR_AUX(x) #x
|
||||
#define ITT_TO_STR(x) ITT_TO_STR_AUX(x)
|
||||
|
||||
#define __ITT_BUILD_ASSERT(expr, suffix) do { \
|
||||
static char __itt_build_check_##suffix[(expr) ? 1 : -1]; \
|
||||
__itt_build_check_##suffix[0] = 0; \
|
||||
} while(0)
|
||||
#define _ITT_BUILD_ASSERT(expr, suffix) __ITT_BUILD_ASSERT((expr), suffix)
|
||||
#define ITT_BUILD_ASSERT(expr) _ITT_BUILD_ASSERT((expr), __LINE__)
|
||||
|
||||
#define ITT_MAGIC { 0xED, 0xAB, 0xAB, 0xEC, 0x0D, 0xEE, 0xDA, 0x30 }
|
||||
|
||||
/* Replace with snapshot date YYYYMMDD for promotion build. */
|
||||
#define API_VERSION_BUILD 20151119
|
||||
|
||||
#ifndef API_VERSION_NUM
|
||||
#define API_VERSION_NUM 0.0.0
|
||||
#endif /* API_VERSION_NUM */
|
||||
|
||||
#define API_VERSION "ITT-API-Version " ITT_TO_STR(API_VERSION_NUM) \
|
||||
" (" ITT_TO_STR(API_VERSION_BUILD) ")"
|
||||
|
||||
/* OS communication functions */
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
#include <windows.h>
|
||||
typedef HMODULE lib_t;
|
||||
typedef DWORD TIDT;
|
||||
typedef CRITICAL_SECTION mutex_t;
|
||||
#define MUTEX_INITIALIZER { 0 }
|
||||
#define strong_alias(name, aliasname) /* empty for Windows */
|
||||
#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
#include <dlfcn.h>
|
||||
#if defined(UNICODE) || defined(_UNICODE)
|
||||
#include <wchar.h>
|
||||
#endif /* UNICODE */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1 /* need for PTHREAD_MUTEX_RECURSIVE */
|
||||
#endif /* _GNU_SOURCE */
|
||||
#ifndef __USE_UNIX98
|
||||
#define __USE_UNIX98 1 /* need for PTHREAD_MUTEX_RECURSIVE, on SLES11.1 with gcc 4.3.4 wherein pthread.h missing dependency on __USE_XOPEN2K8 */
|
||||
#endif /*__USE_UNIX98*/
|
||||
#include <pthread.h>
|
||||
typedef void* lib_t;
|
||||
typedef pthread_t TIDT;
|
||||
typedef pthread_mutex_t mutex_t;
|
||||
#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
||||
#define _strong_alias(name, aliasname) \
|
||||
extern __typeof (name) aliasname __attribute__ ((alias (#name)));
|
||||
#define strong_alias(name, aliasname) _strong_alias(name, aliasname)
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
#define __itt_get_proc(lib, name) GetProcAddress(lib, name)
|
||||
#define __itt_mutex_init(mutex) InitializeCriticalSection(mutex)
|
||||
#define __itt_mutex_lock(mutex) EnterCriticalSection(mutex)
|
||||
#define __itt_mutex_unlock(mutex) LeaveCriticalSection(mutex)
|
||||
#define __itt_load_lib(name) LoadLibraryA(name)
|
||||
#define __itt_unload_lib(handle) FreeLibrary(handle)
|
||||
#define __itt_system_error() (int)GetLastError()
|
||||
#define __itt_fstrcmp(s1, s2) lstrcmpA(s1, s2)
|
||||
#define __itt_fstrnlen(s, l) strnlen_s(s, l)
|
||||
#define __itt_fstrcpyn(s1, b, s2, l) strncpy_s(s1, b, s2, l)
|
||||
#define __itt_fstrdup(s) _strdup(s)
|
||||
#define __itt_thread_id() GetCurrentThreadId()
|
||||
#define __itt_thread_yield() SwitchToThread()
|
||||
#ifndef ITT_SIMPLE_INIT
|
||||
ITT_INLINE long
|
||||
__itt_interlocked_increment(volatile long* ptr) ITT_INLINE_ATTRIBUTE;
|
||||
ITT_INLINE long __itt_interlocked_increment(volatile long* ptr)
|
||||
{
|
||||
return InterlockedIncrement(ptr);
|
||||
}
|
||||
#endif /* ITT_SIMPLE_INIT */
|
||||
#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */
|
||||
#define __itt_get_proc(lib, name) dlsym(lib, name)
|
||||
#define __itt_mutex_init(mutex) {\
|
||||
pthread_mutexattr_t mutex_attr; \
|
||||
int error_code = pthread_mutexattr_init(&mutex_attr); \
|
||||
if (error_code) \
|
||||
__itt_report_error(__itt_error_system, "pthread_mutexattr_init", \
|
||||
error_code); \
|
||||
error_code = pthread_mutexattr_settype(&mutex_attr, \
|
||||
PTHREAD_MUTEX_RECURSIVE); \
|
||||
if (error_code) \
|
||||
__itt_report_error(__itt_error_system, "pthread_mutexattr_settype", \
|
||||
error_code); \
|
||||
error_code = pthread_mutex_init(mutex, &mutex_attr); \
|
||||
if (error_code) \
|
||||
__itt_report_error(__itt_error_system, "pthread_mutex_init", \
|
||||
error_code); \
|
||||
error_code = pthread_mutexattr_destroy(&mutex_attr); \
|
||||
if (error_code) \
|
||||
__itt_report_error(__itt_error_system, "pthread_mutexattr_destroy", \
|
||||
error_code); \
|
||||
}
|
||||
#define __itt_mutex_lock(mutex) pthread_mutex_lock(mutex)
|
||||
#define __itt_mutex_unlock(mutex) pthread_mutex_unlock(mutex)
|
||||
#define __itt_load_lib(name) dlopen(name, RTLD_LAZY)
|
||||
#define __itt_unload_lib(handle) dlclose(handle)
|
||||
#define __itt_system_error() errno
|
||||
#define __itt_fstrcmp(s1, s2) strcmp(s1, s2)
|
||||
|
||||
/* makes customer code define safe APIs for SDL_STRNLEN_S and SDL_STRNCPY_S */
|
||||
#ifdef SDL_STRNLEN_S
|
||||
#define __itt_fstrnlen(s, l) SDL_STRNLEN_S(s, l)
|
||||
#else
|
||||
#define __itt_fstrnlen(s, l) strlen(s)
|
||||
#endif /* SDL_STRNLEN_S */
|
||||
#ifdef SDL_STRNCPY_S
|
||||
#define __itt_fstrcpyn(s1, b, s2, l) SDL_STRNCPY_S(s1, b, s2, l)
|
||||
#else
|
||||
#define __itt_fstrcpyn(s1, b, s2, l) strncpy(s1, s2, l)
|
||||
#endif /* SDL_STRNCPY_S */
|
||||
|
||||
#define __itt_fstrdup(s) strdup(s)
|
||||
#define __itt_thread_id() pthread_self()
|
||||
#define __itt_thread_yield() sched_yield()
|
||||
#if ITT_ARCH==ITT_ARCH_IA64
|
||||
#ifdef __INTEL_COMPILER
|
||||
#define __TBB_machine_fetchadd4(addr, val) __fetchadd4_acq((void *)addr, val)
|
||||
#else /* __INTEL_COMPILER */
|
||||
/* TODO: Add Support for not Intel compilers for IA-64 architecture */
|
||||
#endif /* __INTEL_COMPILER */
|
||||
#elif ITT_ARCH==ITT_ARCH_IA32 || ITT_ARCH==ITT_ARCH_IA32E /* ITT_ARCH!=ITT_ARCH_IA64 */
|
||||
ITT_INLINE long
|
||||
__TBB_machine_fetchadd4(volatile void* ptr, long addend) ITT_INLINE_ATTRIBUTE;
|
||||
ITT_INLINE long __TBB_machine_fetchadd4(volatile void* ptr, long addend)
|
||||
{
|
||||
long result;
|
||||
__asm__ __volatile__("lock\nxadd %0,%1"
|
||||
: "=r"(result),"=m"(*(int*)ptr)
|
||||
: "0"(addend), "m"(*(int*)ptr)
|
||||
: "memory");
|
||||
return result;
|
||||
}
|
||||
#elif ITT_ARCH==ITT_ARCH_ARM || ITT_ARCH==ITT_ARCH_PPC64
|
||||
#define __TBB_machine_fetchadd4(addr, val) __sync_fetch_and_add(addr, val)
|
||||
#endif /* ITT_ARCH==ITT_ARCH_IA64 */
|
||||
#ifndef ITT_SIMPLE_INIT
|
||||
ITT_INLINE long
|
||||
__itt_interlocked_increment(volatile long* ptr) ITT_INLINE_ATTRIBUTE;
|
||||
ITT_INLINE long __itt_interlocked_increment(volatile long* ptr)
|
||||
{
|
||||
return __TBB_machine_fetchadd4(ptr, 1) + 1L;
|
||||
}
|
||||
#endif /* ITT_SIMPLE_INIT */
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
|
||||
typedef enum {
|
||||
__itt_collection_normal = 0,
|
||||
__itt_collection_paused = 1
|
||||
} __itt_collection_state;
|
||||
|
||||
typedef enum {
|
||||
__itt_thread_normal = 0,
|
||||
__itt_thread_ignored = 1
|
||||
} __itt_thread_state;
|
||||
|
||||
#pragma pack(push, 8)
|
||||
|
||||
typedef struct ___itt_thread_info
|
||||
{
|
||||
const char* nameA; /*!< Copy of original name in ASCII. */
|
||||
#if defined(UNICODE) || defined(_UNICODE)
|
||||
const wchar_t* nameW; /*!< Copy of original name in UNICODE. */
|
||||
#else /* UNICODE || _UNICODE */
|
||||
void* nameW;
|
||||
#endif /* UNICODE || _UNICODE */
|
||||
TIDT tid;
|
||||
__itt_thread_state state; /*!< Thread state (paused or normal) */
|
||||
int extra1; /*!< Reserved to the runtime */
|
||||
void* extra2; /*!< Reserved to the runtime */
|
||||
struct ___itt_thread_info* next;
|
||||
} __itt_thread_info;
|
||||
|
||||
#include "ittnotify_types.h" /* For __itt_group_id definition */
|
||||
|
||||
typedef struct ___itt_api_info_20101001
|
||||
{
|
||||
const char* name;
|
||||
void** func_ptr;
|
||||
void* init_func;
|
||||
__itt_group_id group;
|
||||
} __itt_api_info_20101001;
|
||||
|
||||
typedef struct ___itt_api_info
|
||||
{
|
||||
const char* name;
|
||||
void** func_ptr;
|
||||
void* init_func;
|
||||
void* null_func;
|
||||
__itt_group_id group;
|
||||
} __itt_api_info;
|
||||
|
||||
typedef struct __itt_counter_info
|
||||
{
|
||||
const char* nameA; /*!< Copy of original name in ASCII. */
|
||||
#if defined(UNICODE) || defined(_UNICODE)
|
||||
const wchar_t* nameW; /*!< Copy of original name in UNICODE. */
|
||||
#else /* UNICODE || _UNICODE */
|
||||
void* nameW;
|
||||
#endif /* UNICODE || _UNICODE */
|
||||
const char* domainA; /*!< Copy of original name in ASCII. */
|
||||
#if defined(UNICODE) || defined(_UNICODE)
|
||||
const wchar_t* domainW; /*!< Copy of original name in UNICODE. */
|
||||
#else /* UNICODE || _UNICODE */
|
||||
void* domainW;
|
||||
#endif /* UNICODE || _UNICODE */
|
||||
int type;
|
||||
long index;
|
||||
int extra1; /*!< Reserved to the runtime */
|
||||
void* extra2; /*!< Reserved to the runtime */
|
||||
struct __itt_counter_info* next;
|
||||
} __itt_counter_info_t;
|
||||
|
||||
struct ___itt_domain;
|
||||
struct ___itt_string_handle;
|
||||
|
||||
typedef struct ___itt_global
|
||||
{
|
||||
unsigned char magic[8];
|
||||
unsigned long version_major;
|
||||
unsigned long version_minor;
|
||||
unsigned long version_build;
|
||||
volatile long api_initialized;
|
||||
volatile long mutex_initialized;
|
||||
volatile long atomic_counter;
|
||||
mutex_t mutex;
|
||||
lib_t lib;
|
||||
void* error_handler;
|
||||
const char** dll_path_ptr;
|
||||
__itt_api_info* api_list_ptr;
|
||||
struct ___itt_global* next;
|
||||
/* Joinable structures below */
|
||||
__itt_thread_info* thread_list;
|
||||
struct ___itt_domain* domain_list;
|
||||
struct ___itt_string_handle* string_list;
|
||||
__itt_collection_state state;
|
||||
__itt_counter_info_t* counter_list;
|
||||
} __itt_global;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#define NEW_THREAD_INFO_W(gptr,h,h_tail,t,s,n) { \
|
||||
h = (__itt_thread_info*)malloc(sizeof(__itt_thread_info)); \
|
||||
if (h != NULL) { \
|
||||
h->tid = t; \
|
||||
h->nameA = NULL; \
|
||||
h->nameW = n ? _wcsdup(n) : NULL; \
|
||||
h->state = s; \
|
||||
h->extra1 = 0; /* reserved */ \
|
||||
h->extra2 = NULL; /* reserved */ \
|
||||
h->next = NULL; \
|
||||
if (h_tail == NULL) \
|
||||
(gptr)->thread_list = h; \
|
||||
else \
|
||||
h_tail->next = h; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define NEW_THREAD_INFO_A(gptr,h,h_tail,t,s,n) { \
|
||||
h = (__itt_thread_info*)malloc(sizeof(__itt_thread_info)); \
|
||||
if (h != NULL) { \
|
||||
h->tid = t; \
|
||||
h->nameA = n ? __itt_fstrdup(n) : NULL; \
|
||||
h->nameW = NULL; \
|
||||
h->state = s; \
|
||||
h->extra1 = 0; /* reserved */ \
|
||||
h->extra2 = NULL; /* reserved */ \
|
||||
h->next = NULL; \
|
||||
if (h_tail == NULL) \
|
||||
(gptr)->thread_list = h; \
|
||||
else \
|
||||
h_tail->next = h; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define NEW_DOMAIN_W(gptr,h,h_tail,name) { \
|
||||
h = (__itt_domain*)malloc(sizeof(__itt_domain)); \
|
||||
if (h != NULL) { \
|
||||
h->flags = 1; /* domain is enabled by default */ \
|
||||
h->nameA = NULL; \
|
||||
h->nameW = name ? _wcsdup(name) : NULL; \
|
||||
h->extra1 = 0; /* reserved */ \
|
||||
h->extra2 = NULL; /* reserved */ \
|
||||
h->next = NULL; \
|
||||
if (h_tail == NULL) \
|
||||
(gptr)->domain_list = h; \
|
||||
else \
|
||||
h_tail->next = h; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define NEW_DOMAIN_A(gptr,h,h_tail,name) { \
|
||||
h = (__itt_domain*)malloc(sizeof(__itt_domain)); \
|
||||
if (h != NULL) { \
|
||||
h->flags = 1; /* domain is enabled by default */ \
|
||||
h->nameA = name ? __itt_fstrdup(name) : NULL; \
|
||||
h->nameW = NULL; \
|
||||
h->extra1 = 0; /* reserved */ \
|
||||
h->extra2 = NULL; /* reserved */ \
|
||||
h->next = NULL; \
|
||||
if (h_tail == NULL) \
|
||||
(gptr)->domain_list = h; \
|
||||
else \
|
||||
h_tail->next = h; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define NEW_STRING_HANDLE_W(gptr,h,h_tail,name) { \
|
||||
h = (__itt_string_handle*)malloc(sizeof(__itt_string_handle)); \
|
||||
if (h != NULL) { \
|
||||
h->strA = NULL; \
|
||||
h->strW = name ? _wcsdup(name) : NULL; \
|
||||
h->extra1 = 0; /* reserved */ \
|
||||
h->extra2 = NULL; /* reserved */ \
|
||||
h->next = NULL; \
|
||||
if (h_tail == NULL) \
|
||||
(gptr)->string_list = h; \
|
||||
else \
|
||||
h_tail->next = h; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define NEW_STRING_HANDLE_A(gptr,h,h_tail,name) { \
|
||||
h = (__itt_string_handle*)malloc(sizeof(__itt_string_handle)); \
|
||||
if (h != NULL) { \
|
||||
h->strA = name ? __itt_fstrdup(name) : NULL; \
|
||||
h->strW = NULL; \
|
||||
h->extra1 = 0; /* reserved */ \
|
||||
h->extra2 = NULL; /* reserved */ \
|
||||
h->next = NULL; \
|
||||
if (h_tail == NULL) \
|
||||
(gptr)->string_list = h; \
|
||||
else \
|
||||
h_tail->next = h; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define NEW_COUNTER_W(gptr,h,h_tail,name,domain,type) { \
|
||||
h = (__itt_counter_info_t*)malloc(sizeof(__itt_counter_info_t)); \
|
||||
if (h != NULL) { \
|
||||
h->nameA = NULL; \
|
||||
h->nameW = name ? _wcsdup(name) : NULL; \
|
||||
h->domainA = NULL; \
|
||||
h->domainW = name ? _wcsdup(domain) : NULL; \
|
||||
h->type = type; \
|
||||
h->index = 0; \
|
||||
h->next = NULL; \
|
||||
if (h_tail == NULL) \
|
||||
(gptr)->counter_list = h; \
|
||||
else \
|
||||
h_tail->next = h; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define NEW_COUNTER_A(gptr,h,h_tail,name,domain,type) { \
|
||||
h = (__itt_counter_info_t*)malloc(sizeof(__itt_counter_info_t)); \
|
||||
if (h != NULL) { \
|
||||
h->nameA = name ? __itt_fstrdup(name) : NULL; \
|
||||
h->nameW = NULL; \
|
||||
h->domainA = domain ? __itt_fstrdup(domain) : NULL; \
|
||||
h->domainW = NULL; \
|
||||
h->type = type; \
|
||||
h->index = 0; \
|
||||
h->next = NULL; \
|
||||
if (h_tail == NULL) \
|
||||
(gptr)->counter_list = h; \
|
||||
else \
|
||||
h_tail->next = h; \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* _ITTNOTIFY_CONFIG_H_ */
|
|
@ -1,115 +0,0 @@
|
|||
/* <copyright>
|
||||
This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
redistributing this file, you may do so under either license.
|
||||
|
||||
GPL LICENSE SUMMARY
|
||||
|
||||
Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of version 2 of the GNU General Public License as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
The full GNU General Public License is included in this distribution
|
||||
in the file called LICENSE.GPL.
|
||||
|
||||
Contact Information:
|
||||
http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
|
||||
|
||||
BSD LICENSE
|
||||
|
||||
Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</copyright> */
|
||||
|
||||
#ifndef _ITTNOTIFY_TYPES_H_
|
||||
#define _ITTNOTIFY_TYPES_H_
|
||||
|
||||
typedef enum ___itt_group_id
|
||||
{
|
||||
__itt_group_none = 0,
|
||||
__itt_group_legacy = 1<<0,
|
||||
__itt_group_control = 1<<1,
|
||||
__itt_group_thread = 1<<2,
|
||||
__itt_group_mark = 1<<3,
|
||||
__itt_group_sync = 1<<4,
|
||||
__itt_group_fsync = 1<<5,
|
||||
__itt_group_jit = 1<<6,
|
||||
__itt_group_model = 1<<7,
|
||||
__itt_group_splitter_min = 1<<7,
|
||||
__itt_group_counter = 1<<8,
|
||||
__itt_group_frame = 1<<9,
|
||||
__itt_group_stitch = 1<<10,
|
||||
__itt_group_heap = 1<<11,
|
||||
__itt_group_splitter_max = 1<<12,
|
||||
__itt_group_structure = 1<<12,
|
||||
__itt_group_suppress = 1<<13,
|
||||
__itt_group_arrays = 1<<14,
|
||||
__itt_group_all = -1
|
||||
} __itt_group_id;
|
||||
|
||||
#pragma pack(push, 8)
|
||||
|
||||
typedef struct ___itt_group_list
|
||||
{
|
||||
__itt_group_id id;
|
||||
const char* name;
|
||||
} __itt_group_list;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#define ITT_GROUP_LIST(varname) \
|
||||
static __itt_group_list varname[] = { \
|
||||
{ __itt_group_all, "all" }, \
|
||||
{ __itt_group_control, "control" }, \
|
||||
{ __itt_group_thread, "thread" }, \
|
||||
{ __itt_group_mark, "mark" }, \
|
||||
{ __itt_group_sync, "sync" }, \
|
||||
{ __itt_group_fsync, "fsync" }, \
|
||||
{ __itt_group_jit, "jit" }, \
|
||||
{ __itt_group_model, "model" }, \
|
||||
{ __itt_group_counter, "counter" }, \
|
||||
{ __itt_group_frame, "frame" }, \
|
||||
{ __itt_group_stitch, "stitch" }, \
|
||||
{ __itt_group_heap, "heap" }, \
|
||||
{ __itt_group_structure, "structure" }, \
|
||||
{ __itt_group_suppress, "suppress" }, \
|
||||
{ __itt_group_arrays, "arrays" }, \
|
||||
{ __itt_group_none, NULL } \
|
||||
}
|
||||
|
||||
#endif /* _ITTNOTIFY_TYPES_H_ */
|
|
@ -1,312 +0,0 @@
|
|||
/* <copyright>
|
||||
This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
redistributing this file, you may do so under either license.
|
||||
|
||||
GPL LICENSE SUMMARY
|
||||
|
||||
Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of version 2 of the GNU General Public License as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
The full GNU General Public License is included in this distribution
|
||||
in the file called LICENSE.GPL.
|
||||
|
||||
Contact Information:
|
||||
http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
|
||||
|
||||
BSD LICENSE
|
||||
|
||||
Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</copyright> */
|
||||
|
||||
#include "ittnotify_config.h"
|
||||
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
#include <windows.h>
|
||||
#pragma optimize("", off)
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jitprofiling.h"
|
||||
|
||||
static const char rcsid[] = "\n@(#) $Revision: 463960 $\n";
|
||||
|
||||
#define DLL_ENVIRONMENT_VAR "VS_PROFILER"
|
||||
|
||||
#ifndef NEW_DLL_ENVIRONMENT_VAR
|
||||
#if ITT_ARCH==ITT_ARCH_IA32
|
||||
#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32"
|
||||
#else
|
||||
#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64"
|
||||
#endif
|
||||
#endif /* NEW_DLL_ENVIRONMENT_VAR */
|
||||
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
#define DEFAULT_DLLNAME "JitPI.dll"
|
||||
HINSTANCE m_libHandle = NULL;
|
||||
#elif ITT_PLATFORM==ITT_PLATFORM_MAC
|
||||
#define DEFAULT_DLLNAME "libJitPI.dylib"
|
||||
void* m_libHandle = NULL;
|
||||
#else
|
||||
#define DEFAULT_DLLNAME "libJitPI.so"
|
||||
void* m_libHandle = NULL;
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
|
||||
/* default location of JIT profiling agent on Android */
|
||||
#define ANDROID_JIT_AGENT_PATH "/data/intel/libittnotify.so"
|
||||
|
||||
/* the function pointers */
|
||||
typedef unsigned int(JITAPI *TPInitialize)(void);
|
||||
static TPInitialize FUNC_Initialize=NULL;
|
||||
|
||||
typedef unsigned int(JITAPI *TPNotify)(unsigned int, void*);
|
||||
static TPNotify FUNC_NotifyEvent=NULL;
|
||||
|
||||
static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING;
|
||||
|
||||
/* end collector dll part. */
|
||||
|
||||
/* loadiJIT_Funcs() : this function is called just in the beginning
|
||||
* and is responsible to load the functions from BistroJavaCollector.dll
|
||||
* result:
|
||||
* on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1
|
||||
* on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0
|
||||
*/
|
||||
static int loadiJIT_Funcs(void);
|
||||
|
||||
/* global representing whether the collector can't be loaded */
|
||||
static int iJIT_DLL_is_missing = 0;
|
||||
|
||||
ITT_EXTERN_C int JITAPI
|
||||
iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData)
|
||||
{
|
||||
int ReturnValue;
|
||||
|
||||
/* initialization part - the collector has not been loaded yet. */
|
||||
if (!FUNC_NotifyEvent)
|
||||
{
|
||||
if (iJIT_DLL_is_missing)
|
||||
return 0;
|
||||
|
||||
if (!loadiJIT_Funcs())
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED ||
|
||||
event_type == iJVM_EVENT_TYPE_METHOD_UPDATE)
|
||||
{
|
||||
if (((piJIT_Method_Load)EventSpecificData)->method_id == 0)
|
||||
return 0;
|
||||
}
|
||||
else if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2)
|
||||
{
|
||||
if (((piJIT_Method_Load_V2)EventSpecificData)->method_id == 0)
|
||||
return 0;
|
||||
}
|
||||
else if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V3)
|
||||
{
|
||||
if (((piJIT_Method_Load_V3)EventSpecificData)->method_id == 0)
|
||||
return 0;
|
||||
}
|
||||
else if (event_type == iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED)
|
||||
{
|
||||
if (((piJIT_Method_Inline_Load)EventSpecificData)->method_id == 0 ||
|
||||
((piJIT_Method_Inline_Load)EventSpecificData)->parent_method_id == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData);
|
||||
|
||||
return ReturnValue;
|
||||
}
|
||||
|
||||
ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive(void)
|
||||
{
|
||||
if (!iJIT_DLL_is_missing)
|
||||
{
|
||||
loadiJIT_Funcs();
|
||||
}
|
||||
|
||||
return executionMode;
|
||||
}
|
||||
|
||||
/* This function loads the collector dll and the relevant functions.
|
||||
* on success: all functions load, iJIT_DLL_is_missing = 0, return value = 1
|
||||
* on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0
|
||||
*/
|
||||
static int loadiJIT_Funcs(void)
|
||||
{
|
||||
static int bDllWasLoaded = 0;
|
||||
char *dllName = (char*)rcsid; /* !! Just to avoid unused code elimination */
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
DWORD dNameLength = 0;
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
|
||||
if(bDllWasLoaded)
|
||||
{
|
||||
/* dll was already loaded, no need to do it for the second time */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Assumes that the DLL will not be found */
|
||||
iJIT_DLL_is_missing = 1;
|
||||
FUNC_NotifyEvent = NULL;
|
||||
|
||||
if (m_libHandle)
|
||||
{
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
FreeLibrary(m_libHandle);
|
||||
#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
dlclose(m_libHandle);
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
m_libHandle = NULL;
|
||||
}
|
||||
|
||||
/* Try to get the dll name from the environment */
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0);
|
||||
if (dNameLength)
|
||||
{
|
||||
DWORD envret = 0;
|
||||
dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
|
||||
if(dllName != NULL)
|
||||
{
|
||||
envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR,
|
||||
dllName, dNameLength);
|
||||
if (envret)
|
||||
{
|
||||
/* Try to load the dll from the PATH... */
|
||||
m_libHandle = LoadLibraryExA(dllName,
|
||||
NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
}
|
||||
free(dllName);
|
||||
}
|
||||
} else {
|
||||
/* Try to use old VS_PROFILER variable */
|
||||
dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0);
|
||||
if (dNameLength)
|
||||
{
|
||||
DWORD envret = 0;
|
||||
dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
|
||||
if(dllName != NULL)
|
||||
{
|
||||
envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR,
|
||||
dllName, dNameLength);
|
||||
if (envret)
|
||||
{
|
||||
/* Try to load the dll from the PATH... */
|
||||
m_libHandle = LoadLibraryA(dllName);
|
||||
}
|
||||
free(dllName);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
dllName = getenv(NEW_DLL_ENVIRONMENT_VAR);
|
||||
if (!dllName)
|
||||
dllName = getenv(DLL_ENVIRONMENT_VAR);
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
if (!dllName)
|
||||
dllName = ANDROID_JIT_AGENT_PATH;
|
||||
#endif
|
||||
if (dllName)
|
||||
{
|
||||
/* Try to load the dll from the PATH... */
|
||||
m_libHandle = dlopen(dllName, RTLD_LAZY);
|
||||
}
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
|
||||
if (!m_libHandle)
|
||||
{
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
m_libHandle = LoadLibraryA(DEFAULT_DLLNAME);
|
||||
#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY);
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
}
|
||||
|
||||
/* if the dll wasn't loaded - exit. */
|
||||
if (!m_libHandle)
|
||||
{
|
||||
iJIT_DLL_is_missing = 1; /* don't try to initialize
|
||||
* JIT agent the second time
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent");
|
||||
#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
FUNC_NotifyEvent = (TPNotify)dlsym(m_libHandle, "NotifyEvent");
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
if (!FUNC_NotifyEvent)
|
||||
{
|
||||
FUNC_Initialize = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if ITT_PLATFORM==ITT_PLATFORM_WIN
|
||||
FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize");
|
||||
#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
FUNC_Initialize = (TPInitialize)dlsym(m_libHandle, "Initialize");
|
||||
#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
|
||||
if (!FUNC_Initialize)
|
||||
{
|
||||
FUNC_NotifyEvent = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize();
|
||||
|
||||
bDllWasLoaded = 1;
|
||||
iJIT_DLL_is_missing = 0; /* DLL is ok. */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID(void)
|
||||
{
|
||||
static unsigned int methodID = 1;
|
||||
|
||||
if (methodID == 0)
|
||||
return 0; /* ERROR : this is not a valid value */
|
||||
|
||||
return methodID++;
|
||||
}
|
|
@ -1,694 +0,0 @@
|
|||
/* <copyright>
|
||||
This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
redistributing this file, you may do so under either license.
|
||||
|
||||
GPL LICENSE SUMMARY
|
||||
|
||||
Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of version 2 of the GNU General Public License as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
The full GNU General Public License is included in this distribution
|
||||
in the file called LICENSE.GPL.
|
||||
|
||||
Contact Information:
|
||||
http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
|
||||
|
||||
BSD LICENSE
|
||||
|
||||
Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</copyright> */
|
||||
|
||||
#ifndef __JITPROFILING_H__
|
||||
#define __JITPROFILING_H__
|
||||
|
||||
/**
|
||||
* @brief JIT Profiling APIs
|
||||
*
|
||||
* The JIT Profiling API is used to report information about just-in-time
|
||||
* generated code that can be used by performance tools. The user inserts
|
||||
* calls in the code generator to report information before JIT-compiled
|
||||
* code goes to execution. This information is collected at runtime and used
|
||||
* by tools like Intel(R) VTune(TM) Amplifier to display performance metrics
|
||||
* associated with JIT-compiled code.
|
||||
*
|
||||
* These APIs can be used to\n
|
||||
* - **Profile trace-based and method-based JIT-compiled
|
||||
* code**. Some examples of environments that you can profile with these APIs:
|
||||
* dynamic JIT compilation of JavaScript code traces, JIT execution in OpenCL(TM)
|
||||
* software technology, Java/.NET managed execution environments, and custom
|
||||
* ISV JIT engines.
|
||||
* @code
|
||||
* #include <jitprofiling.h>
|
||||
*
|
||||
* if (iJIT_IsProfilingActive != iJIT_SAMPLING_ON) {
|
||||
* return;
|
||||
* }
|
||||
*
|
||||
* iJIT_Method_Load jmethod = {0};
|
||||
* jmethod.method_id = iJIT_GetNewMethodID();
|
||||
* jmethod.method_name = "method_name";
|
||||
* jmethod.class_file_name = "class_name";
|
||||
* jmethod.source_file_name = "source_file_name";
|
||||
* jmethod.method_load_address = code_addr;
|
||||
* jmethod.method_size = code_size;
|
||||
*
|
||||
* iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod);
|
||||
* iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, NULL);
|
||||
* @endcode
|
||||
*
|
||||
* * Expected behavior:
|
||||
* * If any iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event overwrites an
|
||||
* already reported method, then such a method becomes invalid and its
|
||||
* memory region is treated as unloaded. VTune Amplifier displays the metrics
|
||||
* collected by the method until it is overwritten.
|
||||
* * If supplied line number information contains multiple source lines for
|
||||
* the same assembly instruction (code location), then VTune Amplifier picks up
|
||||
* the first line number.
|
||||
* * Dynamically generated code can be associated with a module name.
|
||||
* Use the iJIT_Method_Load_V2 structure.\n
|
||||
* Clarification of some cases:
|
||||
* * If you register a function with the same method ID multiple times,
|
||||
* specifying different module names, then the VTune Amplifier picks up
|
||||
* the module name registered first. If you want to distinguish the same
|
||||
* function between different JIT engines, supply different method IDs for
|
||||
* each function. Other symbolic information (for example, source file)
|
||||
* can be identical.
|
||||
*
|
||||
* - **Analyze split functions** (multiple joint or disjoint code regions
|
||||
* belonging to the same function) **including re-JIT**
|
||||
* with potential overlapping of code regions in time, which is common in
|
||||
* resource-limited environments.
|
||||
* @code
|
||||
* #include <jitprofiling.h>
|
||||
*
|
||||
* unsigned int method_id = iJIT_GetNewMethodID();
|
||||
*
|
||||
* iJIT_Method_Load a = {0};
|
||||
* a.method_id = method_id;
|
||||
* a.method_load_address = 0x100;
|
||||
* a.method_size = 0x20;
|
||||
*
|
||||
* iJIT_Method_Load b = {0};
|
||||
* b.method_id = method_id;
|
||||
* b.method_load_address = 0x200;
|
||||
* b.method_size = 0x30;
|
||||
*
|
||||
* iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&a);
|
||||
* iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&b);
|
||||
* @endcode
|
||||
*
|
||||
* * Expected behaviour:
|
||||
* * If a iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event overwrites an
|
||||
* already reported method, then such a method becomes invalid and
|
||||
* its memory region is treated as unloaded.
|
||||
* * All code regions reported with the same method ID are considered as
|
||||
* belonging to the same method. Symbolic information (method name,
|
||||
* source file name) will be taken from the first notification, and all
|
||||
* subsequent notifications with the same method ID will be processed
|
||||
* only for line number table information. So, the VTune Amplifier will map
|
||||
* samples to a source line using the line number table from the current
|
||||
* notification while taking the source file name from the very first one.\n
|
||||
* Clarification of some cases:\n
|
||||
* * If you register a second code region with a different source file
|
||||
* name and the same method ID, then this information will be saved and
|
||||
* will not be considered as an extension of the first code region, but
|
||||
* VTune Amplifier will use the source file of the first code region and map
|
||||
* performance metrics incorrectly.
|
||||
* * If you register a second code region with the same source file as
|
||||
* for the first region and the same method ID, then the source file will be
|
||||
* discarded but VTune Amplifier will map metrics to the source file correctly.
|
||||
* * If you register a second code region with a null source file and
|
||||
* the same method ID, then provided line number info will be associated
|
||||
* with the source file of the first code region.
|
||||
*
|
||||
* - **Explore inline functions** including multi-level hierarchy of
|
||||
* nested inline methods which shows how performance metrics are distributed through them.
|
||||
* @code
|
||||
* #include <jitprofiling.h>
|
||||
*
|
||||
* // method_id parent_id
|
||||
* // [-- c --] 3000 2000
|
||||
* // [---- d -----] 2001 1000
|
||||
* // [---- b ----] 2000 1000
|
||||
* // [------------ a ----------------] 1000 n/a
|
||||
*
|
||||
* iJIT_Method_Load a = {0};
|
||||
* a.method_id = 1000;
|
||||
*
|
||||
* iJIT_Method_Inline_Load b = {0};
|
||||
* b.method_id = 2000;
|
||||
* b.parent_method_id = 1000;
|
||||
*
|
||||
* iJIT_Method_Inline_Load c = {0};
|
||||
* c.method_id = 3000;
|
||||
* c.parent_method_id = 2000;
|
||||
*
|
||||
* iJIT_Method_Inline_Load d = {0};
|
||||
* d.method_id = 2001;
|
||||
* d.parent_method_id = 1000;
|
||||
*
|
||||
* iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&a);
|
||||
* iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&b);
|
||||
* iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&c);
|
||||
* iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&d);
|
||||
* @endcode
|
||||
*
|
||||
* * Requirements:
|
||||
* * Each inline (iJIT_Method_Inline_Load) method should be associated
|
||||
* with two method IDs: one for itself; one for its immediate parent.
|
||||
* * Address regions of inline methods of the same parent method cannot
|
||||
* overlap each other.
|
||||
* * Execution of the parent method must not be started until it and all
|
||||
* its inline methods are reported.
|
||||
* * Expected behaviour:
|
||||
* * In case of nested inline methods an order of
|
||||
* iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED events is not important.
|
||||
* * If any event overwrites either inline method or top parent method,
|
||||
* then the parent, including inline methods, becomes invalid and its memory
|
||||
* region is treated as unloaded.
|
||||
*
|
||||
* **Life time of allocated data**\n
|
||||
* The client sends an event notification to the agent with event-specific
|
||||
* data, which is a structure. The pointers in the structure refer to memory
|
||||
* allocated by the client, which responsible for releasing it. The pointers are
|
||||
* used by the iJIT_NotifyEvent method to copy client's data in a trace file,
|
||||
* and they are not used after the iJIT_NotifyEvent method returns.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup jitapi JIT Profiling
|
||||
* @ingroup internal
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Enumerator for the types of notifications
|
||||
*/
|
||||
typedef enum iJIT_jvm_event
|
||||
{
|
||||
iJVM_EVENT_TYPE_SHUTDOWN = 2, /**<\brief Send this to shutdown the agent.
|
||||
* Use NULL for event data. */
|
||||
|
||||
iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED = 13, /**<\brief Send when dynamic code is
|
||||
* JIT compiled and loaded into
|
||||
* memory by the JIT engine, but
|
||||
* before the code is executed.
|
||||
* Use iJIT_Method_Load as event
|
||||
* data. */
|
||||
/** @cond exclude_from_documentation */
|
||||
iJVM_EVENT_TYPE_METHOD_UNLOAD_START, /**<\brief Send when compiled dynamic
|
||||
* code is being unloaded from memory.
|
||||
* Use iJIT_Method_Load as event data.*/
|
||||
/** @endcond */
|
||||
|
||||
iJVM_EVENT_TYPE_METHOD_UPDATE, /**<\brief Send to provide new content for
|
||||
* a previously reported dynamic code.
|
||||
* The previous content will be invalidated
|
||||
* starting from the time of the notification.
|
||||
* Use iJIT_Method_Load as event data but
|
||||
* required fields are following:
|
||||
* - method_id identify the code to update.
|
||||
* - method_load_address specify start address
|
||||
* within identified code range
|
||||
* where update should be started.
|
||||
* - method_size specify length of updated code
|
||||
* range. */
|
||||
|
||||
|
||||
iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, /**<\brief Send when an inline dynamic
|
||||
* code is JIT compiled and loaded
|
||||
* into memory by the JIT engine,
|
||||
* but before the parent code region
|
||||
* starts executing.
|
||||
* Use iJIT_Method_Inline_Load as event data.*/
|
||||
|
||||
/** @cond exclude_from_documentation */
|
||||
iJVM_EVENT_TYPE_METHOD_UPDATE_V2,
|
||||
/** @endcond */
|
||||
|
||||
iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2 = 21, /**<\brief Send when a dynamic code is
|
||||
* JIT compiled and loaded into
|
||||
* memory by the JIT engine, but
|
||||
* before the code is executed.
|
||||
* Use iJIT_Method_Load_V2 as event data. */
|
||||
|
||||
iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V3 /**<\brief Send when a dynamic code is
|
||||
* JIT compiled and loaded into
|
||||
* memory by the JIT engine, but
|
||||
* before the code is executed.
|
||||
* Use iJIT_Method_Load_V3 as event data. */
|
||||
} iJIT_JVM_EVENT;
|
||||
|
||||
/**
|
||||
* @brief Enumerator for the agent's mode
|
||||
*/
|
||||
typedef enum _iJIT_IsProfilingActiveFlags
|
||||
{
|
||||
iJIT_NOTHING_RUNNING = 0x0000, /**<\brief The agent is not running;
|
||||
* iJIT_NotifyEvent calls will
|
||||
* not be processed. */
|
||||
iJIT_SAMPLING_ON = 0x0001, /**<\brief The agent is running and
|
||||
* ready to process notifications. */
|
||||
} iJIT_IsProfilingActiveFlags;
|
||||
|
||||
/**
|
||||
* @brief Description of a single entry in the line number information of a code region.
|
||||
* @details A table of line number entries gives information about how the reported code region
|
||||
* is mapped to source file.
|
||||
* Intel(R) VTune(TM) Amplifier uses line number information to attribute
|
||||
* the samples (virtual address) to a line number. \n
|
||||
* It is acceptable to report different code addresses for the same source line:
|
||||
* @code
|
||||
* Offset LineNumber
|
||||
* 1 2
|
||||
* 12 4
|
||||
* 15 2
|
||||
* 18 1
|
||||
* 21 30
|
||||
*
|
||||
* VTune Amplifier constructs the following table using the client data
|
||||
*
|
||||
* Code subrange Line number
|
||||
* 0-1 2
|
||||
* 1-12 4
|
||||
* 12-15 2
|
||||
* 15-18 1
|
||||
* 18-21 30
|
||||
* @endcode
|
||||
*/
|
||||
typedef struct _LineNumberInfo
|
||||
{
|
||||
unsigned int Offset; /**<\brief Offset from the beginning of the code region. */
|
||||
unsigned int LineNumber; /**<\brief Matching source line number offset (from beginning of source file). */
|
||||
|
||||
} *pLineNumberInfo, LineNumberInfo;
|
||||
|
||||
/**
|
||||
* @brief Enumerator for the code architecture.
|
||||
*/
|
||||
typedef enum _iJIT_CodeArchitecture
|
||||
{
|
||||
iJIT_CA_NATIVE = 0, /**<\brief Native to the process architecture that is calling it. */
|
||||
|
||||
iJIT_CA_32, /**<\brief 32-bit machine code. */
|
||||
|
||||
iJIT_CA_64 /**<\brief 64-bit machine code. */
|
||||
|
||||
} iJIT_CodeArchitecture;
|
||||
|
||||
#pragma pack(push, 8)
|
||||
|
||||
/**
|
||||
* @brief Description of a JIT-compiled method
|
||||
* @details When you use the iJIT_Method_Load structure to describe
|
||||
* the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED
|
||||
* as an event type to report it.
|
||||
*/
|
||||
typedef struct _iJIT_Method_Load
|
||||
{
|
||||
unsigned int method_id; /**<\brief Unique method ID. Cannot be 0.
|
||||
* You must either use the API function
|
||||
* iJIT_GetNewMethodID to get a valid and unique
|
||||
* method ID, or else manage ID uniqueness
|
||||
* and correct range by yourself.\n
|
||||
* You must use the same method ID for all code
|
||||
* regions of the same method, otherwise different
|
||||
* method IDs specify different methods. */
|
||||
|
||||
char* method_name; /**<\brief The name of the method. It can be optionally
|
||||
* prefixed with its class name and appended with
|
||||
* its complete signature. Can't be NULL. */
|
||||
|
||||
void* method_load_address; /**<\brief The start virtual address of the method code
|
||||
* region. If NULL, data provided with
|
||||
* event are not accepted. */
|
||||
|
||||
unsigned int method_size; /**<\brief The code size of the method in memory.
|
||||
* If 0, then data provided with the event are not
|
||||
* accepted. */
|
||||
|
||||
unsigned int line_number_size; /**<\brief The number of entries in the line number
|
||||
* table.0 if none. */
|
||||
|
||||
pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info
|
||||
* array. Can be NULL if
|
||||
* line_number_size is 0. See
|
||||
* LineNumberInfo Structure for a
|
||||
* description of a single entry in
|
||||
* the line number info array */
|
||||
|
||||
unsigned int class_id; /**<\brief This field is obsolete. */
|
||||
|
||||
char* class_file_name; /**<\brief Class name. Can be NULL.*/
|
||||
|
||||
char* source_file_name; /**<\brief Source file name. Can be NULL.*/
|
||||
|
||||
} *piJIT_Method_Load, iJIT_Method_Load;
|
||||
|
||||
/**
|
||||
* @brief Description of a JIT-compiled method
|
||||
* @details When you use the iJIT_Method_Load_V2 structure to describe
|
||||
* the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2
|
||||
* as an event type to report it.
|
||||
*/
|
||||
typedef struct _iJIT_Method_Load_V2
|
||||
{
|
||||
unsigned int method_id; /**<\brief Unique method ID. Cannot be 0.
|
||||
* You must either use the API function
|
||||
* iJIT_GetNewMethodID to get a valid and unique
|
||||
* method ID, or else manage ID uniqueness
|
||||
* and correct range by yourself.\n
|
||||
* You must use the same method ID for all code
|
||||
* regions of the same method, otherwise different
|
||||
* method IDs specify different methods. */
|
||||
|
||||
char* method_name; /**<\brief The name of the method. It can be optionally
|
||||
* prefixed with its class name and appended with
|
||||
* its complete signature. Can't be NULL. */
|
||||
|
||||
void* method_load_address; /**<\brief The start virtual address of the method code
|
||||
* region. If NULL, then data provided with the
|
||||
* event are not accepted. */
|
||||
|
||||
unsigned int method_size; /**<\brief The code size of the method in memory.
|
||||
* If 0, then data provided with the event are not
|
||||
* accepted. */
|
||||
|
||||
unsigned int line_number_size; /**<\brief The number of entries in the line number
|
||||
* table. 0 if none. */
|
||||
|
||||
pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info
|
||||
* array. Can be NULL if
|
||||
* line_number_size is 0. See
|
||||
* LineNumberInfo Structure for a
|
||||
* description of a single entry in
|
||||
* the line number info array. */
|
||||
|
||||
char* class_file_name; /**<\brief Class name. Can be NULL. */
|
||||
|
||||
char* source_file_name; /**<\brief Source file name. Can be NULL. */
|
||||
|
||||
char* module_name; /**<\brief Module name. Can be NULL.
|
||||
The module name can be useful for distinguishing among
|
||||
different JIT engines. VTune Amplifier will display
|
||||
reported methods grouped by specific module. */
|
||||
|
||||
} *piJIT_Method_Load_V2, iJIT_Method_Load_V2;
|
||||
|
||||
/**
|
||||
* @brief Description of a JIT-compiled method
|
||||
* @details The iJIT_Method_Load_V3 structure is the same as iJIT_Method_Load_V2
|
||||
* with a newly introduced 'arch' field that specifies architecture of the code region.
|
||||
* When you use the iJIT_Method_Load_V3 structure to describe
|
||||
* the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V3
|
||||
* as an event type to report it.
|
||||
*/
|
||||
typedef struct _iJIT_Method_Load_V3
|
||||
{
|
||||
unsigned int method_id; /**<\brief Unique method ID. Cannot be 0.
|
||||
* You must either use the API function
|
||||
* iJIT_GetNewMethodID to get a valid and unique
|
||||
* method ID, or manage ID uniqueness
|
||||
* and correct range by yourself.\n
|
||||
* You must use the same method ID for all code
|
||||
* regions of the same method, otherwise they are
|
||||
* treated as regions of different methods. */
|
||||
|
||||
char* method_name; /**<\brief The name of the method. It can be optionally
|
||||
* prefixed with its class name and appended with
|
||||
* its complete signature. Cannot be NULL. */
|
||||
|
||||
void* method_load_address; /**<\brief The start virtual address of the method code
|
||||
* region. If NULL, then data provided with the
|
||||
* event are not accepted. */
|
||||
|
||||
unsigned int method_size; /**<\brief The code size of the method in memory.
|
||||
* If 0, then data provided with the event are not
|
||||
* accepted. */
|
||||
|
||||
unsigned int line_number_size; /**<\brief The number of entries in the line number
|
||||
* table. 0 if none. */
|
||||
|
||||
pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info
|
||||
* array. Can be NULL if
|
||||
* line_number_size is 0. See
|
||||
* LineNumberInfo Structure for a
|
||||
* description of a single entry in
|
||||
* the line number info array. */
|
||||
|
||||
char* class_file_name; /**<\brief Class name. Can be NULL. */
|
||||
|
||||
char* source_file_name; /**<\brief Source file name. Can be NULL. */
|
||||
|
||||
char* module_name; /**<\brief Module name. Can be NULL.
|
||||
* The module name can be useful for distinguishing among
|
||||
* different JIT engines. VTune Amplifier will display
|
||||
* reported methods grouped by specific module. */
|
||||
|
||||
iJIT_CodeArchitecture module_arch; /**<\brief Architecture of the method's code region.
|
||||
* By default, it is the same as the process
|
||||
* architecture that is calling it.
|
||||
* For example, you can use it if your 32-bit JIT
|
||||
* engine generates 64-bit code.
|
||||
*
|
||||
* If JIT engine reports both 32-bit and 64-bit types
|
||||
* of methods then VTune Amplifier splits the methods
|
||||
* with the same module name but with different
|
||||
* architectures in two different modules. VTune Amplifier
|
||||
* modifies the original name provided with a 64-bit method
|
||||
* version by ending it with '(64)' */
|
||||
|
||||
} *piJIT_Method_Load_V3, iJIT_Method_Load_V3;
|
||||
|
||||
/**
|
||||
* @brief Description of an inline JIT-compiled method
|
||||
* @details When you use the_iJIT_Method_Inline_Load structure to describe
|
||||
* the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED
|
||||
* as an event type to report it.
|
||||
*/
|
||||
typedef struct _iJIT_Method_Inline_Load
|
||||
{
|
||||
unsigned int method_id; /**<\brief Unique method ID. Cannot be 0.
|
||||
* You must either use the API function
|
||||
* iJIT_GetNewMethodID to get a valid and unique
|
||||
* method ID, or else manage ID uniqueness
|
||||
* and correct range by yourself. */
|
||||
|
||||
unsigned int parent_method_id; /**<\brief Unique immediate parent's method ID.
|
||||
* Cannot be 0.
|
||||
* You must either use the API function
|
||||
* iJIT_GetNewMethodID to get a valid and unique
|
||||
* method ID, or else manage ID uniqueness
|
||||
* and correct range by yourself. */
|
||||
|
||||
char* method_name; /**<\brief The name of the method. It can be optionally
|
||||
* prefixed with its class name and appended with
|
||||
* its complete signature. Can't be NULL. */
|
||||
|
||||
void* method_load_address; /** <\brief The virtual address on which the method
|
||||
* is inlined. If NULL, then data provided with
|
||||
* the event are not accepted. */
|
||||
|
||||
unsigned int method_size; /**<\brief The code size of the method in memory.
|
||||
* If 0, then data provided with the event are not
|
||||
* accepted. */
|
||||
|
||||
unsigned int line_number_size; /**<\brief The number of entries in the line number
|
||||
* table. 0 if none. */
|
||||
|
||||
pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info
|
||||
* array. Can be NULL if
|
||||
* line_number_size is 0. See
|
||||
* LineNumberInfo Structure for a
|
||||
* description of a single entry in
|
||||
* the line number info array */
|
||||
|
||||
char* class_file_name; /**<\brief Class name. Can be NULL.*/
|
||||
|
||||
char* source_file_name; /**<\brief Source file name. Can be NULL.*/
|
||||
|
||||
} *piJIT_Method_Inline_Load, iJIT_Method_Inline_Load;
|
||||
|
||||
/** @cond exclude_from_documentation */
|
||||
/**
|
||||
* @brief Description of a segment type
|
||||
* @details Use the segment type to specify a type of data supplied
|
||||
* with the iJVM_EVENT_TYPE_METHOD_UPDATE_V2 event to be applied to
|
||||
* a certain code trace.
|
||||
*/
|
||||
typedef enum _iJIT_SegmentType
|
||||
{
|
||||
iJIT_CT_UNKNOWN = 0,
|
||||
|
||||
iJIT_CT_CODE, /**<\brief Executable code. */
|
||||
|
||||
iJIT_CT_DATA, /**<\brief Data (not executable code).
|
||||
* VTune Amplifier uses the format string
|
||||
* (see iJIT_Method_Update) to represent
|
||||
* this data in the VTune Amplifier GUI */
|
||||
|
||||
iJIT_CT_KEEP, /**<\brief Use the previous markup for the trace.
|
||||
* Can be used for the following
|
||||
* iJVM_EVENT_TYPE_METHOD_UPDATE_V2 events,
|
||||
* if the type of the previously reported segment
|
||||
* type is the same. */
|
||||
iJIT_CT_EOF
|
||||
} iJIT_SegmentType;
|
||||
|
||||
/**
|
||||
* @brief Description of a dynamic update of the content within JIT-compiled method
|
||||
* @details The JIT engine may generate the methods that are updated at runtime
|
||||
* partially by mixed (data + executable code) content. When you use the iJIT_Method_Update
|
||||
* structure to describe the update of the content within a JIT-compiled method,
|
||||
* use iJVM_EVENT_TYPE_METHOD_UPDATE_V2 as an event type to report it.
|
||||
*
|
||||
* On the first Update event, VTune Amplifier copies the original code range reported by
|
||||
* the iJVM_EVENT_TYPE_METHOD_LOAD event, then modifies it with the supplied bytes and
|
||||
* adds the modified range to the original method. For next update events, VTune Amplifier
|
||||
* does the same but it uses the latest modified version of a code region for update.
|
||||
* Eventually, VTune Amplifier GUI displays multiple code ranges for the method reported by
|
||||
* the iJVM_EVENT_TYPE_METHOD_LOAD event.
|
||||
* Notes:
|
||||
* - Multiple update events with different types for the same trace are allowed
|
||||
* but they must be reported for the same code ranges.
|
||||
* Example,
|
||||
* @code
|
||||
* [-- data---] Allowed
|
||||
* [-- code --] Allowed
|
||||
* [code] Ignored
|
||||
* [-- data---] Allowed
|
||||
* [-- code --] Allowed
|
||||
* [------------ trace ---------]
|
||||
* @endcode
|
||||
* - The types of previously reported events can be changed but they must be reported
|
||||
* for the same code ranges.
|
||||
* Example,
|
||||
* @code
|
||||
* [-- data---] Allowed
|
||||
* [-- code --] Allowed
|
||||
* [-- data---] Allowed
|
||||
* [-- code --] Allowed
|
||||
* [------------ trace ---------]
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
typedef struct _iJIT_Method_Update
|
||||
{
|
||||
void* load_address; /**<\brief Start address of the update within a method */
|
||||
|
||||
unsigned int size; /**<\brief The update size */
|
||||
|
||||
iJIT_SegmentType type; /**<\brief Type of the update */
|
||||
|
||||
const char* data_format; /**<\brief C string that contains a format string
|
||||
* that follows the same specifications as format in printf.
|
||||
* The format string is used for iJIT_CT_CODE only
|
||||
* and cannot be NULL.
|
||||
* Format can be changed on the fly. */
|
||||
} *piJIT_Method_Update, iJIT_Method_Update;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/** @cond exclude_from_documentation */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifndef JITAPI_CDECL
|
||||
# if defined WIN32 || defined _WIN32
|
||||
# define JITAPI_CDECL __cdecl
|
||||
# else /* defined WIN32 || defined _WIN32 */
|
||||
# if defined _M_IX86 || defined __i386__
|
||||
# define JITAPI_CDECL __attribute__ ((cdecl))
|
||||
# else /* _M_IX86 || __i386__ */
|
||||
# define JITAPI_CDECL /* actual only on x86_64 platform */
|
||||
# endif /* _M_IX86 || __i386__ */
|
||||
# endif /* defined WIN32 || defined _WIN32 */
|
||||
#endif /* JITAPI_CDECL */
|
||||
|
||||
#define JITAPI JITAPI_CDECL
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Generates a new unique method ID.
|
||||
*
|
||||
* You must use this API to obtain unique and valid method IDs for methods or
|
||||
* traces reported to the agent if you don't have your own mechanism to generate
|
||||
* unique method IDs.
|
||||
*
|
||||
* @return a new unique method ID. When out of unique method IDs, this API
|
||||
* returns 0, which is not an accepted value.
|
||||
*/
|
||||
unsigned int JITAPI iJIT_GetNewMethodID(void);
|
||||
|
||||
/**
|
||||
* @brief Returns the current mode of the agent.
|
||||
*
|
||||
* @return iJIT_SAMPLING_ON, indicating that agent is running, or
|
||||
* iJIT_NOTHING_RUNNING if no agent is running.
|
||||
*/
|
||||
iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive(void);
|
||||
|
||||
/**
|
||||
* @brief Reports information about JIT-compiled code to the agent.
|
||||
*
|
||||
* The reported information is used to attribute samples obtained from any
|
||||
* Intel(R) VTune(TM) Amplifier collector. This API needs to be called
|
||||
* after JIT compilation and before the first entry into the JIT-compiled
|
||||
* code.
|
||||
*
|
||||
* @param[in] event_type - type of the data sent to the agent
|
||||
* @param[in] EventSpecificData - pointer to event-specific data
|
||||
*
|
||||
* @returns 1 on success, otherwise 0.
|
||||
*/
|
||||
int JITAPI iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
/** @endcond */
|
||||
|
||||
/** @} jitapi group */
|
||||
|
||||
#endif /* __JITPROFILING_H__ */
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Zend JIT |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Dmitry Stogov <dmitry@php.net> |
|
||||
| Xinchen Hui <laruence@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined(__HAIKU__)
|
||||
#include <FindDirectory.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "zend_API.h"
|
||||
#include "zend_elf.h"
|
||||
|
||||
static void* zend_elf_read_sect(int fd, zend_elf_sectheader *sect)
|
||||
{
|
||||
void *s = emalloc(sect->size);
|
||||
|
||||
if (lseek(fd, sect->ofs, SEEK_SET) < 0) {
|
||||
efree(s);
|
||||
return NULL;
|
||||
}
|
||||
if (read(fd, s, sect->size) != (ssize_t)sect->size) {
|
||||
efree(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void zend_elf_load_symbols(void)
|
||||
{
|
||||
zend_elf_header hdr;
|
||||
zend_elf_sectheader sect;
|
||||
int i;
|
||||
#if defined(__linux__)
|
||||
int fd = open("/proc/self/exe", O_RDONLY);
|
||||
#elif defined(__NetBSD__)
|
||||
int fd = open("/proc/curproc/exe", O_RDONLY);
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
char path[PATH_MAX];
|
||||
size_t pathlen = sizeof(path);
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
||||
if (sysctl(mib, 4, path, &pathlen, NULL, 0) == -1) {
|
||||
return;
|
||||
}
|
||||
int fd = open(path, O_RDONLY);
|
||||
#elif defined(__sun)
|
||||
int fd = open("/proc/self/path/a.out", O_RDONLY);
|
||||
#elif defined(__HAIKU__)
|
||||
char path[PATH_MAX];
|
||||
if (find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH,
|
||||
NULL, path, sizeof(path)) != B_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
int fd = open(path, O_RDONLY);
|
||||
#else
|
||||
// To complete eventually for other ELF platforms.
|
||||
// Otherwise APPLE is Mach-O
|
||||
int fd = -1;
|
||||
#endif
|
||||
|
||||
if (fd >= 0) {
|
||||
if (read(fd, &hdr, sizeof(hdr)) == sizeof(hdr)
|
||||
&& hdr.emagic[0] == '\177'
|
||||
&& hdr.emagic[1] == 'E'
|
||||
&& hdr.emagic[2] == 'L'
|
||||
&& hdr.emagic[3] == 'F'
|
||||
&& lseek(fd, hdr.shofs, SEEK_SET) >= 0) {
|
||||
for (i = 0; i < hdr.shnum; i++) {
|
||||
if (read(fd, §, sizeof(sect)) == sizeof(sect)
|
||||
&& sect.type == ELFSECT_TYPE_SYMTAB) {
|
||||
uint32_t n, count = sect.size / sizeof(zend_elf_symbol);
|
||||
zend_elf_symbol *syms = zend_elf_read_sect(fd, §);
|
||||
char *str_tbl;
|
||||
|
||||
if (syms) {
|
||||
if (lseek(fd, hdr.shofs + sect.link * sizeof(sect), SEEK_SET) >= 0
|
||||
&& read(fd, §, sizeof(sect)) == sizeof(sect)
|
||||
&& (str_tbl = (char*)zend_elf_read_sect(fd, §)) != NULL) {
|
||||
for (n = 0; n < count; n++) {
|
||||
if (syms[n].name
|
||||
&& (ELFSYM_TYPE(syms[n].info) == ELFSYM_TYPE_FUNC
|
||||
/*|| ELFSYM_TYPE(syms[n].info) == ELFSYM_TYPE_DATA*/)
|
||||
&& (ELFSYM_BIND(syms[n].info) == ELFSYM_BIND_LOCAL
|
||||
/*|| ELFSYM_BIND(syms[n].info) == ELFSYM_BIND_GLOBAL*/)) {
|
||||
zend_jit_disasm_add_symbol(str_tbl + syms[n].name, syms[n].value, syms[n].size);
|
||||
}
|
||||
}
|
||||
efree(str_tbl);
|
||||
}
|
||||
efree(syms);
|
||||
}
|
||||
if (lseek(fd, hdr.shofs + (i + 1) * sizeof(sect), SEEK_SET) < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Zend JIT |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Dmitry Stogov <dmitry@php.net> |
|
||||
| Xinchen Hui <laruence@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef ZEND_ELF
|
||||
#define ZEND_ELF
|
||||
|
||||
#if SIZEOF_SIZE_T == 8
|
||||
# define ELF64
|
||||
#else
|
||||
# undef ELF64
|
||||
#endif
|
||||
|
||||
typedef struct _zend_elf_header {
|
||||
uint8_t emagic[4];
|
||||
uint8_t eclass;
|
||||
uint8_t eendian;
|
||||
uint8_t eversion;
|
||||
uint8_t eosabi;
|
||||
uint8_t eabiversion;
|
||||
uint8_t epad[7];
|
||||
uint16_t type;
|
||||
uint16_t machine;
|
||||
uint32_t version;
|
||||
uintptr_t entry;
|
||||
uintptr_t phofs;
|
||||
uintptr_t shofs;
|
||||
uint32_t flags;
|
||||
uint16_t ehsize;
|
||||
uint16_t phentsize;
|
||||
uint16_t phnum;
|
||||
uint16_t shentsize;
|
||||
uint16_t shnum;
|
||||
uint16_t shstridx;
|
||||
} zend_elf_header;
|
||||
|
||||
typedef struct zend_elf_sectheader {
|
||||
uint32_t name;
|
||||
uint32_t type;
|
||||
uintptr_t flags;
|
||||
uintptr_t addr;
|
||||
uintptr_t ofs;
|
||||
uintptr_t size;
|
||||
uint32_t link;
|
||||
uint32_t info;
|
||||
uintptr_t align;
|
||||
uintptr_t entsize;
|
||||
} zend_elf_sectheader;
|
||||
|
||||
#define ELFSECT_IDX_ABS 0xfff1
|
||||
|
||||
enum {
|
||||
ELFSECT_TYPE_PROGBITS = 1,
|
||||
ELFSECT_TYPE_SYMTAB = 2,
|
||||
ELFSECT_TYPE_STRTAB = 3,
|
||||
ELFSECT_TYPE_NOBITS = 8,
|
||||
ELFSECT_TYPE_DYNSYM = 11,
|
||||
};
|
||||
|
||||
#define ELFSECT_FLAGS_WRITE (1 << 0)
|
||||
#define ELFSECT_FLAGS_ALLOC (1 << 1)
|
||||
#define ELFSECT_FLAGS_EXEC (1 << 2)
|
||||
#define ELFSECT_FLAGS_TLS (1 << 10)
|
||||
|
||||
typedef struct zend_elf_symbol {
|
||||
#ifdef ELF64
|
||||
uint32_t name;
|
||||
uint8_t info;
|
||||
uint8_t other;
|
||||
uint16_t sectidx;
|
||||
uintptr_t value;
|
||||
uint64_t size;
|
||||
#else
|
||||
uint32_t name;
|
||||
uintptr_t value;
|
||||
uint32_t size;
|
||||
uint8_t info;
|
||||
uint8_t other;
|
||||
uint16_t sectidx;
|
||||
#endif
|
||||
} zend_elf_symbol;
|
||||
|
||||
#define ELFSYM_BIND(info) ((info) >> 4)
|
||||
#define ELFSYM_TYPE(info) ((info) & 0xf)
|
||||
#define ELFSYM_INFO(bind, type) (((bind) << 4) | (type))
|
||||
|
||||
enum {
|
||||
ELFSYM_TYPE_DATA = 2,
|
||||
ELFSYM_TYPE_FUNC = 2,
|
||||
ELFSYM_TYPE_FILE = 4,
|
||||
};
|
||||
|
||||
enum {
|
||||
ELFSYM_BIND_LOCAL = 0,
|
||||
ELFSYM_BIND_GLOBAL = 1,
|
||||
};
|
||||
|
||||
void zend_elf_load_symbols(void);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -165,8 +165,6 @@ ZEND_EXT_API void zend_jit_deactivate(void);
|
|||
ZEND_EXT_API void zend_jit_status(zval *ret);
|
||||
ZEND_EXT_API void zend_jit_restart(void);
|
||||
|
||||
#ifdef ZEND_JIT_IR
|
||||
|
||||
#define ZREG_LOAD (1<<0)
|
||||
#define ZREG_STORE (1<<1)
|
||||
#define ZREG_LAST_USE (1<<2)
|
||||
|
@ -185,39 +183,4 @@ ZEND_EXT_API void zend_jit_restart(void);
|
|||
|
||||
#define ZREG_NONE -1
|
||||
|
||||
#else
|
||||
typedef struct _zend_lifetime_interval zend_lifetime_interval;
|
||||
typedef struct _zend_life_range zend_life_range;
|
||||
|
||||
struct _zend_life_range {
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
zend_life_range *next;
|
||||
};
|
||||
|
||||
#define ZREG_FLAGS_SHIFT 8
|
||||
|
||||
#define ZREG_STORE (1<<0)
|
||||
#define ZREG_LOAD (1<<1)
|
||||
#define ZREG_LAST_USE (1<<2)
|
||||
#define ZREG_SPLIT (1<<3)
|
||||
|
||||
struct _zend_lifetime_interval {
|
||||
int ssa_var;
|
||||
union {
|
||||
struct {
|
||||
ZEND_ENDIAN_LOHI_3(
|
||||
int8_t reg,
|
||||
uint8_t flags,
|
||||
uint16_t reserved
|
||||
)};
|
||||
uint32_t reg_flags;
|
||||
};
|
||||
zend_life_range range;
|
||||
zend_lifetime_interval *hint;
|
||||
zend_lifetime_interval *used_as_hint;
|
||||
zend_lifetime_interval *list_next;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_JIT_H */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Zend JIT |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Dmitry Stogov <dmitry@php.net> |
|
||||
| Hao Sun <hao.sun@arm.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef HAVE_JIT_ARM64_H
|
||||
#define HAVE_JIT_ARM64_H
|
||||
|
||||
typedef enum _zend_reg {
|
||||
ZREG_NONE = -1,
|
||||
|
||||
ZREG_X0,
|
||||
ZREG_X1,
|
||||
ZREG_X2,
|
||||
ZREG_X3,
|
||||
ZREG_X4,
|
||||
ZREG_X5,
|
||||
ZREG_X6,
|
||||
ZREG_X7,
|
||||
ZREG_X8,
|
||||
ZREG_X9,
|
||||
ZREG_X10,
|
||||
ZREG_X11,
|
||||
ZREG_X12,
|
||||
ZREG_X13,
|
||||
ZREG_X14,
|
||||
ZREG_X15,
|
||||
ZREG_X16,
|
||||
ZREG_X17,
|
||||
ZREG_X18,
|
||||
ZREG_X19,
|
||||
ZREG_X20,
|
||||
ZREG_X21,
|
||||
ZREG_X22,
|
||||
ZREG_X23,
|
||||
ZREG_X24,
|
||||
ZREG_X25,
|
||||
ZREG_X26,
|
||||
ZREG_X27,
|
||||
ZREG_X28,
|
||||
ZREG_X29,
|
||||
ZREG_X30,
|
||||
ZREG_X31,
|
||||
|
||||
ZREG_V0,
|
||||
ZREG_V1,
|
||||
ZREG_V2,
|
||||
ZREG_V3,
|
||||
ZREG_V4,
|
||||
ZREG_V5,
|
||||
ZREG_V6,
|
||||
ZREG_V7,
|
||||
ZREG_V8,
|
||||
ZREG_V9,
|
||||
ZREG_V10,
|
||||
ZREG_V11,
|
||||
ZREG_V12,
|
||||
ZREG_V13,
|
||||
ZREG_V14,
|
||||
ZREG_V15,
|
||||
ZREG_V16,
|
||||
ZREG_V17,
|
||||
ZREG_V18,
|
||||
ZREG_V19,
|
||||
ZREG_V20,
|
||||
ZREG_V21,
|
||||
ZREG_V22,
|
||||
ZREG_V23,
|
||||
ZREG_V24,
|
||||
ZREG_V25,
|
||||
ZREG_V26,
|
||||
ZREG_V27,
|
||||
ZREG_V28,
|
||||
ZREG_V29,
|
||||
ZREG_V30,
|
||||
ZREG_V31,
|
||||
|
||||
ZREG_NUM,
|
||||
|
||||
ZREG_THIS, /* used for delayed FETCH_THIS deoptimization */
|
||||
|
||||
/* pseudo constants used by deoptimizer */
|
||||
ZREG_LONG_MIN_MINUS_1,
|
||||
ZREG_LONG_MIN,
|
||||
ZREG_LONG_MAX,
|
||||
ZREG_LONG_MAX_PLUS_1,
|
||||
ZREG_NULL,
|
||||
|
||||
ZREG_ZVAL_TRY_ADDREF,
|
||||
ZREG_ZVAL_COPY_GPR0,
|
||||
} zend_reg;
|
||||
|
||||
typedef struct _zend_jit_registers_buf {
|
||||
uint64_t gpr[32]; /* general purpose integer register */
|
||||
double fpr[32]; /* floating point registers */
|
||||
} zend_jit_registers_buf;
|
||||
|
||||
#define ZREG_RSP ZREG_X31
|
||||
#define ZREG_RLR ZREG_X30
|
||||
#define ZREG_RFP ZREG_X29
|
||||
#define ZREG_RPR ZREG_X18
|
||||
|
||||
#define ZREG_FP ZREG_X27
|
||||
#define ZREG_IP ZREG_X28
|
||||
#define ZREG_RX ZREG_IP
|
||||
|
||||
#define ZREG_REG0 ZREG_X8
|
||||
#define ZREG_REG1 ZREG_X9
|
||||
#define ZREG_REG2 ZREG_X10
|
||||
|
||||
#define ZREG_FPR0 ZREG_V0
|
||||
#define ZREG_FPR1 ZREG_V1
|
||||
|
||||
#define ZREG_TMP1 ZREG_X15
|
||||
#define ZREG_TMP2 ZREG_X16
|
||||
#define ZREG_TMP3 ZREG_X17
|
||||
#define ZREG_FPTMP ZREG_V16
|
||||
|
||||
#define ZREG_COPY ZREG_REG0
|
||||
#define ZREG_FIRST_FPR ZREG_V0
|
||||
|
||||
typedef uint64_t zend_regset;
|
||||
|
||||
#define ZEND_REGSET_64BIT 1
|
||||
|
||||
# define ZEND_REGSET_FIXED \
|
||||
(ZEND_REGSET(ZREG_RSP) | ZEND_REGSET(ZREG_RLR) | ZEND_REGSET(ZREG_RFP) | \
|
||||
ZEND_REGSET(ZREG_RPR) | ZEND_REGSET(ZREG_FP) | ZEND_REGSET(ZREG_IP) | \
|
||||
ZEND_REGSET_INTERVAL(ZREG_TMP1, ZREG_TMP3) | ZEND_REGSET(ZREG_FPTMP))
|
||||
# define ZEND_REGSET_GP \
|
||||
ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_X0, ZREG_X30), ZEND_REGSET_FIXED)
|
||||
# define ZEND_REGSET_FP \
|
||||
ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_V0, ZREG_V31), ZEND_REGSET_FIXED)
|
||||
# define ZEND_REGSET_SCRATCH \
|
||||
(ZEND_REGSET_INTERVAL(ZREG_X0, ZREG_X17) | ZEND_REGSET_INTERVAL(ZREG_V0, ZREG_V7) | \
|
||||
ZEND_REGSET_INTERVAL(ZREG_V16, ZREG_V31))
|
||||
# define ZEND_REGSET_PRESERVED \
|
||||
(ZEND_REGSET_INTERVAL(ZREG_X19, ZREG_X28) | ZEND_REGSET_INTERVAL(ZREG_V8, ZREG_V15))
|
||||
|
||||
#define ZEND_REGSET_LOW_PRIORITY \
|
||||
(ZEND_REGSET(ZREG_REG0) | ZEND_REGSET(ZREG_REG1) | ZEND_REGSET(ZREG_FPR0) | ZEND_REGSET(ZREG_FPR1))
|
||||
|
||||
#endif /* ZEND_JIT_ARM64_H */
|
|
@ -1,781 +0,0 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Zend JIT |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Dmitry Stogov <dmitry@php.net> |
|
||||
| Xinchen Hui <laruence@php.net> |
|
||||
| Hao Sun <hao.sun@arm.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CAPSTONE
|
||||
# define HAVE_DISASM 1
|
||||
# include <capstone.h>
|
||||
# define HAVE_CAPSTONE_ITER 1
|
||||
#elif ZEND_JIT_TARGET_X86
|
||||
# define HAVE_DISASM 1
|
||||
# define DISASM_INTEL_SYNTAX 0
|
||||
|
||||
# include "jit/libudis86/itab.c"
|
||||
# include "jit/libudis86/decode.c"
|
||||
# include "jit/libudis86/syn.c"
|
||||
# if DISASM_INTEL_SYNTAX
|
||||
# include "jit/libudis86/syn-intel.c"
|
||||
# else
|
||||
# include "jit/libudis86/syn-att.c"
|
||||
# endif
|
||||
# include "jit/libudis86/udis86.c"
|
||||
#endif /* HAVE_CAPSTONE */
|
||||
|
||||
#ifdef HAVE_DISASM
|
||||
|
||||
static void zend_jit_disasm_add_symbol(const char *name,
|
||||
uint64_t addr,
|
||||
uint64_t size);
|
||||
|
||||
#ifndef _WIN32
|
||||
# include "jit/zend_elf.c"
|
||||
#endif
|
||||
|
||||
#include "zend_sort.h"
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
struct _sym_node {
|
||||
uint64_t addr;
|
||||
uint64_t end;
|
||||
struct _sym_node *parent;
|
||||
struct _sym_node *child[2];
|
||||
unsigned char info;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
static void zend_syms_rotateleft(zend_sym_node *p) {
|
||||
zend_sym_node *r = p->child[1];
|
||||
p->child[1] = r->child[0];
|
||||
if (r->child[0]) {
|
||||
r->child[0]->parent = p;
|
||||
}
|
||||
r->parent = p->parent;
|
||||
if (p->parent == NULL) {
|
||||
JIT_G(symbols) = r;
|
||||
} else if (p->parent->child[0] == p) {
|
||||
p->parent->child[0] = r;
|
||||
} else {
|
||||
p->parent->child[1] = r;
|
||||
}
|
||||
r->child[0] = p;
|
||||
p->parent = r;
|
||||
}
|
||||
|
||||
static void zend_syms_rotateright(zend_sym_node *p) {
|
||||
zend_sym_node *l = p->child[0];
|
||||
p->child[0] = l->child[1];
|
||||
if (l->child[1]) {
|
||||
l->child[1]->parent = p;
|
||||
}
|
||||
l->parent = p->parent;
|
||||
if (p->parent == NULL) {
|
||||
JIT_G(symbols) = l;
|
||||
} else if (p->parent->child[1] == p) {
|
||||
p->parent->child[1] = l;
|
||||
} else {
|
||||
p->parent->child[0] = l;
|
||||
}
|
||||
l->child[1] = p;
|
||||
p->parent = l;
|
||||
}
|
||||
|
||||
static void zend_jit_disasm_add_symbol(const char *name,
|
||||
uint64_t addr,
|
||||
uint64_t size)
|
||||
{
|
||||
zend_sym_node *sym;
|
||||
size_t len = strlen(name);
|
||||
|
||||
sym = malloc(sizeof(zend_sym_node) + len + 1);
|
||||
if (!sym) {
|
||||
return;
|
||||
}
|
||||
sym->addr = addr;
|
||||
sym->end = (addr + size - 1);
|
||||
memcpy((char*)&sym->name, name, len + 1);
|
||||
sym->parent = sym->child[0] = sym->child[1] = NULL;
|
||||
sym->info = 1;
|
||||
if (JIT_G(symbols)) {
|
||||
zend_sym_node *node = JIT_G(symbols);
|
||||
|
||||
/* insert it into rbtree */
|
||||
do {
|
||||
if (sym->addr > node->addr) {
|
||||
ZEND_ASSERT(sym->addr > (node->end));
|
||||
if (node->child[1]) {
|
||||
node = node->child[1];
|
||||
} else {
|
||||
node->child[1] = sym;
|
||||
sym->parent = node;
|
||||
break;
|
||||
}
|
||||
} else if (sym->addr < node->addr) {
|
||||
if (node->child[0]) {
|
||||
node = node->child[0];
|
||||
} else {
|
||||
node->child[0] = sym;
|
||||
sym->parent = node;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ZEND_ASSERT(sym->addr == node->addr);
|
||||
if (strcmp(name, node->name) == 0 && sym->end < node->end) {
|
||||
/* reduce size of the existing symbol */
|
||||
node->end = sym->end;
|
||||
}
|
||||
free(sym);
|
||||
return;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
/* fix rbtree after instering */
|
||||
while (sym && sym != JIT_G(symbols) && sym->parent->info == 1) {
|
||||
if (sym->parent == sym->parent->parent->child[0]) {
|
||||
node = sym->parent->parent->child[1];
|
||||
if (node && node->info == 1) {
|
||||
sym->parent->info = 0;
|
||||
node->info = 0;
|
||||
sym->parent->parent->info = 1;
|
||||
sym = sym->parent->parent;
|
||||
} else {
|
||||
if (sym == sym->parent->child[1]) {
|
||||
sym = sym->parent;
|
||||
zend_syms_rotateleft(sym);
|
||||
}
|
||||
sym->parent->info = 0;
|
||||
sym->parent->parent->info = 1;
|
||||
zend_syms_rotateright(sym->parent->parent);
|
||||
}
|
||||
} else {
|
||||
node = sym->parent->parent->child[0];
|
||||
if (node && node->info == 1) {
|
||||
sym->parent->info = 0;
|
||||
node->info = 0;
|
||||
sym->parent->parent->info = 1;
|
||||
sym = sym->parent->parent;
|
||||
} else {
|
||||
if (sym == sym->parent->child[0]) {
|
||||
sym = sym->parent;
|
||||
zend_syms_rotateright(sym);
|
||||
}
|
||||
sym->parent->info = 0;
|
||||
sym->parent->parent->info = 1;
|
||||
zend_syms_rotateleft(sym->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
JIT_G(symbols) = sym;
|
||||
}
|
||||
JIT_G(symbols)->info = 0;
|
||||
}
|
||||
|
||||
static void zend_jit_disasm_destroy_symbols(zend_sym_node *n) {
|
||||
if (n) {
|
||||
if (n->child[0]) {
|
||||
zend_jit_disasm_destroy_symbols(n->child[0]);
|
||||
}
|
||||
if (n->child[1]) {
|
||||
zend_jit_disasm_destroy_symbols(n->child[1]);
|
||||
}
|
||||
free(n);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* zend_jit_disasm_find_symbol(uint64_t addr,
|
||||
int64_t *offset) {
|
||||
zend_sym_node *node = JIT_G(symbols);
|
||||
while (node) {
|
||||
if (addr < node->addr) {
|
||||
node = node->child[0];
|
||||
} else if (addr > node->end) {
|
||||
node = node->child[1];
|
||||
} else {
|
||||
*offset = addr - node->addr;
|
||||
return node->name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CAPSTONE
|
||||
static uint64_t zend_jit_disasm_branch_target(csh cs, const cs_insn *insn)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
#if ZEND_JIT_TARGET_X86
|
||||
if (cs_insn_group(cs, insn, X86_GRP_JUMP)) {
|
||||
for (i = 0; i < insn->detail->x86.op_count; i++) {
|
||||
if (insn->detail->x86.operands[i].type == X86_OP_IMM) {
|
||||
return insn->detail->x86.operands[i].imm;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif ZEND_JIT_TARGET_ARM64
|
||||
if (cs_insn_group(cs, insn, ARM64_GRP_JUMP)
|
||||
|| insn->id == ARM64_INS_BL
|
||||
|| insn->id == ARM64_INS_ADR) {
|
||||
for (i = 0; i < insn->detail->arm64.op_count; i++) {
|
||||
if (insn->detail->arm64.operands[i].type == ARM64_OP_IMM)
|
||||
return insn->detail->arm64.operands[i].imm;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char* zend_jit_disasm_resolver(
|
||||
#ifndef HAVE_CAPSTONE
|
||||
struct ud *ud,
|
||||
#endif
|
||||
uint64_t addr,
|
||||
int64_t *offset)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
# ifndef HAVE_CAPSTONE
|
||||
((void)ud);
|
||||
# endif
|
||||
const char *name;
|
||||
void *a = (void*)(uintptr_t)(addr);
|
||||
Dl_info info;
|
||||
|
||||
name = zend_jit_disasm_find_symbol(addr, offset);
|
||||
if (name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
if (dladdr(a, &info)
|
||||
&& info.dli_sname != NULL
|
||||
&& info.dli_saddr == a) {
|
||||
return info.dli_sname;
|
||||
}
|
||||
#else
|
||||
const char *name;
|
||||
name = zend_jit_disasm_find_symbol(addr, offset);
|
||||
if (name) {
|
||||
return name;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int zend_jit_cmp_labels(Bucket *b1, Bucket *b2)
|
||||
{
|
||||
return ((b1->h > b2->h) > 0) ? 1 : -1;
|
||||
}
|
||||
|
||||
static int zend_jit_disasm(const char *name,
|
||||
const char *filename,
|
||||
const zend_op_array *op_array,
|
||||
zend_cfg *cfg,
|
||||
const void *start,
|
||||
size_t size)
|
||||
{
|
||||
const void *end = (void *)((char *)start + size);
|
||||
zval zv, *z;
|
||||
zend_long n, m;
|
||||
HashTable labels;
|
||||
uint64_t addr;
|
||||
int b;
|
||||
#ifdef HAVE_CAPSTONE
|
||||
csh cs;
|
||||
cs_insn *insn;
|
||||
# ifdef HAVE_CAPSTONE_ITER
|
||||
const uint8_t *cs_code;
|
||||
size_t cs_size;
|
||||
uint64_t cs_addr;
|
||||
# else
|
||||
size_t count, i;
|
||||
# endif
|
||||
const char *sym;
|
||||
int64_t offset = 0;
|
||||
char *p, *q, *r;
|
||||
#else
|
||||
struct ud ud;
|
||||
const struct ud_operand *op;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CAPSTONE
|
||||
# if ZEND_JIT_TARGET_X86
|
||||
# if defined(__x86_64__) || defined(_WIN64)
|
||||
if (cs_open(CS_ARCH_X86, CS_MODE_64, &cs) != CS_ERR_OK)
|
||||
return 0;
|
||||
# else
|
||||
if (cs_open(CS_ARCH_X86, CS_MODE_32, &cs) != CS_ERR_OK)
|
||||
return 0;
|
||||
# endif
|
||||
cs_option(cs, CS_OPT_DETAIL, CS_OPT_ON);
|
||||
# if DISASM_INTEL_SYNTAX
|
||||
cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
|
||||
# else
|
||||
cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
|
||||
# endif
|
||||
# elif ZEND_JIT_TARGET_ARM64
|
||||
if (cs_open(CS_ARCH_ARM64, CS_MODE_ARM, &cs) != CS_ERR_OK)
|
||||
return 0;
|
||||
cs_option(cs, CS_OPT_DETAIL, CS_OPT_ON);
|
||||
cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
|
||||
# endif
|
||||
#else
|
||||
ud_init(&ud);
|
||||
# if defined(__x86_64__) || defined(_WIN64)
|
||||
ud_set_mode(&ud, 64);
|
||||
# else
|
||||
ud_set_mode(&ud, 32);
|
||||
# endif
|
||||
# if DISASM_INTEL_SYNTAX
|
||||
ud_set_syntax(&ud, UD_SYN_INTEL);
|
||||
# else
|
||||
ud_set_syntax(&ud, UD_SYN_ATT);
|
||||
# endif
|
||||
ud_set_sym_resolver(&ud, zend_jit_disasm_resolver);
|
||||
#endif /* HAVE_CAPSTONE */
|
||||
|
||||
if (name) {
|
||||
fprintf(stderr, "%s: ; (%s)\n", name, filename ? filename : "unknown");
|
||||
}
|
||||
|
||||
#ifndef HAVE_CAPSTONE
|
||||
ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
|
||||
ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
|
||||
#endif
|
||||
|
||||
zend_hash_init(&labels, 8, NULL, NULL, 0);
|
||||
if (op_array && cfg) {
|
||||
ZVAL_FALSE(&zv);
|
||||
for (b = 0; b < cfg->blocks_count; b++) {
|
||||
if (cfg->blocks[b].flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
|
||||
addr = (uint64_t)(uintptr_t)op_array->opcodes[cfg->blocks[b].start].handler;
|
||||
if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
|
||||
zend_hash_index_add(&labels, addr, &zv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_CAPSTONE
|
||||
ZVAL_TRUE(&zv);
|
||||
# ifdef HAVE_CAPSTONE_ITER
|
||||
cs_code = start;
|
||||
cs_size = (uint8_t*)end - (uint8_t*)start;
|
||||
cs_addr = (uint64_t)(uintptr_t)cs_code;
|
||||
insn = cs_malloc(cs);
|
||||
while (cs_disasm_iter(cs, &cs_code, &cs_size, &cs_addr, insn)) {
|
||||
if ((addr = zend_jit_disasm_branch_target(cs, insn))) {
|
||||
# else
|
||||
count = cs_disasm(cs, start, (uint8_t*)end - (uint8_t*)start, (uintptr_t)start, 0, &insn);
|
||||
for (i = 0; i < count; i++) {
|
||||
if ((addr = zend_jit_disasm_branch_target(cs, &(insn[i])))) {
|
||||
# endif
|
||||
if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
|
||||
zend_hash_index_add(&labels, addr, &zv);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
ZVAL_TRUE(&zv);
|
||||
while (ud_disassemble(&ud)) {
|
||||
op = ud_insn_opr(&ud, 0);
|
||||
if (op && op->type == UD_OP_JIMM) {
|
||||
addr = ud_syn_rel_target(&ud, (struct ud_operand*)op);
|
||||
if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
|
||||
zend_hash_index_add(&labels, addr, &zv);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
zend_hash_sort(&labels, zend_jit_cmp_labels, 0);
|
||||
|
||||
/* label numbering */
|
||||
n = 0; m = 0;
|
||||
ZEND_HASH_MAP_FOREACH_VAL(&labels, z) {
|
||||
if (Z_TYPE_P(z) == IS_FALSE) {
|
||||
m--;
|
||||
ZVAL_LONG(z, m);
|
||||
} else {
|
||||
n++;
|
||||
ZVAL_LONG(z, n);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
#ifdef HAVE_CAPSTONE
|
||||
# ifdef HAVE_CAPSTONE_ITER
|
||||
cs_code = start;
|
||||
cs_size = (uint8_t*)end - (uint8_t*)start;
|
||||
cs_addr = (uint64_t)(uintptr_t)cs_code;
|
||||
while (cs_disasm_iter(cs, &cs_code, &cs_size, &cs_addr, insn)) {
|
||||
z = zend_hash_index_find(&labels, insn->address);
|
||||
# else
|
||||
for (i = 0; i < count; i++) {
|
||||
z = zend_hash_index_find(&labels, insn[i].address);
|
||||
# endif
|
||||
if (z) {
|
||||
if (Z_LVAL_P(z) < 0) {
|
||||
fprintf(stderr, ".ENTRY" ZEND_LONG_FMT ":\n", -Z_LVAL_P(z));
|
||||
} else {
|
||||
fprintf(stderr, ".L" ZEND_LONG_FMT ":\n", Z_LVAL_P(z));
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef HAVE_CAPSTONE_ITER
|
||||
if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) {
|
||||
fprintf(stderr, " %" PRIx64 ":", insn->address);
|
||||
}
|
||||
fprintf(stderr, "\t%s ", insn->mnemonic);
|
||||
p = insn->op_str;
|
||||
# else
|
||||
if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) {
|
||||
fprintf(stderr, " %" PRIx64 ":", insn[i].address);
|
||||
}
|
||||
fprintf(stderr, "\t%s ", insn[i].mnemonic);
|
||||
p = insn[i].op_str;
|
||||
# endif
|
||||
/* Try to replace the target addresses with a symbols */
|
||||
while ((q = strchr(p, 'x')) != NULL) {
|
||||
if (p != q && *(q-1) == '0') {
|
||||
r = q + 1;
|
||||
addr = 0;
|
||||
while (1) {
|
||||
if (*r >= '0' && *r <= '9') {
|
||||
addr = addr * 16 + (*r - '0');
|
||||
} else if (*r >= 'A' && *r <= 'F') {
|
||||
addr = addr * 16 + (*r - 'A' + 10);
|
||||
} else if (*r >= 'a' && *r <= 'f') {
|
||||
addr = addr * 16 + (*r - 'a' + 10);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
r++;
|
||||
}
|
||||
if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
|
||||
if ((z = zend_hash_index_find(&labels, addr))) {
|
||||
if (Z_LVAL_P(z) < 0) {
|
||||
fwrite(p, 1, q - p - 1, stderr);
|
||||
fprintf(stderr, ".ENTRY" ZEND_LONG_FMT, -Z_LVAL_P(z));
|
||||
} else {
|
||||
fwrite(p, 1, q - p - 1, stderr);
|
||||
fprintf(stderr, ".L" ZEND_LONG_FMT, Z_LVAL_P(z));
|
||||
}
|
||||
} else {
|
||||
fwrite(p, 1, r - p, stderr);
|
||||
}
|
||||
} else if ((sym = zend_jit_disasm_resolver(addr, &offset))) {
|
||||
fwrite(p, 1, q - p - 1, stderr);
|
||||
fputs(sym, stderr);
|
||||
if (offset != 0) {
|
||||
if (offset > 0) {
|
||||
fprintf(stderr, "+%" PRIx64, offset);
|
||||
} else {
|
||||
fprintf(stderr, "-%" PRIx64, offset);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fwrite(p, 1, r - p, stderr);
|
||||
}
|
||||
p = r;
|
||||
} else {
|
||||
fwrite(p, 1, q - p + 1, stderr);
|
||||
p = q + 1;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s\n", p);
|
||||
}
|
||||
# ifdef HAVE_CAPSTONE_ITER
|
||||
cs_free(insn, 1);
|
||||
# else
|
||||
cs_free(insn, count);
|
||||
# endif
|
||||
#else
|
||||
ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
|
||||
ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
|
||||
|
||||
while (ud_disassemble(&ud)) {
|
||||
addr = ud_insn_off(&ud);
|
||||
z = zend_hash_index_find(&labels, addr);
|
||||
if (z) {
|
||||
if (Z_LVAL_P(z) < 0) {
|
||||
fprintf(stderr, ".ENTRY" ZEND_LONG_FMT ":\n", -Z_LVAL_P(z));
|
||||
} else {
|
||||
fprintf(stderr, ".L" ZEND_LONG_FMT ":\n", Z_LVAL_P(z));
|
||||
}
|
||||
}
|
||||
op = ud_insn_opr(&ud, 0);
|
||||
if (op && op->type == UD_OP_JIMM) {
|
||||
addr = ud_syn_rel_target(&ud, (struct ud_operand*)op);
|
||||
if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
|
||||
z = zend_hash_index_find(&labels, addr);
|
||||
if (z) {
|
||||
const char *str = ud_insn_asm(&ud);
|
||||
int len;
|
||||
|
||||
len = 0;
|
||||
while (str[len] != 0 && str[len] != ' ' && str[len] != '\t') {
|
||||
len++;
|
||||
}
|
||||
if (str[len] != 0) {
|
||||
while (str[len] == ' ' || str[len] == '\t') {
|
||||
len++;
|
||||
}
|
||||
if (Z_LVAL_P(z) < 0) {
|
||||
fprintf(stderr, "\t%.*s.ENTRY" ZEND_LONG_FMT "\n", len, str, -Z_LVAL_P(z));
|
||||
} else {
|
||||
fprintf(stderr, "\t%.*s.L" ZEND_LONG_FMT "\n", len, str, Z_LVAL_P(z));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) {
|
||||
fprintf(stderr, " %" PRIx64 ":", ud_insn_off(&ud));
|
||||
}
|
||||
fprintf(stderr, "\t%s\n", ud_insn_asm(&ud));
|
||||
}
|
||||
#endif
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
zend_hash_destroy(&labels);
|
||||
|
||||
#ifdef HAVE_CAPSTONE
|
||||
cs_close(&cs);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int zend_jit_disasm_init(void)
|
||||
{
|
||||
#ifndef ZTS
|
||||
#define REGISTER_EG(n) \
|
||||
zend_jit_disasm_add_symbol("EG("#n")", \
|
||||
(uint64_t)(uintptr_t)&executor_globals.n, sizeof(executor_globals.n))
|
||||
REGISTER_EG(uninitialized_zval);
|
||||
REGISTER_EG(exception);
|
||||
REGISTER_EG(vm_interrupt);
|
||||
REGISTER_EG(exception_op);
|
||||
REGISTER_EG(timed_out);
|
||||
REGISTER_EG(current_execute_data);
|
||||
REGISTER_EG(vm_stack_top);
|
||||
REGISTER_EG(vm_stack_end);
|
||||
REGISTER_EG(symbol_table);
|
||||
REGISTER_EG(jit_trace_num);
|
||||
#undef REGISTER_EG
|
||||
#define REGISTER_CG(n) \
|
||||
zend_jit_disasm_add_symbol("CG("#n")", \
|
||||
(uint64_t)(uintptr_t)&compiler_globals.n, sizeof(compiler_globals.n))
|
||||
REGISTER_CG(map_ptr_base);
|
||||
#undef REGISTER_CG
|
||||
#endif
|
||||
|
||||
/* Register JIT helper functions */
|
||||
#define REGISTER_HELPER(n) \
|
||||
zend_jit_disasm_add_symbol(#n, \
|
||||
(uint64_t)(uintptr_t)n, sizeof(void*));
|
||||
REGISTER_HELPER(memcmp);
|
||||
REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
|
||||
REGISTER_HELPER(zend_jit_find_func_helper);
|
||||
REGISTER_HELPER(zend_jit_find_ns_func_helper);
|
||||
REGISTER_HELPER(zend_jit_find_method_helper);
|
||||
REGISTER_HELPER(zend_jit_find_method_tmp_helper);
|
||||
REGISTER_HELPER(zend_jit_push_static_metod_call_frame);
|
||||
REGISTER_HELPER(zend_jit_push_static_metod_call_frame_tmp);
|
||||
REGISTER_HELPER(zend_jit_invalid_method_call);
|
||||
REGISTER_HELPER(zend_jit_invalid_method_call_tmp);
|
||||
REGISTER_HELPER(zend_jit_unref_helper);
|
||||
REGISTER_HELPER(zend_jit_extend_stack_helper);
|
||||
REGISTER_HELPER(zend_jit_int_extend_stack_helper);
|
||||
REGISTER_HELPER(zend_jit_leave_nested_func_helper);
|
||||
REGISTER_HELPER(zend_jit_leave_top_func_helper);
|
||||
REGISTER_HELPER(zend_jit_leave_func_helper);
|
||||
REGISTER_HELPER(zend_jit_symtable_find);
|
||||
REGISTER_HELPER(zend_jit_hash_index_lookup_rw_no_packed);
|
||||
REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
|
||||
REGISTER_HELPER(zend_jit_hash_lookup_rw);
|
||||
REGISTER_HELPER(zend_jit_symtable_lookup_rw);
|
||||
REGISTER_HELPER(zend_jit_symtable_lookup_w);
|
||||
REGISTER_HELPER(zend_jit_undefined_op_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper);
|
||||
REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper);
|
||||
// REGISTER_HELPER(zend_jit_fetch_dim_obj_unset_helper);
|
||||
REGISTER_HELPER(zend_jit_assign_dim_helper);
|
||||
REGISTER_HELPER(zend_jit_assign_dim_op_helper);
|
||||
REGISTER_HELPER(zend_jit_fast_assign_concat_helper);
|
||||
REGISTER_HELPER(zend_jit_fast_concat_helper);
|
||||
REGISTER_HELPER(zend_jit_fast_concat_tmp_helper);
|
||||
REGISTER_HELPER(zend_jit_isset_dim_helper);
|
||||
REGISTER_HELPER(zend_jit_free_call_frame);
|
||||
REGISTER_HELPER(zend_jit_fetch_global_helper);
|
||||
REGISTER_HELPER(zend_jit_verify_arg_slow);
|
||||
REGISTER_HELPER(zend_jit_verify_return_slow);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
|
||||
REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
|
||||
REGISTER_HELPER(zend_jit_check_array_promotion);
|
||||
REGISTER_HELPER(zend_jit_create_typed_ref);
|
||||
REGISTER_HELPER(zend_jit_extract_helper);
|
||||
REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
|
||||
REGISTER_HELPER(zend_jit_copy_extra_args_helper);
|
||||
REGISTER_HELPER(zend_jit_deprecated_helper);
|
||||
REGISTER_HELPER(zend_jit_assign_const_to_typed_ref);
|
||||
REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref);
|
||||
REGISTER_HELPER(zend_jit_assign_var_to_typed_ref);
|
||||
REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref);
|
||||
REGISTER_HELPER(zend_jit_assign_const_to_typed_ref2);
|
||||
REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref2);
|
||||
REGISTER_HELPER(zend_jit_assign_var_to_typed_ref2);
|
||||
REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref2);
|
||||
REGISTER_HELPER(zend_jit_pre_inc_typed_ref);
|
||||
REGISTER_HELPER(zend_jit_pre_dec_typed_ref);
|
||||
REGISTER_HELPER(zend_jit_post_inc_typed_ref);
|
||||
REGISTER_HELPER(zend_jit_post_dec_typed_ref);
|
||||
REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
|
||||
REGISTER_HELPER(zend_jit_assign_op_to_typed_ref_tmp);
|
||||
REGISTER_HELPER(zend_jit_only_vars_by_reference);
|
||||
REGISTER_HELPER(zend_jit_invalid_array_access);
|
||||
REGISTER_HELPER(zend_jit_invalid_property_read);
|
||||
REGISTER_HELPER(zend_jit_invalid_property_write);
|
||||
REGISTER_HELPER(zend_jit_invalid_property_incdec);
|
||||
REGISTER_HELPER(zend_jit_invalid_property_assign);
|
||||
REGISTER_HELPER(zend_jit_invalid_property_assign_op);
|
||||
REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
|
||||
REGISTER_HELPER(zend_jit_pre_inc);
|
||||
REGISTER_HELPER(zend_jit_pre_dec);
|
||||
REGISTER_HELPER(zend_runtime_jit);
|
||||
REGISTER_HELPER(zend_jit_hot_func);
|
||||
REGISTER_HELPER(zend_jit_check_constant);
|
||||
REGISTER_HELPER(zend_jit_get_constant);
|
||||
REGISTER_HELPER(zend_jit_array_free);
|
||||
REGISTER_HELPER(zend_jit_zval_array_dup);
|
||||
REGISTER_HELPER(zend_jit_add_arrays_helper);
|
||||
REGISTER_HELPER(zend_jit_assign_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_assign_obj_op_helper);
|
||||
REGISTER_HELPER(zend_jit_assign_to_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_inc_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_dec_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_post_inc_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_post_dec_typed_prop);
|
||||
REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_post_inc_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_post_dec_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_rope_end);
|
||||
REGISTER_HELPER(zend_jit_free_trampoline_helper);
|
||||
REGISTER_HELPER(zend_jit_exception_in_interrupt_handler_helper);
|
||||
#undef REGISTER_HELPER
|
||||
|
||||
#ifndef _WIN32
|
||||
zend_elf_load_symbols();
|
||||
#endif
|
||||
|
||||
if (zend_vm_kind() == ZEND_VM_KIND_HYBRID) {
|
||||
zend_op opline;
|
||||
|
||||
memset(&opline, 0, sizeof(opline));
|
||||
|
||||
opline.opcode = ZEND_DO_UCALL;
|
||||
opline.result_type = IS_UNUSED;
|
||||
zend_vm_set_opcode_handler(&opline);
|
||||
zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
|
||||
|
||||
opline.opcode = ZEND_DO_UCALL;
|
||||
opline.result_type = IS_VAR;
|
||||
zend_vm_set_opcode_handler(&opline);
|
||||
zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
|
||||
|
||||
opline.opcode = ZEND_DO_FCALL_BY_NAME;
|
||||
opline.result_type = IS_UNUSED;
|
||||
zend_vm_set_opcode_handler(&opline);
|
||||
zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
|
||||
|
||||
opline.opcode = ZEND_DO_FCALL_BY_NAME;
|
||||
opline.result_type = IS_VAR;
|
||||
zend_vm_set_opcode_handler(&opline);
|
||||
zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
|
||||
|
||||
opline.opcode = ZEND_DO_FCALL;
|
||||
opline.result_type = IS_UNUSED;
|
||||
zend_vm_set_opcode_handler(&opline);
|
||||
zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
|
||||
|
||||
opline.opcode = ZEND_DO_FCALL;
|
||||
opline.result_type = IS_VAR;
|
||||
zend_vm_set_opcode_handler(&opline);
|
||||
zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
|
||||
|
||||
opline.opcode = ZEND_RETURN;
|
||||
opline.op1_type = IS_CONST;
|
||||
zend_vm_set_opcode_handler(&opline);
|
||||
zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
|
||||
|
||||
opline.opcode = ZEND_RETURN;
|
||||
opline.op1_type = IS_TMP_VAR;
|
||||
zend_vm_set_opcode_handler(&opline);
|
||||
zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
|
||||
|
||||
opline.opcode = ZEND_RETURN;
|
||||
opline.op1_type = IS_VAR;
|
||||
zend_vm_set_opcode_handler(&opline);
|
||||
zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
|
||||
|
||||
opline.opcode = ZEND_RETURN;
|
||||
opline.op1_type = IS_CV;
|
||||
zend_vm_set_opcode_handler(&opline);
|
||||
zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
|
||||
|
||||
zend_jit_disasm_add_symbol("ZEND_HYBRID_HALT_LABEL", (uint64_t)(uintptr_t)zend_jit_halt_op->handler, sizeof(void*));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void zend_jit_disasm_shutdown(void)
|
||||
{
|
||||
if (JIT_G(symbols)) {
|
||||
zend_jit_disasm_destroy_symbols(JIT_G(symbols));
|
||||
JIT_G(symbols) = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_DISASM */
|
|
@ -1,522 +0,0 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Zend JIT |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Dmitry Stogov <dmitry@php.net> |
|
||||
| Xinchen Hui <laruence@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
| Based on Mike Pall's implementation of GDB interface for LuaJIT. |
|
||||
| LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/ |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
#define HAVE_GDB
|
||||
|
||||
#include "zend_jit_gdb.h"
|
||||
#include "zend_elf.h"
|
||||
#include "zend_gdb.h"
|
||||
|
||||
/* DWARF definitions. */
|
||||
#define DW_CIE_VERSION 1
|
||||
|
||||
/* CFA (Canonical frame address) */
|
||||
enum {
|
||||
DW_CFA_nop = 0x0,
|
||||
DW_CFA_offset_extended = 0x5,
|
||||
DW_CFA_def_cfa = 0xc,
|
||||
DW_CFA_def_cfa_offset = 0xe,
|
||||
DW_CFA_offset_extended_sf = 0x11,
|
||||
DW_CFA_advance_loc = 0x40,
|
||||
DW_CFA_offset = 0x80
|
||||
};
|
||||
|
||||
enum {
|
||||
DW_EH_PE_udata4 = 0x03,
|
||||
DW_EH_PE_textrel = 0x20
|
||||
};
|
||||
|
||||
enum {
|
||||
DW_TAG_compile_unit = 0x11
|
||||
};
|
||||
|
||||
enum {
|
||||
DW_children_no = 0,
|
||||
DW_children_yes = 1
|
||||
};
|
||||
|
||||
enum {
|
||||
DW_AT_name = 0x03,
|
||||
DW_AT_stmt_list = 0x10,
|
||||
DW_AT_low_pc = 0x11,
|
||||
DW_AT_high_pc = 0x12
|
||||
};
|
||||
|
||||
enum {
|
||||
DW_FORM_addr = 0x01,
|
||||
DW_FORM_data4 = 0x06,
|
||||
DW_FORM_string = 0x08
|
||||
};
|
||||
|
||||
enum {
|
||||
DW_LNS_extended_op = 0,
|
||||
DW_LNS_copy = 1,
|
||||
DW_LNS_advance_pc = 2,
|
||||
DW_LNS_advance_line = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
DW_LNE_end_sequence = 1,
|
||||
DW_LNE_set_address = 2
|
||||
};
|
||||
|
||||
enum {
|
||||
#if defined(__i386__)
|
||||
DW_REG_AX, DW_REG_CX, DW_REG_DX, DW_REG_BX,
|
||||
DW_REG_SP, DW_REG_BP, DW_REG_SI, DW_REG_DI,
|
||||
DW_REG_RA,
|
||||
#elif defined(__x86_64__)
|
||||
/* Yes, the order is strange, but correct. */
|
||||
DW_REG_AX, DW_REG_DX, DW_REG_CX, DW_REG_BX,
|
||||
DW_REG_SI, DW_REG_DI, DW_REG_BP, DW_REG_SP,
|
||||
DW_REG_8, DW_REG_9, DW_REG_10, DW_REG_11,
|
||||
DW_REG_12, DW_REG_13, DW_REG_14, DW_REG_15,
|
||||
DW_REG_RA,
|
||||
#elif defined(__aarch64__)
|
||||
DW_REG_SP = 31,
|
||||
DW_REG_RA = 30,
|
||||
DW_REG_X29 = 29,
|
||||
#else
|
||||
#error "Unsupported target architecture"
|
||||
#endif
|
||||
};
|
||||
|
||||
enum {
|
||||
GDBJIT_SECT_NULL,
|
||||
GDBJIT_SECT_text,
|
||||
GDBJIT_SECT_eh_frame,
|
||||
GDBJIT_SECT_shstrtab,
|
||||
GDBJIT_SECT_strtab,
|
||||
GDBJIT_SECT_symtab,
|
||||
GDBJIT_SECT_debug_info,
|
||||
GDBJIT_SECT_debug_abbrev,
|
||||
GDBJIT_SECT_debug_line,
|
||||
GDBJIT_SECT__MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
GDBJIT_SYM_UNDEF,
|
||||
GDBJIT_SYM_FILE,
|
||||
GDBJIT_SYM_FUNC,
|
||||
GDBJIT_SYM__MAX
|
||||
};
|
||||
|
||||
typedef struct _zend_gdbjit_obj {
|
||||
zend_elf_header hdr;
|
||||
zend_elf_sectheader sect[GDBJIT_SECT__MAX];
|
||||
zend_elf_symbol sym[GDBJIT_SYM__MAX];
|
||||
uint8_t space[4096];
|
||||
} zend_gdbjit_obj;
|
||||
|
||||
static const zend_elf_header zend_elfhdr_template = {
|
||||
.emagic = { 0x7f, 'E', 'L', 'F' },
|
||||
#ifdef ELF64
|
||||
.eclass = 2,
|
||||
#else
|
||||
.eclass = 1,
|
||||
#endif
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
.eendian = 2,
|
||||
#else
|
||||
.eendian = 1,
|
||||
#endif
|
||||
.eversion = 1,
|
||||
#if defined(Linux)
|
||||
.eosabi = 0, /* Nope, it's not 3. ??? */
|
||||
#elif defined(__FreeBSD__)
|
||||
.eosabi = 9,
|
||||
#elif defined(__OpenBSD__)
|
||||
.eosabi = 12,
|
||||
#elif defined(__NetBSD__)
|
||||
.eosabi = 2,
|
||||
#elif defined(__DragonFly__)
|
||||
.eosabi = 0,
|
||||
#elif (defined(__sun__) && defined(__svr4__))
|
||||
.eosabi = 6,
|
||||
#else
|
||||
.eosabi = 0,
|
||||
#endif
|
||||
.eabiversion = 0,
|
||||
.epad = { 0, 0, 0, 0, 0, 0, 0 },
|
||||
.type = 1,
|
||||
#if defined(__i386__)
|
||||
.machine = 3,
|
||||
#elif defined(__x86_64__)
|
||||
.machine = 62,
|
||||
#elif defined(__aarch64__)
|
||||
.machine = 183,
|
||||
#else
|
||||
# error "Unsupported target architecture"
|
||||
#endif
|
||||
.version = 1,
|
||||
.entry = 0,
|
||||
.phofs = 0,
|
||||
.shofs = offsetof(zend_gdbjit_obj, sect),
|
||||
.flags = 0,
|
||||
.ehsize = sizeof(zend_elf_header),
|
||||
.phentsize = 0,
|
||||
.phnum = 0,
|
||||
.shentsize = sizeof(zend_elf_sectheader),
|
||||
.shnum = GDBJIT_SECT__MAX,
|
||||
.shstridx = GDBJIT_SECT_shstrtab
|
||||
};
|
||||
|
||||
/* Context for generating the ELF object for the GDB JIT API. */
|
||||
typedef struct _zend_gdbjit_ctx {
|
||||
uint8_t *p; /* Pointer to next address in obj.space. */
|
||||
uint8_t *startp; /* Pointer to start address in obj.space. */
|
||||
uintptr_t mcaddr; /* Machine code address. */
|
||||
uint32_t szmcode; /* Size of machine code. */
|
||||
int32_t lineno; /* Starting line number. */
|
||||
const char *name; /* JIT function name */
|
||||
const char *filename; /* Starting file name. */
|
||||
size_t objsize; /* Final size of ELF object. */
|
||||
zend_gdbjit_obj obj; /* In-memory ELF object. */
|
||||
} zend_gdbjit_ctx;
|
||||
|
||||
/* Add a zero-terminated string */
|
||||
static uint32_t zend_gdbjit_strz(zend_gdbjit_ctx *ctx, const char *str)
|
||||
{
|
||||
uint8_t *p = ctx->p;
|
||||
uint32_t ofs = (uint32_t)(p - ctx->startp);
|
||||
do {
|
||||
*p++ = (uint8_t)*str;
|
||||
} while (*str++);
|
||||
ctx->p = p;
|
||||
return ofs;
|
||||
}
|
||||
|
||||
/* Add a ULEB128 value */
|
||||
static void zend_gdbjit_uleb128(zend_gdbjit_ctx *ctx, uint32_t v)
|
||||
{
|
||||
uint8_t *p = ctx->p;
|
||||
for (; v >= 0x80; v >>= 7)
|
||||
*p++ = (uint8_t)((v & 0x7f) | 0x80);
|
||||
*p++ = (uint8_t)v;
|
||||
ctx->p = p;
|
||||
}
|
||||
|
||||
/* Add a SLEB128 value */
|
||||
static void zend_gdbjit_sleb128(zend_gdbjit_ctx *ctx, int32_t v)
|
||||
{
|
||||
uint8_t *p = ctx->p;
|
||||
for (; (uint32_t)(v+0x40) >= 0x80; v >>= 7)
|
||||
*p++ = (uint8_t)((v & 0x7f) | 0x80);
|
||||
*p++ = (uint8_t)(v & 0x7f);
|
||||
ctx->p = p;
|
||||
}
|
||||
|
||||
static void zend_gdbjit_secthdr(zend_gdbjit_ctx *ctx)
|
||||
{
|
||||
zend_elf_sectheader *sect;
|
||||
|
||||
*ctx->p++ = '\0';
|
||||
|
||||
#define SECTDEF(id, tp, al) \
|
||||
sect = &ctx->obj.sect[GDBJIT_SECT_##id]; \
|
||||
sect->name = zend_gdbjit_strz(ctx, "." #id); \
|
||||
sect->type = ELFSECT_TYPE_##tp; \
|
||||
sect->align = (al)
|
||||
|
||||
SECTDEF(text, NOBITS, 16);
|
||||
sect->flags = ELFSECT_FLAGS_ALLOC|ELFSECT_FLAGS_EXEC;
|
||||
sect->addr = ctx->mcaddr;
|
||||
sect->ofs = 0;
|
||||
sect->size = ctx->szmcode;
|
||||
|
||||
SECTDEF(eh_frame, PROGBITS, sizeof(uintptr_t));
|
||||
sect->flags = ELFSECT_FLAGS_ALLOC;
|
||||
|
||||
SECTDEF(shstrtab, STRTAB, 1);
|
||||
SECTDEF(strtab, STRTAB, 1);
|
||||
|
||||
SECTDEF(symtab, SYMTAB, sizeof(uintptr_t));
|
||||
sect->ofs = offsetof(zend_gdbjit_obj, sym);
|
||||
sect->size = sizeof(ctx->obj.sym);
|
||||
sect->link = GDBJIT_SECT_strtab;
|
||||
sect->entsize = sizeof(zend_elf_symbol);
|
||||
sect->info = GDBJIT_SYM_FUNC;
|
||||
|
||||
SECTDEF(debug_info, PROGBITS, 1);
|
||||
SECTDEF(debug_abbrev, PROGBITS, 1);
|
||||
SECTDEF(debug_line, PROGBITS, 1);
|
||||
|
||||
#undef SECTDEF
|
||||
}
|
||||
|
||||
static void zend_gdbjit_symtab(zend_gdbjit_ctx *ctx)
|
||||
{
|
||||
zend_elf_symbol *sym;
|
||||
|
||||
*ctx->p++ = '\0';
|
||||
|
||||
sym = &ctx->obj.sym[GDBJIT_SYM_FILE];
|
||||
sym->name = zend_gdbjit_strz(ctx, "JIT code");
|
||||
sym->sectidx = ELFSECT_IDX_ABS;
|
||||
sym->info = ELFSYM_INFO(ELFSYM_BIND_LOCAL, ELFSYM_TYPE_FILE);
|
||||
|
||||
sym = &ctx->obj.sym[GDBJIT_SYM_FUNC];
|
||||
sym->name = zend_gdbjit_strz(ctx, ctx->name);
|
||||
sym->sectidx = GDBJIT_SECT_text;
|
||||
sym->value = 0;
|
||||
sym->size = ctx->szmcode;
|
||||
sym->info = ELFSYM_INFO(ELFSYM_BIND_GLOBAL, ELFSYM_TYPE_FUNC);
|
||||
}
|
||||
|
||||
typedef ZEND_SET_ALIGNED(1, uint16_t unaligned_uint16_t);
|
||||
typedef ZEND_SET_ALIGNED(1, uint32_t unaligned_uint32_t);
|
||||
typedef ZEND_SET_ALIGNED(1, uintptr_t unaligned_uintptr_t);
|
||||
|
||||
#define SECTALIGN(p, a) \
|
||||
((p) = (uint8_t *)(((uintptr_t)(p) + ((a)-1)) & ~(uintptr_t)((a)-1)))
|
||||
|
||||
/* Shortcuts to generate DWARF structures. */
|
||||
#define DB(x) (*p++ = (x))
|
||||
#define DI8(x) (*(int8_t *)p = (x), p++)
|
||||
#define DU16(x) (*(unaligned_uint16_t *)p = (x), p += 2)
|
||||
#define DU32(x) (*(unaligned_uint32_t *)p = (x), p += 4)
|
||||
#define DADDR(x) (*(unaligned_uintptr_t *)p = (x), p += sizeof(uintptr_t))
|
||||
#define DUV(x) (ctx->p = p, zend_gdbjit_uleb128(ctx, (x)), p = ctx->p)
|
||||
#define DSV(x) (ctx->p = p, zend_gdbjit_sleb128(ctx, (x)), p = ctx->p)
|
||||
#define DSTR(str) (ctx->p = p, zend_gdbjit_strz(ctx, (str)), p = ctx->p)
|
||||
#define DALIGNNOP(s) while ((uintptr_t)p & ((s)-1)) *p++ = DW_CFA_nop
|
||||
#define DSECT(name, stmt) \
|
||||
{ unaligned_uint32_t *szp_##name = (uint32_t *)p; p += 4; stmt \
|
||||
*szp_##name = (uint32_t)((p-(uint8_t *)szp_##name)-4); }
|
||||
|
||||
static void zend_gdbjit_ehframe(zend_gdbjit_ctx *ctx, uint32_t sp_offset, uint32_t sp_adjustment)
|
||||
{
|
||||
uint8_t *p = ctx->p;
|
||||
uint8_t *framep = p;
|
||||
|
||||
/* DWARF EH CIE (Common Information Entry) */
|
||||
DSECT(CIE,
|
||||
DU32(0); /* CIE ID. */
|
||||
DB(DW_CIE_VERSION); /* Version */
|
||||
DSTR("zR"); /* Augmentation String. */
|
||||
DUV(1); /* Code alignment factor. */
|
||||
DSV(-(int32_t)sizeof(uintptr_t)); /* Data alignment factor. */
|
||||
DB(DW_REG_RA); /* Return address register. */
|
||||
DB(1); DB(DW_EH_PE_textrel|DW_EH_PE_udata4); /* Augmentation data. */
|
||||
#if defined(__x86_64__) || defined(i386)
|
||||
DB(DW_CFA_def_cfa); DUV(DW_REG_SP); DUV(sizeof(uintptr_t));
|
||||
DB(DW_CFA_offset|DW_REG_RA); DUV(1);
|
||||
#elif defined(__aarch64__)
|
||||
DB(DW_CFA_def_cfa); DUV(DW_REG_SP); DUV(0);
|
||||
#endif
|
||||
DALIGNNOP(sizeof(uintptr_t));
|
||||
)
|
||||
|
||||
/* DWARF EH FDE (Frame Description Entry). */
|
||||
DSECT(FDE,
|
||||
DU32((uint32_t)(p-framep)); /* Offset to CIE Pointer. */
|
||||
DU32(0); /* Machine code offset relative to .text. */
|
||||
DU32(ctx->szmcode); /* Machine code length. */
|
||||
DB(0); /* Augmentation data. */
|
||||
DB(DW_CFA_def_cfa_offset); DUV(sp_offset);
|
||||
#if defined(__aarch64__)
|
||||
if (sp_offset) {
|
||||
if (sp_adjustment && sp_adjustment < sp_offset) {
|
||||
DB(DW_CFA_offset|DW_REG_X29); DUV(sp_adjustment / sizeof(uintptr_t));
|
||||
DB(DW_CFA_offset|DW_REG_RA); DUV((sp_adjustment / sizeof(uintptr_t)) - 1);
|
||||
} else {
|
||||
DB(DW_CFA_offset|DW_REG_X29); DUV(sp_offset / sizeof(uintptr_t));
|
||||
DB(DW_CFA_offset|DW_REG_RA); DUV((sp_offset / sizeof(uintptr_t)) - 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (sp_adjustment && sp_adjustment > sp_offset) {
|
||||
DB(DW_CFA_advance_loc|1); DB(DW_CFA_def_cfa_offset); DUV(sp_adjustment);
|
||||
#if defined(__aarch64__)
|
||||
if (!sp_offset) {
|
||||
DB(DW_CFA_offset|DW_REG_X29); DUV(sp_adjustment / sizeof(uintptr_t));
|
||||
DB(DW_CFA_offset|DW_REG_RA); DUV((sp_adjustment / sizeof(uintptr_t)) - 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
DALIGNNOP(sizeof(uintptr_t));
|
||||
)
|
||||
|
||||
ctx->p = p;
|
||||
}
|
||||
|
||||
static void zend_gdbjit_debuginfo(zend_gdbjit_ctx *ctx)
|
||||
{
|
||||
uint8_t *p = ctx->p;
|
||||
|
||||
DSECT(info,
|
||||
DU16(2); /* DWARF version. */
|
||||
DU32(0); /* Abbrev offset. */
|
||||
DB(sizeof(uintptr_t)); /* Pointer size. */
|
||||
|
||||
DUV(1); /* Abbrev #1: DW_TAG_compile_unit. */
|
||||
DSTR(ctx->filename); /* DW_AT_name. */
|
||||
DADDR(ctx->mcaddr); /* DW_AT_low_pc. */
|
||||
DADDR(ctx->mcaddr + ctx->szmcode); /* DW_AT_high_pc. */
|
||||
DU32(0); /* DW_AT_stmt_list. */
|
||||
);
|
||||
|
||||
ctx->p = p;
|
||||
}
|
||||
|
||||
static void zend_gdbjit_debugabbrev(zend_gdbjit_ctx *ctx)
|
||||
{
|
||||
uint8_t *p = ctx->p;
|
||||
|
||||
/* Abbrev #1: DW_TAG_compile_unit. */
|
||||
DUV(1);
|
||||
DUV(DW_TAG_compile_unit);
|
||||
DB(DW_children_no);
|
||||
DUV(DW_AT_name);
|
||||
DUV(DW_FORM_string);
|
||||
DUV(DW_AT_low_pc);
|
||||
DUV(DW_FORM_addr);
|
||||
DUV(DW_AT_high_pc);
|
||||
DUV(DW_FORM_addr);
|
||||
DUV(DW_AT_stmt_list);
|
||||
DUV(DW_FORM_data4);
|
||||
DB(0);
|
||||
DB(0);
|
||||
|
||||
ctx->p = p;
|
||||
}
|
||||
|
||||
#define DLNE(op, s) (DB(DW_LNS_extended_op), DUV(1+(s)), DB((op)))
|
||||
|
||||
static void zend_gdbjit_debugline(zend_gdbjit_ctx *ctx)
|
||||
{
|
||||
uint8_t *p = ctx->p;
|
||||
|
||||
DSECT(line,
|
||||
DU16(2); /* DWARF version. */
|
||||
DSECT(header,
|
||||
DB(1); /* Minimum instruction length. */
|
||||
DB(1); /* is_stmt. */
|
||||
DI8(0); /* Line base for special opcodes. */
|
||||
DB(2); /* Line range for special opcodes. */
|
||||
DB(3+1); /* Opcode base at DW_LNS_advance_line+1. */
|
||||
DB(0); DB(1); DB(1); /* Standard opcode lengths. */
|
||||
/* Directory table. */
|
||||
DB(0);
|
||||
/* File name table. */
|
||||
DSTR(ctx->filename); DUV(0); DUV(0); DUV(0);
|
||||
DB(0);
|
||||
);
|
||||
DLNE(DW_LNE_set_address, sizeof(uintptr_t));
|
||||
DADDR(ctx->mcaddr);
|
||||
if (ctx->lineno) (DB(DW_LNS_advance_line), DSV(ctx->lineno-1));
|
||||
DB(DW_LNS_copy);
|
||||
DB(DW_LNS_advance_pc); DUV(ctx->szmcode);
|
||||
DLNE(DW_LNE_end_sequence, 0);
|
||||
);
|
||||
|
||||
ctx->p = p;
|
||||
}
|
||||
|
||||
|
||||
#undef DLNE
|
||||
|
||||
/* Undef shortcuts. */
|
||||
#undef DB
|
||||
#undef DI8
|
||||
#undef DU16
|
||||
#undef DU32
|
||||
#undef DADDR
|
||||
#undef DUV
|
||||
#undef DSV
|
||||
#undef DSTR
|
||||
#undef DALIGNNOP
|
||||
#undef DSECT
|
||||
|
||||
typedef void (*zend_gdbjit_initf) (zend_gdbjit_ctx *ctx);
|
||||
|
||||
static void zend_gdbjit_initsect(zend_gdbjit_ctx *ctx, int sect)
|
||||
{
|
||||
ctx->startp = ctx->p;
|
||||
ctx->obj.sect[sect].ofs = (uintptr_t)((char *)ctx->p - (char *)&ctx->obj);
|
||||
}
|
||||
|
||||
static void zend_gdbjit_initsect_done(zend_gdbjit_ctx *ctx, int sect)
|
||||
{
|
||||
ctx->obj.sect[sect].size = (uintptr_t)(ctx->p - ctx->startp);
|
||||
}
|
||||
|
||||
static void zend_gdbjit_buildobj(zend_gdbjit_ctx *ctx, uint32_t sp_offset, uint32_t sp_adjustment)
|
||||
{
|
||||
zend_gdbjit_obj *obj = &ctx->obj;
|
||||
|
||||
/* Fill in ELF header and clear structures. */
|
||||
memcpy(&obj->hdr, &zend_elfhdr_template, sizeof(zend_elf_header));
|
||||
memset(&obj->sect, 0, sizeof(zend_elf_sectheader) * GDBJIT_SECT__MAX);
|
||||
memset(&obj->sym, 0, sizeof(zend_elf_symbol) * GDBJIT_SYM__MAX);
|
||||
|
||||
/* Initialize sections. */
|
||||
ctx->p = obj->space;
|
||||
zend_gdbjit_initsect(ctx, GDBJIT_SECT_shstrtab); zend_gdbjit_secthdr(ctx); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_shstrtab);
|
||||
zend_gdbjit_initsect(ctx, GDBJIT_SECT_strtab); zend_gdbjit_symtab(ctx); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_strtab);
|
||||
zend_gdbjit_initsect(ctx, GDBJIT_SECT_debug_info); zend_gdbjit_debuginfo(ctx); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_debug_info);
|
||||
zend_gdbjit_initsect(ctx, GDBJIT_SECT_debug_abbrev); zend_gdbjit_debugabbrev(ctx); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_debug_abbrev);
|
||||
zend_gdbjit_initsect(ctx, GDBJIT_SECT_debug_line); zend_gdbjit_debugline(ctx); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_debug_line);
|
||||
SECTALIGN(ctx->p, sizeof(uintptr_t));
|
||||
zend_gdbjit_initsect(ctx, GDBJIT_SECT_eh_frame); zend_gdbjit_ehframe(ctx, sp_offset, sp_adjustment); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_eh_frame);
|
||||
ctx->objsize = (size_t)((char *)ctx->p - (char *)obj);
|
||||
|
||||
ZEND_ASSERT(ctx->objsize < sizeof(zend_gdbjit_obj));
|
||||
}
|
||||
|
||||
int zend_jit_gdb_register(const char *name,
|
||||
const zend_op_array *op_array,
|
||||
const void *start,
|
||||
size_t size,
|
||||
uint32_t sp_offset,
|
||||
uint32_t sp_adjustment)
|
||||
{
|
||||
zend_gdbjit_ctx ctx;
|
||||
|
||||
ctx.mcaddr = (uintptr_t)start;
|
||||
ctx.szmcode = (uint32_t)size;
|
||||
ctx.name = name;
|
||||
ctx.filename = op_array ? ZSTR_VAL(op_array->filename) : "unknown";
|
||||
ctx.lineno = op_array ? op_array->line_start : 0;
|
||||
|
||||
zend_gdbjit_buildobj(&ctx, sp_offset, sp_adjustment);
|
||||
|
||||
return zend_gdb_register_code(&ctx.obj, ctx.objsize);
|
||||
}
|
||||
|
||||
int zend_jit_gdb_unregister(void)
|
||||
{
|
||||
zend_gdb_unregister_all();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void zend_jit_gdb_init(void)
|
||||
{
|
||||
#if 0
|
||||
/* This might enable registration of all JIT-ed code, but unfortunately,
|
||||
* in case of many functions, this takes enormous time. */
|
||||
if (zend_gdb_present()) {
|
||||
JIT_G(debug) |= ZEND_JIT_DEBUG_GDB;
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Zend JIT |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Dmitry Stogov <dmitry@php.net> |
|
||||
| Xinchen Hui <laruence@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef HAVE_ZEND_JIT_GDB_H
|
||||
#define HAVE_ZEND_JIT_GDB_H
|
||||
|
||||
#include "zend_compile.h"
|
||||
|
||||
#define HAVE_GDB
|
||||
|
||||
int zend_jit_gdb_register(const char *name,
|
||||
const zend_op_array *op_array,
|
||||
const void *start,
|
||||
size_t size,
|
||||
uint32_t sp_offset,
|
||||
uint32_t sp_adjustment);
|
||||
|
||||
int zend_jit_gdb_unregister(void);
|
||||
void zend_jit_gdb_init(void);
|
||||
|
||||
#endif /* HAVE_ZEND_JIT_GDB_H */
|
|
@ -21,97 +21,6 @@
|
|||
#ifndef ZEND_JIT_INTERNAL_H
|
||||
#define ZEND_JIT_INTERNAL_H
|
||||
|
||||
#ifndef ZEND_JIT_IR
|
||||
|
||||
#include "zend_bitset.h"
|
||||
|
||||
/* Register Set */
|
||||
#define ZEND_REGSET_EMPTY 0
|
||||
|
||||
#define ZEND_REGSET_IS_EMPTY(regset) \
|
||||
(regset == ZEND_REGSET_EMPTY)
|
||||
|
||||
#define ZEND_REGSET_IS_SINGLETON(regset) \
|
||||
(regset && !(regset & (regset - 1)))
|
||||
|
||||
#if (!ZEND_REGSET_64BIT)
|
||||
#define ZEND_REGSET(reg) \
|
||||
(1u << (reg))
|
||||
#else
|
||||
#define ZEND_REGSET(reg) \
|
||||
(1ull << (reg))
|
||||
#endif
|
||||
|
||||
#if (!ZEND_REGSET_64BIT)
|
||||
#define ZEND_REGSET_INTERVAL(reg1, reg2) \
|
||||
(((1u << ((reg2) - (reg1) + 1)) - 1) << (reg1))
|
||||
#else
|
||||
#define ZEND_REGSET_INTERVAL(reg1, reg2) \
|
||||
(((1ull << ((reg2) - (reg1) + 1)) - 1) << (reg1))
|
||||
#endif
|
||||
|
||||
#define ZEND_REGSET_IN(regset, reg) \
|
||||
(((regset) & ZEND_REGSET(reg)) != 0)
|
||||
|
||||
#define ZEND_REGSET_INCL(regset, reg) \
|
||||
(regset) |= ZEND_REGSET(reg)
|
||||
|
||||
#define ZEND_REGSET_EXCL(regset, reg) \
|
||||
(regset) &= ~ZEND_REGSET(reg)
|
||||
|
||||
#define ZEND_REGSET_UNION(set1, set2) \
|
||||
((set1) | (set2))
|
||||
|
||||
#define ZEND_REGSET_INTERSECTION(set1, set2) \
|
||||
((set1) & (set2))
|
||||
|
||||
#define ZEND_REGSET_DIFFERENCE(set1, set2) \
|
||||
((set1) & ~(set2))
|
||||
|
||||
#if !defined(_WIN32)
|
||||
# if (!ZEND_REGSET_64BIT)
|
||||
# define ZEND_REGSET_FIRST(set) ((zend_reg)__builtin_ctz(set))
|
||||
# define ZEND_REGSET_LAST(set) ((zend_reg)(__builtin_clz(set)^31))
|
||||
# else
|
||||
# define ZEND_REGSET_FIRST(set) ((zend_reg)__builtin_ctzll(set))
|
||||
# define ZEND_REGSET_LAST(set) ((zend_reg)(__builtin_clzll(set)^63))
|
||||
# endif
|
||||
#else
|
||||
# include <intrin.h>
|
||||
uint32_t __inline __zend_jit_ctz(uint32_t value) {
|
||||
DWORD trailing_zero = 0;
|
||||
if (_BitScanForward(&trailing_zero, value)) {
|
||||
return trailing_zero;
|
||||
}
|
||||
return 32;
|
||||
}
|
||||
uint32_t __inline __zend_jit_clz(uint32_t value) {
|
||||
DWORD leading_zero = 0;
|
||||
if (_BitScanReverse(&leading_zero, value)) {
|
||||
return 31 - leading_zero;
|
||||
}
|
||||
return 32;
|
||||
}
|
||||
# define ZEND_REGSET_FIRST(set) ((zend_reg)__zend_jit_ctz(set))
|
||||
# define ZEND_REGSET_LAST(set) ((zend_reg)(__zend_jit_clz(set)^31))
|
||||
#endif
|
||||
|
||||
#define ZEND_REGSET_FOREACH(set, reg) \
|
||||
do { \
|
||||
zend_regset _tmp = (set); \
|
||||
while (!ZEND_REGSET_IS_EMPTY(_tmp)) { \
|
||||
zend_reg _reg = ZEND_REGSET_FIRST(_tmp); \
|
||||
ZEND_REGSET_EXCL(_tmp, _reg); \
|
||||
reg = _reg; \
|
||||
|
||||
#define ZEND_REGSET_FOREACH_END() \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Register Names */
|
||||
extern const char *zend_reg_name[];
|
||||
#endif /* ZEND_JIT_IR */
|
||||
|
||||
/* Address Encoding */
|
||||
typedef uintptr_t zend_jit_addr;
|
||||
|
||||
|
@ -140,58 +49,6 @@ typedef uintptr_t zend_jit_addr;
|
|||
#define Z_OFFSET(addr) ((uint32_t)((addr)>>_ZEND_ADDR_OFFSET_SHIFT))
|
||||
#define Z_REG(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_SHIFT) & _ZEND_ADDR_REG_MASK))
|
||||
|
||||
#ifndef ZEND_JIT_IR
|
||||
|
||||
#define _ZEND_ADDR_REG_STORE_BIT 8
|
||||
#define _ZEND_ADDR_REG_LOAD_BIT 9
|
||||
#define _ZEND_ADDR_REG_LAST_USE_BIT 10
|
||||
|
||||
#define Z_STORE(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_STORE_BIT) & 1))
|
||||
#define Z_LOAD(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_LOAD_BIT) & 1))
|
||||
#define Z_LAST_USE(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_LAST_USE_BIT) & 1))
|
||||
|
||||
#define OP_REG_EX(reg, store, load, last_use) \
|
||||
((reg) | \
|
||||
((store) ? (1 << (_ZEND_ADDR_REG_STORE_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) | \
|
||||
((load) ? (1 << (_ZEND_ADDR_REG_LOAD_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) | \
|
||||
((last_use) ? (1 << (_ZEND_ADDR_REG_LAST_USE_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) \
|
||||
)
|
||||
|
||||
#define OP_REG(ssa_op, op) \
|
||||
(ra && ssa_op->op >= 0 && ra[ssa_op->op] ? \
|
||||
OP_REG_EX(ra[ssa_op->op]->reg, \
|
||||
(ra[ssa_op->op]->flags & ZREG_STORE), \
|
||||
(ra[ssa_op->op]->flags & ZREG_LOAD), \
|
||||
zend_ival_is_last_use(ra[ssa_op->op], ssa_op - ssa->ops) \
|
||||
) : ZREG_NONE)
|
||||
|
||||
static zend_always_inline zend_jit_addr _zend_jit_decode_op(uint8_t op_type, znode_op op, const zend_op *opline, zend_reg reg)
|
||||
{
|
||||
if (op_type == IS_CONST) {
|
||||
#if ZEND_USE_ABS_CONST_ADDR
|
||||
return ZEND_ADDR_CONST_ZVAL(op.zv);
|
||||
#else
|
||||
return ZEND_ADDR_CONST_ZVAL(RT_CONSTANT(opline, op));
|
||||
#endif
|
||||
} else {
|
||||
ZEND_ASSERT(op_type & (IS_CV|IS_TMP_VAR|IS_VAR));
|
||||
if (reg != ZREG_NONE) {
|
||||
return ZEND_ADDR_REG(reg);
|
||||
} else {
|
||||
return ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define OP_ADDR(opline, type, op) \
|
||||
_zend_jit_decode_op((opline)->type, (opline)->op, opline, ZREG_NONE)
|
||||
|
||||
#define OP_REG_ADDR(opline, type, _op, _ssa_op) \
|
||||
_zend_jit_decode_op((opline)->type, (opline)->_op, opline, \
|
||||
OP_REG(ssa_op, _ssa_op))
|
||||
|
||||
#else /* ZEND_JIT_IR */
|
||||
|
||||
#define ZEND_ADDR_REF_ZVAL(ref) \
|
||||
((((zend_jit_addr)(uintptr_t)(ref)) << _ZEND_ADDR_REG_SHIFT) | \
|
||||
IS_REF_ZVAL)
|
||||
|
@ -225,8 +82,6 @@ static zend_always_inline zend_jit_addr _zend_jit_decode_op(uint8_t op_type, zno
|
|||
ZEND_ADDR_REG(ssa_op->_ssa_op) : \
|
||||
OP_ADDR(opline, type, op))
|
||||
|
||||
#endif /* ZEND_JIT_IR */
|
||||
|
||||
#define OP1_ADDR() \
|
||||
OP_ADDR(opline, op1_type, op1)
|
||||
#define OP2_ADDR() \
|
||||
|
@ -258,15 +113,10 @@ static zend_always_inline bool zend_jit_same_addr(zend_jit_addr addr1, zend_jit_
|
|||
{
|
||||
if (addr1 == addr2) {
|
||||
return 1;
|
||||
#ifndef ZEND_JIT_IR
|
||||
} else if (Z_MODE(addr1) == IS_REG && Z_MODE(addr2) == IS_REG) {
|
||||
return Z_REG(addr1) == Z_REG(addr2);
|
||||
#else
|
||||
} else if (Z_MODE(addr1) == IS_REG && Z_MODE(addr2) == IS_REG) {
|
||||
return Z_SSA_VAR(addr1) == Z_SSA_VAR(addr2);
|
||||
} else if (Z_MODE(addr1) == IS_REF_ZVAL && Z_MODE(addr2) == IS_REF_ZVAL) {
|
||||
return Z_IR_REF(addr1) == Z_IR_REF(addr2);
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -569,36 +419,12 @@ typedef struct _zend_jit_trace_exit_info {
|
|||
uint32_t flags; /* set of ZEND_JIT_EXIT_... */
|
||||
uint32_t stack_size;
|
||||
uint32_t stack_offset;
|
||||
#ifdef ZEND_JIT_IR
|
||||
int32_t poly_func_ref;
|
||||
int32_t poly_this_ref;
|
||||
int8_t poly_func_reg;
|
||||
int8_t poly_this_reg;
|
||||
#endif
|
||||
} zend_jit_trace_exit_info;
|
||||
|
||||
#ifndef ZEND_JIT_IR
|
||||
typedef union _zend_jit_trace_stack {
|
||||
int32_t ssa_var;
|
||||
uint32_t info;
|
||||
struct {
|
||||
uint8_t type; /* variable type (for type inference) */
|
||||
uint8_t mem_type; /* stack slot type (for eliminate dead type store) */
|
||||
int8_t reg;
|
||||
uint8_t flags;
|
||||
};
|
||||
} zend_jit_trace_stack;
|
||||
|
||||
#define STACK_VAR(_stack, _slot) \
|
||||
(_stack)[_slot].ssa_var
|
||||
#define SET_STACK_VAR(_stack, _slot, _ssa_var) do { \
|
||||
(_stack)[_slot].ssa_var = _ssa_var; \
|
||||
} while (0)
|
||||
|
||||
#define CLEAR_STACK_REF(_stack, _slot)
|
||||
|
||||
#else /* ZEND_JIT_IR */
|
||||
|
||||
typedef struct _zend_jit_trace_stack {
|
||||
union {
|
||||
uint32_t info;
|
||||
|
@ -633,8 +459,6 @@ typedef struct _zend_jit_trace_stack {
|
|||
(_stack)[_slot].flags = _flags; \
|
||||
} while (0)
|
||||
|
||||
#endif /* ZEND_JIT_IR */
|
||||
|
||||
#define STACK_INFO(_stack, _slot) \
|
||||
(_stack)[_slot].info
|
||||
#define STACK_TYPE(_stack, _slot) \
|
||||
|
@ -675,12 +499,10 @@ typedef struct _zend_jit_trace_stack {
|
|||
#define ZEND_JIT_TRACE_LOOP (1<<1)
|
||||
#define ZEND_JIT_TRACE_USES_INITIAL_IP (1<<2)
|
||||
|
||||
#ifdef ZEND_JIT_IR
|
||||
typedef union _zend_jit_exit_const {
|
||||
int64_t i;
|
||||
double d;
|
||||
} zend_jit_exit_const;
|
||||
#endif
|
||||
|
||||
typedef struct _zend_jit_trace_info {
|
||||
uint32_t id; /* trace id */
|
||||
|
@ -701,10 +523,8 @@ typedef struct _zend_jit_trace_info {
|
|||
zend_jit_trace_exit_info *exit_info; /* info about side exits */
|
||||
zend_jit_trace_stack *stack_map;
|
||||
//uint32_t loop_offset;
|
||||
#ifdef ZEND_JIT_IR
|
||||
uint32_t consts_count; /* number of side exits */
|
||||
zend_jit_exit_const *constants;
|
||||
#endif
|
||||
} zend_jit_trace_info;
|
||||
|
||||
struct _zend_jit_trace_stack_frame {
|
||||
|
@ -823,9 +643,6 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_ret_trace_helper(ZEND_OPCODE_HAND
|
|||
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_trace_helper(ZEND_OPCODE_HANDLER_ARGS);
|
||||
|
||||
int ZEND_FASTCALL zend_jit_trace_hot_root(zend_execute_data *execute_data, const zend_op *opline);
|
||||
#ifndef ZEND_JIT_IR
|
||||
int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs);
|
||||
#endif
|
||||
zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *execute_data, const zend_op *opline, zend_jit_trace_rec *trace_buffer, uint8_t start, uint32_t is_megamorphc);
|
||||
|
||||
static zend_always_inline const zend_op* zend_jit_trace_get_exit_opline(zend_jit_trace_rec *trace, const zend_op *opline, bool *exit_if_true)
|
||||
|
@ -910,14 +727,6 @@ static zend_always_inline bool zend_long_is_power_of_two(zend_long x)
|
|||
return (x > 0) && !(x & (x - 1));
|
||||
}
|
||||
|
||||
#ifndef ZEND_JIT_IR
|
||||
static zend_always_inline uint32_t zend_long_floor_log2(zend_long x)
|
||||
{
|
||||
ZEND_ASSERT(zend_long_is_power_of_two(x));
|
||||
return zend_ulong_ntz(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* from http://aggregate.org/MAGIC/ */
|
||||
static zend_always_inline uint32_t ones32(uint32_t x)
|
||||
{
|
||||
|
|
|
@ -1,327 +0,0 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Zend JIT |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Dmitry Stogov <dmitry@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#define HAVE_PERFTOOLS 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#if !defined(HAVE_OS_SIGNPOST_H)
|
||||
#if defined(__linux__)
|
||||
#include <sys/syscall.h>
|
||||
#elif defined(__darwin__)
|
||||
# include <pthread.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
# include <sys/thr.h>
|
||||
# include <sys/sysctl.h>
|
||||
#elif defined(__NetBSD__)
|
||||
# include <lwp.h>
|
||||
#elif defined(__DragonFly__)
|
||||
# include <sys/lwp.h>
|
||||
# include <sys/sysctl.h>
|
||||
#elif defined(__sun)
|
||||
// avoiding thread.h inclusion as it conflicts with vtunes types.
|
||||
extern unsigned int thr_self(void);
|
||||
#elif defined(__HAIKU__)
|
||||
#include <FindDirectory.h>
|
||||
#endif
|
||||
|
||||
#include "zend_elf.h"
|
||||
#include "zend_mmap.h"
|
||||
|
||||
/*
|
||||
* 1) Profile using perf-<pid>.map
|
||||
*
|
||||
* perf record php -d opcache.huge_code_pages=0 -d opcache.jit_debug=0x10 bench.php
|
||||
* perf report
|
||||
*
|
||||
* 2) Profile using jit-<pid>.dump
|
||||
*
|
||||
* perf record -k 1 php -d opcache.huge_code_pages=0 -d opcache.jit_debug=0x20 bench.php
|
||||
* perf inject -j -i perf.data -o perf.data.jitted
|
||||
* perf report -i perf.data.jitted
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define ZEND_PERF_JITDUMP_HEADER_MAGIC 0x4A695444
|
||||
#define ZEND_PERF_JITDUMP_HEADER_VERSION 1
|
||||
|
||||
#define ZEND_PERF_JITDUMP_RECORD_LOAD 0
|
||||
#define ZEND_PERF_JITDUMP_RECORD_MOVE 1
|
||||
#define ZEND_PERF_JITDUMP_RECORD_DEBUG_INFO 2
|
||||
#define ZEND_PERF_JITDUMP_RECORD_CLOSE 3
|
||||
#define ZEND_PERF_JITDUMP_UNWINDING_UNFO 4
|
||||
|
||||
#define ALIGN8(size) (((size) + 7) & ~7)
|
||||
#define PADDING8(size) (ALIGN8(size) - (size))
|
||||
|
||||
typedef struct zend_perf_jitdump_header {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t size;
|
||||
uint32_t elf_mach_target;
|
||||
uint32_t reserved;
|
||||
uint32_t process_id;
|
||||
uint64_t time_stamp;
|
||||
uint64_t flags;
|
||||
} zend_perf_jitdump_header;
|
||||
|
||||
typedef struct _zend_perf_jitdump_record {
|
||||
uint32_t event;
|
||||
uint32_t size;
|
||||
uint64_t time_stamp;
|
||||
} zend_perf_jitdump_record;
|
||||
|
||||
typedef struct _zend_perf_jitdump_load_record {
|
||||
zend_perf_jitdump_record hdr;
|
||||
uint32_t process_id;
|
||||
uint32_t thread_id;
|
||||
uint64_t vma;
|
||||
uint64_t code_address;
|
||||
uint64_t code_size;
|
||||
uint64_t code_id;
|
||||
} zend_perf_jitdump_load_record;
|
||||
|
||||
static int jitdump_fd = -1;
|
||||
static void *jitdump_mem = MAP_FAILED;
|
||||
|
||||
static uint64_t zend_perf_timestamp(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return ((uint64_t)ts.tv_sec * 1000000000) + ts.tv_nsec;
|
||||
}
|
||||
|
||||
static void zend_jit_perf_jitdump_open(void)
|
||||
{
|
||||
char filename[64];
|
||||
int fd, ret;
|
||||
zend_elf_header elf_hdr;
|
||||
zend_perf_jitdump_header jit_hdr;
|
||||
|
||||
sprintf(filename, "/tmp/jit-%d.dump", getpid());
|
||||
if (!zend_perf_timestamp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
fd = open("/proc/self/exe", O_RDONLY);
|
||||
#elif defined(__NetBSD__)
|
||||
fd = open("/proc/curproc/exe", O_RDONLY);
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
char path[PATH_MAX];
|
||||
size_t pathlen = sizeof(path);
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
||||
if (sysctl(mib, 4, path, &pathlen, NULL, 0) == -1) {
|
||||
return;
|
||||
}
|
||||
fd = open(path, O_RDONLY);
|
||||
#elif defined(__sun)
|
||||
fd = open("/proc/self/path/a.out", O_RDONLY);
|
||||
#elif defined(__HAIKU__)
|
||||
char path[PATH_MAX];
|
||||
if (find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH,
|
||||
NULL, path, sizeof(path)) != B_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
#else
|
||||
fd = -1;
|
||||
#endif
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ret = read(fd, &elf_hdr, sizeof(elf_hdr));
|
||||
close(fd);
|
||||
|
||||
if (ret != sizeof(elf_hdr) ||
|
||||
elf_hdr.emagic[0] != 0x7f ||
|
||||
elf_hdr.emagic[1] != 'E' ||
|
||||
elf_hdr.emagic[2] != 'L' ||
|
||||
elf_hdr.emagic[3] != 'F') {
|
||||
return;
|
||||
}
|
||||
|
||||
jitdump_fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0666);
|
||||
if (jitdump_fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t page_size = sysconf(_SC_PAGESIZE);
|
||||
jitdump_mem = mmap(NULL,
|
||||
page_size,
|
||||
PROT_READ|PROT_EXEC,
|
||||
MAP_PRIVATE, jitdump_fd, 0);
|
||||
|
||||
if (jitdump_mem == MAP_FAILED) {
|
||||
close(jitdump_fd);
|
||||
jitdump_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
zend_mmap_set_name(jitdump_mem, page_size, "zend_jitdump");
|
||||
|
||||
memset(&jit_hdr, 0, sizeof(jit_hdr));
|
||||
jit_hdr.magic = ZEND_PERF_JITDUMP_HEADER_MAGIC;
|
||||
jit_hdr.version = ZEND_PERF_JITDUMP_HEADER_VERSION;
|
||||
jit_hdr.size = sizeof(jit_hdr);
|
||||
jit_hdr.elf_mach_target = elf_hdr.machine;
|
||||
jit_hdr.process_id = getpid();
|
||||
jit_hdr.time_stamp = zend_perf_timestamp();
|
||||
jit_hdr.flags = 0;
|
||||
zend_quiet_write(jitdump_fd, &jit_hdr, sizeof(jit_hdr));
|
||||
}
|
||||
|
||||
static void zend_jit_perf_jitdump_close(void)
|
||||
{
|
||||
if (jitdump_fd >= 0) {
|
||||
zend_perf_jitdump_record rec;
|
||||
|
||||
rec.event = ZEND_PERF_JITDUMP_RECORD_CLOSE;
|
||||
rec.size = sizeof(rec);
|
||||
rec.time_stamp = zend_perf_timestamp();
|
||||
zend_quiet_write(jitdump_fd, &rec, sizeof(rec));
|
||||
close(jitdump_fd);
|
||||
|
||||
if (jitdump_mem != MAP_FAILED) {
|
||||
munmap(jitdump_mem, sysconf(_SC_PAGESIZE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void zend_jit_perf_jitdump_register(const char *name, void *start, size_t size)
|
||||
{
|
||||
if (jitdump_fd >= 0) {
|
||||
static uint64_t id = 1;
|
||||
zend_perf_jitdump_load_record rec;
|
||||
size_t len = strlen(name);
|
||||
uint32_t thread_id = 0;
|
||||
#if defined(__linux__)
|
||||
thread_id = syscall(SYS_gettid);
|
||||
#elif defined(__darwin__)
|
||||
uint64_t thread_id_u64;
|
||||
pthread_threadid_np(NULL, &thread_id_u64);
|
||||
thread_id = (uint32_t) thread_id_u64;
|
||||
#elif defined(__FreeBSD__)
|
||||
long tid;
|
||||
thr_self(&tid);
|
||||
thread_id = (uint32_t)tid;
|
||||
#elif defined(__OpenBSD__)
|
||||
thread_id = getthrid();
|
||||
#elif defined(__NetBSD__)
|
||||
thread_id = _lwp_self();
|
||||
#elif defined(__DragonFly__)
|
||||
thread_id = lwp_gettid();
|
||||
#elif defined(__sun)
|
||||
thread_id = thr_self();
|
||||
#endif
|
||||
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.hdr.event = ZEND_PERF_JITDUMP_RECORD_LOAD;
|
||||
rec.hdr.size = sizeof(rec) + len + 1 + size;
|
||||
rec.hdr.time_stamp = zend_perf_timestamp();
|
||||
rec.process_id = getpid();
|
||||
rec.thread_id = thread_id;
|
||||
rec.vma = (uint64_t)(uintptr_t)start;
|
||||
rec.code_address = (uint64_t)(uintptr_t)start;
|
||||
rec.code_size = (uint64_t)size;
|
||||
rec.code_id = id++;
|
||||
|
||||
zend_quiet_write(jitdump_fd, &rec, sizeof(rec));
|
||||
zend_quiet_write(jitdump_fd, name, len + 1);
|
||||
zend_quiet_write(jitdump_fd, start, size);
|
||||
}
|
||||
}
|
||||
|
||||
static void zend_jit_perf_map_register(const char *name, void *start, size_t size)
|
||||
{
|
||||
static FILE *fp = NULL;
|
||||
|
||||
if (!fp) {
|
||||
char filename[64];
|
||||
|
||||
sprintf(filename, "/tmp/perf-%d.map", getpid());
|
||||
fp = fopen(filename, "w");
|
||||
if (!fp) {
|
||||
return;
|
||||
}
|
||||
setlinebuf(fp);
|
||||
}
|
||||
fprintf(fp, "%zx %zx %s\n", (size_t)(uintptr_t)start, size, name);
|
||||
}
|
||||
#else
|
||||
#include <os/log.h>
|
||||
#include <os/signpost.h>
|
||||
|
||||
/*
|
||||
* 1) To generate an Instrument tracing data:
|
||||
* xcrun xctrace record --template <Template name> --launch -- php
|
||||
* xcrun xctrace record --template Logging --launch -- php -dopcache.jit=1255 -dopcache.jit_debug=32 bench.php
|
||||
* 2) An instrument trace folder is created:
|
||||
* e.g. open Launch_php_2022-07-03_15.41.05_5F96D825.trace
|
||||
*/
|
||||
|
||||
static os_log_t jitdump_fd;
|
||||
static os_signpost_id_t jitdump_sp = OS_SIGNPOST_ID_NULL;
|
||||
|
||||
static void zend_jit_perf_jitdump_open(void)
|
||||
{
|
||||
/**
|
||||
* The `os_log_t` list per namespace is maintained by the os
|
||||
* and are not deallocated by (and not deallocatable)
|
||||
* but are reusable.
|
||||
*/
|
||||
jitdump_fd = os_log_create("net.php.opcache.jit", OS_LOG_CATEGORY_POINTS_OF_INTEREST);
|
||||
jitdump_sp = os_signpost_id_generate(jitdump_fd);
|
||||
|
||||
if (jitdump_sp != OS_SIGNPOST_ID_NULL && jitdump_sp != OS_SIGNPOST_ID_INVALID) {
|
||||
os_signpost_interval_begin(jitdump_fd, jitdump_sp, "zend_jitdump");
|
||||
}
|
||||
}
|
||||
|
||||
static void zend_jit_perf_jitdump_close(void)
|
||||
{
|
||||
if (jitdump_sp != OS_SIGNPOST_ID_NULL && jitdump_sp != OS_SIGNPOST_ID_INVALID) {
|
||||
os_signpost_interval_end(jitdump_fd, jitdump_sp, "zend_jitdump");
|
||||
}
|
||||
}
|
||||
|
||||
static void zend_jit_perf_jitdump_register(const char *name, void *start, size_t size)
|
||||
{
|
||||
}
|
||||
|
||||
static void zend_jit_perf_map_register(const char *name, void *start, size_t size)
|
||||
{
|
||||
os_signpost_id_t map = os_signpost_id_make_with_pointer(jitdump_fd, start);
|
||||
if (map != OS_SIGNPOST_ID_NULL && map != OS_SIGNPOST_ID_INVALID) {
|
||||
os_signpost_event_emit(jitdump_fd, map, "zend_jitdump_name", "%s", name);
|
||||
os_signpost_event_emit(jitdump_fd, map, "zend_jitdump_size", "%lu", size);
|
||||
}
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -28,13 +28,6 @@
|
|||
#include "Optimizer/zend_func_info.h"
|
||||
#include "Optimizer/zend_call_graph.h"
|
||||
#include "zend_jit.h"
|
||||
#ifndef ZEND_JIT_IR
|
||||
#if ZEND_JIT_TARGET_X86
|
||||
# include "zend_jit_x86.h"
|
||||
#elif ZEND_JIT_TARGET_ARM64
|
||||
# include "zend_jit_arm64.h"
|
||||
#endif
|
||||
#endif /* ZEND_JIT_IR */
|
||||
|
||||
#include "zend_jit_internal.h"
|
||||
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Zend JIT |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Dmitry Stogov <dmitry@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#if defined(__x86_64__) || defined(i386)
|
||||
|
||||
#define HAVE_VTUNE 1
|
||||
|
||||
#include "jit/vtune/jitprofiling.h"
|
||||
#include "jit/vtune/jitprofiling.c"
|
||||
|
||||
static void zend_jit_vtune_register(const char *name,
|
||||
const void *start,
|
||||
size_t size)
|
||||
{
|
||||
iJIT_Method_Load jmethod = {0};
|
||||
|
||||
if (iJIT_IsProfilingActive() != iJIT_SAMPLING_ON) {
|
||||
return;
|
||||
}
|
||||
|
||||
jmethod.method_id = iJIT_GetNewMethodID();
|
||||
jmethod.method_name = (char*)name;
|
||||
jmethod.class_file_name = NULL;
|
||||
jmethod.source_file_name = NULL;
|
||||
jmethod.method_load_address = (void*)start;
|
||||
jmethod.method_size = size;
|
||||
|
||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod);
|
||||
}
|
||||
|
||||
#endif /* defined(__x86_64__) || defined(i386) */
|
File diff suppressed because it is too large
Load diff
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Zend JIT |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Dmitry Stogov <dmitry@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef HAVE_JIT_X86_H
|
||||
#define HAVE_JIT_X86_H
|
||||
|
||||
typedef enum _zend_reg {
|
||||
ZREG_NONE = -1,
|
||||
|
||||
ZREG_R0,
|
||||
ZREG_R1,
|
||||
ZREG_R2,
|
||||
ZREG_R3,
|
||||
ZREG_R4,
|
||||
ZREG_R5,
|
||||
ZREG_R6,
|
||||
ZREG_R7,
|
||||
|
||||
#if defined(__x86_64__) || defined(_WIN64)
|
||||
ZREG_R8,
|
||||
ZREG_R9,
|
||||
ZREG_R10,
|
||||
ZREG_R11,
|
||||
ZREG_R12,
|
||||
ZREG_R13,
|
||||
ZREG_R14,
|
||||
ZREG_R15,
|
||||
#endif
|
||||
|
||||
ZREG_XMM0,
|
||||
ZREG_XMM1,
|
||||
ZREG_XMM2,
|
||||
ZREG_XMM3,
|
||||
ZREG_XMM4,
|
||||
ZREG_XMM5,
|
||||
ZREG_XMM6,
|
||||
ZREG_XMM7,
|
||||
|
||||
#if defined(__x86_64__) || defined(_WIN64)
|
||||
ZREG_XMM8,
|
||||
ZREG_XMM9,
|
||||
ZREG_XMM10,
|
||||
ZREG_XMM11,
|
||||
ZREG_XMM12,
|
||||
ZREG_XMM13,
|
||||
ZREG_XMM14,
|
||||
ZREG_XMM15,
|
||||
#endif
|
||||
|
||||
ZREG_NUM,
|
||||
|
||||
ZREG_THIS, /* used for delayed FETCH_THIS deoptimization */
|
||||
|
||||
/* pseudo constants used by deoptimizer */
|
||||
ZREG_LONG_MIN_MINUS_1,
|
||||
ZREG_LONG_MIN,
|
||||
ZREG_LONG_MAX,
|
||||
ZREG_LONG_MAX_PLUS_1,
|
||||
ZREG_NULL,
|
||||
|
||||
ZREG_ZVAL_TRY_ADDREF,
|
||||
ZREG_ZVAL_COPY_GPR0,
|
||||
} zend_reg;
|
||||
|
||||
typedef struct _zend_jit_registers_buf {
|
||||
#if defined(__x86_64__) || defined(_WIN64)
|
||||
uint64_t gpr[16]; /* general purpose integer register */
|
||||
double fpr[16]; /* floating point registers */
|
||||
#else
|
||||
uint32_t gpr[8]; /* general purpose integer register */
|
||||
double fpr[8]; /* floating point registers */
|
||||
#endif
|
||||
} zend_jit_registers_buf;
|
||||
|
||||
#define ZREG_FIRST_FPR ZREG_XMM0
|
||||
#define ZREG_COPY ZREG_R0
|
||||
|
||||
#define ZREG_RAX ZREG_R0
|
||||
#define ZREG_RCX ZREG_R1
|
||||
#define ZREG_RDX ZREG_R2
|
||||
#define ZREG_RBX ZREG_R3
|
||||
#define ZREG_RSP ZREG_R4
|
||||
#define ZREG_RBP ZREG_R5
|
||||
#define ZREG_RSI ZREG_R6
|
||||
#define ZREG_RDI ZREG_R7
|
||||
|
||||
#ifdef _WIN64
|
||||
# define ZREG_FP ZREG_R14
|
||||
# define ZREG_IP ZREG_R15
|
||||
#elif defined(__x86_64__)
|
||||
# define ZREG_FP ZREG_R14
|
||||
# define ZREG_IP ZREG_R15
|
||||
#else
|
||||
# define ZREG_FP ZREG_RSI
|
||||
# define ZREG_IP ZREG_RDI
|
||||
#endif
|
||||
|
||||
#define ZREG_RX ZREG_IP
|
||||
|
||||
typedef uint32_t zend_regset;
|
||||
|
||||
#define ZEND_REGSET_64BIT 0
|
||||
|
||||
#ifdef _WIN64
|
||||
# define ZEND_REGSET_FIXED \
|
||||
(ZEND_REGSET(ZREG_RSP) | ZEND_REGSET(ZREG_R14) | ZEND_REGSET(ZREG_R15))
|
||||
# define ZEND_REGSET_GP \
|
||||
ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_R0, ZREG_R15), ZEND_REGSET_FIXED)
|
||||
# define ZEND_REGSET_FP \
|
||||
ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_XMM0, ZREG_XMM15), ZEND_REGSET_FIXED)
|
||||
# define ZEND_REGSET_SCRATCH \
|
||||
(ZEND_REGSET(ZREG_RAX) | ZEND_REGSET(ZREG_RDX) | ZEND_REGSET(ZREG_RCX) | ZEND_REGSET_INTERVAL(ZREG_R8, ZREG_R11) | ZEND_REGSET_FP)
|
||||
# define ZEND_REGSET_PRESERVED \
|
||||
(ZEND_REGSET(ZREG_RBX) | ZEND_REGSET(ZREG_RBP) | ZEND_REGSET(ZREG_R12) | ZEND_REGSET(ZREG_R13) | ZEND_REGSET(ZREG_RDI) | ZEND_REGSET(ZREG_RSI))
|
||||
#elif defined(__x86_64__)
|
||||
# define ZEND_REGSET_FIXED \
|
||||
(ZEND_REGSET(ZREG_RSP) | ZEND_REGSET(ZREG_R14) | ZEND_REGSET(ZREG_R15))
|
||||
# define ZEND_REGSET_GP \
|
||||
ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_R0, ZREG_R15), ZEND_REGSET_FIXED)
|
||||
# define ZEND_REGSET_FP \
|
||||
ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_XMM0, ZREG_XMM15), ZEND_REGSET_FIXED)
|
||||
# define ZEND_REGSET_SCRATCH \
|
||||
(ZEND_REGSET(ZREG_RAX) | ZEND_REGSET(ZREG_RDI) | ZEND_REGSET(ZREG_RSI) | ZEND_REGSET(ZREG_RDX) | ZEND_REGSET(ZREG_RCX) | ZEND_REGSET_INTERVAL(ZREG_R8, ZREG_R11) | ZEND_REGSET_FP)
|
||||
# define ZEND_REGSET_PRESERVED \
|
||||
(ZEND_REGSET(ZREG_RBX) | ZEND_REGSET(ZREG_RBP) | ZEND_REGSET(ZREG_R12) | ZEND_REGSET(ZREG_R13))
|
||||
#else
|
||||
# define ZEND_REGSET_FIXED \
|
||||
(ZEND_REGSET(ZREG_RSP) | ZEND_REGSET(ZREG_RSI) | ZEND_REGSET(ZREG_RDI))
|
||||
# define ZEND_REGSET_GP \
|
||||
ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_R0, ZREG_R7), ZEND_REGSET_FIXED)
|
||||
# define ZEND_REGSET_FP \
|
||||
ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_XMM0, ZREG_XMM7), ZEND_REGSET_FIXED)
|
||||
# define ZEND_REGSET_SCRATCH \
|
||||
(ZEND_REGSET(ZREG_RAX) | ZEND_REGSET(ZREG_RCX) | ZEND_REGSET(ZREG_RDX) | ZEND_REGSET_FP)
|
||||
# define ZEND_REGSET_PRESERVED \
|
||||
(ZEND_REGSET(ZREG_RBX) | ZEND_REGSET(ZREG_RBP))
|
||||
#endif
|
||||
|
||||
#define ZEND_REGSET_LOW_PRIORITY \
|
||||
(ZEND_REGSET(ZREG_R0) | ZEND_REGSET(ZREG_R1) | ZEND_REGSET(ZREG_XMM0) | ZEND_REGSET(ZREG_XMM1))
|
||||
|
||||
#endif /* ZEND_JIT_X86_H */
|
Loading…
Add table
Add a link
Reference in a new issue