forked from Popn_Tools/popnhax
Compare commits
61 Commits
Author | SHA1 | Date | |
---|---|---|---|
ceb015ce8a | |||
adadae9067 | |||
a28dcbd882 | |||
4c0000870e | |||
3d8d6a83ad | |||
4c44fa2eff | |||
93a5982bc4 | |||
ac5c4e6ad7 | |||
28d58fe172 | |||
02b193bfab | |||
f51e0799a7 | |||
c953aaf8f4 | |||
e29320ebcb | |||
434918c330 | |||
d95b3226d7 | |||
2b0eb747c7 | |||
cb44d59378 | |||
48e82ae476 | |||
6da8c893b5 | |||
a86516dc2f | |||
ddf377886e | |||
9f6eae91fc | |||
4704ba05d1 | |||
32f7c5bd36 | |||
c65106127a | |||
716c7ea0a8 | |||
cb70073921 | |||
3cddbf8f5c | |||
a20a9caede | |||
cef663b310 | |||
880af43da6 | |||
f4f97e0b24 | |||
0ecb8a8d58 | |||
1ad701e725 | |||
f569e9dd4b | |||
4c5751a694 | |||
15b1bf20a7 | |||
4d618e5d1c | |||
607c2842b6 | |||
dd109549b0 | |||
edea20b403 | |||
3fef3f58bf | |||
6dfed35c5f | |||
15122be9b7 | |||
151c90352d | |||
0e1f365ac2 | |||
e9bdbaa9f7 | |||
814edb296f | |||
52048c2133 | |||
3083c62c67 | |||
11801e6340 | |||
f2802c5bd7 | |||
a4a4e53da1 | |||
fd529834b5 | |||
0cb685ef4b | |||
dc987c46ac | |||
4706d117a1 | |||
2535fba8d6 | |||
ccf3a4c8f8 | |||
c3e8eb5f13 | |||
783dafbe97 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*:Zone.Identifier
|
8
Makefile
8
Makefile
@ -232,8 +232,8 @@ $$(dll_$1_$2_$3) $$(implib_$1_$2_$3): $$(obj_$1_$2_$3) $$(abslib_$1_$2_$3) \
|
|||||||
$(ccache) $$(toolchain_$1)gcc -shared $$(srcdir_$3)/$3.def \
|
$(ccache) $$(toolchain_$1)gcc -shared $$(srcdir_$3)/$3.def \
|
||||||
-o $$(dll_$1_$2_$3) -Wl,--out-implib,$$(implib_$1_$2_$3) \
|
-o $$(dll_$1_$2_$3) -Wl,--out-implib,$$(implib_$1_$2_$3) \
|
||||||
$$^ $$(ldflags_$3) $(optflags_$1)
|
$$^ $$(ldflags_$3) $(optflags_$1)
|
||||||
strip -s $$(dll_$1_$2_$3)
|
$$(toolchain_$1)strip -s $$(dll_$1_$2_$3)
|
||||||
ranlib $$(implib_$1_$2_$3)
|
$$(toolchain_$1)ranlib $$(implib_$1_$2_$3)
|
||||||
|
|
||||||
endef
|
endef
|
||||||
|
|
||||||
@ -248,7 +248,7 @@ exe_$1_$2_$3 := $$(bindir_$1_$2)/$3.exe
|
|||||||
$$(exe_$1_$2_$3): $$(obj_$1_$2_$3) $$(abslib_$1_$2_$3) $$(absdpl_$1_$2_$3) \
|
$$(exe_$1_$2_$3): $$(obj_$1_$2_$3) $$(abslib_$1_$2_$3) $$(absdpl_$1_$2_$3) \
|
||||||
| $$(bindir_$1_$2)
|
| $$(bindir_$1_$2)
|
||||||
$(ccache) $$(toolchain_$1)gcc -o $$@ $$^ $$(ldflags_$3) $(optflags_$1)
|
$(ccache) $$(toolchain_$1)gcc -o $$@ $$^ $$(ldflags_$3) $(optflags_$1)
|
||||||
strip -s $$@
|
$$(toolchain_$1)strip -s $$@
|
||||||
|
|
||||||
endef
|
endef
|
||||||
|
|
||||||
@ -259,7 +259,7 @@ define t_import
|
|||||||
impdef_$1_$2_$3 ?= imports/import_$1_$2_$3.def
|
impdef_$1_$2_$3 ?= imports/import_$1_$2_$3.def
|
||||||
|
|
||||||
$$(bindir_$1_$2)/lib$3.a: $$(impdef_$1_$2_$3) | $$(bindir_$1_$2)
|
$$(bindir_$1_$2)/lib$3.a: $$(impdef_$1_$2_$3) | $$(bindir_$1_$2)
|
||||||
dlltool -l $$@ -d $$<
|
$$(toolchain_$1)dlltool -l $$@ -d $$<
|
||||||
|
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
23
Module.mk
23
Module.mk
@ -6,6 +6,7 @@ avsvers_64 := 1700 1509
|
|||||||
imps += avs avs-ea3
|
imps += avs avs-ea3
|
||||||
|
|
||||||
include util/Module.mk
|
include util/Module.mk
|
||||||
|
include libdisasm/Module.mk
|
||||||
include minhook/Module.mk
|
include minhook/Module.mk
|
||||||
include popnhax/Module.mk
|
include popnhax/Module.mk
|
||||||
|
|
||||||
@ -14,17 +15,15 @@ include popnhax/Module.mk
|
|||||||
#
|
#
|
||||||
|
|
||||||
zipdir := $(BUILDDIR)/zip
|
zipdir := $(BUILDDIR)/zip
|
||||||
|
popnhax_version := $(shell grep "define PROGRAM_VERSION" popnhax/dllmain.cc | cut -d'"' -f2)
|
||||||
|
|
||||||
$(zipdir)/:
|
$(BUILDDIR)/popnhax_v$(popnhax_version).zip: \
|
||||||
mkdir -p $@
|
build/bin/avs2_1508-32/popnhax.dll
|
||||||
|
@echo ... $@
|
||||||
|
@mkdir -p $(zipdir)
|
||||||
|
@cp -a -p build/bin/avs2_1508-32/popnhax.dll $(zipdir)
|
||||||
|
@cp -r -a -p dist/popnhax/* $(zipdir)
|
||||||
|
@cd $(zipdir) \
|
||||||
|
&& zip -r ../popnhax_v$(popnhax_version).zip ./*
|
||||||
|
|
||||||
$(BUILDDIR)/popnhax.zip: \
|
all: $(BUILDDIR)/popnhax_v$(popnhax_version).zip
|
||||||
build/bin/avs2_1508-32/popnhax.dll \
|
|
||||||
dist/popnhax/popnhax.xml \
|
|
||||||
dist/popnhax/D3d9.dll \
|
|
||||||
dist/popnhax/ifs_hook.dll \
|
|
||||||
| $(zipdir)/
|
|
||||||
echo ... $@
|
|
||||||
zip -j $@ $^
|
|
||||||
|
|
||||||
all: $(BUILDDIR)/popnhax.zip
|
|
||||||
|
26
README.md
26
README.md
@ -2,10 +2,32 @@
|
|||||||
|
|
||||||
# popnhax
|
# popnhax
|
||||||
|
|
||||||
Arcade game patcher.
|
Patcher for pop'n music arcade game.
|
||||||
|
|
||||||
|
Featuring pfree, instant retire, visual and audio offset adjust, 1000Hz input polling for true ms-based timing, unlimited favorites, auto hi-speed selection, iidx-like hard gauge and more..
|
||||||
|
|
||||||
Based on [bemanihax](https://github.com/windyfairy/bemanihax) whose an updated version was included with omnimix v1
|
Based on [bemanihax](https://github.com/windyfairy/bemanihax) whose an updated version was included with omnimix v1
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
Refer to [popnhax.xml](https://github.com/CrazyRedMachine/popnhax/blob/main/dist/popnhax/popnhax.xml) for complete list and explanations
|
||||||
|
|
||||||
|
More info could be found in [Release Notes](https://github.com/CrazyRedMachine/popnhax/releases) or in the [popnhax_tools](https://github.com/CrazyRedMachine/popnhax_tools) repository.
|
||||||
|
|
||||||
|
### Run Instructions
|
||||||
|
|
||||||
|
- Extract all files directly in the `contents` folder of your install.
|
||||||
|
|
||||||
|
(**Note**: if you're running your dlls from `modules` subfolder, please rather copy them back into `contents` folder).
|
||||||
|
|
||||||
|
- Edit `popnhax.xml` with a text editor and set your desired options.
|
||||||
|
|
||||||
|
- Add `popnhax.dll` as an inject dll to your gamestart command or option menu.
|
||||||
|
|
||||||
|
eg. modify your gamestart.bat to add `-k popnhax.dll` or `-K popnhax.dll` depending on the launcher you use.
|
||||||
|
|
||||||
|
Some launchers also feature an option menu (accessible by pressing F4 ingame), in which case you can locate the "Inject Hook" setting in option tab. Enter `popnhax.dll` there.
|
||||||
|
|
||||||
### Build Instructions
|
### Build Instructions
|
||||||
|
|
||||||
Should be working out of the box with MSYS2/MinGW32. Just run `make`.
|
Using WSL is the recommended method. Just run `make`.
|
||||||
|
0
dist/popnhax/_update
vendored
Normal file
0
dist/popnhax/_update
vendored
Normal file
BIN
dist/popnhax/data_mods/_popnhax_assets/tex/gmcmh.ifs
vendored
Normal file
BIN
dist/popnhax/data_mods/_popnhax_assets/tex/gmcmh.ifs
vendored
Normal file
Binary file not shown.
BIN
dist/popnhax/data_mods/_popnhax_assets/tex/system24/ms_ifs/cate_cc.png
vendored
Normal file
BIN
dist/popnhax/data_mods/_popnhax_assets/tex/system24/ms_ifs/cate_cc.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
dist/popnhax/data_mods/_popnhax_assets/tex/system25/ms_ifs/cate_cc.png
vendored
Normal file
BIN
dist/popnhax/data_mods/_popnhax_assets/tex/system25/ms_ifs/cate_cc.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
dist/popnhax/data_mods/_popnhax_assets/tex/system26/ms_ifs/cate_cc.png
vendored
Normal file
BIN
dist/popnhax/data_mods/_popnhax_assets/tex/system26/ms_ifs/cate_cc.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
dist/popnhax/data_mods/_popnhax_assets/tex/system27/ms_ifs/cate_cc.png
vendored
Normal file
BIN
dist/popnhax/data_mods/_popnhax_assets/tex/system27/ms_ifs/cate_cc.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
82
dist/popnhax/popnhax.xml
vendored
82
dist/popnhax/popnhax.xml
vendored
@ -5,6 +5,22 @@
|
|||||||
<patch_db __type="bool">0</patch_db>
|
<patch_db __type="bool">0</patch_db>
|
||||||
<!-- Force unlock music, charts, characters, and deco parts when applicable -->
|
<!-- Force unlock music, charts, characters, and deco parts when applicable -->
|
||||||
<force_unlocks __type="bool">0</force_unlocks>
|
<force_unlocks __type="bool">0</force_unlocks>
|
||||||
|
<!-- Put customs into their own category (0: no, 1: simple category with all customs, 2: subcategories by folder name) -->
|
||||||
|
<custom_categ __type="u8">2</custom_categ>
|
||||||
|
<!-- Prevent customs from showing up in version folders -->
|
||||||
|
<custom_exclude_from_version __type="bool">1</custom_exclude_from_version>
|
||||||
|
<!-- Prevent customs from showing up in level folders -->
|
||||||
|
<custom_exclude_from_level __type="bool">0</custom_exclude_from_level>
|
||||||
|
|
||||||
|
<!-- Other categories -->
|
||||||
|
<!-- Bring back score challenge in the game for servers supporting it (only for kaimei onwards) -->
|
||||||
|
<score_challenge __type="bool">0</score_challenge>
|
||||||
|
<!-- Handle favorites through data_mods/<game>.<friendID>.fav files (Note: allows UNLIMITED favorites as well as favorites without an account/server) -->
|
||||||
|
<local_favorites __type="bool">0</local_favorites>
|
||||||
|
|
||||||
|
<!-- Framerate -->
|
||||||
|
<!-- Fix animation speed at higher framerate for a smoother experience (lower visual latency) -->
|
||||||
|
<high_framerate __type="bool">0</high_framerate>
|
||||||
|
|
||||||
<!-- Classic patches -->
|
<!-- Classic patches -->
|
||||||
<!-- Prevent crash on boot when using a different default audio source (aka HDMI audio patch) -->
|
<!-- Prevent crash on boot when using a different default audio source (aka HDMI audio patch) -->
|
||||||
@ -26,10 +42,8 @@
|
|||||||
<!-- Press numpad 9 in song to retire instantly, or on result screen to leave game session (thank you for playing) -->
|
<!-- Press numpad 9 in song to retire instantly, or on result screen to leave game session (thank you for playing) -->
|
||||||
<!-- quick_retire with pfree also enables quick retry: press numpad 8 during song or on result screen to retry (keep holding to skip option select) -->
|
<!-- quick_retire with pfree also enables quick retry: press numpad 8 during song or on result screen to retry (keep holding to skip option select) -->
|
||||||
<quick_retire __type="bool">0</quick_retire>
|
<quick_retire __type="bool">0</quick_retire>
|
||||||
|
<!-- Press 9 on option select screen to go back to song selection (requires quick_retire) -->
|
||||||
<!-- Network features -->
|
<back_to_song_select __type="bool">0</back_to_song_select>
|
||||||
<!-- Bring back score challenge in the game for servers supporting it (only for kaimei onwards) -->
|
|
||||||
<score_challenge __type="bool">0</score_challenge>
|
|
||||||
|
|
||||||
<!-- Audio offset -->
|
<!-- Audio offset -->
|
||||||
<!-- Offset the audio by x ms (negative plays audio earlier). This will disable keysounds -->
|
<!-- Offset the audio by x ms (negative plays audio earlier). This will disable keysounds -->
|
||||||
@ -49,7 +63,7 @@
|
|||||||
<hispeed_default_bpm __type="u16">0</hispeed_default_bpm>
|
<hispeed_default_bpm __type="u16">0</hispeed_default_bpm>
|
||||||
|
|
||||||
<!-- IIDX-like hard gauge (start with full gauge, instant fail if gauge drops to 0) -->
|
<!-- IIDX-like hard gauge (start with full gauge, instant fail if gauge drops to 0) -->
|
||||||
<!-- Gauge details: increment: +0.1% for each cool/great/good (like spicy gauge), decrement: -9% for each bad, or -4.5% if gauge <=30% ) -->
|
<!-- Gauge details: increment: +0.1% for each cool/great/good (like spicy gauge), decrement: -9% for each bad, or -4.5% if gauge <=30% (like IIDX) -->
|
||||||
<iidx_hard_gauge __type="bool">0</iidx_hard_gauge>
|
<iidx_hard_gauge __type="bool">0</iidx_hard_gauge>
|
||||||
<!-- Force full options by default (useful when no numpad is available) -->
|
<!-- Force full options by default (useful when no numpad is available) -->
|
||||||
<force_full_opt __type="bool">0</force_full_opt>
|
<force_full_opt __type="bool">0</force_full_opt>
|
||||||
@ -86,32 +100,28 @@
|
|||||||
<!-- Enable practice mode menu, (r-ran, constant chart speed, slow motion, etc...) -->
|
<!-- Enable practice mode menu, (r-ran, constant chart speed, slow motion, etc...) -->
|
||||||
<!-- PLEASE USE OFFLINE ONLY -->
|
<!-- PLEASE USE OFFLINE ONLY -->
|
||||||
<practice_mode __type="bool">0</practice_mode>
|
<practice_mode __type="bool">0</practice_mode>
|
||||||
<!-- Press 9 on option select screen to go back to song selection (requires quick_retire) -->
|
|
||||||
<!-- Note: causes issues with sounds on song select -->
|
|
||||||
<back_to_song_select __type="bool">0</back_to_song_select>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ========================================================================================
|
<!-- ========================================================================================
|
||||||
DEBUG OPTIONS FOLLOW (GENERALLY SHOULD NOT BE CHANGED UNLESS YOU KNOW WHAT YOU'RE DOING)
|
DEBUG OPTIONS FOLLOW (GENERALLY SHOULD NOT BE CHANGED UNLESS YOU KNOW WHAT YOU'RE DOING)
|
||||||
======================================================================================== -->
|
======================================================================================== -->
|
||||||
|
|
||||||
<!-- Datecode and Multiboot -->
|
<!-- Datecode and Multiboot -->
|
||||||
<!-- Force a different datecode than the one found in ea3-config (yyyymmdd00) -->
|
<!-- Force a different datecode than the one found in ea3-config (yyyymmdd00), or use "auto" to let music limit decide for you if patch_db is on -->
|
||||||
<force_datecode __type="str"></force_datecode>
|
<force_datecode __type="str">auto</force_datecode>
|
||||||
<!-- Also apply force_datecode to network packets -->
|
<!-- Also apply force_datecode to network packets -->
|
||||||
<network_datecode __type="bool">1</network_datecode>
|
<network_datecode __type="bool">1</network_datecode>
|
||||||
<!-- Disable multiboot auto conf tuning (which takes place when using popn22_yyyymmddrr.dll format and an xml without force_datecode option) -->
|
<!-- Disable multiboot auto conf tuning (which takes place when using popn22_yyyymmddrr.dll format and an xml without another datecode in force_datecode) -->
|
||||||
<disable_multiboot __type="bool">0</disable_multiboot>
|
<disable_multiboot __type="bool">0</disable_multiboot>
|
||||||
|
|
||||||
<!-- Timing and lanes -->
|
<!-- Timing and lanes -->
|
||||||
|
<!-- Base visual offset (value will be added to the base SD (-60) and base HD (-76) values) -->
|
||||||
|
<base_offset __type="s8">0</base_offset>
|
||||||
<!-- Automatically play keysounds during songs -->
|
<!-- Automatically play keysounds during songs -->
|
||||||
<disable_keysounds __type="bool">0</disable_keysounds>
|
<disable_keysounds __type="bool">0</disable_keysounds>
|
||||||
<!-- Offset the keysounds by x ms (negative is earlier). With disable_keysounds, becomes an audio offset -->
|
<!-- Offset the keysounds by x ms (negative is earlier). With disable_keysounds, becomes an audio offset -->
|
||||||
<keysound_offset __type="s8">0</keysound_offset>
|
<keysound_offset __type="s8">0</keysound_offset>
|
||||||
<!-- Adjust pop-kun and beam brightness (won't affect long popkuns) -->
|
<!-- Adjust pop-kun and beam brightness (won't affect long popkuns) -->
|
||||||
<beam_brightness __type="s8">0</beam_brightness>
|
<beam_brightness __type="s8">0</beam_brightness>
|
||||||
<!-- Disable the builtin frame limiter (faster/smoother animations at 120fps+) -->
|
|
||||||
<fps_uncap __type="bool">0</fps_uncap>
|
|
||||||
<!-- 1000Hz polling thread priority (for enhanced_polling only, might cause crashes on some systems if set too high)
|
<!-- 1000Hz polling thread priority (for enhanced_polling only, might cause crashes on some systems if set too high)
|
||||||
values THREAD_PRIORITY_LOWEST -2
|
values THREAD_PRIORITY_LOWEST -2
|
||||||
THREAD_PRIORITY_BELOW_NORMAL -1
|
THREAD_PRIORITY_BELOW_NORMAL -1
|
||||||
@ -121,28 +131,40 @@
|
|||||||
THREAD_PRIORITY_TIME_CRITICAL 15 -->
|
THREAD_PRIORITY_TIME_CRITICAL 15 -->
|
||||||
<enhanced_polling_priority __type="s8">1</enhanced_polling_priority>
|
<enhanced_polling_priority __type="s8">1</enhanced_polling_priority>
|
||||||
|
|
||||||
<!-- Song db patches -->
|
<!-- Framerate -->
|
||||||
<!-- Auto select patch file from data_mods folder (will detect datecode from ea3-config or force_datecode option) -->
|
<!-- Reference fps value for high_framerate animation speed (0: use monitor refreshrate and disable frame limiter) -->
|
||||||
|
<high_framerate_fps __type="u16">0</high_framerate_fps>
|
||||||
|
<!-- Tune the builtin frame limiter the closest to high_framerate_fps -->
|
||||||
|
<high_framerate_limiter __type="bool">1</high_framerate_limiter>
|
||||||
|
<!-- Disable the builtin frame limiter -->
|
||||||
|
<fps_uncap __type="bool">0</fps_uncap>
|
||||||
|
|
||||||
|
<!-- Song db patches (requires patch_db) -->
|
||||||
|
<!-- Auto select patch file from data_mods folder based on music limit, or datecode otherwise (will detect datecode from ea3-config or force_datecode option) -->
|
||||||
<patch_xml_auto __type="bool">1</patch_xml_auto>
|
<patch_xml_auto __type="bool">1</patch_xml_auto>
|
||||||
<!-- Manually set XML file containing patches (requires patch_xml_auto to be disabled) -->
|
<!-- Manually set XML file containing patches (requires patch_xml_auto to be disabled) -->
|
||||||
<patch_xml_filename __type="str"></patch_xml_filename>
|
<patch_xml_filename __type="str"></patch_xml_filename>
|
||||||
<!-- Force the newly created buffers to be the same size as the original buffers -->
|
<!-- Do not perform music limit checks for patch_xml_auto (not recommended) -->
|
||||||
<disable_expansions __type="bool">0</disable_expansions>
|
<ignore_music_limit __type="bool">0</ignore_music_limit>
|
||||||
<!-- Copy the new table information over top the old tables (automatically enables disable_expansions) -->
|
|
||||||
<disable_redirection __type="bool">0</disable_redirection>
|
<!-- Custom category options (requires patch_db) -->
|
||||||
|
<!-- Also exclude omnimix (song id < 3000) tracks from version/level (requires custom_exclude_from_level or custom_exclude_from_version) -->
|
||||||
|
<exclude_omni __type="bool">0</exclude_omni>
|
||||||
|
<!-- Any new chart added to an existing song moves the song to the customs folder -->
|
||||||
|
<partial_entries __type="bool">0</partial_entries>
|
||||||
|
<!-- Minimum songid for a song to be seen as "custom" (e.g. use 4000 for real customs only) -->
|
||||||
|
<custom_categ_min_songid __type="u16">0</custom_categ_min_songid>
|
||||||
|
<!-- Category title for customs -->
|
||||||
|
<custom_category_title __type="str">Customs</custom_category_title>
|
||||||
|
<!-- Format used for category title (in BM2DXFontScript format, refer to BM2DXFontScript.md in popnhax_tools repo) -->
|
||||||
|
<custom_category_format __type="str">[ol:4][olc:d92f0d]%s</custom_category_format>
|
||||||
|
<!-- Format used for custom song titles on song select (Note: colors not working for kaimei and above, but rotation does, e.g. "* [rz:3]%s[/rz]" ) -->
|
||||||
|
<custom_track_title_format __type="str"></custom_track_title_format>
|
||||||
|
<!-- Optional secondary format used for older games only (Full colors supported, e.g. "[ol:4][olc:d92f0d]%s") -->
|
||||||
|
<custom_track_title_format2 __type="str"></custom_track_title_format2>
|
||||||
|
|
||||||
<!-- Translation -->
|
<!-- Translation -->
|
||||||
<!-- Disable .dict string replacements and .ips patches -->
|
<!-- Disable .dict string replacements and .ips patches -->
|
||||||
<disable_translation __type="bool">0</disable_translation>
|
<disable_translation __type="bool">0</disable_translation>
|
||||||
<!-- Dump applied translations and dll runtime data to help debug translation -->
|
|
||||||
<translation_debug __type="bool">0</translation_debug>
|
|
||||||
|
|
||||||
<!-- HARD Gauge alteration modes -->
|
|
||||||
<!-- Turn hard gauge into survival gauge (1: former COURSE gauge (-3.42%), 2: NORMAL gauge decrease rate (-4.99%), 3: IIDX HARD gauge decrease rate (-9%), 4: HARD gauge decrease rate (-19.94%)) -->
|
|
||||||
<survival_gauge __type="u8">0</survival_gauge>
|
|
||||||
<!-- Survival gauge has IIDX-like decrease rate adjustment (decrease amount halved when gauge is at 30% or less) -->
|
|
||||||
<survival_iidx __type="bool">0</survival_iidx>
|
|
||||||
<!-- Set survival gauge increase rate to spicy (+01/+01 instead of +02/+01) -->
|
|
||||||
<survival_spicy __type="bool">0</survival_spicy>
|
|
||||||
|
|
||||||
</popnhax>
|
</popnhax>
|
||||||
|
43
libdisasm/Makefile.am
Normal file
43
libdisasm/Makefile.am
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
include_HEADERS = libdis.h
|
||||||
|
lib_LTLIBRARIES = libdisasm.la
|
||||||
|
libdisasm_la_SOURCES = \
|
||||||
|
ia32_implicit.c \
|
||||||
|
ia32_implicit.h \
|
||||||
|
ia32_insn.c \
|
||||||
|
ia32_insn.h \
|
||||||
|
ia32_invariant.c \
|
||||||
|
ia32_invariant.h \
|
||||||
|
ia32_modrm.c \
|
||||||
|
ia32_modrm.h \
|
||||||
|
ia32_opcode_tables.c \
|
||||||
|
ia32_opcode_tables.h \
|
||||||
|
ia32_operand.c \
|
||||||
|
ia32_operand.h \
|
||||||
|
ia32_reg.c \
|
||||||
|
ia32_reg.h \
|
||||||
|
ia32_settings.c \
|
||||||
|
ia32_settings.h \
|
||||||
|
libdis.h \
|
||||||
|
qword.h \
|
||||||
|
x86_disasm.c \
|
||||||
|
x86_format.c \
|
||||||
|
x86_imm.c \
|
||||||
|
x86_imm.h \
|
||||||
|
x86_insn.c \
|
||||||
|
x86_misc.c \
|
||||||
|
x86_operand_list.c \
|
||||||
|
x86_operand_list.h
|
||||||
|
|
||||||
|
# Cheat to get non-autoconf swig into tarball,
|
||||||
|
# even if it doesn't build by default.
|
||||||
|
EXTRA_DIST = \
|
||||||
|
swig/Makefile \
|
||||||
|
swig/libdisasm.i \
|
||||||
|
swig/libdisasm_oop.i \
|
||||||
|
swig/python/Makefile-swig \
|
||||||
|
swig/perl/Makefile-swig \
|
||||||
|
swig/perl/Makefile.PL \
|
||||||
|
swig/ruby/Makefile-swig \
|
||||||
|
swig/ruby/extconf.rb \
|
||||||
|
swig/tcl/Makefile-swig \
|
||||||
|
swig/README
|
544
libdisasm/Makefile.in
Normal file
544
libdisasm/Makefile.in
Normal file
@ -0,0 +1,544 @@
|
|||||||
|
# Makefile.in generated by automake 1.10 from Makefile.am.
|
||||||
|
# @configure_input@
|
||||||
|
|
||||||
|
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||||
|
# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||||
|
# This Makefile.in is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||||
|
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
# PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
@SET_MAKE@
|
||||||
|
|
||||||
|
|
||||||
|
VPATH = @srcdir@
|
||||||
|
pkgdatadir = $(datadir)/@PACKAGE@
|
||||||
|
pkglibdir = $(libdir)/@PACKAGE@
|
||||||
|
pkgincludedir = $(includedir)/@PACKAGE@
|
||||||
|
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||||
|
install_sh_DATA = $(install_sh) -c -m 644
|
||||||
|
install_sh_PROGRAM = $(install_sh) -c
|
||||||
|
install_sh_SCRIPT = $(install_sh) -c
|
||||||
|
INSTALL_HEADER = $(INSTALL_DATA)
|
||||||
|
transform = $(program_transform_name)
|
||||||
|
NORMAL_INSTALL = :
|
||||||
|
PRE_INSTALL = :
|
||||||
|
POST_INSTALL = :
|
||||||
|
NORMAL_UNINSTALL = :
|
||||||
|
PRE_UNINSTALL = :
|
||||||
|
POST_UNINSTALL = :
|
||||||
|
build_triplet = @build@
|
||||||
|
host_triplet = @host@
|
||||||
|
subdir = libdisasm
|
||||||
|
DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \
|
||||||
|
$(srcdir)/Makefile.in TODO
|
||||||
|
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||||
|
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
|
||||||
|
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||||
|
$(ACLOCAL_M4)
|
||||||
|
mkinstalldirs = $(install_sh) -d
|
||||||
|
CONFIG_HEADER = $(top_builddir)/config.h
|
||||||
|
CONFIG_CLEAN_FILES =
|
||||||
|
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||||
|
am__vpath_adj = case $$p in \
|
||||||
|
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||||
|
*) f=$$p;; \
|
||||||
|
esac;
|
||||||
|
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
|
||||||
|
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
|
||||||
|
libLTLIBRARIES_INSTALL = $(INSTALL)
|
||||||
|
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||||
|
libdisasm_la_LIBADD =
|
||||||
|
am_libdisasm_la_OBJECTS = ia32_implicit.lo ia32_insn.lo \
|
||||||
|
ia32_invariant.lo ia32_modrm.lo ia32_opcode_tables.lo \
|
||||||
|
ia32_operand.lo ia32_reg.lo ia32_settings.lo x86_disasm.lo \
|
||||||
|
x86_format.lo x86_imm.lo x86_insn.lo x86_misc.lo \
|
||||||
|
x86_operand_list.lo
|
||||||
|
libdisasm_la_OBJECTS = $(am_libdisasm_la_OBJECTS)
|
||||||
|
DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
|
||||||
|
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||||
|
am__depfiles_maybe = depfiles
|
||||||
|
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||||
|
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||||
|
LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||||
|
--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||||
|
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||||
|
CCLD = $(CC)
|
||||||
|
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||||
|
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||||
|
$(LDFLAGS) -o $@
|
||||||
|
SOURCES = $(libdisasm_la_SOURCES)
|
||||||
|
DIST_SOURCES = $(libdisasm_la_SOURCES)
|
||||||
|
includeHEADERS_INSTALL = $(INSTALL_HEADER)
|
||||||
|
HEADERS = $(include_HEADERS)
|
||||||
|
ETAGS = etags
|
||||||
|
CTAGS = ctags
|
||||||
|
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||||
|
ACLOCAL = @ACLOCAL@
|
||||||
|
AMTAR = @AMTAR@
|
||||||
|
AR = @AR@
|
||||||
|
AUTOCONF = @AUTOCONF@
|
||||||
|
AUTOHEADER = @AUTOHEADER@
|
||||||
|
AUTOMAKE = @AUTOMAKE@
|
||||||
|
AWK = @AWK@
|
||||||
|
CC = @CC@
|
||||||
|
CCDEPMODE = @CCDEPMODE@
|
||||||
|
CFLAGS = @CFLAGS@
|
||||||
|
CPP = @CPP@
|
||||||
|
CPPFLAGS = @CPPFLAGS@
|
||||||
|
CXX = @CXX@
|
||||||
|
CXXCPP = @CXXCPP@
|
||||||
|
CXXDEPMODE = @CXXDEPMODE@
|
||||||
|
CXXFLAGS = @CXXFLAGS@
|
||||||
|
CYGPATH_W = @CYGPATH_W@
|
||||||
|
DEFS = @DEFS@
|
||||||
|
DEPDIR = @DEPDIR@
|
||||||
|
ECHO = @ECHO@
|
||||||
|
ECHO_C = @ECHO_C@
|
||||||
|
ECHO_N = @ECHO_N@
|
||||||
|
ECHO_T = @ECHO_T@
|
||||||
|
EGREP = @EGREP@
|
||||||
|
EXEEXT = @EXEEXT@
|
||||||
|
F77 = @F77@
|
||||||
|
FFLAGS = @FFLAGS@
|
||||||
|
GREP = @GREP@
|
||||||
|
INSTALL = @INSTALL@
|
||||||
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
|
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||||
|
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||||
|
LDFLAGS = @LDFLAGS@
|
||||||
|
LIBOBJS = @LIBOBJS@
|
||||||
|
LIBS = @LIBS@
|
||||||
|
LIBTOOL = @LIBTOOL@
|
||||||
|
LN_S = @LN_S@
|
||||||
|
LTLIBOBJS = @LTLIBOBJS@
|
||||||
|
MAINT = @MAINT@
|
||||||
|
MAKEINFO = @MAKEINFO@
|
||||||
|
MKDIR_P = @MKDIR_P@
|
||||||
|
OBJEXT = @OBJEXT@
|
||||||
|
PACKAGE = @PACKAGE@
|
||||||
|
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||||
|
PACKAGE_NAME = @PACKAGE_NAME@
|
||||||
|
PACKAGE_STRING = @PACKAGE_STRING@
|
||||||
|
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||||
|
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||||
|
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||||
|
RANLIB = @RANLIB@
|
||||||
|
SED = @SED@
|
||||||
|
SET_MAKE = @SET_MAKE@
|
||||||
|
SHELL = @SHELL@
|
||||||
|
STRIP = @STRIP@
|
||||||
|
VERSION = @VERSION@
|
||||||
|
abs_builddir = @abs_builddir@
|
||||||
|
abs_srcdir = @abs_srcdir@
|
||||||
|
abs_top_builddir = @abs_top_builddir@
|
||||||
|
abs_top_srcdir = @abs_top_srcdir@
|
||||||
|
ac_ct_CC = @ac_ct_CC@
|
||||||
|
ac_ct_CXX = @ac_ct_CXX@
|
||||||
|
ac_ct_F77 = @ac_ct_F77@
|
||||||
|
am__include = @am__include@
|
||||||
|
am__leading_dot = @am__leading_dot@
|
||||||
|
am__quote = @am__quote@
|
||||||
|
am__tar = @am__tar@
|
||||||
|
am__untar = @am__untar@
|
||||||
|
bindir = @bindir@
|
||||||
|
build = @build@
|
||||||
|
build_alias = @build_alias@
|
||||||
|
build_cpu = @build_cpu@
|
||||||
|
build_os = @build_os@
|
||||||
|
build_vendor = @build_vendor@
|
||||||
|
builddir = @builddir@
|
||||||
|
datadir = @datadir@
|
||||||
|
datarootdir = @datarootdir@
|
||||||
|
docdir = @docdir@
|
||||||
|
dvidir = @dvidir@
|
||||||
|
exec_prefix = @exec_prefix@
|
||||||
|
host = @host@
|
||||||
|
host_alias = @host_alias@
|
||||||
|
host_cpu = @host_cpu@
|
||||||
|
host_os = @host_os@
|
||||||
|
host_vendor = @host_vendor@
|
||||||
|
htmldir = @htmldir@
|
||||||
|
includedir = @includedir@
|
||||||
|
infodir = @infodir@
|
||||||
|
install_sh = @install_sh@
|
||||||
|
libdir = @libdir@
|
||||||
|
libexecdir = @libexecdir@
|
||||||
|
localedir = @localedir@
|
||||||
|
localstatedir = @localstatedir@
|
||||||
|
mandir = @mandir@
|
||||||
|
mkdir_p = @mkdir_p@
|
||||||
|
oldincludedir = @oldincludedir@
|
||||||
|
pdfdir = @pdfdir@
|
||||||
|
prefix = @prefix@
|
||||||
|
program_transform_name = @program_transform_name@
|
||||||
|
psdir = @psdir@
|
||||||
|
sbindir = @sbindir@
|
||||||
|
sharedstatedir = @sharedstatedir@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
sysconfdir = @sysconfdir@
|
||||||
|
target_alias = @target_alias@
|
||||||
|
top_builddir = @top_builddir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
include_HEADERS = libdis.h
|
||||||
|
lib_LTLIBRARIES = libdisasm.la
|
||||||
|
libdisasm_la_SOURCES = \
|
||||||
|
ia32_implicit.c \
|
||||||
|
ia32_implicit.h \
|
||||||
|
ia32_insn.c \
|
||||||
|
ia32_insn.h \
|
||||||
|
ia32_invariant.c \
|
||||||
|
ia32_invariant.h \
|
||||||
|
ia32_modrm.c \
|
||||||
|
ia32_modrm.h \
|
||||||
|
ia32_opcode_tables.c \
|
||||||
|
ia32_opcode_tables.h \
|
||||||
|
ia32_operand.c \
|
||||||
|
ia32_operand.h \
|
||||||
|
ia32_reg.c \
|
||||||
|
ia32_reg.h \
|
||||||
|
ia32_settings.c \
|
||||||
|
ia32_settings.h \
|
||||||
|
libdis.h \
|
||||||
|
qword.h \
|
||||||
|
x86_disasm.c \
|
||||||
|
x86_format.c \
|
||||||
|
x86_imm.c \
|
||||||
|
x86_imm.h \
|
||||||
|
x86_insn.c \
|
||||||
|
x86_misc.c \
|
||||||
|
x86_operand_list.c \
|
||||||
|
x86_operand_list.h
|
||||||
|
|
||||||
|
|
||||||
|
# Cheat to get non-autoconf swig into tarball,
|
||||||
|
# even if it doesn't build by default.
|
||||||
|
EXTRA_DIST = \
|
||||||
|
swig/Makefile \
|
||||||
|
swig/libdisasm.i \
|
||||||
|
swig/libdisasm_oop.i \
|
||||||
|
swig/python/Makefile-swig \
|
||||||
|
swig/perl/Makefile-swig \
|
||||||
|
swig/perl/Makefile.PL \
|
||||||
|
swig/ruby/Makefile-swig \
|
||||||
|
swig/ruby/extconf.rb \
|
||||||
|
swig/tcl/Makefile-swig \
|
||||||
|
swig/README
|
||||||
|
|
||||||
|
all: all-am
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
.SUFFIXES: .c .lo .o .obj
|
||||||
|
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||||
|
@for dep in $?; do \
|
||||||
|
case '$(am__configure_deps)' in \
|
||||||
|
*$$dep*) \
|
||||||
|
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
|
||||||
|
&& exit 0; \
|
||||||
|
exit 1;; \
|
||||||
|
esac; \
|
||||||
|
done; \
|
||||||
|
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libdisasm/Makefile'; \
|
||||||
|
cd $(top_srcdir) && \
|
||||||
|
$(AUTOMAKE) --gnu libdisasm/Makefile
|
||||||
|
.PRECIOUS: Makefile
|
||||||
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
|
@case '$?' in \
|
||||||
|
*config.status*) \
|
||||||
|
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||||
|
*) \
|
||||||
|
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||||
|
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||||
|
esac;
|
||||||
|
|
||||||
|
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||||
|
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||||
|
|
||||||
|
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||||
|
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||||
|
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
||||||
|
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||||
|
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
|
||||||
|
@$(NORMAL_INSTALL)
|
||||||
|
test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
|
||||||
|
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
|
||||||
|
if test -f $$p; then \
|
||||||
|
f=$(am__strip_dir) \
|
||||||
|
echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
|
||||||
|
$(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
|
||||||
|
else :; fi; \
|
||||||
|
done
|
||||||
|
|
||||||
|
uninstall-libLTLIBRARIES:
|
||||||
|
@$(NORMAL_UNINSTALL)
|
||||||
|
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
|
||||||
|
p=$(am__strip_dir) \
|
||||||
|
echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
|
||||||
|
$(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
|
||||||
|
done
|
||||||
|
|
||||||
|
clean-libLTLIBRARIES:
|
||||||
|
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
|
||||||
|
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
|
||||||
|
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||||
|
test "$$dir" != "$$p" || dir=.; \
|
||||||
|
echo "rm -f \"$${dir}/so_locations\""; \
|
||||||
|
rm -f "$${dir}/so_locations"; \
|
||||||
|
done
|
||||||
|
libdisasm.la: $(libdisasm_la_OBJECTS) $(libdisasm_la_DEPENDENCIES)
|
||||||
|
$(LINK) -rpath $(libdir) $(libdisasm_la_OBJECTS) $(libdisasm_la_LIBADD) $(LIBS)
|
||||||
|
|
||||||
|
mostlyclean-compile:
|
||||||
|
-rm -f *.$(OBJEXT)
|
||||||
|
|
||||||
|
distclean-compile:
|
||||||
|
-rm -f *.tab.c
|
||||||
|
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_implicit.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_insn.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_invariant.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_modrm.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_opcode_tables.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_operand.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_reg.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_settings.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_disasm.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_format.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_imm.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_insn.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_misc.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_operand_list.Plo@am__quote@
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||||
|
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||||
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||||
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
|
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
|
||||||
|
|
||||||
|
.c.obj:
|
||||||
|
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||||
|
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||||
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||||
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
|
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
|
||||||
|
|
||||||
|
.c.lo:
|
||||||
|
@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||||
|
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||||
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||||
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
|
@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
|
||||||
|
|
||||||
|
mostlyclean-libtool:
|
||||||
|
-rm -f *.lo
|
||||||
|
|
||||||
|
clean-libtool:
|
||||||
|
-rm -rf .libs _libs
|
||||||
|
install-includeHEADERS: $(include_HEADERS)
|
||||||
|
@$(NORMAL_INSTALL)
|
||||||
|
test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
|
||||||
|
@list='$(include_HEADERS)'; for p in $$list; do \
|
||||||
|
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||||
|
f=$(am__strip_dir) \
|
||||||
|
echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \
|
||||||
|
$(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \
|
||||||
|
done
|
||||||
|
|
||||||
|
uninstall-includeHEADERS:
|
||||||
|
@$(NORMAL_UNINSTALL)
|
||||||
|
@list='$(include_HEADERS)'; for p in $$list; do \
|
||||||
|
f=$(am__strip_dir) \
|
||||||
|
echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \
|
||||||
|
rm -f "$(DESTDIR)$(includedir)/$$f"; \
|
||||||
|
done
|
||||||
|
|
||||||
|
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||||
|
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||||
|
unique=`for i in $$list; do \
|
||||||
|
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||||
|
done | \
|
||||||
|
$(AWK) ' { files[$$0] = 1; } \
|
||||||
|
END { for (i in files) print i; }'`; \
|
||||||
|
mkid -fID $$unique
|
||||||
|
tags: TAGS
|
||||||
|
|
||||||
|
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||||
|
$(TAGS_FILES) $(LISP)
|
||||||
|
tags=; \
|
||||||
|
here=`pwd`; \
|
||||||
|
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||||
|
unique=`for i in $$list; do \
|
||||||
|
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||||
|
done | \
|
||||||
|
$(AWK) ' { files[$$0] = 1; } \
|
||||||
|
END { for (i in files) print i; }'`; \
|
||||||
|
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
|
||||||
|
test -n "$$unique" || unique=$$empty_fix; \
|
||||||
|
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||||
|
$$tags $$unique; \
|
||||||
|
fi
|
||||||
|
ctags: CTAGS
|
||||||
|
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||||
|
$(TAGS_FILES) $(LISP)
|
||||||
|
tags=; \
|
||||||
|
here=`pwd`; \
|
||||||
|
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||||
|
unique=`for i in $$list; do \
|
||||||
|
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||||
|
done | \
|
||||||
|
$(AWK) ' { files[$$0] = 1; } \
|
||||||
|
END { for (i in files) print i; }'`; \
|
||||||
|
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|
||||||
|
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||||
|
$$tags $$unique
|
||||||
|
|
||||||
|
GTAGS:
|
||||||
|
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||||
|
&& cd $(top_srcdir) \
|
||||||
|
&& gtags -i $(GTAGS_ARGS) $$here
|
||||||
|
|
||||||
|
distclean-tags:
|
||||||
|
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||||
|
|
||||||
|
distdir: $(DISTFILES)
|
||||||
|
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||||
|
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||||
|
list='$(DISTFILES)'; \
|
||||||
|
dist_files=`for file in $$list; do echo $$file; done | \
|
||||||
|
sed -e "s|^$$srcdirstrip/||;t" \
|
||||||
|
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||||
|
case $$dist_files in \
|
||||||
|
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||||
|
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||||
|
sort -u` ;; \
|
||||||
|
esac; \
|
||||||
|
for file in $$dist_files; do \
|
||||||
|
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||||
|
if test -d $$d/$$file; then \
|
||||||
|
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||||
|
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||||
|
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
|
||||||
|
fi; \
|
||||||
|
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
|
||||||
|
else \
|
||||||
|
test -f $(distdir)/$$file \
|
||||||
|
|| cp -p $$d/$$file $(distdir)/$$file \
|
||||||
|
|| exit 1; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
check-am: all-am
|
||||||
|
check: check-am
|
||||||
|
all-am: Makefile $(LTLIBRARIES) $(HEADERS)
|
||||||
|
installdirs:
|
||||||
|
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \
|
||||||
|
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||||
|
done
|
||||||
|
install: install-am
|
||||||
|
install-exec: install-exec-am
|
||||||
|
install-data: install-data-am
|
||||||
|
uninstall: uninstall-am
|
||||||
|
|
||||||
|
install-am: all-am
|
||||||
|
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||||
|
|
||||||
|
installcheck: installcheck-am
|
||||||
|
install-strip:
|
||||||
|
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||||
|
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||||
|
`test -z '$(STRIP)' || \
|
||||||
|
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||||
|
mostlyclean-generic:
|
||||||
|
|
||||||
|
clean-generic:
|
||||||
|
|
||||||
|
distclean-generic:
|
||||||
|
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||||
|
|
||||||
|
maintainer-clean-generic:
|
||||||
|
@echo "This command is intended for maintainers to use"
|
||||||
|
@echo "it deletes files that may require special tools to rebuild."
|
||||||
|
clean: clean-am
|
||||||
|
|
||||||
|
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
|
||||||
|
mostlyclean-am
|
||||||
|
|
||||||
|
distclean: distclean-am
|
||||||
|
-rm -rf ./$(DEPDIR)
|
||||||
|
-rm -f Makefile
|
||||||
|
distclean-am: clean-am distclean-compile distclean-generic \
|
||||||
|
distclean-tags
|
||||||
|
|
||||||
|
dvi: dvi-am
|
||||||
|
|
||||||
|
dvi-am:
|
||||||
|
|
||||||
|
html: html-am
|
||||||
|
|
||||||
|
info: info-am
|
||||||
|
|
||||||
|
info-am:
|
||||||
|
|
||||||
|
install-data-am: install-includeHEADERS
|
||||||
|
|
||||||
|
install-dvi: install-dvi-am
|
||||||
|
|
||||||
|
install-exec-am: install-libLTLIBRARIES
|
||||||
|
|
||||||
|
install-html: install-html-am
|
||||||
|
|
||||||
|
install-info: install-info-am
|
||||||
|
|
||||||
|
install-man:
|
||||||
|
|
||||||
|
install-pdf: install-pdf-am
|
||||||
|
|
||||||
|
install-ps: install-ps-am
|
||||||
|
|
||||||
|
installcheck-am:
|
||||||
|
|
||||||
|
maintainer-clean: maintainer-clean-am
|
||||||
|
-rm -rf ./$(DEPDIR)
|
||||||
|
-rm -f Makefile
|
||||||
|
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||||
|
|
||||||
|
mostlyclean: mostlyclean-am
|
||||||
|
|
||||||
|
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||||
|
mostlyclean-libtool
|
||||||
|
|
||||||
|
pdf: pdf-am
|
||||||
|
|
||||||
|
pdf-am:
|
||||||
|
|
||||||
|
ps: ps-am
|
||||||
|
|
||||||
|
ps-am:
|
||||||
|
|
||||||
|
uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
|
||||||
|
|
||||||
|
.MAKE: install-am install-strip
|
||||||
|
|
||||||
|
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||||
|
clean-libLTLIBRARIES clean-libtool ctags distclean \
|
||||||
|
distclean-compile distclean-generic distclean-libtool \
|
||||||
|
distclean-tags distdir dvi dvi-am html html-am info info-am \
|
||||||
|
install install-am install-data install-data-am install-dvi \
|
||||||
|
install-dvi-am install-exec install-exec-am install-html \
|
||||||
|
install-html-am install-includeHEADERS install-info \
|
||||||
|
install-info-am install-libLTLIBRARIES install-man install-pdf \
|
||||||
|
install-pdf-am install-ps install-ps-am install-strip \
|
||||||
|
installcheck installcheck-am installdirs maintainer-clean \
|
||||||
|
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||||
|
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||||
|
tags uninstall uninstall-am uninstall-includeHEADERS \
|
||||||
|
uninstall-libLTLIBRARIES
|
||||||
|
|
||||||
|
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||||
|
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||||
|
.NOEXPORT:
|
19
libdisasm/Module.mk
Normal file
19
libdisasm/Module.mk
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
libs += libdisasm
|
||||||
|
|
||||||
|
cflags += -w
|
||||||
|
|
||||||
|
src_libdisasm := \
|
||||||
|
ia32_implicit.c \
|
||||||
|
ia32_insn.c \
|
||||||
|
ia32_invariant.c \
|
||||||
|
ia32_modrm.c \
|
||||||
|
ia32_opcode_tables.c \
|
||||||
|
ia32_operand.c \
|
||||||
|
ia32_reg.c \
|
||||||
|
ia32_settings.c \
|
||||||
|
x86_disasm.c \
|
||||||
|
x86_format.c \
|
||||||
|
x86_imm.c \
|
||||||
|
x86_insn.c \
|
||||||
|
x86_misc.c \
|
||||||
|
x86_operand_list.c
|
43
libdisasm/TODO
Normal file
43
libdisasm/TODO
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
x86_format.c
|
||||||
|
------------
|
||||||
|
intel: jmpf -> jmp, callf -> call
|
||||||
|
att: jmpf -> ljmp, callf -> lcall
|
||||||
|
|
||||||
|
opcode table
|
||||||
|
------------
|
||||||
|
finish typing instructions
|
||||||
|
fix flag clear/set/toggle types
|
||||||
|
|
||||||
|
ix64 stuff
|
||||||
|
----------
|
||||||
|
document output file formats in web page
|
||||||
|
features doc: register aliases, implicit operands, stack mods,
|
||||||
|
ring0 flags, eflags, cpu model/isa
|
||||||
|
|
||||||
|
ia32_handle_* implementation
|
||||||
|
|
||||||
|
fix operand 0F C2
|
||||||
|
CMPPS
|
||||||
|
|
||||||
|
* sysenter, sysexit as CALL types -- preceded by MSR writes
|
||||||
|
* SYSENTER/SYSEXIT stack : overwrites SS, ESP
|
||||||
|
* stos, cmps, scas, movs, ins, outs, lods -> OP_PTR
|
||||||
|
* OP_SIZE in implicit operands
|
||||||
|
* use OP_SIZE to choose reg sizes!
|
||||||
|
|
||||||
|
DONE?? :
|
||||||
|
implicit operands: provide action ?
|
||||||
|
e.g. add/inc for stach, write, etc
|
||||||
|
replace table numbers in opcodes.dat with
|
||||||
|
#defines for table names
|
||||||
|
|
||||||
|
replace 0 with INSN_INVALID [or maybe FF for imnvalid and 00 for Not Applicable */
|
||||||
|
no wait that is only for prefix tables -- n/p
|
||||||
|
|
||||||
|
if ( prefx) only use if insn != invalid
|
||||||
|
|
||||||
|
these should cover all the wacky disasm exceptions
|
||||||
|
|
||||||
|
for the rep one we can chet, match only a 0x90
|
||||||
|
|
||||||
|
todo: privilege | ring
|
422
libdisasm/ia32_implicit.c
Normal file
422
libdisasm/ia32_implicit.c
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "ia32_implicit.h"
|
||||||
|
#include "ia32_insn.h"
|
||||||
|
#include "ia32_reg.h"
|
||||||
|
#include "x86_operand_list.h"
|
||||||
|
|
||||||
|
/* Conventions: Register operands which are aliases of another register
|
||||||
|
* operand (e.g. AX in one operand and AL in another) assume that the
|
||||||
|
* operands are different registers and that alias tracking will resolve
|
||||||
|
* data flow. This means that something like
|
||||||
|
* mov ax, al
|
||||||
|
* would have 'write only' access for AX and 'read only' access for AL,
|
||||||
|
* even though both AL and AX are read and written */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t operand;
|
||||||
|
} op_implicit_list_t;
|
||||||
|
|
||||||
|
static op_implicit_list_t list_aaa[] =
|
||||||
|
/* 37 : AAA : rw AL */
|
||||||
|
/* 3F : AAS : rw AL */
|
||||||
|
{{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* aaa */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_aad[] =
|
||||||
|
/* D5 0A, D5 (ib) : AAD : rw AX */
|
||||||
|
/* D4 0A, D4 (ib) : AAM : rw AX */
|
||||||
|
{{ OP_R | OP_W, REG_WORD_OFFSET }, {0}}; /* aad */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_call[] =
|
||||||
|
/* E8, FF, 9A, FF : CALL : rw ESP, rw EIP */
|
||||||
|
/* C2, C3, CA, CB : RET : rw ESP, rw EIP */
|
||||||
|
{{ OP_R | OP_W, REG_EIP_INDEX },
|
||||||
|
{ OP_R | OP_W, REG_ESP_INDEX }, {0}}; /* call, ret */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_cbw[] =
|
||||||
|
/* 98 : CBW : r AL, rw AX */
|
||||||
|
{{ OP_R | OP_W, REG_WORD_OFFSET },
|
||||||
|
{ OP_R, REG_BYTE_OFFSET}, {0}}; /* cbw */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_cwde[] =
|
||||||
|
/* 98 : CWDE : r AX, rw EAX */
|
||||||
|
{{ OP_R | OP_W, REG_DWORD_OFFSET },
|
||||||
|
{ OP_R, REG_WORD_OFFSET }, {0}}; /* cwde */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_clts[] =
|
||||||
|
/* 0F 06 : CLTS : rw CR0 */
|
||||||
|
{{ OP_R | OP_W, REG_CTRL_OFFSET}, {0}}; /* clts */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_cmpxchg[] =
|
||||||
|
/* 0F B0 : CMPXCHG : rw AL */
|
||||||
|
{{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* cmpxchg */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_cmpxchgb[] =
|
||||||
|
/* 0F B1 : CMPXCHG : rw EAX */
|
||||||
|
{{ OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* cmpxchg */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_cmpxchg8b[] =
|
||||||
|
/* 0F C7 : CMPXCHG8B : rw EDX, rw EAX, r ECX, r EBX */
|
||||||
|
{{ OP_R | OP_W, REG_DWORD_OFFSET },
|
||||||
|
{ OP_R | OP_W, REG_DWORD_OFFSET + 2 },
|
||||||
|
{ OP_R, REG_DWORD_OFFSET + 1 },
|
||||||
|
{ OP_R, REG_DWORD_OFFSET + 3 }, {0}}; /* cmpxchg8b */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_cpuid[] =
|
||||||
|
/* 0F A2 : CPUID : rw EAX, w EBX, w ECX, w EDX */
|
||||||
|
{{ OP_R | OP_W, REG_DWORD_OFFSET },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 1 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 2 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 3 }, {0}}; /* cpuid */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_cwd[] =
|
||||||
|
/* 99 : CWD/CWQ : rw EAX, w EDX */
|
||||||
|
{{ OP_R | OP_W, REG_DWORD_OFFSET },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 2 }, {0}}; /* cwd */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_daa[] =
|
||||||
|
/* 27 : DAA : rw AL */
|
||||||
|
/* 2F : DAS : rw AL */
|
||||||
|
{{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* daa */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_idiv[] =
|
||||||
|
/* F6 : DIV, IDIV : r AX, w AL, w AH */
|
||||||
|
/* FIXED: first op was EAX, not Aw. TODO: verify! */
|
||||||
|
{{ OP_R, REG_WORD_OFFSET },
|
||||||
|
{ OP_W, REG_BYTE_OFFSET },
|
||||||
|
{ OP_W, REG_BYTE_OFFSET + 4 }, {0}}; /* div */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_div[] =
|
||||||
|
/* F7 : DIV, IDIV : rw EDX, rw EAX */
|
||||||
|
{{ OP_R | OP_W, REG_DWORD_OFFSET + 2 },
|
||||||
|
{ OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* div */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_enter[] =
|
||||||
|
/* C8 : ENTER : rw ESP w EBP */
|
||||||
|
{{ OP_R | OP_W, REG_DWORD_OFFSET + 4 },
|
||||||
|
{ OP_R, REG_DWORD_OFFSET + 5 }, {0}}; /* enter */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_f2xm1[] =
|
||||||
|
/* D9 F0 : F2XM1 : rw ST(0) */
|
||||||
|
/* D9 E1 : FABS : rw ST(0) */
|
||||||
|
/* D9 E0 : FCHS : rw ST(0) */
|
||||||
|
/* D9 FF : FCOS : rw ST(0)*/
|
||||||
|
/* D8, DA : FDIV : rw ST(0) */
|
||||||
|
/* D8, DA : FDIVR : rw ST(0) */
|
||||||
|
/* D9 F2 : FPTAN : rw ST(0) */
|
||||||
|
/* D9 FC : FRNDINT : rw ST(0) */
|
||||||
|
/* D9 FB : FSINCOS : rw ST(0) */
|
||||||
|
/* D9 FE : FSIN : rw ST(0) */
|
||||||
|
/* D9 FA : FSQRT : rw ST(0) */
|
||||||
|
/* D9 F4 : FXTRACT : rw ST(0) */
|
||||||
|
{{ OP_R | OP_W, REG_FPU_OFFSET }, {0}}; /* f2xm1 */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_fcom[] =
|
||||||
|
/* D8, DC, DE D9 : FCOM : r ST(0) */
|
||||||
|
/* DE, DA : FICOM : r ST(0) */
|
||||||
|
/* DF, D8 : FIST : r ST(0) */
|
||||||
|
/* D9 E4 : FTST : r ST(0) */
|
||||||
|
/* D9 E5 : FXAM : r ST(0) */
|
||||||
|
{{ OP_R, REG_FPU_OFFSET }, {0}}; /* fcom */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_fpatan[] =
|
||||||
|
/* D9 F3 : FPATAN : r ST(0), rw ST(1) */
|
||||||
|
{{ OP_R, REG_FPU_OFFSET }, {0}}; /* fpatan */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_fprem[] =
|
||||||
|
/* D9 F8, D9 F5 : FPREM : rw ST(0) r ST(1) */
|
||||||
|
/* D9 FD : FSCALE : rw ST(0), r ST(1) */
|
||||||
|
{{ OP_R | OP_W, REG_FPU_OFFSET },
|
||||||
|
{ OP_R, REG_FPU_OFFSET + 1 }, {0}}; /* fprem */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_faddp[] =
|
||||||
|
/* DE C1 : FADDP : r ST(0), rw ST(1) */
|
||||||
|
/* DE E9 : FSUBP : r ST(0), rw ST(1) */
|
||||||
|
/* D9 F1 : FYL2X : r ST(0), rw ST(1) */
|
||||||
|
/* D9 F9 : FYL2XP1 : r ST(0), rw ST(1) */
|
||||||
|
{{ OP_R, REG_FPU_OFFSET },
|
||||||
|
{ OP_R | OP_W, REG_FPU_OFFSET + 1 }, {0}}; /* faddp */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_fucompp[] =
|
||||||
|
/* DA E9 : FUCOMPP : r ST(0), r ST(1) */
|
||||||
|
{{ OP_R, REG_FPU_OFFSET },
|
||||||
|
{ OP_R, REG_FPU_OFFSET + 1 }, {0}}; /* fucompp */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_imul[] =
|
||||||
|
/* F6 : IMUL : r AL, w AX */
|
||||||
|
/* F6 : MUL : r AL, w AX */
|
||||||
|
{{ OP_R, REG_BYTE_OFFSET },
|
||||||
|
{ OP_W, REG_WORD_OFFSET }, {0}}; /* imul */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_mul[] =
|
||||||
|
/* F7 : IMUL : rw EAX, w EDX */
|
||||||
|
/* F7 : MUL : rw EAX, w EDX */
|
||||||
|
{{ OP_R | OP_W, REG_DWORD_OFFSET },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 2 }, {0}}; /* imul */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_lahf[] =
|
||||||
|
/* 9F : LAHF : r EFLAGS, w AH */
|
||||||
|
{{ OP_R, REG_FLAGS_INDEX },
|
||||||
|
{ OP_W, REG_BYTE_OFFSET + 4 }, {0}}; /* lahf */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_ldmxcsr[] =
|
||||||
|
/* 0F AE : LDMXCSR : w MXCSR SSE Control Status Reg */
|
||||||
|
{{ OP_W, REG_MXCSG_INDEX }, {0}}; /* ldmxcsr */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_leave[] =
|
||||||
|
/* C9 : LEAVE : rw ESP, w EBP */
|
||||||
|
{{ OP_R | OP_W, REG_ESP_INDEX },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 5 }, {0}}; /* leave */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_lgdt[] =
|
||||||
|
/* 0F 01 : LGDT : w GDTR */
|
||||||
|
{{ OP_W, REG_GDTR_INDEX }, {0}}; /* lgdt */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_lidt[] =
|
||||||
|
/* 0F 01 : LIDT : w IDTR */
|
||||||
|
{{ OP_W, REG_IDTR_INDEX }, {0}}; /* lidt */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_lldt[] =
|
||||||
|
/* 0F 00 : LLDT : w LDTR */
|
||||||
|
{{ OP_W, REG_LDTR_INDEX }, {0}}; /* lldt */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_lmsw[] =
|
||||||
|
/* 0F 01 : LMSW : w CR0 */
|
||||||
|
{{ OP_W, REG_CTRL_OFFSET }, {0}}; /* lmsw */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_loop[] =
|
||||||
|
/* E0, E1, E2 : LOOP : rw ECX */
|
||||||
|
{{ OP_R | OP_W, REG_DWORD_OFFSET + 1 }, {0}};/* loop */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_ltr[] =
|
||||||
|
/* 0F 00 : LTR : w Task Register */
|
||||||
|
{{ OP_W, REG_TR_INDEX }, {0}}; /* ltr */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_pop[] =
|
||||||
|
/* 8F, 58, 1F, 07, 17, 0F A1, 0F A9 : POP : rw ESP */
|
||||||
|
/* FF, 50, 6A, 68, 0E, 16, 1E, 06, 0F A0, 0F A8 : PUSH : rw ESP */
|
||||||
|
{{ OP_R | OP_W, REG_ESP_INDEX }, {0}}; /* pop, push */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_popad[] =
|
||||||
|
/* 61 : POPAD : rw esp, w edi esi ebp ebx edx ecx eax */
|
||||||
|
{{ OP_R | OP_W, REG_ESP_INDEX },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 7 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 6 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 5 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 3 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 2 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 1 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET }, {0}}; /* popad */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_popfd[] =
|
||||||
|
/* 9D : POPFD : rw esp, w eflags */
|
||||||
|
{{ OP_R | OP_W, REG_ESP_INDEX },
|
||||||
|
{ OP_W, REG_FLAGS_INDEX }, {0}}; /* popfd */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_pushad[] =
|
||||||
|
/* FF, 50, 6A, 68, 0E, 16, 1E, 06, 0F A0, 0F A8 : PUSH : rw ESP */
|
||||||
|
/* 60 : PUSHAD : rw esp, r eax ecx edx ebx esp ebp esi edi */
|
||||||
|
{{ OP_R | OP_W, REG_ESP_INDEX },
|
||||||
|
{ OP_R, REG_DWORD_OFFSET },
|
||||||
|
{ OP_R, REG_DWORD_OFFSET + 1 },
|
||||||
|
{ OP_R, REG_DWORD_OFFSET + 2 },
|
||||||
|
{ OP_R, REG_DWORD_OFFSET + 3 },
|
||||||
|
{ OP_R, REG_DWORD_OFFSET + 5 },
|
||||||
|
{ OP_R, REG_DWORD_OFFSET + 6 },
|
||||||
|
{ OP_R, REG_DWORD_OFFSET + 7 }, {0}}; /* pushad */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_pushfd[] =
|
||||||
|
/* 9C : PUSHFD : rw esp, r eflags */
|
||||||
|
{{ OP_R | OP_W, REG_ESP_INDEX },
|
||||||
|
{ OP_R, REG_FLAGS_INDEX }, {0}}; /* pushfd */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_rdmsr[] =
|
||||||
|
/* 0F 32 : RDMSR : r ECX, w EDX, w EAX */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET + 1 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 2 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET }, {0}}; /* rdmsr */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_rdpmc[] =
|
||||||
|
/* 0F 33 : RDPMC : r ECX, w EDX, w EAX */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET + 1 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET + 2 },
|
||||||
|
{ OP_W, REG_DWORD_OFFSET }, {0}}; /* rdpmc */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_rdtsc[] =
|
||||||
|
/* 0F 31 : RDTSC : rw EDX, rw EAX */
|
||||||
|
{{ OP_R | OP_W, REG_DWORD_OFFSET + 2 },
|
||||||
|
{ OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* rdtsc */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_rep[] =
|
||||||
|
/* F3, F2 ... : REP : rw ECX */
|
||||||
|
{{ OP_R | OP_W, REG_DWORD_OFFSET + 1 }, {0}};/* rep */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_rsm[] =
|
||||||
|
/* 0F AA : RSM : r CR4, r CR0 */
|
||||||
|
{{ OP_R, REG_CTRL_OFFSET + 4 },
|
||||||
|
{ OP_R, REG_CTRL_OFFSET }, {0}}; /* rsm */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_sahf[] =
|
||||||
|
/* 9E : SAHF : r ah, rw eflags (set SF ZF AF PF CF) */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sahf */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_sgdt[] =
|
||||||
|
/* 0F : SGDT : r gdtr */
|
||||||
|
/* TODO: finish this! */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sgdt */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_sidt[] =
|
||||||
|
/* 0F : SIDT : r idtr */
|
||||||
|
/* TODO: finish this! */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sidt */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_sldt[] =
|
||||||
|
/* 0F : SLDT : r ldtr */
|
||||||
|
/* TODO: finish this! */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sldt */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_smsw[] =
|
||||||
|
/* 0F : SMSW : r CR0 */
|
||||||
|
/* TODO: finish this! */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* smsw */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_stmxcsr[] =
|
||||||
|
/* 0F AE : STMXCSR : r MXCSR */
|
||||||
|
/* TODO: finish this! */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* stmxcsr */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_str[] =
|
||||||
|
/* 0F 00 : STR : r TR (task register) */
|
||||||
|
/* TODO: finish this! */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* str */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_sysenter[] =
|
||||||
|
/* 0F 34 : SYSENTER : w cs, w eip, w ss, w esp, r CR0, w eflags
|
||||||
|
* r sysenter_cs_msr, sysenter_esp_msr, sysenter_eip_msr */
|
||||||
|
/* TODO: finish this! */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sysenter */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_sysexit[] =
|
||||||
|
/* 0F 35 : SYSEXIT : r edx, r ecx, w cs, w eip, w ss, w esp
|
||||||
|
* r sysenter_cs_msr */
|
||||||
|
/* TODO: finish this! */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sysexit */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_wrmsr[] =
|
||||||
|
/* 0F 30 : WRMST : r edx, r eax, r ecx */
|
||||||
|
/* TODO: finish this! */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* wrmsr */
|
||||||
|
|
||||||
|
static op_implicit_list_t list_xlat[] =
|
||||||
|
/* D7 : XLAT : rw al r ebx (ptr) */
|
||||||
|
/* TODO: finish this! */
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* xlat */
|
||||||
|
/* TODO:
|
||||||
|
* monitor 0f 01 c8 eax OP_R ecx OP_R edx OP_R
|
||||||
|
* mwait 0f 01 c9 eax OP_R ecx OP_R
|
||||||
|
*/
|
||||||
|
static op_implicit_list_t list_monitor[] =
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* monitor */
|
||||||
|
static op_implicit_list_t list_mwait[] =
|
||||||
|
{{ OP_R, REG_DWORD_OFFSET }, {0}}; /* mwait */
|
||||||
|
|
||||||
|
op_implicit_list_t *op_implicit_list[] = {
|
||||||
|
/* This is a list of implicit operands which are read/written by
|
||||||
|
* various x86 instructions. Note that modifications to the stack
|
||||||
|
* register are mentioned here, but that additional information on
|
||||||
|
* the effect an instruction has on the stack is contained in the
|
||||||
|
* x86_insn_t 'stack_mod' and 'stack_mod_val' fields. Use of the
|
||||||
|
* eflags register, i.e. setting, clearing, and testing flags, is
|
||||||
|
* not recorded here but rather in the flags_set and flags_tested
|
||||||
|
* fields of the x86_insn_t.*/
|
||||||
|
NULL,
|
||||||
|
list_aaa, list_aad, list_call, list_cbw, /* 1 - 4 */
|
||||||
|
list_cwde, list_clts, list_cmpxchg, list_cmpxchgb, /* 5 - 8 */
|
||||||
|
list_cmpxchg8b, list_cpuid, list_cwd, list_daa, /* 9 - 12 */
|
||||||
|
list_idiv, list_div, list_enter, list_f2xm1, /* 13 - 16 */
|
||||||
|
list_fcom, list_fpatan, list_fprem, list_faddp, /* 17 - 20 */
|
||||||
|
list_fucompp, list_imul, list_mul, list_lahf, /* 21 - 24 */
|
||||||
|
list_ldmxcsr, list_leave, list_lgdt, list_lidt, /* 25 - 28 */
|
||||||
|
list_lldt, list_lmsw, list_loop, list_ltr, /* 29 - 32 */
|
||||||
|
list_pop, list_popad, list_popfd, list_pushad, /* 33 - 36 */
|
||||||
|
list_pushfd, list_rdmsr, list_rdpmc, list_rdtsc, /* 37 - 40 */
|
||||||
|
/* NOTE: 'REP' is a hack since it is a prefix: if its position
|
||||||
|
* in the table changes, then change IDX_IMPLICIT_REP in the .h */
|
||||||
|
list_rep, list_rsm, list_sahf, list_sgdt, /* 41 - 44 */
|
||||||
|
list_sidt, list_sldt, list_smsw, list_stmxcsr, /* 45 - 48 */
|
||||||
|
list_str, list_sysenter, list_sysexit, list_wrmsr, /* 49 - 52 */
|
||||||
|
list_xlat, list_monitor, list_mwait, /* 53 - 55*/
|
||||||
|
NULL /* end of list */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LAST_IMPL_IDX 55
|
||||||
|
|
||||||
|
static void handle_impl_reg( x86_op_t *op, uint32_t val ) {
|
||||||
|
x86_reg_t *reg = &op->data.reg;
|
||||||
|
op->type = op_register;
|
||||||
|
ia32_handle_register( reg, (unsigned int) val );
|
||||||
|
switch (reg->size) {
|
||||||
|
case 1:
|
||||||
|
op->datatype = op_byte; break;
|
||||||
|
case 2:
|
||||||
|
op->datatype = op_word; break;
|
||||||
|
case 4:
|
||||||
|
op->datatype = op_dword; break;
|
||||||
|
case 8:
|
||||||
|
op->datatype = op_qword; break;
|
||||||
|
case 10:
|
||||||
|
op->datatype = op_extreal; break;
|
||||||
|
case 16:
|
||||||
|
op->datatype = op_dqword; break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 'impl_idx' is the value from the opcode table: between 1 and LAST_IMPL_IDX */
|
||||||
|
/* returns number of operands added */
|
||||||
|
unsigned int ia32_insn_implicit_ops( x86_insn_t *insn, unsigned int impl_idx ) {
|
||||||
|
op_implicit_list_t *list;
|
||||||
|
x86_op_t *op;
|
||||||
|
unsigned int num = 0;
|
||||||
|
|
||||||
|
if (! impl_idx || impl_idx > LAST_IMPL_IDX ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( list = op_implicit_list[impl_idx]; list->type; list++, num++ ) {
|
||||||
|
enum x86_op_access access = (enum x86_op_access) OP_PERM(list->type);
|
||||||
|
enum x86_op_flags flags = (enum x86_op_flags) (OP_FLAGS(list->type) >> 12);
|
||||||
|
|
||||||
|
op = NULL;
|
||||||
|
/* In some cases (MUL), EAX is an implicit operand hardcoded in
|
||||||
|
* the instruction without being explicitly listed in assembly.
|
||||||
|
* For this situation, find the hardcoded operand and add the
|
||||||
|
* implied flag rather than adding a new implicit operand. */
|
||||||
|
x86_oplist_t * existing;
|
||||||
|
if (ia32_true_register_id(list->operand) == REG_DWORD_OFFSET) {
|
||||||
|
for ( existing = insn->operands; existing; existing = existing->next ) {
|
||||||
|
if (existing->op.type == op_register &&
|
||||||
|
existing->op.data.reg.id == list->operand) {
|
||||||
|
op = &existing->op;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!op) {
|
||||||
|
op = x86_operand_new( insn );
|
||||||
|
/* all implicit operands are registers */
|
||||||
|
handle_impl_reg( op, list->operand );
|
||||||
|
/* decrement the 'explicit count' incremented by default in
|
||||||
|
* x86_operand_new */
|
||||||
|
insn->explicit_count = insn->explicit_count -1;
|
||||||
|
}
|
||||||
|
if (!op) {
|
||||||
|
return num; /* gah! return early */
|
||||||
|
}
|
||||||
|
op->access |= access;
|
||||||
|
op->flags |= flags;
|
||||||
|
op->flags |= op_implied;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
13
libdisasm/ia32_implicit.h
Normal file
13
libdisasm/ia32_implicit.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef IA32_IMPLICIT_H
|
||||||
|
#define IA32_IMPLICIT_H
|
||||||
|
|
||||||
|
#include "libdis.h"
|
||||||
|
|
||||||
|
/* OK, this is a hack to deal with prefixes having implicit operands...
|
||||||
|
* thought I had removed all the old hackishness ;( */
|
||||||
|
|
||||||
|
#define IDX_IMPLICIT_REP 41 /* change this if the table changes! */
|
||||||
|
|
||||||
|
unsigned int ia32_insn_implicit_ops( x86_insn_t *insn, unsigned int impl_idx );
|
||||||
|
|
||||||
|
#endif
|
625
libdisasm/ia32_insn.c
Normal file
625
libdisasm/ia32_insn.c
Normal file
@ -0,0 +1,625 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "qword.h"
|
||||||
|
|
||||||
|
#include "ia32_insn.h"
|
||||||
|
#include "ia32_opcode_tables.h"
|
||||||
|
|
||||||
|
#include "ia32_reg.h"
|
||||||
|
#include "ia32_operand.h"
|
||||||
|
#include "ia32_implicit.h"
|
||||||
|
#include "ia32_settings.h"
|
||||||
|
|
||||||
|
#include "libdis.h"
|
||||||
|
|
||||||
|
extern ia32_table_desc_t ia32_tables[];
|
||||||
|
extern ia32_settings_t ia32_settings;
|
||||||
|
|
||||||
|
#define IS_SP( op ) (op->type == op_register && \
|
||||||
|
(op->data.reg.id == REG_ESP_INDEX || \
|
||||||
|
op->data.reg.alias == REG_ESP_INDEX) )
|
||||||
|
#define IS_IMM( op ) (op->type == op_immediate )
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
# define INLINE
|
||||||
|
#else
|
||||||
|
# define INLINE inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* for calculating stack modification based on an operand */
|
||||||
|
static INLINE int32_t long_from_operand( x86_op_t *op ) {
|
||||||
|
|
||||||
|
if (! IS_IMM(op) ) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( op->datatype ) {
|
||||||
|
case op_byte:
|
||||||
|
return (int32_t) op->data.sbyte;
|
||||||
|
case op_word:
|
||||||
|
return (int32_t) op->data.sword;
|
||||||
|
case op_qword:
|
||||||
|
return (int32_t) op->data.sqword;
|
||||||
|
case op_dword:
|
||||||
|
return op->data.sdword;
|
||||||
|
default:
|
||||||
|
/* these are not used in stack insn */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* determine what this insn does to the stack */
|
||||||
|
static void ia32_stack_mod(x86_insn_t *insn) {
|
||||||
|
x86_op_t *dest, *src = NULL;
|
||||||
|
|
||||||
|
if (! insn || ! insn->operands ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest = &insn->operands->op;
|
||||||
|
if ( dest ) {
|
||||||
|
src = &insn->operands->next->op;
|
||||||
|
}
|
||||||
|
|
||||||
|
insn->stack_mod = 0;
|
||||||
|
insn->stack_mod_val = 0;
|
||||||
|
|
||||||
|
switch ( insn->type ) {
|
||||||
|
case insn_call:
|
||||||
|
case insn_callcc:
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = insn->addr_size * -1;
|
||||||
|
break;
|
||||||
|
case insn_push:
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = insn->addr_size * -1;
|
||||||
|
break;
|
||||||
|
case insn_return:
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = insn->addr_size;
|
||||||
|
case insn_int: case insn_intcc:
|
||||||
|
case insn_iret:
|
||||||
|
break;
|
||||||
|
case insn_pop:
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
if (! IS_SP( dest ) ) {
|
||||||
|
insn->stack_mod_val = insn->op_size;
|
||||||
|
} /* else we don't know the stack change in a pop esp */
|
||||||
|
break;
|
||||||
|
case insn_enter:
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = 0; /* TODO : FIX */
|
||||||
|
break;
|
||||||
|
case insn_leave:
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = 0; /* TODO : FIX */
|
||||||
|
break;
|
||||||
|
case insn_pushregs:
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = 0; /* TODO : FIX */
|
||||||
|
break;
|
||||||
|
case insn_popregs:
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = 0; /* TODO : FIX */
|
||||||
|
break;
|
||||||
|
case insn_pushflags:
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = 0; /* TODO : FIX */
|
||||||
|
break;
|
||||||
|
case insn_popflags:
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = 0; /* TODO : FIX */
|
||||||
|
break;
|
||||||
|
case insn_add:
|
||||||
|
if ( IS_SP( dest ) ) {
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = long_from_operand( src );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case insn_sub:
|
||||||
|
if ( IS_SP( dest ) ) {
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = long_from_operand( src );
|
||||||
|
insn->stack_mod_val *= -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case insn_inc:
|
||||||
|
if ( IS_SP( dest ) ) {
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case insn_dec:
|
||||||
|
if ( IS_SP( dest ) ) {
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
insn->stack_mod_val = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case insn_mov: case insn_movcc:
|
||||||
|
case insn_xchg: case insn_xchgcc:
|
||||||
|
case insn_mul: case insn_div:
|
||||||
|
case insn_shl: case insn_shr:
|
||||||
|
case insn_rol: case insn_ror:
|
||||||
|
case insn_and: case insn_or:
|
||||||
|
case insn_not: case insn_neg:
|
||||||
|
case insn_xor:
|
||||||
|
if ( IS_SP( dest ) ) {
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (! strcmp("enter", insn->mnemonic) ) {
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
} else if (! strcmp("leave", insn->mnemonic) ) {
|
||||||
|
insn->stack_mod = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for mov, etc we return 0 -- unknown stack mod */
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the cpu details for this insn from cpu flags int */
|
||||||
|
static void ia32_handle_cpu( x86_insn_t *insn, unsigned int cpu ) {
|
||||||
|
insn->cpu = (enum x86_insn_cpu) CPU_MODEL(cpu);
|
||||||
|
insn->isa = (enum x86_insn_isa) (ISA_SUBSET(cpu)) >> 16;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle mnemonic type and group */
|
||||||
|
static void ia32_handle_mnemtype(x86_insn_t *insn, unsigned int mnemtype) {
|
||||||
|
unsigned int type = mnemtype & ~INS_FLAG_MASK;
|
||||||
|
insn->group = (enum x86_insn_group) (INS_GROUP(type)) >> 12;
|
||||||
|
insn->type = (enum x86_insn_type) INS_TYPE(type);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ia32_handle_notes(x86_insn_t *insn, unsigned int notes) {
|
||||||
|
insn->note = (enum x86_insn_note) notes;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ia32_handle_eflags( x86_insn_t *insn, unsigned int eflags) {
|
||||||
|
unsigned int flags;
|
||||||
|
|
||||||
|
/* handle flags effected */
|
||||||
|
flags = INS_FLAGS_TEST(eflags);
|
||||||
|
/* handle weird OR cases */
|
||||||
|
/* these are either JLE (ZF | SF<>OF) or JBE (CF | ZF) */
|
||||||
|
if (flags & INS_TEST_OR) {
|
||||||
|
flags &= ~INS_TEST_OR;
|
||||||
|
if ( flags & INS_TEST_ZERO ) {
|
||||||
|
flags &= ~INS_TEST_ZERO;
|
||||||
|
if ( flags & INS_TEST_CARRY ) {
|
||||||
|
flags &= ~INS_TEST_CARRY ;
|
||||||
|
flags |= (int)insn_carry_or_zero_set;
|
||||||
|
} else if ( flags & INS_TEST_SFNEOF ) {
|
||||||
|
flags &= ~INS_TEST_SFNEOF;
|
||||||
|
flags |= (int)insn_zero_set_or_sign_ne_oflow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
insn->flags_tested = (enum x86_flag_status) flags;
|
||||||
|
|
||||||
|
insn->flags_set = (enum x86_flag_status) INS_FLAGS_SET(eflags) >> 16;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ia32_handle_prefix( x86_insn_t *insn, unsigned int prefixes ) {
|
||||||
|
|
||||||
|
insn->prefix = (enum x86_insn_prefix) prefixes & PREFIX_MASK; // >> 20;
|
||||||
|
if (! (insn->prefix & PREFIX_PRINT_MASK) ) {
|
||||||
|
/* no printable prefixes */
|
||||||
|
insn->prefix = insn_no_prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* concat all prefix strings */
|
||||||
|
if ( (unsigned int)insn->prefix & PREFIX_LOCK ) {
|
||||||
|
strncat(insn->prefix_string, "lock ", 32 -
|
||||||
|
strlen(insn->prefix_string));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (unsigned int)insn->prefix & PREFIX_REPNZ ) {
|
||||||
|
strncat(insn->prefix_string, "repnz ", 32 -
|
||||||
|
strlen(insn->prefix_string));
|
||||||
|
} else if ( (unsigned int)insn->prefix & PREFIX_REPZ ) {
|
||||||
|
strncat(insn->prefix_string, "repz ", 32 -
|
||||||
|
strlen(insn->prefix_string));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void reg_32_to_16( x86_op_t *op, x86_insn_t *insn, void *arg ) {
|
||||||
|
|
||||||
|
/* if this is a 32-bit register and it is a general register ... */
|
||||||
|
if ( op->type == op_register && op->data.reg.size == 4 &&
|
||||||
|
(op->data.reg.type & reg_gen) ) {
|
||||||
|
/* WORD registers are 8 indices off from DWORD registers */
|
||||||
|
ia32_handle_register( &(op->data.reg),
|
||||||
|
op->data.reg.id + 8 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_insn_metadata( x86_insn_t *insn, ia32_insn_t *raw_insn ) {
|
||||||
|
ia32_handle_mnemtype( insn, raw_insn->mnem_flag );
|
||||||
|
ia32_handle_notes( insn, raw_insn->notes );
|
||||||
|
ia32_handle_eflags( insn, raw_insn->flags_effected );
|
||||||
|
ia32_handle_cpu( insn, raw_insn->cpu );
|
||||||
|
ia32_stack_mod( insn );
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t ia32_decode_insn( unsigned char *buf, size_t buf_len,
|
||||||
|
ia32_insn_t *raw_insn, x86_insn_t *insn,
|
||||||
|
unsigned int prefixes ) {
|
||||||
|
size_t size, op_size;
|
||||||
|
unsigned char modrm;
|
||||||
|
|
||||||
|
/* this should never happen, but just in case... */
|
||||||
|
if ( raw_insn->mnem_flag == INS_INVALID ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ia32_settings.options & opt_16_bit) {
|
||||||
|
insn->op_size = ( prefixes & PREFIX_OP_SIZE ) ? 4 : 2;
|
||||||
|
insn->addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 4 : 2;
|
||||||
|
} else {
|
||||||
|
insn->op_size = ( prefixes & PREFIX_OP_SIZE ) ? 2 : 4;
|
||||||
|
insn->addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 2 : 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ++++ 1. Copy mnemonic and mnemonic-flags to CODE struct */
|
||||||
|
if ((ia32_settings.options & opt_att_mnemonics) && raw_insn->mnemonic_att[0]) {
|
||||||
|
strncpy( insn->mnemonic, raw_insn->mnemonic_att, 16 );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strncpy( insn->mnemonic, raw_insn->mnemonic, 16 );
|
||||||
|
}
|
||||||
|
ia32_handle_prefix( insn, prefixes );
|
||||||
|
|
||||||
|
handle_insn_metadata( insn, raw_insn );
|
||||||
|
|
||||||
|
/* prefetch the next byte in case it is a modr/m byte -- saves
|
||||||
|
* worrying about whether the 'mod/rm' operand or the 'reg' operand
|
||||||
|
* occurs first */
|
||||||
|
modrm = GET_BYTE( buf, buf_len );
|
||||||
|
|
||||||
|
/* ++++ 2. Decode Explicit Operands */
|
||||||
|
/* Intel uses up to 3 explicit operands in its instructions;
|
||||||
|
* the first is 'dest', the second is 'src', and the third
|
||||||
|
* is an additional source value (usually an immediate value,
|
||||||
|
* e.g. in the MUL instructions). These three explicit operands
|
||||||
|
* are encoded in the opcode tables, even if they are not used
|
||||||
|
* by the instruction. Additional implicit operands are stored
|
||||||
|
* in a supplemental table and are handled later. */
|
||||||
|
|
||||||
|
op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->dest,
|
||||||
|
raw_insn->dest_flag, prefixes, modrm );
|
||||||
|
/* advance buffer, increase size if necessary */
|
||||||
|
buf += op_size;
|
||||||
|
buf_len -= op_size;
|
||||||
|
size = op_size;
|
||||||
|
|
||||||
|
op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->src,
|
||||||
|
raw_insn->src_flag, prefixes, modrm );
|
||||||
|
buf += op_size;
|
||||||
|
buf_len -= op_size;
|
||||||
|
size += op_size;
|
||||||
|
|
||||||
|
op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->aux,
|
||||||
|
raw_insn->aux_flag, prefixes, modrm );
|
||||||
|
size += op_size;
|
||||||
|
|
||||||
|
|
||||||
|
/* ++++ 3. Decode Implicit Operands */
|
||||||
|
/* apply implicit operands */
|
||||||
|
ia32_insn_implicit_ops( insn, raw_insn->implicit_ops );
|
||||||
|
/* we have one small inelegant hack here, to deal with
|
||||||
|
* the two prefixes that have implicit operands. If Intel
|
||||||
|
* adds more, we'll change the algorithm to suit :) */
|
||||||
|
if ( (prefixes & PREFIX_REPZ) || (prefixes & PREFIX_REPNZ) ) {
|
||||||
|
ia32_insn_implicit_ops( insn, IDX_IMPLICIT_REP );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 16-bit hack: foreach operand, if 32-bit reg, make 16-bit reg */
|
||||||
|
if ( insn->op_size == 2 ) {
|
||||||
|
x86_operand_foreach( insn, reg_32_to_16, NULL, op_any );
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* convenience routine */
|
||||||
|
#define USES_MOD_RM(flag) \
|
||||||
|
(flag == ADDRMETH_E || flag == ADDRMETH_M || flag == ADDRMETH_Q || \
|
||||||
|
flag == ADDRMETH_W || flag == ADDRMETH_R)
|
||||||
|
|
||||||
|
static int uses_modrm_flag( unsigned int flag ) {
|
||||||
|
unsigned int meth;
|
||||||
|
if ( flag == ARG_NONE ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
meth = (flag & ADDRMETH_MASK);
|
||||||
|
if ( USES_MOD_RM(meth) ) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This routine performs the actual byte-by-byte opcode table lookup.
|
||||||
|
* Originally it was pretty simple: get a byte, adjust it to a proper
|
||||||
|
* index into the table, then check the table row at that index to
|
||||||
|
* determine what to do next. But is anything that simple with Intel?
|
||||||
|
* This is now a huge, convoluted mess, mostly of bitter comments. */
|
||||||
|
/* buf: pointer to next byte to read from stream
|
||||||
|
* buf_len: length of buf
|
||||||
|
* table: index of table to use for lookups
|
||||||
|
* raw_insn: output pointer that receives opcode definition
|
||||||
|
* prefixes: output integer that is encoded with prefixes in insn
|
||||||
|
* returns : number of bytes consumed from stream during lookup */
|
||||||
|
size_t ia32_table_lookup( unsigned char *buf, size_t buf_len,
|
||||||
|
unsigned int table, ia32_insn_t **raw_insn,
|
||||||
|
unsigned int *prefixes ) {
|
||||||
|
unsigned char *next, op = buf[0]; /* byte value -- 'opcode' */
|
||||||
|
size_t size = 1, sub_size = 0, next_len;
|
||||||
|
ia32_table_desc_t *table_desc;
|
||||||
|
unsigned int subtable, prefix = 0, recurse_table = 0;
|
||||||
|
|
||||||
|
table_desc = &ia32_tables[table];
|
||||||
|
|
||||||
|
op = GET_BYTE( buf, buf_len );
|
||||||
|
|
||||||
|
if ( table_desc->type == tbl_fpu && op > table_desc->maxlim) {
|
||||||
|
/* one of the fucking FPU tables out of the 00-BH range */
|
||||||
|
/* OK,. this is a bit of a hack -- the proper way would
|
||||||
|
* have been to use subtables in the 00-BF FPU opcode tables,
|
||||||
|
* but that is rather wasteful of space... */
|
||||||
|
table_desc = &ia32_tables[table +1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PERFORM TABLE LOOKUP */
|
||||||
|
|
||||||
|
/* ModR/M trick: shift extension bits into lowest bits of byte */
|
||||||
|
/* Note: non-ModR/M tables have a shift value of 0 */
|
||||||
|
op >>= table_desc->shift;
|
||||||
|
|
||||||
|
/* ModR/M trick: mask out high bits to turn extension into an index */
|
||||||
|
/* Note: non-ModR/M tables have a mask value of 0xFF */
|
||||||
|
op &= table_desc->mask;
|
||||||
|
|
||||||
|
|
||||||
|
/* Sparse table trick: check that byte is <= max value */
|
||||||
|
/* Note: full (256-entry) tables have a maxlim of 155 */
|
||||||
|
if ( op > table_desc->maxlim ) {
|
||||||
|
/* this is a partial table, truncated at the tail,
|
||||||
|
and op is out of range! */
|
||||||
|
return INVALID_INSN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sparse table trick: check that byte is >= min value */
|
||||||
|
/* Note: full (256-entry) tables have a minlim of 0 */
|
||||||
|
if ( table_desc->minlim > op ) {
|
||||||
|
/* this is a partial table, truncated at the head,
|
||||||
|
and op is out of range! */
|
||||||
|
return INVALID_INSN;
|
||||||
|
}
|
||||||
|
/* adjust op to be an offset from table index 0 */
|
||||||
|
op -= table_desc->minlim;
|
||||||
|
|
||||||
|
/* Yay! 'op' is now fully adjusted to be an index into 'table' */
|
||||||
|
*raw_insn = &(table_desc->table[op]);
|
||||||
|
//printf("BYTE %X TABLE %d OP %X\n", buf[0], table, op );
|
||||||
|
|
||||||
|
if ( (*raw_insn)->mnem_flag & INS_FLAG_PREFIX ) {
|
||||||
|
prefix = (*raw_insn)->mnem_flag & PREFIX_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* handle escape to a multibyte/coproc/extension/etc table */
|
||||||
|
/* NOTE: if insn is a prefix and has a subtable, then we
|
||||||
|
* only recurse if this is the first prefix byte --
|
||||||
|
* that is, if *prefixes is 0.
|
||||||
|
* NOTE also that suffix tables are handled later */
|
||||||
|
subtable = (*raw_insn)->table;
|
||||||
|
|
||||||
|
if ( subtable && ia32_tables[subtable].type != tbl_suffix &&
|
||||||
|
(! prefix || ! *prefixes) ) {
|
||||||
|
|
||||||
|
if ( ia32_tables[subtable].type == tbl_ext_ext ||
|
||||||
|
ia32_tables[subtable].type == tbl_fpu_ext ) {
|
||||||
|
/* opcode extension: reuse current byte in buffer */
|
||||||
|
next = buf;
|
||||||
|
next_len = buf_len;
|
||||||
|
} else {
|
||||||
|
/* "normal" opcode: advance to next byte in buffer */
|
||||||
|
if ( buf_len > 1 ) {
|
||||||
|
next = &buf[1];
|
||||||
|
next_len = buf_len - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// buffer is truncated
|
||||||
|
return INVALID_INSN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* we encountered a multibyte opcode: recurse using the
|
||||||
|
* table specified in the opcode definition */
|
||||||
|
sub_size = ia32_table_lookup( next, next_len, subtable,
|
||||||
|
raw_insn, prefixes );
|
||||||
|
|
||||||
|
/* SSE/prefix hack: if the original opcode def was a
|
||||||
|
* prefix that specified a subtable, and the subtable
|
||||||
|
* lookup returned a valid insn, then we have encountered
|
||||||
|
* an SSE opcode definition; otherwise, we pretend we
|
||||||
|
* never did the subtable lookup, and deal with the
|
||||||
|
* prefix normally later */
|
||||||
|
if ( prefix && ( sub_size == INVALID_INSN ||
|
||||||
|
INS_TYPE((*raw_insn)->mnem_flag) == INS_INVALID ) ) {
|
||||||
|
/* this is a prefix, not an SSE insn :
|
||||||
|
* lookup next byte in main table,
|
||||||
|
* subsize will be reset during the
|
||||||
|
* main table lookup */
|
||||||
|
recurse_table = 1;
|
||||||
|
} else {
|
||||||
|
/* this is either a subtable (two-byte) insn
|
||||||
|
* or an invalid insn: either way, set prefix
|
||||||
|
* to NULL and end the opcode lookup */
|
||||||
|
prefix = 0;
|
||||||
|
// short-circuit lookup on invalid insn
|
||||||
|
if (sub_size == INVALID_INSN) return INVALID_INSN;
|
||||||
|
}
|
||||||
|
} else if ( prefix ) {
|
||||||
|
recurse_table = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* by default, we assume that we have the opcode definition,
|
||||||
|
* and there is no need to recurse on the same table, but
|
||||||
|
* if we do then a prefix was encountered... */
|
||||||
|
if ( recurse_table ) {
|
||||||
|
/* this must have been a prefix: use the same table for
|
||||||
|
* lookup of the next byte */
|
||||||
|
sub_size = ia32_table_lookup( &buf[1], buf_len - 1, table,
|
||||||
|
raw_insn, prefixes );
|
||||||
|
|
||||||
|
// short-circuit lookup on invalid insn
|
||||||
|
if (sub_size == INVALID_INSN) return INVALID_INSN;
|
||||||
|
|
||||||
|
/* a bit of a hack for branch hints */
|
||||||
|
if ( prefix & BRANCH_HINT_MASK ) {
|
||||||
|
if ( INS_GROUP((*raw_insn)->mnem_flag) == INS_EXEC ) {
|
||||||
|
/* segment override prefixes are invalid for
|
||||||
|
* all branch instructions, so delete them */
|
||||||
|
prefix &= ~PREFIX_REG_MASK;
|
||||||
|
} else {
|
||||||
|
prefix &= ~BRANCH_HINT_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* apply prefix to instruction */
|
||||||
|
|
||||||
|
/* TODO: implement something enforcing prefix groups */
|
||||||
|
(*prefixes) |= prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if this lookup was in a ModR/M table, then an opcode byte is
|
||||||
|
* NOT consumed: subtract accordingly. NOTE that if none of the
|
||||||
|
* operands used the ModR/M, then we need to consume the byte
|
||||||
|
* here, but ONLY in the 'top-level' opcode extension table */
|
||||||
|
|
||||||
|
if ( table_desc->type == tbl_ext_ext ) {
|
||||||
|
/* extensions-to-extensions never consume a byte */
|
||||||
|
--size;
|
||||||
|
} else if ( (table_desc->type == tbl_extension ||
|
||||||
|
table_desc->type == tbl_fpu ||
|
||||||
|
table_desc->type == tbl_fpu_ext ) &&
|
||||||
|
/* extensions that have an operand encoded in ModR/M
|
||||||
|
* never consume a byte */
|
||||||
|
(uses_modrm_flag((*raw_insn)->dest_flag) ||
|
||||||
|
uses_modrm_flag((*raw_insn)->src_flag) ) ) {
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size += sub_size;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t handle_insn_suffix( unsigned char *buf, size_t buf_len,
|
||||||
|
ia32_insn_t *raw_insn, x86_insn_t * insn ) {
|
||||||
|
ia32_table_desc_t *table_desc;
|
||||||
|
ia32_insn_t *sfx_insn;
|
||||||
|
size_t size;
|
||||||
|
unsigned int prefixes = 0;
|
||||||
|
|
||||||
|
table_desc = &ia32_tables[raw_insn->table];
|
||||||
|
size = ia32_table_lookup( buf, buf_len, raw_insn->table, &sfx_insn,
|
||||||
|
&prefixes );
|
||||||
|
if (size == INVALID_INSN || sfx_insn->mnem_flag == INS_INVALID ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy( insn->mnemonic, sfx_insn->mnemonic, 16 );
|
||||||
|
handle_insn_metadata( insn, sfx_insn );
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* invalid instructions are handled by returning 0 [error] from the
|
||||||
|
* function, setting the size of the insn to 1 byte, and copying
|
||||||
|
* the byte at the start of the invalid insn into the x86_insn_t.
|
||||||
|
* if the caller is saving the x86_insn_t for invalid instructions,
|
||||||
|
* instead of discarding them, this will maintain a consistent
|
||||||
|
* address space in the x86_insn_ts */
|
||||||
|
|
||||||
|
/* this function is called by the controlling disassembler, so its name and
|
||||||
|
* calling convention cannot be changed */
|
||||||
|
/* buf points to the loc of the current opcode (start of the
|
||||||
|
* instruction) in the instruction stream. The instruction
|
||||||
|
* stream is assumed to be a buffer of bytes read directly
|
||||||
|
* from the file for the purpose of disassembly; a mem-mapped
|
||||||
|
* file is ideal for * this.
|
||||||
|
* insn points to a code structure to be filled by instr_decode
|
||||||
|
* returns the size of the decoded instruction in bytes */
|
||||||
|
size_t ia32_disasm_addr( unsigned char * buf, size_t buf_len,
|
||||||
|
x86_insn_t *insn ) {
|
||||||
|
ia32_insn_t *raw_insn = NULL;
|
||||||
|
unsigned int prefixes = 0;
|
||||||
|
size_t size, sfx_size;
|
||||||
|
|
||||||
|
if ( (ia32_settings.options & opt_ignore_nulls) && buf_len > 3 &&
|
||||||
|
!buf[0] && !buf[1] && !buf[2] && !buf[3]) {
|
||||||
|
/* IF IGNORE_NULLS is set AND
|
||||||
|
* first 4 bytes in the intruction stream are NULL
|
||||||
|
* THEN return 0 (END_OF_DISASSEMBLY) */
|
||||||
|
/* TODO: set errno */
|
||||||
|
MAKE_INVALID( insn, buf );
|
||||||
|
return 0; /* 4 00 bytes in a row? This isn't code! */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform recursive table lookup starting with main table (0) */
|
||||||
|
size = ia32_table_lookup(buf, buf_len, idx_Main, &raw_insn, &prefixes);
|
||||||
|
if ( size == INVALID_INSN || size > buf_len || raw_insn->mnem_flag == INS_INVALID ) {
|
||||||
|
MAKE_INVALID( insn, buf );
|
||||||
|
/* TODO: set errno */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We now have the opcode itself figured out: we can decode
|
||||||
|
* the rest of the instruction. */
|
||||||
|
size += ia32_decode_insn( &buf[size], buf_len - size, raw_insn, insn,
|
||||||
|
prefixes );
|
||||||
|
if ( raw_insn->mnem_flag & INS_FLAG_SUFFIX ) {
|
||||||
|
/* AMD 3DNow! suffix -- get proper operand type here */
|
||||||
|
sfx_size = handle_insn_suffix( &buf[size], buf_len - size,
|
||||||
|
raw_insn, insn );
|
||||||
|
if (! sfx_size ) {
|
||||||
|
/* TODO: set errno */
|
||||||
|
MAKE_INVALID( insn, buf );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size += sfx_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! size ) {
|
||||||
|
/* invalid insn */
|
||||||
|
MAKE_INVALID( insn, buf );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
insn->size = size;
|
||||||
|
return size; /* return size of instruction in bytes */
|
||||||
|
}
|
506
libdisasm/ia32_insn.h
Normal file
506
libdisasm/ia32_insn.h
Normal file
@ -0,0 +1,506 @@
|
|||||||
|
#ifndef IA32_INSN_H
|
||||||
|
#define IA32_INSN_H
|
||||||
|
/* this file contains the structure of opcode definitions and the
|
||||||
|
* constants they use */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "libdis.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define GET_BYTE( buf, buf_len ) buf_len ? *buf : 0
|
||||||
|
|
||||||
|
#define OP_SIZE_16 1
|
||||||
|
#define OP_SIZE_32 2
|
||||||
|
#define ADDR_SIZE_16 4
|
||||||
|
#define ADDR_SIZE_32 8
|
||||||
|
|
||||||
|
#define MAX_INSTRUCTION_SIZE 20
|
||||||
|
|
||||||
|
/* invalid instructions are handled by returning 0 [error] from the
|
||||||
|
* function, setting the size of the insn to 1 byte, and copying
|
||||||
|
* the byte at the start of the invalid insn into the x86_insn_t.
|
||||||
|
* if the caller is saving the x86_insn_t for invalid instructions,
|
||||||
|
* instead of discarding them, this will maintain a consistent
|
||||||
|
* address space in the x86_insn_ts */
|
||||||
|
|
||||||
|
#define INVALID_INSN ((size_t) -1) /* return value for invalid insn */
|
||||||
|
#define MAKE_INVALID( i, buf ) \
|
||||||
|
strcpy( i->mnemonic, "invalid" ); \
|
||||||
|
x86_oplist_free( i ); \
|
||||||
|
i->size = 1; \
|
||||||
|
i->group = insn_none; \
|
||||||
|
i->type = insn_invalid; \
|
||||||
|
memcpy( i->bytes, buf, 1 );
|
||||||
|
|
||||||
|
|
||||||
|
size_t ia32_disasm_addr( unsigned char * buf, size_t buf_len,
|
||||||
|
x86_insn_t *insn);
|
||||||
|
|
||||||
|
|
||||||
|
/* --------------------------------------------------------- Table Lookup */
|
||||||
|
/* IA32 Instruction defintion for ia32_opcodes.c */
|
||||||
|
typedef struct {
|
||||||
|
unsigned int table; /* escape to this sub-table */
|
||||||
|
unsigned int mnem_flag; /* Flags referring to mnemonic */
|
||||||
|
unsigned int notes; /* Notes for this instruction */
|
||||||
|
unsigned int dest_flag, src_flag, aux_flag; /* and for specific operands */
|
||||||
|
unsigned int cpu; /* minimumCPU [AND with clocks?? */
|
||||||
|
char mnemonic[16]; /* buffers for building instruction */
|
||||||
|
char mnemonic_att[16]; /* at&t style mnemonic name */
|
||||||
|
int32_t dest;
|
||||||
|
int32_t src;
|
||||||
|
int32_t aux;
|
||||||
|
unsigned int flags_effected;
|
||||||
|
unsigned int implicit_ops; /* implicit operands */
|
||||||
|
} ia32_insn_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* --------------------------------------------------------- Prefixes */
|
||||||
|
/* Prefix Flags */
|
||||||
|
/* Prefixes, same order as in the manual */
|
||||||
|
/* had to reverse the values of the first three as they were entered into
|
||||||
|
* libdis.h incorrectly. */
|
||||||
|
#define PREFIX_LOCK 0x0004
|
||||||
|
#define PREFIX_REPNZ 0x0002
|
||||||
|
#define PREFIX_REPZ 0x0001
|
||||||
|
#define PREFIX_OP_SIZE 0x0010
|
||||||
|
#define PREFIX_ADDR_SIZE 0x0020
|
||||||
|
#define PREFIX_CS 0x0100
|
||||||
|
#define PREFIX_SS 0x0200
|
||||||
|
#define PREFIX_DS 0x0300
|
||||||
|
#define PREFIX_ES 0x0400
|
||||||
|
#define PREFIX_FS 0x0500
|
||||||
|
#define PREFIX_GS 0x0600
|
||||||
|
#define PREFIX_TAKEN 0x1000 /* branch taken */
|
||||||
|
#define PREFIX_NOTTAKEN 0x2000 /* branch not taken */
|
||||||
|
#define PREFIX_REG_MASK 0x0F00
|
||||||
|
#define BRANCH_HINT_MASK 0x3000
|
||||||
|
#define PREFIX_PRINT_MASK 0x000F /* printable prefixes */
|
||||||
|
#define PREFIX_MASK 0xFFFF
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------- CPU Type */
|
||||||
|
|
||||||
|
#define cpu_8086 0x0001
|
||||||
|
#define cpu_80286 0x0002
|
||||||
|
#define cpu_80386 0x0003
|
||||||
|
#define cpu_80387 0x0004 /* originally these were a co-proc */
|
||||||
|
#define cpu_80486 0x0005
|
||||||
|
#define cpu_PENTIUM 0x0006
|
||||||
|
#define cpu_PENTPRO 0x0007
|
||||||
|
#define cpu_PENTIUM2 0x0008
|
||||||
|
#define cpu_PENTIUM3 0x0009
|
||||||
|
#define cpu_PENTIUM4 0x000A
|
||||||
|
#define cpu_K6 0x0010
|
||||||
|
#define cpu_K7 0x0020
|
||||||
|
#define cpu_ATHLON 0x0030
|
||||||
|
#define CPU_MODEL_MASK 0xFFFF
|
||||||
|
#define CPU_MODEL(cpu) (cpu & CPU_MODEL_MASK)
|
||||||
|
/* intel instruction subsets */
|
||||||
|
#define isa_GP 0x10000 /* General Purpose Instructions */
|
||||||
|
#define isa_FPU 0x20000 /* FPU instructions */
|
||||||
|
#define isa_FPUMGT 0x30000 /* FPU/SIMD Management */
|
||||||
|
#define isa_MMX 0x40000 /* MMX */
|
||||||
|
#define isa_SSE1 0x50000 /* SSE */
|
||||||
|
#define isa_SSE2 0x60000 /* SSE 2 */
|
||||||
|
#define isa_SSE3 0x70000 /* SSE 3 */
|
||||||
|
#define isa_3DNOW 0x80000 /* AMD 3d Now */
|
||||||
|
#define isa_SYS 0x90000 /* System Instructions */
|
||||||
|
#define ISA_SUBSET_MASK 0xFFFF0000
|
||||||
|
#define ISA_SUBSET(isa) (isa & ISA_SUBSET_MASK)
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------ Operand Decoding */
|
||||||
|
#define ARG_NONE 0
|
||||||
|
|
||||||
|
/* Using a mask allows us to store info such as OP_SIGNED in the
|
||||||
|
* operand flags field */
|
||||||
|
#define OPFLAGS_MASK 0x0000FFFF
|
||||||
|
|
||||||
|
/* Operand Addressing Methods, per intel manual */
|
||||||
|
#define ADDRMETH_MASK 0x00FF0000
|
||||||
|
|
||||||
|
/* note: for instructions with implied operands, use no ADDRMETH */
|
||||||
|
#define ADDRMETH_A 0x00010000
|
||||||
|
#define ADDRMETH_C 0x00020000
|
||||||
|
#define ADDRMETH_D 0x00030000
|
||||||
|
#define ADDRMETH_E 0x00040000
|
||||||
|
#define ADDRMETH_F 0x00050000
|
||||||
|
#define ADDRMETH_G 0x00060000
|
||||||
|
#define ADDRMETH_I 0x00070000
|
||||||
|
#define ADDRMETH_J 0x00080000
|
||||||
|
#define ADDRMETH_M 0x00090000
|
||||||
|
#define ADDRMETH_O 0x000A0000
|
||||||
|
#define ADDRMETH_P 0x000B0000
|
||||||
|
#define ADDRMETH_Q 0x000C0000
|
||||||
|
#define ADDRMETH_R 0x000D0000
|
||||||
|
#define ADDRMETH_S 0x000E0000
|
||||||
|
#define ADDRMETH_T 0x000F0000
|
||||||
|
#define ADDRMETH_V 0x00100000
|
||||||
|
#define ADDRMETH_W 0x00110000
|
||||||
|
#define ADDRMETH_X 0x00120000
|
||||||
|
#define ADDRMETH_Y 0x00130000
|
||||||
|
#define ADDRMETH_RR 0x00140000 /* gen reg hard-coded in opcode */
|
||||||
|
#define ADDRMETH_RS 0x00150000 /* seg reg hard-coded in opcode */
|
||||||
|
#define ADDRMETH_RT 0x00160000 /* test reg hard-coded in opcode */
|
||||||
|
#define ADDRMETH_RF 0x00170000 /* fpu reg hard-coded in opcode */
|
||||||
|
#define ADDRMETH_II 0x00180000 /* immediate hard-coded in opcode */
|
||||||
|
#define ADDRMETH_PP 0x00190000 /* mm reg ONLY in modr/m field */
|
||||||
|
#define ADDRMETH_VV 0x001A0000 /* xmm reg ONLY in mod/rm field */
|
||||||
|
|
||||||
|
/* Operand Types, per intel manual */
|
||||||
|
#define OPTYPE_MASK 0xFF000000
|
||||||
|
|
||||||
|
#define OPTYPE_a 0x01000000 /* BOUND: h:h or w:w */
|
||||||
|
#define OPTYPE_b 0x02000000 /* byte */
|
||||||
|
#define OPTYPE_c 0x03000000 /* byte or word */
|
||||||
|
#define OPTYPE_d 0x04000000 /* word */
|
||||||
|
#define OPTYPE_dq 0x05000000 /* qword */
|
||||||
|
#define OPTYPE_p 0x06000000 /* 16:16 or 16:32 pointer */
|
||||||
|
#define OPTYPE_pi 0x07000000 /* dword MMX reg */
|
||||||
|
#define OPTYPE_ps 0x08000000 /* 128-bit single fp */
|
||||||
|
#define OPTYPE_q 0x09000000 /* dword */
|
||||||
|
#define OPTYPE_s 0x0A000000 /* 6-byte descriptor */
|
||||||
|
#define OPTYPE_ss 0x0B000000 /* scalar of 128-bit single fp */
|
||||||
|
#define OPTYPE_si 0x0C000000 /* word general register */
|
||||||
|
#define OPTYPE_v 0x0D000000 /* hword or word */
|
||||||
|
#define OPTYPE_w 0x0E000000 /* hword */
|
||||||
|
#define OPTYPE_m 0x0F000000 /* to handle LEA */
|
||||||
|
#define OPTYPE_none 0xFF000000 /* no valid operand size, INVLPG */
|
||||||
|
|
||||||
|
/* custom ones for FPU instructions */
|
||||||
|
#define OPTYPE_fs 0x10000000 /* pointer to single-real*/
|
||||||
|
#define OPTYPE_fd 0x20000000 /* pointer to double real */
|
||||||
|
#define OPTYPE_fe 0x30000000 /* pointer to extended real */
|
||||||
|
#define OPTYPE_fb 0x40000000 /* pointer to packed BCD */
|
||||||
|
#define OPTYPE_fv 0x50000000 /* pointer to FPU env: 14|28-bytes */
|
||||||
|
#define OPTYPE_ft 0x60000000 /* pointer to FPU state: 94|108-bytes */
|
||||||
|
#define OPTYPE_fx 0x70000000 /* pointer to FPU regs: 512 bites */
|
||||||
|
#define OPTYPE_fp 0x80000000 /* general fpu register: dbl ext */
|
||||||
|
|
||||||
|
/* SSE2 operand types */
|
||||||
|
#define OPTYPE_sd 0x90000000 /* scalar of 128-bit double fp */
|
||||||
|
#define OPTYPE_pd 0xA0000000 /* 128-bit double fp */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------- Opcode Table Descriptions */
|
||||||
|
/* the table type describes how to handle byte/size increments before
|
||||||
|
* and after lookup. Some tables re-use the current byte, others
|
||||||
|
* consume a byte only if the ModR/M encodes no operands, etc */
|
||||||
|
enum ia32_tbl_type_id {
|
||||||
|
tbl_opcode = 0, /* standard opcode table: no surprises */
|
||||||
|
tbl_prefix, /* Prefix Override, e.g. 66/F2/F3 */
|
||||||
|
tbl_suffix, /* 3D Now style */
|
||||||
|
tbl_extension, /* ModR/M extension: 00-FF -> 00-07 */
|
||||||
|
tbl_ext_ext, /* extension of modr/m using R/M field */
|
||||||
|
tbl_fpu, /* fpu table: 00-BF -> 00-0F */
|
||||||
|
tbl_fpu_ext /* fpu extension : C0-FF -> 00-1F */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* How it works:
|
||||||
|
* Bytes are 'consumed' if the next table lookup requires that the byte
|
||||||
|
* pointer be advanced in the instruction stream. 'Does not consume' means
|
||||||
|
* that, when the lookup function recurses, the same byte it re-used in the
|
||||||
|
* new table. It also means that size is not decremented, for example when
|
||||||
|
* a ModR/M byte is used. Note that tbl_extension (ModR/M) instructions that
|
||||||
|
* do not increase the size of an insn with their operands have a forced
|
||||||
|
3 size increase in the lookup algo. Weird, yes, confusing, yes, welcome
|
||||||
|
* to the Intel ISA. Another note: tbl_prefix is used as an override, so an
|
||||||
|
* empty insn in a prefix table causes the instruction in the original table
|
||||||
|
* to be used, rather than an invalid insn being generated.
|
||||||
|
* tbl_opcode uses current byte and consumes it
|
||||||
|
* tbl_prefix uses current byte but does not consume it
|
||||||
|
* tbl_suffix uses and consumes last byte in insn
|
||||||
|
* tbl_extension uses current byte but does not consume it
|
||||||
|
* tbl_ext_ext uses current byte but does not consume it
|
||||||
|
* tbl_fpu uses current byte and consumes it
|
||||||
|
* tbl_fpu_ext uses current byte but does not consume it
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Convenience struct for opcode tables : these will be stored in a
|
||||||
|
* 'table of tables' so we can use a table index instead of a pointer */
|
||||||
|
typedef struct { /* Assembly instruction tables */
|
||||||
|
ia32_insn_t *table; /* Pointer to table of instruction encodings */
|
||||||
|
enum ia32_tbl_type_id type;
|
||||||
|
unsigned char shift; /* amount to shift modrm byte */
|
||||||
|
unsigned char mask; /* bit mask for look up */
|
||||||
|
unsigned char minlim,maxlim; /* limits on min/max entries. */
|
||||||
|
} ia32_table_desc_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------- 'Cooked' Operand Type Info */
|
||||||
|
/* Permissions: */
|
||||||
|
#define OP_R 0x001 /* operand is READ */
|
||||||
|
#define OP_W 0x002 /* operand is WRITTEN */
|
||||||
|
#define OP_RW 0x003 /* (OP_R|OP_W): convenience macro */
|
||||||
|
#define OP_X 0x004 /* operand is EXECUTED */
|
||||||
|
|
||||||
|
#define OP_PERM_MASK 0x0000007 /* perms are NOT mutually exclusive */
|
||||||
|
#define OP_PERM( type ) (type & OP_PERM_MASK)
|
||||||
|
|
||||||
|
/* Flags */
|
||||||
|
#define OP_SIGNED 0x010 /* operand is signed */
|
||||||
|
|
||||||
|
#define OP_FLAG_MASK 0x0F0 /* mods are NOT mutually exclusive */
|
||||||
|
#define OP_FLAGS( type ) (type & OP_FLAG_MASK)
|
||||||
|
|
||||||
|
#define OP_REG_MASK 0x0000FFFF /* lower WORD is register ID */
|
||||||
|
#define OP_REGTBL_MASK 0xFFFF0000 /* higher word is register type [gen/dbg] */
|
||||||
|
#define OP_REGID( type ) (type & OP_REG_MASK)
|
||||||
|
#define OP_REGTYPE( type ) (type & OP_REGTBL_MASK)
|
||||||
|
|
||||||
|
/* ------------------------------------------'Cooked' Instruction Type Info */
|
||||||
|
/* high-bit opcode types/insn meta-types */
|
||||||
|
#define INS_FLAG_PREFIX 0x10000000 /* insn is a prefix */
|
||||||
|
#define INS_FLAG_SUFFIX 0x20000000 /* followed by a suffix byte */
|
||||||
|
#define INS_FLAG_MASK 0xFF000000
|
||||||
|
|
||||||
|
/* insn notes */
|
||||||
|
#define INS_NOTE_RING0 0x00000001 /* insn is privileged */
|
||||||
|
#define INS_NOTE_SMM 0x00000002 /* Sys Mgt Mode only */
|
||||||
|
#define INS_NOTE_SERIAL 0x00000004 /* serializes */
|
||||||
|
#define INS_NOTE_NONSWAP 0x00000008 /* insn is not swapped in att format */ // could be separate field?
|
||||||
|
#define INS_NOTE_NOSUFFIX 0x00000010 /* insn has no size suffix in att format */ // could be separate field?
|
||||||
|
//#define INS_NOTE_NMI
|
||||||
|
|
||||||
|
#define INS_INVALID 0
|
||||||
|
|
||||||
|
/* instruction groups */
|
||||||
|
#define INS_EXEC 0x1000
|
||||||
|
#define INS_ARITH 0x2000
|
||||||
|
#define INS_LOGIC 0x3000
|
||||||
|
#define INS_STACK 0x4000
|
||||||
|
#define INS_COND 0x5000
|
||||||
|
#define INS_LOAD 0x6000
|
||||||
|
#define INS_ARRAY 0x7000
|
||||||
|
#define INS_BIT 0x8000
|
||||||
|
#define INS_FLAG 0x9000
|
||||||
|
#define INS_FPU 0xA000
|
||||||
|
#define INS_TRAPS 0xD000
|
||||||
|
#define INS_SYSTEM 0xE000
|
||||||
|
#define INS_OTHER 0xF000
|
||||||
|
|
||||||
|
#define INS_GROUP_MASK 0xF000
|
||||||
|
#define INS_GROUP( type ) ( type & INS_GROUP_MASK )
|
||||||
|
|
||||||
|
/* INS_EXEC group */
|
||||||
|
#define INS_BRANCH (INS_EXEC | 0x01) /* Unconditional branch */
|
||||||
|
#define INS_BRANCHCC (INS_EXEC | 0x02) /* Conditional branch */
|
||||||
|
#define INS_CALL (INS_EXEC | 0x03) /* Jump to subroutine */
|
||||||
|
#define INS_CALLCC (INS_EXEC | 0x04) /* Jump to subroutine */
|
||||||
|
#define INS_RET (INS_EXEC | 0x05) /* Return from subroutine */
|
||||||
|
|
||||||
|
/* INS_ARITH group */
|
||||||
|
#define INS_ADD (INS_ARITH | 0x01)
|
||||||
|
#define INS_SUB (INS_ARITH | 0x02)
|
||||||
|
#define INS_MUL (INS_ARITH | 0x03)
|
||||||
|
#define INS_DIV (INS_ARITH | 0x04)
|
||||||
|
#define INS_INC (INS_ARITH | 0x05) /* increment */
|
||||||
|
#define INS_DEC (INS_ARITH | 0x06) /* decrement */
|
||||||
|
#define INS_SHL (INS_ARITH | 0x07) /* shift right */
|
||||||
|
#define INS_SHR (INS_ARITH | 0x08) /* shift left */
|
||||||
|
#define INS_ROL (INS_ARITH | 0x09) /* rotate left */
|
||||||
|
#define INS_ROR (INS_ARITH | 0x0A) /* rotate right */
|
||||||
|
#define INS_MIN (INS_ARITH | 0x0B) /* min func */
|
||||||
|
#define INS_MAX (INS_ARITH | 0x0C) /* max func */
|
||||||
|
#define INS_AVG (INS_ARITH | 0x0D) /* avg func */
|
||||||
|
#define INS_FLR (INS_ARITH | 0x0E) /* floor func */
|
||||||
|
#define INS_CEIL (INS_ARITH | 0x0F) /* ceiling func */
|
||||||
|
|
||||||
|
/* INS_LOGIC group */
|
||||||
|
#define INS_AND (INS_LOGIC | 0x01)
|
||||||
|
#define INS_OR (INS_LOGIC | 0x02)
|
||||||
|
#define INS_XOR (INS_LOGIC | 0x03)
|
||||||
|
#define INS_NOT (INS_LOGIC | 0x04)
|
||||||
|
#define INS_NEG (INS_LOGIC | 0x05)
|
||||||
|
#define INS_NAND (INS_LOGIC | 0x06)
|
||||||
|
|
||||||
|
/* INS_STACK group */
|
||||||
|
#define INS_PUSH (INS_STACK | 0x01)
|
||||||
|
#define INS_POP (INS_STACK | 0x02)
|
||||||
|
#define INS_PUSHREGS (INS_STACK | 0x03) /* push register context */
|
||||||
|
#define INS_POPREGS (INS_STACK | 0x04) /* pop register context */
|
||||||
|
#define INS_PUSHFLAGS (INS_STACK | 0x05) /* push all flags */
|
||||||
|
#define INS_POPFLAGS (INS_STACK | 0x06) /* pop all flags */
|
||||||
|
#define INS_ENTER (INS_STACK | 0x07) /* enter stack frame */
|
||||||
|
#define INS_LEAVE (INS_STACK | 0x08) /* leave stack frame */
|
||||||
|
|
||||||
|
/* INS_COND group */
|
||||||
|
#define INS_TEST (INS_COND | 0x01)
|
||||||
|
#define INS_CMP (INS_COND | 0x02)
|
||||||
|
|
||||||
|
/* INS_LOAD group */
|
||||||
|
#define INS_MOV (INS_LOAD | 0x01)
|
||||||
|
#define INS_MOVCC (INS_LOAD | 0x02)
|
||||||
|
#define INS_XCHG (INS_LOAD | 0x03)
|
||||||
|
#define INS_XCHGCC (INS_LOAD | 0x04)
|
||||||
|
#define INS_CONV (INS_LOAD | 0x05) /* move and convert type */
|
||||||
|
|
||||||
|
/* INS_ARRAY group */
|
||||||
|
#define INS_STRCMP (INS_ARRAY | 0x01)
|
||||||
|
#define INS_STRLOAD (INS_ARRAY | 0x02)
|
||||||
|
#define INS_STRMOV (INS_ARRAY | 0x03)
|
||||||
|
#define INS_STRSTOR (INS_ARRAY | 0x04)
|
||||||
|
#define INS_XLAT (INS_ARRAY | 0x05)
|
||||||
|
|
||||||
|
/* INS_BIT group */
|
||||||
|
#define INS_BITTEST (INS_BIT | 0x01)
|
||||||
|
#define INS_BITSET (INS_BIT | 0x02)
|
||||||
|
#define INS_BITCLR (INS_BIT | 0x03)
|
||||||
|
|
||||||
|
/* INS_FLAG group */
|
||||||
|
#define INS_CLEARCF (INS_FLAG | 0x01) /* clear Carry flag */
|
||||||
|
#define INS_CLEARZF (INS_FLAG | 0x02) /* clear Zero flag */
|
||||||
|
#define INS_CLEAROF (INS_FLAG | 0x03) /* clear Overflow flag */
|
||||||
|
#define INS_CLEARDF (INS_FLAG | 0x04) /* clear Direction flag */
|
||||||
|
#define INS_CLEARSF (INS_FLAG | 0x05) /* clear Sign flag */
|
||||||
|
#define INS_CLEARPF (INS_FLAG | 0x06) /* clear Parity flag */
|
||||||
|
#define INS_SETCF (INS_FLAG | 0x07)
|
||||||
|
#define INS_SETZF (INS_FLAG | 0x08)
|
||||||
|
#define INS_SETOF (INS_FLAG | 0x09)
|
||||||
|
#define INS_SETDF (INS_FLAG | 0x0A)
|
||||||
|
#define INS_SETSF (INS_FLAG | 0x0B)
|
||||||
|
#define INS_SETPF (INS_FLAG | 0x0C)
|
||||||
|
#define INS_TOGCF (INS_FLAG | 0x10) /* toggle */
|
||||||
|
#define INS_TOGZF (INS_FLAG | 0x20)
|
||||||
|
#define INS_TOGOF (INS_FLAG | 0x30)
|
||||||
|
#define INS_TOGDF (INS_FLAG | 0x40)
|
||||||
|
#define INS_TOGSF (INS_FLAG | 0x50)
|
||||||
|
#define INS_TOGPF (INS_FLAG | 0x60)
|
||||||
|
|
||||||
|
/* INS_FPU */
|
||||||
|
#define INS_FMOV (INS_FPU | 0x1)
|
||||||
|
#define INS_FMOVCC (INS_FPU | 0x2)
|
||||||
|
#define INS_FNEG (INS_FPU | 0x3)
|
||||||
|
#define INS_FABS (INS_FPU | 0x4)
|
||||||
|
#define INS_FADD (INS_FPU | 0x5)
|
||||||
|
#define INS_FSUB (INS_FPU | 0x6)
|
||||||
|
#define INS_FMUL (INS_FPU | 0x7)
|
||||||
|
#define INS_FDIV (INS_FPU | 0x8)
|
||||||
|
#define INS_FSQRT (INS_FPU | 0x9)
|
||||||
|
#define INS_FCMP (INS_FPU | 0xA)
|
||||||
|
#define INS_FCOS (INS_FPU | 0xC) /* cosine */
|
||||||
|
#define INS_FLDPI (INS_FPU | 0xD) /* load pi */
|
||||||
|
#define INS_FLDZ (INS_FPU | 0xE) /* load 0 */
|
||||||
|
#define INS_FTAN (INS_FPU | 0xF) /* tanget */
|
||||||
|
#define INS_FSINE (INS_FPU | 0x10) /* sine */
|
||||||
|
#define INS_FSYS (INS_FPU | 0x20) /* misc */
|
||||||
|
|
||||||
|
/* INS_TRAP */
|
||||||
|
#define INS_TRAP (INS_TRAPS | 0x01) /* generate trap */
|
||||||
|
#define INS_TRAPCC (INS_TRAPS | 0x02) /* conditional trap gen */
|
||||||
|
#define INS_TRET (INS_TRAPS | 0x03) /* return from trap */
|
||||||
|
#define INS_BOUNDS (INS_TRAPS | 0x04) /* gen bounds trap */
|
||||||
|
#define INS_DEBUG (INS_TRAPS | 0x05) /* gen breakpoint trap */
|
||||||
|
#define INS_TRACE (INS_TRAPS | 0x06) /* gen single step trap */
|
||||||
|
#define INS_INVALIDOP (INS_TRAPS | 0x07) /* gen invalid insn */
|
||||||
|
#define INS_OFLOW (INS_TRAPS | 0x08) /* gen overflow trap */
|
||||||
|
#define INS_ICEBP (INS_TRAPS | 0x09) /* ICE breakpoint */
|
||||||
|
|
||||||
|
/* INS_SYSTEM */
|
||||||
|
#define INS_HALT (INS_SYSTEM | 0x01) /* halt machine */
|
||||||
|
#define INS_IN (INS_SYSTEM | 0x02) /* input form port */
|
||||||
|
#define INS_OUT (INS_SYSTEM | 0x03) /* output to port */
|
||||||
|
#define INS_CPUID (INS_SYSTEM | 0x04) /* identify cpu */
|
||||||
|
|
||||||
|
/* INS_OTHER */
|
||||||
|
#define INS_NOP (INS_OTHER | 0x01)
|
||||||
|
#define INS_BCDCONV (INS_OTHER | 0x02) /* convert to/from BCD */
|
||||||
|
#define INS_SZCONV (INS_OTHER | 0x03) /* convert size of operand */
|
||||||
|
#define INS_SALC (INS_OTHER | 0x04) /* set %al on carry */
|
||||||
|
#define INS_UNKNOWN (INS_OTHER | 0x05)
|
||||||
|
|
||||||
|
|
||||||
|
#define INS_TYPE_MASK 0xFFFF
|
||||||
|
#define INS_TYPE( type ) ( type & INS_TYPE_MASK )
|
||||||
|
|
||||||
|
/* flags effected by instruction */
|
||||||
|
#define INS_TEST_CARRY 0x01 /* carry */
|
||||||
|
#define INS_TEST_ZERO 0x02 /* zero/equal */
|
||||||
|
#define INS_TEST_OFLOW 0x04 /* overflow */
|
||||||
|
#define INS_TEST_DIR 0x08 /* direction */
|
||||||
|
#define INS_TEST_SIGN 0x10 /* negative */
|
||||||
|
#define INS_TEST_PARITY 0x20 /* parity */
|
||||||
|
#define INS_TEST_OR 0x40 /* used in jle */
|
||||||
|
#define INS_TEST_NCARRY 0x100 /* ! carry */
|
||||||
|
#define INS_TEST_NZERO 0x200 /* ! zero */
|
||||||
|
#define INS_TEST_NOFLOW 0x400 /* ! oflow */
|
||||||
|
#define INS_TEST_NDIR 0x800 /* ! dir */
|
||||||
|
#define INS_TEST_NSIGN 0x100 /* ! sign */
|
||||||
|
#define INS_TEST_NPARITY 0x2000 /* ! parity */
|
||||||
|
/* SF == OF */
|
||||||
|
#define INS_TEST_SFEQOF 0x4000
|
||||||
|
/* SF != OF */
|
||||||
|
#define INS_TEST_SFNEOF 0x8000
|
||||||
|
|
||||||
|
#define INS_TEST_ALL INS_TEST_CARRY | INS_TEST_ZERO | \
|
||||||
|
INS_TEST_OFLOW | INS_TEST_SIGN | \
|
||||||
|
INS_TEST_PARITY
|
||||||
|
|
||||||
|
#define INS_SET_CARRY 0x010000 /* carry */
|
||||||
|
#define INS_SET_ZERO 0x020000 /* zero/equal */
|
||||||
|
#define INS_SET_OFLOW 0x040000 /* overflow */
|
||||||
|
#define INS_SET_DIR 0x080000 /* direction */
|
||||||
|
#define INS_SET_SIGN 0x100000 /* negative */
|
||||||
|
#define INS_SET_PARITY 0x200000 /* parity */
|
||||||
|
#define INS_SET_NCARRY 0x1000000
|
||||||
|
#define INS_SET_NZERO 0x2000000
|
||||||
|
#define INS_SET_NOFLOW 0x4000000
|
||||||
|
#define INS_SET_NDIR 0x8000000
|
||||||
|
#define INS_SET_NSIGN 0x10000000
|
||||||
|
#define INS_SET_NPARITY 0x20000000
|
||||||
|
#define INS_SET_SFEQOF 0x40000000
|
||||||
|
#define INS_SET_SFNEOF 0x80000000
|
||||||
|
|
||||||
|
#define INS_SET_ALL INS_SET_CARRY | INS_SET_ZERO | \
|
||||||
|
INS_SET_OFLOW | INS_SET_SIGN | \
|
||||||
|
INS_SET_PARITY
|
||||||
|
|
||||||
|
#define INS_TEST_MASK 0x0000FFFF
|
||||||
|
#define INS_FLAGS_TEST(x) (x & INS_TEST_MASK)
|
||||||
|
#define INS_SET_MASK 0xFFFF0000
|
||||||
|
#define INS_FLAGS_SET(x) (x & INS_SET_MASK)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* TODO: actually start using these */
|
||||||
|
#define X86_PAIR_NP 1 /* not pairable; execs in U */
|
||||||
|
#define X86_PAIR_PU 2 /* pairable in U pipe */
|
||||||
|
#define X86_PAIR_PV 3 /* pairable in V pipe */
|
||||||
|
#define X86_PAIR_UV 4 /* pairable in UV pipe */
|
||||||
|
#define X86_PAIR_FX 5 /* pairable with FXCH */
|
||||||
|
|
||||||
|
#define X86_EXEC_PORT_0 1
|
||||||
|
#define X86_EXEC_PORT_1 2
|
||||||
|
#define X86_EXEC_PORT_2 4
|
||||||
|
#define X86_EXEC_PORT_3 8
|
||||||
|
#define X86_EXEC_PORT_4 16
|
||||||
|
|
||||||
|
#define X86_EXEC_UNITS
|
||||||
|
|
||||||
|
typedef struct { /* representation of an insn during decoding */
|
||||||
|
uint32_t flags; /* runtime settings */
|
||||||
|
/* instruction prefixes and other foolishness */
|
||||||
|
uint32_t prefix; /* encoding of prefix */
|
||||||
|
char prefix_str[16]; /* mnemonics for prefix */
|
||||||
|
uint32_t branch_hint; /* gah! */
|
||||||
|
unsigned int cpu_ver; /* TODO: cpu version */
|
||||||
|
unsigned int clocks; /* TODO: clock cycles: min/max */
|
||||||
|
unsigned char last_prefix;
|
||||||
|
/* runtime intruction decoding helpers */
|
||||||
|
unsigned char mode; /* 16, 32, 64 */
|
||||||
|
unsigned char gen_regs; /* offset of default general reg set */
|
||||||
|
unsigned char sz_operand; /* operand size for insn */
|
||||||
|
unsigned char sz_address; /* address size for insn */
|
||||||
|
unsigned char uops; /* uops per insn */
|
||||||
|
unsigned char pairing; /* np,pu,pv.lv */
|
||||||
|
unsigned char exec_unit;
|
||||||
|
unsigned char exec_port;
|
||||||
|
unsigned char latency;
|
||||||
|
} ia32_info_t;
|
||||||
|
#define MODE_32 0 /* default */
|
||||||
|
#define MODE_16 1
|
||||||
|
#define MODE_64 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
313
libdisasm/ia32_invariant.c
Normal file
313
libdisasm/ia32_invariant.c
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ia32_invariant.h"
|
||||||
|
#include "ia32_insn.h"
|
||||||
|
#include "ia32_settings.h"
|
||||||
|
|
||||||
|
extern ia32_table_desc_t *ia32_tables;
|
||||||
|
extern ia32_settings_t ia32_settings;
|
||||||
|
|
||||||
|
extern size_t ia32_table_lookup( unsigned char *buf, size_t buf_len,
|
||||||
|
unsigned int table, ia32_insn_t **raw_insn,
|
||||||
|
unsigned int *prefixes );
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------- ModR/M, SIB */
|
||||||
|
/* Convenience flags */
|
||||||
|
#define MODRM_EA 1 /* ModR/M is an effective addr */
|
||||||
|
#define MODRM_reg 2 /* ModR/M is a register */
|
||||||
|
|
||||||
|
/* ModR/M flags */
|
||||||
|
#define MODRM_RM_SIB 0x04 /* R/M == 100 */
|
||||||
|
#define MODRM_RM_NOREG 0x05 /* R/B == 101 */
|
||||||
|
/* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */
|
||||||
|
#define MODRM_MOD_NODISP 0x00 /* mod == 00 */
|
||||||
|
#define MODRM_MOD_DISP8 0x01 /* mod == 01 */
|
||||||
|
#define MODRM_MOD_DISP32 0x02 /* mod == 10 */
|
||||||
|
#define MODRM_MOD_NOEA 0x03 /* mod == 11 */
|
||||||
|
/* 16-bit modrm flags */
|
||||||
|
#define MOD16_MOD_NODISP 0
|
||||||
|
#define MOD16_MOD_DISP8 1
|
||||||
|
#define MOD16_MOD_DISP16 2
|
||||||
|
#define MOD16_MOD_REG 3
|
||||||
|
|
||||||
|
#define MOD16_RM_BXSI 0
|
||||||
|
#define MOD16_RM_BXDI 1
|
||||||
|
#define MOD16_RM_BPSI 2
|
||||||
|
#define MOD16_RM_BPDI 3
|
||||||
|
#define MOD16_RM_SI 4
|
||||||
|
#define MOD16_RM_DI 5
|
||||||
|
#define MOD16_RM_BP 6
|
||||||
|
#define MOD16_RM_BX 7
|
||||||
|
|
||||||
|
/* SIB flags */
|
||||||
|
#define SIB_INDEX_NONE 0x04
|
||||||
|
#define SIB_BASE_EBP 0x05
|
||||||
|
#define SIB_SCALE_NOBASE 0x00
|
||||||
|
|
||||||
|
/* Convenience struct for modR/M bitfield */
|
||||||
|
struct modRM_byte {
|
||||||
|
unsigned int mod : 2;
|
||||||
|
unsigned int reg : 3;
|
||||||
|
unsigned int rm : 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Convenience struct for SIB bitfield */
|
||||||
|
struct SIB_byte {
|
||||||
|
unsigned int scale : 2;
|
||||||
|
unsigned int index : 3;
|
||||||
|
unsigned int base : 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
static void byte_decode(unsigned char b, struct modRM_byte *modrm) {
|
||||||
|
#else
|
||||||
|
static inline void byte_decode(unsigned char b, struct modRM_byte *modrm) {
|
||||||
|
#endif
|
||||||
|
/* generic bitfield-packing routine */
|
||||||
|
|
||||||
|
modrm->mod = b >> 6; /* top 2 bits */
|
||||||
|
modrm->reg = (b & 56) >> 3; /* middle 3 bits */
|
||||||
|
modrm->rm = b & 7; /* bottom 3 bits */
|
||||||
|
}
|
||||||
|
static int ia32_invariant_modrm( unsigned char *in, unsigned char *out,
|
||||||
|
unsigned int mode_16, x86_invariant_op_t *op) {
|
||||||
|
struct modRM_byte modrm;
|
||||||
|
struct SIB_byte sib;
|
||||||
|
unsigned char *c, *cin;
|
||||||
|
unsigned short *s;
|
||||||
|
unsigned int *i;
|
||||||
|
int size = 0; /* modrm byte is already counted */
|
||||||
|
|
||||||
|
|
||||||
|
byte_decode(*in, &modrm); /* get bitfields */
|
||||||
|
|
||||||
|
out[0] = in[0]; /* save modrm byte */
|
||||||
|
cin = &in[1];
|
||||||
|
c = &out[1];
|
||||||
|
s = (unsigned short *)&out[1];
|
||||||
|
i = (unsigned int *)&out[1];
|
||||||
|
|
||||||
|
op->type = op_expression;
|
||||||
|
op->flags |= op_pointer;
|
||||||
|
if ( ! mode_16 && modrm.rm == MODRM_RM_SIB &&
|
||||||
|
modrm.mod != MODRM_MOD_NOEA ) {
|
||||||
|
size ++;
|
||||||
|
byte_decode(*cin, (struct modRM_byte *)(void*)&sib);
|
||||||
|
|
||||||
|
out[1] = in[1]; /* save sib byte */
|
||||||
|
cin = &in[2];
|
||||||
|
c = &out[2];
|
||||||
|
s = (unsigned short *)&out[2];
|
||||||
|
i = (unsigned int *)&out[2];
|
||||||
|
|
||||||
|
if ( sib.base == SIB_BASE_EBP && ! modrm.mod ) {
|
||||||
|
/* disp 32 is variant! */
|
||||||
|
memset( i, X86_WILDCARD_BYTE, 4 );
|
||||||
|
size += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! modrm.mod && modrm.rm == 101) {
|
||||||
|
if ( mode_16 ) { /* straight RVA in disp */
|
||||||
|
memset( s, X86_WILDCARD_BYTE, 2 );
|
||||||
|
size += 2;
|
||||||
|
} else {
|
||||||
|
memset( i, X86_WILDCARD_BYTE, 2 );
|
||||||
|
size += 4;
|
||||||
|
}
|
||||||
|
} else if (modrm.mod && modrm.mod < 3) {
|
||||||
|
if (modrm.mod == MODRM_MOD_DISP8) { /* offset in disp */
|
||||||
|
*c = *cin;
|
||||||
|
size += 1;
|
||||||
|
} else if ( mode_16 ) {
|
||||||
|
*s = (* ((unsigned short *) cin));
|
||||||
|
size += 2;
|
||||||
|
} else {
|
||||||
|
*i = (*((unsigned int *) cin));
|
||||||
|
size += 4;
|
||||||
|
}
|
||||||
|
} else if ( modrm.mod == 3 ) {
|
||||||
|
op->type = op_register;
|
||||||
|
op->flags &= ~op_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int ia32_decode_invariant( unsigned char *buf, size_t buf_len,
|
||||||
|
ia32_insn_t *t, unsigned char *out,
|
||||||
|
unsigned int prefixes, x86_invariant_t *inv) {
|
||||||
|
|
||||||
|
unsigned int addr_size, op_size, mode_16;
|
||||||
|
unsigned int op_flags[3] = { t->dest_flag, t->src_flag, t->aux_flag };
|
||||||
|
int x, type, bytes = 0, size = 0, modrm = 0;
|
||||||
|
|
||||||
|
/* set addressing mode */
|
||||||
|
if (ia32_settings.options & opt_16_bit) {
|
||||||
|
op_size = ( prefixes & PREFIX_OP_SIZE ) ? 4 : 2;
|
||||||
|
addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 4 : 2;
|
||||||
|
mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 0 : 1;
|
||||||
|
} else {
|
||||||
|
op_size = ( prefixes & PREFIX_OP_SIZE ) ? 2 : 4;
|
||||||
|
addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 2 : 4;
|
||||||
|
mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (x = 0; x < 3; x++) {
|
||||||
|
inv->operands[x].access = (enum x86_op_access)
|
||||||
|
OP_PERM(op_flags[x]);
|
||||||
|
inv->operands[x].flags = (enum x86_op_flags)
|
||||||
|
(OP_FLAGS(op_flags[x]) >> 12);
|
||||||
|
|
||||||
|
switch (op_flags[x] & OPTYPE_MASK) {
|
||||||
|
case OPTYPE_c:
|
||||||
|
size = (op_size == 4) ? 2 : 1;
|
||||||
|
break;
|
||||||
|
case OPTYPE_a: case OPTYPE_v:
|
||||||
|
size = (op_size == 4) ? 4 : 2;
|
||||||
|
break;
|
||||||
|
case OPTYPE_p:
|
||||||
|
size = (op_size == 4) ? 6 : 4;
|
||||||
|
break;
|
||||||
|
case OPTYPE_b:
|
||||||
|
size = 1;
|
||||||
|
break;
|
||||||
|
case OPTYPE_w:
|
||||||
|
size = 2;
|
||||||
|
break;
|
||||||
|
case OPTYPE_d: case OPTYPE_fs: case OPTYPE_fd:
|
||||||
|
case OPTYPE_fe: case OPTYPE_fb: case OPTYPE_fv:
|
||||||
|
case OPTYPE_si: case OPTYPE_fx:
|
||||||
|
size = 4;
|
||||||
|
break;
|
||||||
|
case OPTYPE_s:
|
||||||
|
size = 6;
|
||||||
|
break;
|
||||||
|
case OPTYPE_q: case OPTYPE_pi:
|
||||||
|
size = 8;
|
||||||
|
break;
|
||||||
|
case OPTYPE_dq: case OPTYPE_ps: case OPTYPE_ss:
|
||||||
|
case OPTYPE_pd: case OPTYPE_sd:
|
||||||
|
size = 16;
|
||||||
|
break;
|
||||||
|
case OPTYPE_m:
|
||||||
|
size = (addr_size == 4) ? 4 : 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = op_flags[x] & ADDRMETH_MASK;
|
||||||
|
switch (type) {
|
||||||
|
case ADDRMETH_E: case ADDRMETH_M: case ADDRMETH_Q:
|
||||||
|
case ADDRMETH_R: case ADDRMETH_W:
|
||||||
|
modrm = 1;
|
||||||
|
bytes += ia32_invariant_modrm( buf, out,
|
||||||
|
mode_16, &inv->operands[x]);
|
||||||
|
break;
|
||||||
|
case ADDRMETH_C: case ADDRMETH_D: case ADDRMETH_G:
|
||||||
|
case ADDRMETH_P: case ADDRMETH_S: case ADDRMETH_T:
|
||||||
|
case ADDRMETH_V:
|
||||||
|
inv->operands[x].type = op_register;
|
||||||
|
modrm = 1;
|
||||||
|
break;
|
||||||
|
case ADDRMETH_A: case ADDRMETH_O:
|
||||||
|
/* pad with xF4's */
|
||||||
|
memset( &out[bytes + modrm], X86_WILDCARD_BYTE,
|
||||||
|
size );
|
||||||
|
bytes += size;
|
||||||
|
inv->operands[x].type = op_offset;
|
||||||
|
if ( type == ADDRMETH_O ) {
|
||||||
|
inv->operands[x].flags |= op_signed |
|
||||||
|
op_pointer;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ADDRMETH_I: case ADDRMETH_J:
|
||||||
|
/* grab imm value */
|
||||||
|
if ((op_flags[x] & OPTYPE_MASK) == OPTYPE_v) {
|
||||||
|
/* assume this is an address */
|
||||||
|
memset( &out[bytes + modrm],
|
||||||
|
X86_WILDCARD_BYTE, size );
|
||||||
|
} else {
|
||||||
|
memcpy( &out[bytes + modrm],
|
||||||
|
&buf[bytes + modrm], size );
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes += size;
|
||||||
|
if ( type == ADDRMETH_J ) {
|
||||||
|
if ( size == 1 ) {
|
||||||
|
inv->operands[x].type =
|
||||||
|
op_relative_near;
|
||||||
|
} else {
|
||||||
|
inv->operands[x].type =
|
||||||
|
op_relative_far;
|
||||||
|
}
|
||||||
|
inv->operands[x].flags |= op_signed;
|
||||||
|
} else {
|
||||||
|
inv->operands[x].type = op_immediate;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ADDRMETH_F:
|
||||||
|
inv->operands[x].type = op_register;
|
||||||
|
break;
|
||||||
|
case ADDRMETH_X:
|
||||||
|
inv->operands[x].flags |= op_signed |
|
||||||
|
op_pointer | op_ds_seg | op_string;
|
||||||
|
break;
|
||||||
|
case ADDRMETH_Y:
|
||||||
|
inv->operands[x].flags |= op_signed |
|
||||||
|
op_pointer | op_es_seg | op_string;
|
||||||
|
break;
|
||||||
|
case ADDRMETH_RR:
|
||||||
|
inv->operands[x].type = op_register;
|
||||||
|
break;
|
||||||
|
case ADDRMETH_II:
|
||||||
|
inv->operands[x].type = op_immediate;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
inv->operands[x].type = op_unused;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bytes + modrm);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ia32_disasm_invariant( unsigned char * buf, size_t buf_len,
|
||||||
|
x86_invariant_t *inv ) {
|
||||||
|
ia32_insn_t *raw_insn = NULL;
|
||||||
|
unsigned int prefixes;
|
||||||
|
unsigned int type;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
/* Perform recursive table lookup starting with main table (0) */
|
||||||
|
size = ia32_table_lookup( buf, buf_len, 0, &raw_insn, &prefixes );
|
||||||
|
if ( size == INVALID_INSN || size > buf_len ) {
|
||||||
|
/* TODO: set errno */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy opcode bytes to buffer */
|
||||||
|
memcpy( inv->bytes, buf, size );
|
||||||
|
|
||||||
|
/* set mnemonic type and group */
|
||||||
|
type = raw_insn->mnem_flag & ~INS_FLAG_MASK;
|
||||||
|
inv->group = (enum x86_insn_group) (INS_GROUP(type)) >> 12;
|
||||||
|
inv->type = (enum x86_insn_type) INS_TYPE(type);
|
||||||
|
|
||||||
|
/* handle operands */
|
||||||
|
size += ia32_decode_invariant( buf + size, buf_len - size, raw_insn,
|
||||||
|
&buf[size - 1], prefixes, inv );
|
||||||
|
|
||||||
|
inv->size = size;
|
||||||
|
|
||||||
|
return size; /* return size of instruction in bytes */
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ia32_disasm_size( unsigned char *buf, size_t buf_len ) {
|
||||||
|
x86_invariant_t inv = { {0} };
|
||||||
|
return( ia32_disasm_invariant( buf, buf_len, &inv ) );
|
||||||
|
}
|
11
libdisasm/ia32_invariant.h
Normal file
11
libdisasm/ia32_invariant.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef IA32_INVARIANT_H
|
||||||
|
#define IA32_INVARIANT_H
|
||||||
|
|
||||||
|
#include "libdis.h"
|
||||||
|
|
||||||
|
size_t ia32_disasm_invariant( unsigned char *buf, size_t buf_len,
|
||||||
|
x86_invariant_t *inv);
|
||||||
|
|
||||||
|
size_t ia32_disasm_size( unsigned char *buf, size_t buf_len );
|
||||||
|
|
||||||
|
#endif
|
310
libdisasm/ia32_modrm.c
Normal file
310
libdisasm/ia32_modrm.c
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
#include "ia32_modrm.h"
|
||||||
|
#include "ia32_reg.h"
|
||||||
|
#include "x86_imm.h"
|
||||||
|
|
||||||
|
/* NOTE: when decoding ModR/M and SIB, we have to add 1 to all register
|
||||||
|
* values obtained from decoding the ModR/M or SIB byte, since they
|
||||||
|
* are encoded with eAX = 0 and the tables in ia32_reg.c use eAX = 1.
|
||||||
|
* ADDENDUM: this is only the case when the register value is used
|
||||||
|
* directly as an index into the register table, not when it is added to
|
||||||
|
* a genregs offset. */
|
||||||
|
|
||||||
|
/* -------------------------------- ModR/M, SIB */
|
||||||
|
/* ModR/M flags */
|
||||||
|
#define MODRM_RM_SIB 0x04 /* R/M == 100 */
|
||||||
|
#define MODRM_RM_NOREG 0x05 /* R/B == 101 */
|
||||||
|
|
||||||
|
/* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */
|
||||||
|
#define MODRM_MOD_NODISP 0x00 /* mod == 00 */
|
||||||
|
#define MODRM_MOD_DISP8 0x01 /* mod == 01 */
|
||||||
|
#define MODRM_MOD_DISP32 0x02 /* mod == 10 */
|
||||||
|
#define MODRM_MOD_NOEA 0x03 /* mod == 11 */
|
||||||
|
|
||||||
|
/* 16-bit modrm flags */
|
||||||
|
#define MOD16_MOD_NODISP 0
|
||||||
|
#define MOD16_MOD_DISP8 1
|
||||||
|
#define MOD16_MOD_DISP16 2
|
||||||
|
#define MOD16_MOD_REG 3
|
||||||
|
|
||||||
|
#define MOD16_RM_BXSI 0
|
||||||
|
#define MOD16_RM_BXDI 1
|
||||||
|
#define MOD16_RM_BPSI 2
|
||||||
|
#define MOD16_RM_BPDI 3
|
||||||
|
#define MOD16_RM_SI 4
|
||||||
|
#define MOD16_RM_DI 5
|
||||||
|
#define MOD16_RM_BP 6
|
||||||
|
#define MOD16_RM_BX 7
|
||||||
|
|
||||||
|
/* SIB flags */
|
||||||
|
#define SIB_INDEX_NONE 0x04
|
||||||
|
#define SIB_BASE_EBP 0x05
|
||||||
|
#define SIB_SCALE_NOBASE 0x00
|
||||||
|
|
||||||
|
/* Convenience struct for modR/M bitfield */
|
||||||
|
struct modRM_byte {
|
||||||
|
unsigned int mod : 2;
|
||||||
|
unsigned int reg : 3;
|
||||||
|
unsigned int rm : 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Convenience struct for SIB bitfield */
|
||||||
|
struct SIB_byte {
|
||||||
|
unsigned int scale : 2;
|
||||||
|
unsigned int index : 3;
|
||||||
|
unsigned int base : 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int modrm_rm[] = {0,1,2,3,MODRM_RM_SIB,MODRM_MOD_DISP32,6,7};
|
||||||
|
int modrm_reg[] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||||
|
int modrm_mod[] = {0, MODRM_MOD_DISP8, MODRM_MOD_DISP32, MODRM_MOD_NOEA};
|
||||||
|
int sib_scl[] = {0, 2, 4, 8};
|
||||||
|
int sib_idx[] = {0, 1, 2, 3, SIB_INDEX_NONE, 5, 6, 7 };
|
||||||
|
int sib_bas[] = {0, 1, 2, 3, 4, SIB_SCALE_NOBASE, 6, 7 };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* this is needed to replace x86_imm_signsized() which does not sign-extend
|
||||||
|
* to dest */
|
||||||
|
static unsigned int imm32_signsized( unsigned char *buf, size_t buf_len,
|
||||||
|
int32_t *dest, unsigned int size ) {
|
||||||
|
if ( size > buf_len ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
*dest = *((signed char *) buf);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*dest = *((signed short *) buf);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
default:
|
||||||
|
*dest = *((signed int *) buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void byte_decode(unsigned char b, struct modRM_byte *modrm) {
|
||||||
|
/* generic bitfield-packing routine */
|
||||||
|
|
||||||
|
modrm->mod = b >> 6; /* top 2 bits */
|
||||||
|
modrm->reg = (b & 56) >> 3; /* middle 3 bits */
|
||||||
|
modrm->rm = b & 7; /* bottom 3 bits */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t sib_decode( unsigned char *buf, size_t buf_len, x86_ea_t *ea,
|
||||||
|
unsigned int mod ) {
|
||||||
|
/* set Address Expression fields (scale, index, base, disp)
|
||||||
|
* according to the contents of the SIB byte.
|
||||||
|
* b points to the SIB byte in the instruction-stream buffer; the
|
||||||
|
* byte after b[0] is therefore the byte after the SIB
|
||||||
|
* returns number of bytes 'used', including the SIB byte */
|
||||||
|
size_t size = 1; /* start at 1 for SIB byte */
|
||||||
|
struct SIB_byte sib;
|
||||||
|
|
||||||
|
if ( buf_len < 1 ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte_decode( *buf, (struct modRM_byte *)(void*)&sib ); /* get bit-fields */
|
||||||
|
|
||||||
|
if ( sib.base == SIB_BASE_EBP && ! mod ) { /* if base == 101 (ebp) */
|
||||||
|
/* IF BASE == EBP, deal with exception */
|
||||||
|
/* IF (ModR/M did not create a Disp */
|
||||||
|
/* ... create a 32-bit Displacement */
|
||||||
|
imm32_signsized( &buf[1], buf_len, &ea->disp, sizeof(int32_t));
|
||||||
|
ea->disp_size = sizeof(int32_t);
|
||||||
|
ea->disp_sign = (ea->disp < 0) ? 1 : 0;
|
||||||
|
size += 4; /* add sizeof disp to count */
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* ELSE BASE refers to a General Register */
|
||||||
|
ia32_handle_register( &ea->base, sib.base + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set scale to 1, 2, 4, 8 */
|
||||||
|
ea->scale = 1 << sib.scale;
|
||||||
|
|
||||||
|
if (sib.index != SIB_INDEX_NONE) {
|
||||||
|
/* IF INDEX is not 'ESP' (100) */
|
||||||
|
ia32_handle_register( &ea->index, sib.index + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return (size); /* return number of bytes processed */
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t modrm_decode16( unsigned char *buf, unsigned int buf_len,
|
||||||
|
x86_op_t *op, struct modRM_byte *modrm ) {
|
||||||
|
/* 16-bit mode: hackish, but not as hackish as 32-bit mode ;) */
|
||||||
|
size_t size = 1; /* # of bytes decoded [1 for modR/M byte] */
|
||||||
|
x86_ea_t * ea = &op->data.expression;
|
||||||
|
|
||||||
|
switch( modrm->rm ) {
|
||||||
|
case MOD16_RM_BXSI:
|
||||||
|
ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3);
|
||||||
|
ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6);
|
||||||
|
break;
|
||||||
|
case MOD16_RM_BXDI:
|
||||||
|
ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3);
|
||||||
|
ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7);
|
||||||
|
case MOD16_RM_BPSI:
|
||||||
|
op->flags |= op_ss_seg;
|
||||||
|
ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5);
|
||||||
|
ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6);
|
||||||
|
break;
|
||||||
|
case MOD16_RM_BPDI:
|
||||||
|
op->flags |= op_ss_seg;
|
||||||
|
ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5);
|
||||||
|
ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7);
|
||||||
|
break;
|
||||||
|
case MOD16_RM_SI:
|
||||||
|
ia32_handle_register(&ea->base, REG_WORD_OFFSET + 6);
|
||||||
|
break;
|
||||||
|
case MOD16_RM_DI:
|
||||||
|
ia32_handle_register(&ea->base, REG_WORD_OFFSET + 7);
|
||||||
|
break;
|
||||||
|
case MOD16_RM_BP:
|
||||||
|
if ( modrm->mod != MOD16_MOD_NODISP ) {
|
||||||
|
op->flags |= op_ss_seg;
|
||||||
|
ia32_handle_register(&ea->base,
|
||||||
|
REG_WORD_OFFSET + 5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MOD16_RM_BX:
|
||||||
|
ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move to byte after ModR/M */
|
||||||
|
++buf;
|
||||||
|
--buf_len;
|
||||||
|
|
||||||
|
if ( modrm->mod == MOD16_MOD_DISP8 ) {
|
||||||
|
imm32_signsized( buf, buf_len, &ea->disp, sizeof(char) );
|
||||||
|
ea->disp_sign = (ea->disp < 0) ? 1 : 0;
|
||||||
|
ea->disp_size = sizeof(char);
|
||||||
|
size += sizeof(char);
|
||||||
|
} else if ( modrm->mod == MOD16_MOD_DISP16 ) {
|
||||||
|
imm32_signsized( buf, buf_len, &ea->disp, sizeof(short) );
|
||||||
|
ea->disp_sign = (ea->disp < 0) ? 1 : 0;
|
||||||
|
ea->disp_size = sizeof(short);
|
||||||
|
size += sizeof(short);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO : Mark index modes
|
||||||
|
Use addressing mode flags to imply arrays (index), structure (disp),
|
||||||
|
two-dimensional arrays [disp + index], classes [ea reg], and so on.
|
||||||
|
*/
|
||||||
|
size_t ia32_modrm_decode( unsigned char *buf, unsigned int buf_len,
|
||||||
|
x86_op_t *op, x86_insn_t *insn, size_t gen_regs ) {
|
||||||
|
/* create address expression and/or fill operand based on value of
|
||||||
|
* ModR/M byte. Calls sib_decode as appropriate.
|
||||||
|
* flags specifies whether Reg or mod+R/M fields are being decoded
|
||||||
|
* returns the number of bytes in the instruction, including modR/M */
|
||||||
|
struct modRM_byte modrm;
|
||||||
|
size_t size = 1; /* # of bytes decoded [1 for modR/M byte] */
|
||||||
|
x86_ea_t * ea;
|
||||||
|
|
||||||
|
|
||||||
|
byte_decode(*buf, &modrm); /* get bitfields */
|
||||||
|
|
||||||
|
/* first, handle the case where the mod field is a register only */
|
||||||
|
if ( modrm.mod == MODRM_MOD_NOEA ) {
|
||||||
|
op->type = op_register;
|
||||||
|
ia32_handle_register(&op->data.reg, modrm.rm + gen_regs);
|
||||||
|
/* increase insn size by 1 for modrm byte */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* then deal with cases where there is an effective address */
|
||||||
|
ea = &op->data.expression;
|
||||||
|
op->type = op_expression;
|
||||||
|
op->flags |= op_pointer;
|
||||||
|
|
||||||
|
if ( insn->addr_size == 2 ) {
|
||||||
|
/* gah! 16 bit mode! */
|
||||||
|
return modrm_decode16( buf, buf_len, op, &modrm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move to byte after ModR/M */
|
||||||
|
++buf;
|
||||||
|
--buf_len;
|
||||||
|
|
||||||
|
if (modrm.mod == MODRM_MOD_NODISP) { /* if mod == 00 */
|
||||||
|
|
||||||
|
/* IF MOD == No displacement, just Indirect Register */
|
||||||
|
if (modrm.rm == MODRM_RM_NOREG) { /* if r/m == 101 */
|
||||||
|
/* IF RM == No Register, just Displacement */
|
||||||
|
/* This is an Intel Moronic Exception TM */
|
||||||
|
imm32_signsized( buf, buf_len, &ea->disp,
|
||||||
|
sizeof(int32_t) );
|
||||||
|
ea->disp_size = sizeof(int32_t);
|
||||||
|
ea->disp_sign = (ea->disp < 0) ? 1 : 0;
|
||||||
|
size += 4; /* add sizeof disp to count */
|
||||||
|
|
||||||
|
} else if (modrm.rm == MODRM_RM_SIB) { /* if r/m == 100 */
|
||||||
|
/* ELSE IF an SIB byte is present */
|
||||||
|
/* TODO: check for 0 retval */
|
||||||
|
size += sib_decode( buf, buf_len, ea, modrm.mod);
|
||||||
|
/* move to byte after SIB for displacement */
|
||||||
|
++buf;
|
||||||
|
--buf_len;
|
||||||
|
} else { /* modR/M specifies base register */
|
||||||
|
/* ELSE RM encodes a general register */
|
||||||
|
ia32_handle_register( &ea->base, modrm.rm + 1 );
|
||||||
|
}
|
||||||
|
} else { /* mod is 01 or 10 */
|
||||||
|
if (modrm.rm == MODRM_RM_SIB) { /* rm == 100 */
|
||||||
|
/* IF base is an AddrExpr specified by an SIB byte */
|
||||||
|
/* TODO: check for 0 retval */
|
||||||
|
size += sib_decode( buf, buf_len, ea, modrm.mod);
|
||||||
|
/* move to byte after SIB for displacement */
|
||||||
|
++buf;
|
||||||
|
--buf_len;
|
||||||
|
} else {
|
||||||
|
/* ELSE base is a general register */
|
||||||
|
ia32_handle_register( &ea->base, modrm.rm + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ELSE mod + r/m specify a disp##[base] or disp##(SIB) */
|
||||||
|
if (modrm.mod == MODRM_MOD_DISP8) { /* mod == 01 */
|
||||||
|
/* If this is an 8-bit displacement */
|
||||||
|
imm32_signsized( buf, buf_len, &ea->disp,
|
||||||
|
sizeof(char));
|
||||||
|
ea->disp_size = sizeof(char);
|
||||||
|
ea->disp_sign = (ea->disp < 0) ? 1 : 0;
|
||||||
|
size += 1; /* add sizeof disp to count */
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Displacement is dependent on address size */
|
||||||
|
imm32_signsized( buf, buf_len, &ea->disp,
|
||||||
|
insn->addr_size);
|
||||||
|
ea->disp_size = insn->addr_size;
|
||||||
|
ea->disp_sign = (ea->disp < 0) ? 1 : 0;
|
||||||
|
size += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size; /* number of bytes found in instruction */
|
||||||
|
}
|
||||||
|
|
||||||
|
void ia32_reg_decode( unsigned char byte, x86_op_t *op, size_t gen_regs ) {
|
||||||
|
struct modRM_byte modrm;
|
||||||
|
byte_decode( byte, &modrm ); /* get bitfields */
|
||||||
|
|
||||||
|
/* set operand to register ID */
|
||||||
|
op->type = op_register;
|
||||||
|
ia32_handle_register(&op->data.reg, modrm.reg + gen_regs);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
13
libdisasm/ia32_modrm.h
Normal file
13
libdisasm/ia32_modrm.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef IA32_MODRM_H
|
||||||
|
#define IA32_MODRM_H
|
||||||
|
|
||||||
|
#include "libdis.h"
|
||||||
|
#include "ia32_insn.h"
|
||||||
|
|
||||||
|
size_t ia32_modrm_decode( unsigned char *buf, unsigned int buf_len,
|
||||||
|
x86_op_t *op, x86_insn_t *insn,
|
||||||
|
size_t gen_regs );
|
||||||
|
|
||||||
|
void ia32_reg_decode( unsigned char byte, x86_op_t *op, size_t gen_regs );
|
||||||
|
|
||||||
|
#endif
|
2939
libdisasm/ia32_opcode_tables.c
Normal file
2939
libdisasm/ia32_opcode_tables.c
Normal file
File diff suppressed because it is too large
Load Diff
57
libdisasm/ia32_opcode_tables.h
Normal file
57
libdisasm/ia32_opcode_tables.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#define idx_Main 0
|
||||||
|
#define idx_66 1
|
||||||
|
#define idx_F2 2
|
||||||
|
#define idx_F3 3
|
||||||
|
#define idx_0F 4
|
||||||
|
#define idx_660F 5
|
||||||
|
#define idx_F20F 6
|
||||||
|
#define idx_F30F 7
|
||||||
|
#define idx_0F00 8
|
||||||
|
#define idx_0F01 9
|
||||||
|
#define idx_0F0111 10
|
||||||
|
#define idx_0F12 11
|
||||||
|
#define idx_0F16 12
|
||||||
|
#define idx_0F18 13
|
||||||
|
#define idx_0F71 14
|
||||||
|
#define idx_660F71 15
|
||||||
|
#define idx_0F72 16
|
||||||
|
#define idx_660F72 17
|
||||||
|
#define idx_0F73 18
|
||||||
|
#define idx_660F73 19
|
||||||
|
#define idx_0FAE 20
|
||||||
|
#define idx_0FBA 21
|
||||||
|
#define idx_0FC7 22
|
||||||
|
#define idx_0FB9 23
|
||||||
|
#define idx_C6 24
|
||||||
|
#define idx_C7 25
|
||||||
|
#define idx_80 26
|
||||||
|
#define idx_81 27
|
||||||
|
#define idx_82 28
|
||||||
|
#define idx_83 29
|
||||||
|
#define idx_C0 30
|
||||||
|
#define idx_C1 31
|
||||||
|
#define idx_D0 32
|
||||||
|
#define idx_D1 33
|
||||||
|
#define idx_D2 34
|
||||||
|
#define idx_D3 35
|
||||||
|
#define idx_F6 36
|
||||||
|
#define idx_F7 37
|
||||||
|
#define idx_FE 38
|
||||||
|
#define idx_FF 39
|
||||||
|
#define idx_D8 40
|
||||||
|
#define idx_D8C0 41
|
||||||
|
#define idx_D9 42
|
||||||
|
#define idx_D9C0 43
|
||||||
|
#define idx_DA 44
|
||||||
|
#define idx_DAC0 45
|
||||||
|
#define idx_DB 46
|
||||||
|
#define idx_DBC0 47
|
||||||
|
#define idx_DC 48
|
||||||
|
#define idx_DCC0 49
|
||||||
|
#define idx_DD 50
|
||||||
|
#define idx_DDC0 51
|
||||||
|
#define idx_DE 52
|
||||||
|
#define idx_DEC0 53
|
||||||
|
#define idx_DF 54
|
||||||
|
#define idx_DFC0 55
|
||||||
|
#define idx_0F0F 56
|
425
libdisasm/ia32_operand.c
Normal file
425
libdisasm/ia32_operand.c
Normal file
@ -0,0 +1,425 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "libdis.h"
|
||||||
|
#include "ia32_insn.h"
|
||||||
|
#include "ia32_operand.h"
|
||||||
|
#include "ia32_modrm.h"
|
||||||
|
#include "ia32_reg.h"
|
||||||
|
#include "x86_imm.h"
|
||||||
|
#include "x86_operand_list.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* apply segment override to memory operand in insn */
|
||||||
|
static void apply_seg( x86_op_t *op, unsigned int prefixes ) {
|
||||||
|
if (! prefixes ) return;
|
||||||
|
|
||||||
|
/* apply overrides from prefix */
|
||||||
|
switch ( prefixes & PREFIX_REG_MASK ) {
|
||||||
|
case PREFIX_CS:
|
||||||
|
op->flags |= op_cs_seg; break;
|
||||||
|
case PREFIX_SS:
|
||||||
|
op->flags |= op_ss_seg; break;
|
||||||
|
case PREFIX_DS:
|
||||||
|
op->flags |= op_ds_seg; break;
|
||||||
|
case PREFIX_ES:
|
||||||
|
op->flags |= op_es_seg; break;
|
||||||
|
case PREFIX_FS:
|
||||||
|
op->flags |= op_fs_seg; break;
|
||||||
|
case PREFIX_GS:
|
||||||
|
op->flags |= op_gs_seg; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t decode_operand_value( unsigned char *buf, size_t buf_len,
|
||||||
|
x86_op_t *op, x86_insn_t *insn,
|
||||||
|
unsigned int addr_meth, size_t op_size,
|
||||||
|
unsigned int op_value, unsigned char modrm,
|
||||||
|
size_t gen_regs ) {
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
/* ++ Do Operand Addressing Method / Decode operand ++ */
|
||||||
|
switch (addr_meth) {
|
||||||
|
/* This sets the operand Size based on the Intel Opcode Map
|
||||||
|
* (Vol 2, Appendix A). Letter encodings are from section
|
||||||
|
* A.1.1, 'Codes for Addressing Method' */
|
||||||
|
|
||||||
|
/* ---------------------- Addressing Method -------------- */
|
||||||
|
/* Note that decoding mod ModR/M operand adjusts the size of
|
||||||
|
* the instruction, but decoding the reg operand does not.
|
||||||
|
* This should not cause any problems, as every 'reg' operand
|
||||||
|
* has an associated 'mod' operand.
|
||||||
|
* Goddamn-Intel-Note:
|
||||||
|
* Some Intel addressing methods [M, R] specify that modR/M
|
||||||
|
* byte may only refer to a memory address/may only refer to
|
||||||
|
* a register -- however Intel provides no clues on what to do
|
||||||
|
* if, say, the modR/M for an M opcode decodes to a register
|
||||||
|
* rather than a memory address ... returning 0 is out of the
|
||||||
|
* question, as this would be an Immediate or a RelOffset, so
|
||||||
|
* instead these modR/Ms are decoded with total disregard to
|
||||||
|
* the M, R constraints. */
|
||||||
|
|
||||||
|
/* MODRM -- mod operand. sets size to at least 1! */
|
||||||
|
case ADDRMETH_E: /* ModR/M present, Gen reg or memory */
|
||||||
|
size = ia32_modrm_decode( buf, buf_len, op, insn,
|
||||||
|
gen_regs );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_M: /* ModR/M only refers to memory */
|
||||||
|
size = ia32_modrm_decode( buf, buf_len, op, insn,
|
||||||
|
gen_regs );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_Q: /* ModR/M present, MMX or Memory */
|
||||||
|
size = ia32_modrm_decode( buf, buf_len, op, insn,
|
||||||
|
REG_MMX_OFFSET );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_R: /* ModR/M mod == gen reg */
|
||||||
|
size = ia32_modrm_decode( buf, buf_len, op, insn,
|
||||||
|
gen_regs );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_W: /* ModR/M present, mem or SIMD reg */
|
||||||
|
size = ia32_modrm_decode( buf, buf_len, op, insn,
|
||||||
|
REG_SIMD_OFFSET );
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* MODRM -- reg operand. does not effect size! */
|
||||||
|
case ADDRMETH_C: /* ModR/M reg == control reg */
|
||||||
|
ia32_reg_decode( modrm, op, REG_CTRL_OFFSET );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_D: /* ModR/M reg == debug reg */
|
||||||
|
ia32_reg_decode( modrm, op, REG_DEBUG_OFFSET );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_G: /* ModR/M reg == gen-purpose reg */
|
||||||
|
ia32_reg_decode( modrm, op, gen_regs );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_P: /* ModR/M reg == qword MMX reg */
|
||||||
|
ia32_reg_decode( modrm, op, REG_MMX_OFFSET );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_S: /* ModR/M reg == segment reg */
|
||||||
|
ia32_reg_decode( modrm, op, REG_SEG_OFFSET );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_T: /* ModR/M reg == test reg */
|
||||||
|
ia32_reg_decode( modrm, op, REG_TEST_OFFSET );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_V: /* ModR/M reg == SIMD reg */
|
||||||
|
ia32_reg_decode( modrm, op, REG_SIMD_OFFSET );
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* No MODRM : note these set operand type explicitly */
|
||||||
|
case ADDRMETH_A: /* No modR/M -- direct addr */
|
||||||
|
op->type = op_absolute;
|
||||||
|
|
||||||
|
/* segment:offset address used in far calls */
|
||||||
|
x86_imm_sized( buf, buf_len,
|
||||||
|
&op->data.absolute.segment, 2 );
|
||||||
|
if ( insn->addr_size == 4 ) {
|
||||||
|
x86_imm_sized( buf, buf_len,
|
||||||
|
&op->data.absolute.offset.off32, 4 );
|
||||||
|
size = 6;
|
||||||
|
} else {
|
||||||
|
x86_imm_sized( buf, buf_len,
|
||||||
|
&op->data.absolute.offset.off16, 2 );
|
||||||
|
size = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ADDRMETH_I: /* Immediate val */
|
||||||
|
op->type = op_immediate;
|
||||||
|
/* if it ever becomes legal to have imm as dest and
|
||||||
|
* there is a src ModR/M operand, we are screwed! */
|
||||||
|
if ( op->flags & op_signed ) {
|
||||||
|
x86_imm_signsized(buf, buf_len, &op->data.byte,
|
||||||
|
op_size);
|
||||||
|
} else {
|
||||||
|
x86_imm_sized(buf, buf_len, &op->data.byte,
|
||||||
|
op_size);
|
||||||
|
}
|
||||||
|
size = op_size;
|
||||||
|
break;
|
||||||
|
case ADDRMETH_J: /* Rel offset to add to IP [jmp] */
|
||||||
|
/* this fills op->data.near_offset or
|
||||||
|
op->data.far_offset depending on the size of
|
||||||
|
the operand */
|
||||||
|
op->flags |= op_signed;
|
||||||
|
if ( op_size == 1 ) {
|
||||||
|
/* one-byte near offset */
|
||||||
|
op->type = op_relative_near;
|
||||||
|
x86_imm_signsized(buf, buf_len,
|
||||||
|
&op->data.relative_near, 1);
|
||||||
|
} else {
|
||||||
|
/* far offset...is this truly signed? */
|
||||||
|
op->type = op_relative_far;
|
||||||
|
x86_imm_signsized(buf, buf_len,
|
||||||
|
&op->data.relative_far, op_size );
|
||||||
|
}
|
||||||
|
size = op_size;
|
||||||
|
break;
|
||||||
|
case ADDRMETH_O: /* No ModR/M; op is word/dword offset */
|
||||||
|
/* NOTE: these are actually RVAs not offsets to seg!! */
|
||||||
|
/* note bene: 'O' ADDR_METH uses addr_size to
|
||||||
|
determine operand size */
|
||||||
|
op->type = op_offset;
|
||||||
|
op->flags |= op_pointer;
|
||||||
|
x86_imm_sized( buf, buf_len, &op->data.offset,
|
||||||
|
insn->addr_size );
|
||||||
|
|
||||||
|
size = insn->addr_size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Hard-coded: these are specified in the insn definition */
|
||||||
|
case ADDRMETH_F: /* EFLAGS register */
|
||||||
|
op->type = op_register;
|
||||||
|
op->flags |= op_hardcode;
|
||||||
|
ia32_handle_register( &op->data.reg, REG_FLAGS_INDEX );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_X: /* Memory addressed by DS:SI [string] */
|
||||||
|
op->type = op_expression;
|
||||||
|
op->flags |= op_hardcode;
|
||||||
|
op->flags |= op_ds_seg | op_pointer | op_string;
|
||||||
|
ia32_handle_register( &op->data.expression.base,
|
||||||
|
REG_DWORD_OFFSET + 6 );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_Y: /* Memory addressed by ES:DI [string] */
|
||||||
|
op->type = op_expression;
|
||||||
|
op->flags |= op_hardcode;
|
||||||
|
op->flags |= op_es_seg | op_pointer | op_string;
|
||||||
|
ia32_handle_register( &op->data.expression.base,
|
||||||
|
REG_DWORD_OFFSET + 7 );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_RR: /* Gen Register hard-coded in opcode */
|
||||||
|
op->type = op_register;
|
||||||
|
op->flags |= op_hardcode;
|
||||||
|
ia32_handle_register( &op->data.reg,
|
||||||
|
op_value + gen_regs );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_RS: /* Seg Register hard-coded in opcode */
|
||||||
|
op->type = op_register;
|
||||||
|
op->flags |= op_hardcode;
|
||||||
|
ia32_handle_register( &op->data.reg,
|
||||||
|
op_value + REG_SEG_OFFSET );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_RF: /* FPU Register hard-coded in opcode */
|
||||||
|
op->type = op_register;
|
||||||
|
op->flags |= op_hardcode;
|
||||||
|
ia32_handle_register( &op->data.reg,
|
||||||
|
op_value + REG_FPU_OFFSET );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_RT: /* TST Register hard-coded in opcode */
|
||||||
|
op->type = op_register;
|
||||||
|
op->flags |= op_hardcode;
|
||||||
|
ia32_handle_register( &op->data.reg,
|
||||||
|
op_value + REG_TEST_OFFSET );
|
||||||
|
break;
|
||||||
|
case ADDRMETH_II: /* Immediate hard-coded in opcode */
|
||||||
|
op->type = op_immediate;
|
||||||
|
op->data.dword = op_value;
|
||||||
|
op->flags |= op_hardcode;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0: /* Operand is not used */
|
||||||
|
default:
|
||||||
|
/* ignore -- operand not used in this insn */
|
||||||
|
op->type = op_unused; /* this shouldn't happen! */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t decode_operand_size( unsigned int op_type, x86_insn_t *insn,
|
||||||
|
x86_op_t *op ){
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
/* ++ Do Operand Type ++ */
|
||||||
|
switch (op_type) {
|
||||||
|
/* This sets the operand Size based on the Intel Opcode Map
|
||||||
|
* (Vol 2, Appendix A). Letter encodings are from section
|
||||||
|
* A.1.2, 'Codes for Operand Type' */
|
||||||
|
/* NOTE: in this routines, 'size' refers to the size
|
||||||
|
* of the operand in the raw (encoded) instruction;
|
||||||
|
* 'datatype' stores the actual size and datatype
|
||||||
|
* of the operand */
|
||||||
|
|
||||||
|
/* ------------------------ Operand Type ----------------- */
|
||||||
|
case OPTYPE_c: /* byte or word [op size attr] */
|
||||||
|
size = (insn->op_size == 4) ? 2 : 1;
|
||||||
|
op->datatype = (size == 4) ? op_word : op_byte;
|
||||||
|
break;
|
||||||
|
case OPTYPE_a: /* 2 word or 2 dword [op size attr] */
|
||||||
|
/* pointer to a 16:16 or 32:32 BOUNDS operand */
|
||||||
|
size = (insn->op_size == 4) ? 8 : 4;
|
||||||
|
op->datatype = (size == 4) ? op_bounds32 : op_bounds16;
|
||||||
|
break;
|
||||||
|
case OPTYPE_v: /* word or dword [op size attr] */
|
||||||
|
size = (insn->op_size == 4) ? 4 : 2;
|
||||||
|
op->datatype = (size == 4) ? op_dword : op_word;
|
||||||
|
break;
|
||||||
|
case OPTYPE_p: /* 32/48-bit ptr [op size attr] */
|
||||||
|
/* technically these flags are not accurate: the
|
||||||
|
* value s a 16:16 pointer or a 16:32 pointer, where
|
||||||
|
* the first '16' is a segment */
|
||||||
|
size = (insn->addr_size == 4) ? 6 : 4;
|
||||||
|
op->datatype = (size == 4) ? op_descr32 : op_descr16;
|
||||||
|
break;
|
||||||
|
case OPTYPE_b: /* byte, ignore op-size */
|
||||||
|
size = 1;
|
||||||
|
op->datatype = op_byte;
|
||||||
|
break;
|
||||||
|
case OPTYPE_w: /* word, ignore op-size */
|
||||||
|
size = 2;
|
||||||
|
op->datatype = op_word;
|
||||||
|
break;
|
||||||
|
case OPTYPE_d: /* dword , ignore op-size */
|
||||||
|
size = 4;
|
||||||
|
op->datatype = op_dword;
|
||||||
|
break;
|
||||||
|
case OPTYPE_s: /* 6-byte psuedo-descriptor */
|
||||||
|
/* ptr to 6-byte value which is 32:16 in 32-bit
|
||||||
|
* mode, or 8:24:16 in 16-bit mode. The high byte
|
||||||
|
* is ignored in 16-bit mode. */
|
||||||
|
size = 6;
|
||||||
|
op->datatype = (insn->addr_size == 4) ?
|
||||||
|
op_pdescr32 : op_pdescr16;
|
||||||
|
break;
|
||||||
|
case OPTYPE_q: /* qword, ignore op-size */
|
||||||
|
size = 8;
|
||||||
|
op->datatype = op_qword;
|
||||||
|
break;
|
||||||
|
case OPTYPE_dq: /* d-qword, ignore op-size */
|
||||||
|
size = 16;
|
||||||
|
op->datatype = op_dqword;
|
||||||
|
break;
|
||||||
|
case OPTYPE_ps: /* 128-bit FP data */
|
||||||
|
size = 16;
|
||||||
|
/* really this is 4 packed SP FP values */
|
||||||
|
op->datatype = op_ssimd;
|
||||||
|
break;
|
||||||
|
case OPTYPE_pd: /* 128-bit FP data */
|
||||||
|
size = 16;
|
||||||
|
/* really this is 2 packed DP FP values */
|
||||||
|
op->datatype = op_dsimd;
|
||||||
|
break;
|
||||||
|
case OPTYPE_ss: /* Scalar elem of 128-bit FP data */
|
||||||
|
size = 16;
|
||||||
|
/* this only looks at the low dword (4 bytes)
|
||||||
|
* of the xmmm register passed as a param.
|
||||||
|
* This is a 16-byte register where only 4 bytes
|
||||||
|
* are used in the insn. Painful, ain't it? */
|
||||||
|
op->datatype = op_sssimd;
|
||||||
|
break;
|
||||||
|
case OPTYPE_sd: /* Scalar elem of 128-bit FP data */
|
||||||
|
size = 16;
|
||||||
|
/* this only looks at the low qword (8 bytes)
|
||||||
|
* of the xmmm register passed as a param.
|
||||||
|
* This is a 16-byte register where only 8 bytes
|
||||||
|
* are used in the insn. Painful, again... */
|
||||||
|
op->datatype = op_sdsimd;
|
||||||
|
break;
|
||||||
|
case OPTYPE_pi: /* qword mmx register */
|
||||||
|
size = 8;
|
||||||
|
op->datatype = op_qword;
|
||||||
|
break;
|
||||||
|
case OPTYPE_si: /* dword integer register */
|
||||||
|
size = 4;
|
||||||
|
op->datatype = op_dword;
|
||||||
|
break;
|
||||||
|
case OPTYPE_fs: /* single-real */
|
||||||
|
size = 4;
|
||||||
|
op->datatype = op_sreal;
|
||||||
|
break;
|
||||||
|
case OPTYPE_fd: /* double real */
|
||||||
|
size = 8;
|
||||||
|
op->datatype = op_dreal;
|
||||||
|
break;
|
||||||
|
case OPTYPE_fe: /* extended real */
|
||||||
|
size = 10;
|
||||||
|
op->datatype = op_extreal;
|
||||||
|
break;
|
||||||
|
case OPTYPE_fb: /* packed BCD */
|
||||||
|
size = 10;
|
||||||
|
op->datatype = op_bcd;
|
||||||
|
break;
|
||||||
|
case OPTYPE_fv: /* pointer to FPU env: 14 or 28-bytes */
|
||||||
|
size = (insn->addr_size == 4)? 28 : 14;
|
||||||
|
op->datatype = (size == 28)? op_fpuenv32: op_fpuenv16;
|
||||||
|
break;
|
||||||
|
case OPTYPE_ft: /* pointer to FPU env: 94 or 108 bytes */
|
||||||
|
size = (insn->addr_size == 4)? 108 : 94;
|
||||||
|
op->datatype = (size == 108)?
|
||||||
|
op_fpustate32: op_fpustate16;
|
||||||
|
break;
|
||||||
|
case OPTYPE_fx: /* 512-byte register stack */
|
||||||
|
size = 512;
|
||||||
|
op->datatype = op_fpregset;
|
||||||
|
break;
|
||||||
|
case OPTYPE_fp: /* floating point register */
|
||||||
|
size = 10; /* double extended precision */
|
||||||
|
op->datatype = op_fpreg;
|
||||||
|
break;
|
||||||
|
case OPTYPE_m: /* fake operand type used for "lea Gv, M" */
|
||||||
|
size = insn->addr_size;
|
||||||
|
op->datatype = (size == 4) ? op_dword : op_word;
|
||||||
|
break;
|
||||||
|
case OPTYPE_none: /* handle weird instructions that have no encoding but use a dword datatype, like invlpg */
|
||||||
|
size = 0;
|
||||||
|
op->datatype = op_none;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
size = insn->op_size;
|
||||||
|
op->datatype = (size == 4) ? op_dword : op_word;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ia32_decode_operand( unsigned char *buf, size_t buf_len,
|
||||||
|
x86_insn_t *insn, unsigned int raw_op,
|
||||||
|
unsigned int raw_flags, unsigned int prefixes,
|
||||||
|
unsigned char modrm ) {
|
||||||
|
unsigned int addr_meth, op_type, op_size, gen_regs;
|
||||||
|
x86_op_t *op;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
/* ++ Yank optype and addr mode out of operand flags */
|
||||||
|
addr_meth = raw_flags & ADDRMETH_MASK;
|
||||||
|
op_type = raw_flags & OPTYPE_MASK;
|
||||||
|
|
||||||
|
if ( raw_flags == ARG_NONE ) {
|
||||||
|
/* operand is not used in this instruction */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate a new operand */
|
||||||
|
op = x86_operand_new( insn );
|
||||||
|
|
||||||
|
/* ++ Copy flags from opcode table to x86_insn_t */
|
||||||
|
op->access = (enum x86_op_access) OP_PERM(raw_flags);
|
||||||
|
op->flags = (enum x86_op_flags) (OP_FLAGS(raw_flags) >> 12);
|
||||||
|
|
||||||
|
/* Get size (for decoding) and datatype of operand */
|
||||||
|
op_size = decode_operand_size(op_type, insn, op);
|
||||||
|
|
||||||
|
/* override default register set based on Operand Type */
|
||||||
|
/* this allows mixing of 8, 16, and 32 bit regs in insn */
|
||||||
|
if (op_size == 1) {
|
||||||
|
gen_regs = REG_BYTE_OFFSET;
|
||||||
|
} else if (op_size == 2) {
|
||||||
|
gen_regs = REG_WORD_OFFSET;
|
||||||
|
} else {
|
||||||
|
gen_regs = REG_DWORD_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = decode_operand_value( buf, buf_len, op, insn, addr_meth,
|
||||||
|
op_size, raw_op, modrm, gen_regs );
|
||||||
|
|
||||||
|
/* if operand is an address, apply any segment override prefixes */
|
||||||
|
if ( op->type == op_expression || op->type == op_offset ) {
|
||||||
|
apply_seg(op, prefixes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size; /* return number of bytes in instruction */
|
||||||
|
}
|
11
libdisasm/ia32_operand.h
Normal file
11
libdisasm/ia32_operand.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef IA32_OPERAND_H
|
||||||
|
#define IA32_OPERAND_H
|
||||||
|
|
||||||
|
#include "libdis.h"
|
||||||
|
#include "ia32_insn.h"
|
||||||
|
|
||||||
|
size_t ia32_decode_operand( unsigned char *buf, size_t buf_len,
|
||||||
|
x86_insn_t *insn, unsigned int raw_op,
|
||||||
|
unsigned int raw_flags, unsigned int prefixes,
|
||||||
|
unsigned char modrm );
|
||||||
|
#endif
|
234
libdisasm/ia32_reg.c
Normal file
234
libdisasm/ia32_reg.c
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ia32_reg.h"
|
||||||
|
#include "ia32_insn.h"
|
||||||
|
|
||||||
|
#define NUM_X86_REGS 92
|
||||||
|
|
||||||
|
/* register sizes */
|
||||||
|
#define REG_DWORD_SIZE 4
|
||||||
|
#define REG_WORD_SIZE 2
|
||||||
|
#define REG_BYTE_SIZE 1
|
||||||
|
#define REG_MMX_SIZE 8
|
||||||
|
#define REG_SIMD_SIZE 16
|
||||||
|
#define REG_DEBUG_SIZE 4
|
||||||
|
#define REG_CTRL_SIZE 4
|
||||||
|
#define REG_TEST_SIZE 4
|
||||||
|
#define REG_SEG_SIZE 2
|
||||||
|
#define REG_FPU_SIZE 10
|
||||||
|
#define REG_FLAGS_SIZE 4
|
||||||
|
#define REG_FPCTRL_SIZE 2
|
||||||
|
#define REG_FPSTATUS_SIZE 2
|
||||||
|
#define REG_FPTAG_SIZE 2
|
||||||
|
#define REG_EIP_SIZE 4
|
||||||
|
#define REG_IP_SIZE 2
|
||||||
|
|
||||||
|
/* REGISTER ALIAS TABLE:
|
||||||
|
*
|
||||||
|
* NOTE: the MMX register mapping is fixed to the physical registers
|
||||||
|
* used by the FPU. The floating FP stack does not effect the location
|
||||||
|
* of the MMX registers, so this aliasing is not 100% accurate.
|
||||||
|
* */
|
||||||
|
static struct {
|
||||||
|
unsigned char alias; /* id of register this is an alias for */
|
||||||
|
unsigned char shift; /* # of bits register must be shifted */
|
||||||
|
} ia32_reg_aliases[] = {
|
||||||
|
{ 0,0 },
|
||||||
|
{ REG_DWORD_OFFSET, 0 }, /* al : 1 */
|
||||||
|
{ REG_DWORD_OFFSET, 8 }, /* ah : 2 */
|
||||||
|
{ REG_DWORD_OFFSET, 0 }, /* ax : 3 */
|
||||||
|
{ REG_DWORD_OFFSET + 1, 0 }, /* cl : 4 */
|
||||||
|
{ REG_DWORD_OFFSET + 1, 8 }, /* ch : 5 */
|
||||||
|
{ REG_DWORD_OFFSET + 1, 0 }, /* cx : 6 */
|
||||||
|
{ REG_DWORD_OFFSET + 2, 0 }, /* dl : 7 */
|
||||||
|
{ REG_DWORD_OFFSET + 2, 8 }, /* dh : 8 */
|
||||||
|
{ REG_DWORD_OFFSET + 2, 0 }, /* dx : 9 */
|
||||||
|
{ REG_DWORD_OFFSET + 3, 0 }, /* bl : 10 */
|
||||||
|
{ REG_DWORD_OFFSET + 3, 8 }, /* bh : 11 */
|
||||||
|
{ REG_DWORD_OFFSET + 3, 0 }, /* bx : 12 */
|
||||||
|
{ REG_DWORD_OFFSET + 4, 0 }, /* sp : 13 */
|
||||||
|
{ REG_DWORD_OFFSET + 5, 0 }, /* bp : 14 */
|
||||||
|
{ REG_DWORD_OFFSET + 6, 0 }, /* si : 15 */
|
||||||
|
{ REG_DWORD_OFFSET + 7, 0 }, /* di : 16 */
|
||||||
|
{ REG_EIP_INDEX, 0 }, /* ip : 17 */
|
||||||
|
{ REG_FPU_OFFSET, 0 }, /* mm0 : 18 */
|
||||||
|
{ REG_FPU_OFFSET + 1, 0 }, /* mm1 : 19 */
|
||||||
|
{ REG_FPU_OFFSET + 2, 0 }, /* mm2 : 20 */
|
||||||
|
{ REG_FPU_OFFSET + 3, 0 }, /* mm3 : 21 */
|
||||||
|
{ REG_FPU_OFFSET + 4, 0 }, /* mm4 : 22 */
|
||||||
|
{ REG_FPU_OFFSET + 5, 0 }, /* mm5 : 23 */
|
||||||
|
{ REG_FPU_OFFSET + 6, 0 }, /* mm6 : 24 */
|
||||||
|
{ REG_FPU_OFFSET + 7, 0 } /* mm7 : 25 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* REGISTER TABLE: size, type, and name of every register in the
|
||||||
|
* CPU. Does not include MSRs since the are, after all,
|
||||||
|
* model specific. */
|
||||||
|
static struct {
|
||||||
|
unsigned int size;
|
||||||
|
enum x86_reg_type type;
|
||||||
|
unsigned int alias;
|
||||||
|
char mnemonic[8];
|
||||||
|
} ia32_reg_table[NUM_X86_REGS + 2] = {
|
||||||
|
{ 0, 0, 0, "" },
|
||||||
|
/* REG_DWORD_OFFSET */
|
||||||
|
{ REG_DWORD_SIZE, reg_gen | reg_ret, 0, "eax" },
|
||||||
|
{ REG_DWORD_SIZE, reg_gen | reg_count, 0, "ecx" },
|
||||||
|
{ REG_DWORD_SIZE, reg_gen, 0, "edx" },
|
||||||
|
{ REG_DWORD_SIZE, reg_gen, 0, "ebx" },
|
||||||
|
/* REG_ESP_INDEX */
|
||||||
|
{ REG_DWORD_SIZE, reg_gen | reg_sp, 0, "esp" },
|
||||||
|
{ REG_DWORD_SIZE, reg_gen | reg_fp, 0, "ebp" },
|
||||||
|
{ REG_DWORD_SIZE, reg_gen | reg_src, 0, "esi" },
|
||||||
|
{ REG_DWORD_SIZE, reg_gen | reg_dest, 0, "edi" },
|
||||||
|
/* REG_WORD_OFFSET */
|
||||||
|
{ REG_WORD_SIZE, reg_gen | reg_ret, 3, "ax" },
|
||||||
|
{ REG_WORD_SIZE, reg_gen | reg_count, 6, "cx" },
|
||||||
|
{ REG_WORD_SIZE, reg_gen, 9, "dx" },
|
||||||
|
{ REG_WORD_SIZE, reg_gen, 12, "bx" },
|
||||||
|
{ REG_WORD_SIZE, reg_gen | reg_sp, 13, "sp" },
|
||||||
|
{ REG_WORD_SIZE, reg_gen | reg_fp, 14, "bp" },
|
||||||
|
{ REG_WORD_SIZE, reg_gen | reg_src, 15, "si" },
|
||||||
|
{ REG_WORD_SIZE, reg_gen | reg_dest, 16, "di" },
|
||||||
|
/* REG_BYTE_OFFSET */
|
||||||
|
{ REG_BYTE_SIZE, reg_gen, 1, "al" },
|
||||||
|
{ REG_BYTE_SIZE, reg_gen, 4, "cl" },
|
||||||
|
{ REG_BYTE_SIZE, reg_gen, 7, "dl" },
|
||||||
|
{ REG_BYTE_SIZE, reg_gen, 10, "bl" },
|
||||||
|
{ REG_BYTE_SIZE, reg_gen, 2, "ah" },
|
||||||
|
{ REG_BYTE_SIZE, reg_gen, 5, "ch" },
|
||||||
|
{ REG_BYTE_SIZE, reg_gen, 8, "dh" },
|
||||||
|
{ REG_BYTE_SIZE, reg_gen, 11, "bh" },
|
||||||
|
/* REG_MMX_OFFSET */
|
||||||
|
{ REG_MMX_SIZE, reg_simd, 18, "mm0" },
|
||||||
|
{ REG_MMX_SIZE, reg_simd, 19, "mm1" },
|
||||||
|
{ REG_MMX_SIZE, reg_simd, 20, "mm2" },
|
||||||
|
{ REG_MMX_SIZE, reg_simd, 21, "mm3" },
|
||||||
|
{ REG_MMX_SIZE, reg_simd, 22, "mm4" },
|
||||||
|
{ REG_MMX_SIZE, reg_simd, 23, "mm5" },
|
||||||
|
{ REG_MMX_SIZE, reg_simd, 24, "mm6" },
|
||||||
|
{ REG_MMX_SIZE, reg_simd, 25, "mm7" },
|
||||||
|
/* REG_SIMD_OFFSET */
|
||||||
|
{ REG_SIMD_SIZE, reg_simd, 0, "xmm0" },
|
||||||
|
{ REG_SIMD_SIZE, reg_simd, 0, "xmm1" },
|
||||||
|
{ REG_SIMD_SIZE, reg_simd, 0, "xmm2" },
|
||||||
|
{ REG_SIMD_SIZE, reg_simd, 0, "xmm3" },
|
||||||
|
{ REG_SIMD_SIZE, reg_simd, 0, "xmm4" },
|
||||||
|
{ REG_SIMD_SIZE, reg_simd, 0, "xmm5" },
|
||||||
|
{ REG_SIMD_SIZE, reg_simd, 0, "xmm6" },
|
||||||
|
{ REG_SIMD_SIZE, reg_simd, 0, "xmm7" },
|
||||||
|
/* REG_DEBUG_OFFSET */
|
||||||
|
{ REG_DEBUG_SIZE, reg_sys, 0, "dr0" },
|
||||||
|
{ REG_DEBUG_SIZE, reg_sys, 0, "dr1" },
|
||||||
|
{ REG_DEBUG_SIZE, reg_sys, 0, "dr2" },
|
||||||
|
{ REG_DEBUG_SIZE, reg_sys, 0, "dr3" },
|
||||||
|
{ REG_DEBUG_SIZE, reg_sys, 0, "dr4" },
|
||||||
|
{ REG_DEBUG_SIZE, reg_sys, 0, "dr5" },
|
||||||
|
{ REG_DEBUG_SIZE, reg_sys, 0, "dr6" },
|
||||||
|
{ REG_DEBUG_SIZE, reg_sys, 0, "dr7" },
|
||||||
|
/* REG_CTRL_OFFSET */
|
||||||
|
{ REG_CTRL_SIZE, reg_sys, 0, "cr0" },
|
||||||
|
{ REG_CTRL_SIZE, reg_sys, 0, "cr1" },
|
||||||
|
{ REG_CTRL_SIZE, reg_sys, 0, "cr2" },
|
||||||
|
{ REG_CTRL_SIZE, reg_sys, 0, "cr3" },
|
||||||
|
{ REG_CTRL_SIZE, reg_sys, 0, "cr4" },
|
||||||
|
{ REG_CTRL_SIZE, reg_sys, 0, "cr5" },
|
||||||
|
{ REG_CTRL_SIZE, reg_sys, 0, "cr6" },
|
||||||
|
{ REG_CTRL_SIZE, reg_sys, 0, "cr7" },
|
||||||
|
/* REG_TEST_OFFSET */
|
||||||
|
{ REG_TEST_SIZE, reg_sys, 0, "tr0" },
|
||||||
|
{ REG_TEST_SIZE, reg_sys, 0, "tr1" },
|
||||||
|
{ REG_TEST_SIZE, reg_sys, 0, "tr2" },
|
||||||
|
{ REG_TEST_SIZE, reg_sys, 0, "tr3" },
|
||||||
|
{ REG_TEST_SIZE, reg_sys, 0, "tr4" },
|
||||||
|
{ REG_TEST_SIZE, reg_sys, 0, "tr5" },
|
||||||
|
{ REG_TEST_SIZE, reg_sys, 0, "tr6" },
|
||||||
|
{ REG_TEST_SIZE, reg_sys, 0, "tr7" },
|
||||||
|
/* REG_SEG_OFFSET */
|
||||||
|
{ REG_SEG_SIZE, reg_seg, 0, "es" },
|
||||||
|
{ REG_SEG_SIZE, reg_seg, 0, "cs" },
|
||||||
|
{ REG_SEG_SIZE, reg_seg, 0, "ss" },
|
||||||
|
{ REG_SEG_SIZE, reg_seg, 0, "ds" },
|
||||||
|
{ REG_SEG_SIZE, reg_seg, 0, "fs" },
|
||||||
|
{ REG_SEG_SIZE, reg_seg, 0, "gs" },
|
||||||
|
/* REG_LDTR_INDEX */
|
||||||
|
{ REG_DWORD_SIZE, reg_sys, 0, "ldtr" },
|
||||||
|
/* REG_GDTR_INDEX */
|
||||||
|
{ REG_DWORD_SIZE, reg_sys, 0, "gdtr" },
|
||||||
|
/* REG_FPU_OFFSET */
|
||||||
|
{ REG_FPU_SIZE, reg_fpu, 0, "st(0)" },
|
||||||
|
{ REG_FPU_SIZE, reg_fpu, 0, "st(1)" },
|
||||||
|
{ REG_FPU_SIZE, reg_fpu, 0, "st(2)" },
|
||||||
|
{ REG_FPU_SIZE, reg_fpu, 0, "st(3)" },
|
||||||
|
{ REG_FPU_SIZE, reg_fpu, 0, "st(4)" },
|
||||||
|
{ REG_FPU_SIZE, reg_fpu, 0, "st(5)" },
|
||||||
|
{ REG_FPU_SIZE, reg_fpu, 0, "st(6)" },
|
||||||
|
{ REG_FPU_SIZE, reg_fpu, 0, "st(7)" },
|
||||||
|
/* REG_FLAGS_INDEX : 81 */
|
||||||
|
{ REG_FLAGS_SIZE, reg_cond, 0, "eflags" },
|
||||||
|
/* REG_FPCTRL_INDEX : 82*/
|
||||||
|
{ REG_FPCTRL_SIZE, reg_fpu | reg_sys, 0, "fpctrl" },
|
||||||
|
/* REG_FPSTATUS_INDEX : 83*/
|
||||||
|
{ REG_FPSTATUS_SIZE, reg_fpu | reg_sys, 0, "fpstat" },
|
||||||
|
/* REG_FPTAG_INDEX : 84 */
|
||||||
|
{ REG_FPTAG_SIZE, reg_fpu | reg_sys, 0, "fptag" },
|
||||||
|
/* REG_EIP_INDEX : 85 */
|
||||||
|
{ REG_EIP_SIZE, reg_pc, 0, "eip" },
|
||||||
|
/* REG_IP_INDEX : 86 */
|
||||||
|
{ REG_IP_SIZE, reg_pc, 17, "ip" },
|
||||||
|
/* REG_IDTR_INDEX : 87 */
|
||||||
|
{ REG_DWORD_SIZE, reg_sys, 0, "idtr" },
|
||||||
|
/* REG_MXCSG_INDEX : SSE Control Reg : 88 */
|
||||||
|
{ REG_DWORD_SIZE, reg_sys | reg_simd, 0, "mxcsr" },
|
||||||
|
/* REG_TR_INDEX : Task Register : 89 */
|
||||||
|
{ 16 + 64, reg_sys, 0, "tr" },
|
||||||
|
/* REG_CSMSR_INDEX : SYSENTER_CS_MSR : 90 */
|
||||||
|
{ REG_DWORD_SIZE, reg_sys, 0, "cs_msr" },
|
||||||
|
/* REG_ESPMSR_INDEX : SYSENTER_ESP_MSR : 91 */
|
||||||
|
{ REG_DWORD_SIZE, reg_sys, 0, "esp_msr" },
|
||||||
|
/* REG_EIPMSR_INDEX : SYSENTER_EIP_MSR : 92 */
|
||||||
|
{ REG_DWORD_SIZE, reg_sys, 0, "eip_msr" },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static size_t sz_regtable = NUM_X86_REGS + 1;
|
||||||
|
|
||||||
|
|
||||||
|
void ia32_handle_register( x86_reg_t *reg, size_t id ) {
|
||||||
|
unsigned int alias;
|
||||||
|
if (! id || id > sz_regtable ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset( reg, 0, sizeof(x86_reg_t) );
|
||||||
|
|
||||||
|
strncpy( reg->name, ia32_reg_table[id].mnemonic, MAX_REGNAME );
|
||||||
|
|
||||||
|
reg->type = ia32_reg_table[id].type;
|
||||||
|
reg->size = ia32_reg_table[id].size;
|
||||||
|
|
||||||
|
alias = ia32_reg_table[id].alias;
|
||||||
|
if ( alias ) {
|
||||||
|
reg->alias = ia32_reg_aliases[alias].alias;
|
||||||
|
reg->shift = ia32_reg_aliases[alias].shift;
|
||||||
|
}
|
||||||
|
reg->id = id;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ia32_true_register_id( size_t id ) {
|
||||||
|
size_t reg;
|
||||||
|
|
||||||
|
if (! id || id > sz_regtable ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = id;
|
||||||
|
if (ia32_reg_table[reg].alias) {
|
||||||
|
reg = ia32_reg_aliases[ia32_reg_table[reg].alias].alias;
|
||||||
|
}
|
||||||
|
return reg;
|
||||||
|
}
|
41
libdisasm/ia32_reg.h
Normal file
41
libdisasm/ia32_reg.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef IA32_REG_H
|
||||||
|
#define IA32_REG_H
|
||||||
|
|
||||||
|
#include <sys/types.h> /* for size_t */
|
||||||
|
#include "libdis.h" /* for x86_reg_t */
|
||||||
|
|
||||||
|
/* NOTE these are used in opcode tables for hard-coded registers */
|
||||||
|
#define REG_DWORD_OFFSET 1 /* 0 + 1 */
|
||||||
|
#define REG_ECX_INDEX 2 /* 0 + 1 + 1 */
|
||||||
|
#define REG_ESP_INDEX 5 /* 0 + 4 + 1 */
|
||||||
|
#define REG_EBP_INDEX 6 /* 0 + 5 + 1 */
|
||||||
|
#define REG_ESI_INDEX 7 /* 0 + 6 + 1 */
|
||||||
|
#define REG_EDI_INDEX 8 /* 0 + 7 + 1 */
|
||||||
|
#define REG_WORD_OFFSET 9 /* 1 * 8 + 1 */
|
||||||
|
#define REG_BYTE_OFFSET 17 /* 2 * 8 + 1 */
|
||||||
|
#define REG_MMX_OFFSET 25 /* 3 * 8 + 1 */
|
||||||
|
#define REG_SIMD_OFFSET 33 /* 4 * 8 + 1 */
|
||||||
|
#define REG_DEBUG_OFFSET 41 /* 5 * 8 + 1 */
|
||||||
|
#define REG_CTRL_OFFSET 49 /* 6 * 8 + 1 */
|
||||||
|
#define REG_TEST_OFFSET 57 /* 7 * 8 + 1 */
|
||||||
|
#define REG_SEG_OFFSET 65 /* 8 * 8 + 1 */
|
||||||
|
#define REG_LDTR_INDEX 71 /* 8 * 8 + 1 + 1 */
|
||||||
|
#define REG_GDTR_INDEX 72 /* 8 * 8 + 2 + 1 */
|
||||||
|
#define REG_FPU_OFFSET 73 /* 9 * 8 + 1 */
|
||||||
|
#define REG_FLAGS_INDEX 81 /* 10 * 8 + 1 */
|
||||||
|
#define REG_FPCTRL_INDEX 82 /* 10 * 8 + 1 + 1 */
|
||||||
|
#define REG_FPSTATUS_INDEX 83 /* 10 * 8 + 2 + 1 */
|
||||||
|
#define REG_FPTAG_INDEX 84 /* 10 * 8 + 3 + 1 */
|
||||||
|
#define REG_EIP_INDEX 85 /* 10 * 8 + 4 + 1 */
|
||||||
|
#define REG_IP_INDEX 86 /* 10 * 8 + 5 + 1 */
|
||||||
|
#define REG_IDTR_INDEX 87 /* 10 * 8 + 6 + 1 */
|
||||||
|
#define REG_MXCSG_INDEX 88 /* 10 * 8 + 7 + 1 */
|
||||||
|
#define REG_TR_INDEX 89 /* 10 * 8 + 8 + 1 */
|
||||||
|
#define REG_CSMSR_INDEX 90 /* 10 * 8 + 9 + 1 */
|
||||||
|
#define REG_ESPMSR_INDEX 91 /* 10 * 8 + 10 + 1 */
|
||||||
|
#define REG_EIPMSR_INDEX 92 /* 10 * 8 + 11 + 1 */
|
||||||
|
|
||||||
|
void ia32_handle_register( x86_reg_t *reg, size_t id );
|
||||||
|
size_t ia32_true_register_id( size_t id );
|
||||||
|
|
||||||
|
#endif
|
13
libdisasm/ia32_settings.c
Normal file
13
libdisasm/ia32_settings.c
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include "libdis.h"
|
||||||
|
#include "ia32_settings.h"
|
||||||
|
#include "ia32_reg.h"
|
||||||
|
#include "ia32_insn.h"
|
||||||
|
|
||||||
|
ia32_settings_t ia32_settings = {
|
||||||
|
1, 0xF4,
|
||||||
|
MAX_INSTRUCTION_SIZE,
|
||||||
|
4, 4, 8, 4, 8,
|
||||||
|
REG_ESP_INDEX, REG_EBP_INDEX, REG_EIP_INDEX, REG_FLAGS_INDEX,
|
||||||
|
REG_DWORD_OFFSET, REG_SEG_OFFSET, REG_FPU_OFFSET,
|
||||||
|
opt_none
|
||||||
|
};
|
27
libdisasm/ia32_settings.h
Normal file
27
libdisasm/ia32_settings.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef IA32_SETTINGS_H
|
||||||
|
#define IA32_SETTINGS_H
|
||||||
|
|
||||||
|
#include "libdis.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* options */
|
||||||
|
unsigned char endian, /* 0 = big, 1 = little */
|
||||||
|
wc_byte, /* wildcard byte */
|
||||||
|
max_insn, /* max insn size */
|
||||||
|
sz_addr, /* default address size */
|
||||||
|
sz_oper, /* default operand size */
|
||||||
|
sz_byte, /* # bits in byte */
|
||||||
|
sz_word, /* # bytes in machine word */
|
||||||
|
sz_dword; /* # bytes in machine dword */
|
||||||
|
unsigned int id_sp_reg, /* id of stack pointer */
|
||||||
|
id_fp_reg, /* id of frame pointer */
|
||||||
|
id_ip_reg, /* id of instruction pointer */
|
||||||
|
id_flag_reg, /* id of flags register */
|
||||||
|
offset_gen_regs, /* start of general regs */
|
||||||
|
offset_seg_regs, /* start of segment regs */
|
||||||
|
offset_fpu_regs; /* start of floating point regs */
|
||||||
|
/* user-controlled settings */
|
||||||
|
enum x86_options options;
|
||||||
|
} ia32_settings_t;
|
||||||
|
|
||||||
|
#endif
|
836
libdisasm/libdis.h
Normal file
836
libdisasm/libdis.h
Normal file
@ -0,0 +1,836 @@
|
|||||||
|
#ifndef LIBDISASM_H
|
||||||
|
#define LIBDISASM_H
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* 'NEW" types
|
||||||
|
* __________________________________________________________________________*/
|
||||||
|
#ifndef LIBDISASM_QWORD_H /* do not interfere with qword.h */
|
||||||
|
#define LIBDISASM_QWORD_H
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef __int64 qword_t;
|
||||||
|
#else
|
||||||
|
typedef int64_t qword_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 'NEW" x86 API
|
||||||
|
* __________________________________________________________________________*/
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================================= Error Reporting */
|
||||||
|
/* REPORT CODES
|
||||||
|
* These are passed to a reporter function passed at initialization.
|
||||||
|
* Each code determines the type of the argument passed to the reporter;
|
||||||
|
* this allows the report to recover from errors, or just log them.
|
||||||
|
*/
|
||||||
|
enum x86_report_codes {
|
||||||
|
report_disasm_bounds, /* RVA OUT OF BOUNDS : The disassembler could
|
||||||
|
not disassemble the supplied RVA as it is
|
||||||
|
out of the range of the buffer. The
|
||||||
|
application should store the address and
|
||||||
|
attempt to determine what section of the
|
||||||
|
binary it is in, then disassemble the
|
||||||
|
address from the bytes in that section.
|
||||||
|
data: uint32_t rva */
|
||||||
|
report_insn_bounds, /* INSTRUCTION OUT OF BOUNDS: The disassembler
|
||||||
|
could not disassemble the instruction as
|
||||||
|
the instruction would require bytes beyond
|
||||||
|
the end of the current buffer. This usually
|
||||||
|
indicated garbage bytes at the end of a
|
||||||
|
buffer, or an incorrectly-sized buffer.
|
||||||
|
data: uint32_t rva */
|
||||||
|
report_invalid_insn, /* INVALID INSTRUCTION: The disassembler could
|
||||||
|
not disassemble the instruction as it has an
|
||||||
|
invalid combination of opcodes and operands.
|
||||||
|
This will stop automated disassembly; the
|
||||||
|
application can restart the disassembly
|
||||||
|
after the invalid instruction.
|
||||||
|
data: uint32_t rva */
|
||||||
|
report_unknown
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 'arg' is optional arbitrary data provided by the code passing the
|
||||||
|
* callback -- for example, it could be 'this' or 'self' in OOP code.
|
||||||
|
* 'code' is provided by libdisasm, it is one of the above
|
||||||
|
* 'data' is provided by libdisasm and is context-specific, per the enums */
|
||||||
|
typedef void (*DISASM_REPORTER)( enum x86_report_codes code,
|
||||||
|
void *data, void *arg );
|
||||||
|
|
||||||
|
|
||||||
|
/* x86_report_error : Call the register reporter to report an error */
|
||||||
|
void x86_report_error( enum x86_report_codes code, void *data );
|
||||||
|
|
||||||
|
/* ========================================= Libdisasm Management Routines */
|
||||||
|
enum x86_options { /* these can be ORed together */
|
||||||
|
opt_none= 0,
|
||||||
|
opt_ignore_nulls=1, /* ignore sequences of > 4 NULL bytes */
|
||||||
|
opt_16_bit=2, /* 16-bit/DOS disassembly */
|
||||||
|
opt_att_mnemonics=4, /* use AT&T syntax names for alternate opcode mnemonics */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* management routines */
|
||||||
|
/* 'arg' is caller-specific data which is passed as the first argument
|
||||||
|
* to the reporter callback routine */
|
||||||
|
int x86_init( enum x86_options options, DISASM_REPORTER reporter, void *arg);
|
||||||
|
void x86_set_reporter( DISASM_REPORTER reporter, void *arg);
|
||||||
|
void x86_set_options( enum x86_options options );
|
||||||
|
enum x86_options x86_get_options( void );
|
||||||
|
int x86_cleanup(void);
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================================= Instruction Representation */
|
||||||
|
/* these defines are only intended for use in the array decl's */
|
||||||
|
#define MAX_REGNAME 8
|
||||||
|
|
||||||
|
#define MAX_PREFIX_STR 32
|
||||||
|
#define MAX_MNEM_STR 16
|
||||||
|
#define MAX_INSN_SIZE 20 /* same as in i386.h */
|
||||||
|
#define MAX_OP_STRING 32 /* max possible operand size in string form */
|
||||||
|
#define MAX_OP_RAW_STRING 64 /* max possible operand size in raw form */
|
||||||
|
#define MAX_OP_XML_STRING 256 /* max possible operand size in xml form */
|
||||||
|
#define MAX_NUM_OPERANDS 8 /* max # implicit and explicit operands */
|
||||||
|
/* in these, the '2 *' is arbitrary: the max # of operands should require
|
||||||
|
* more space than the rest of the insn */
|
||||||
|
#define MAX_INSN_STRING 512 /* 2 * 8 * MAX_OP_STRING */
|
||||||
|
#define MAX_INSN_RAW_STRING 1024 /* 2 * 8 * MAX_OP_RAW_STRING */
|
||||||
|
#define MAX_INSN_XML_STRING 4096 /* 2 * 8 * MAX_OP_XML_STRING */
|
||||||
|
|
||||||
|
enum x86_reg_type { /* NOTE: these may be ORed together */
|
||||||
|
reg_gen = 0x00001, /* general purpose */
|
||||||
|
reg_in = 0x00002, /* incoming args, ala RISC */
|
||||||
|
reg_out = 0x00004, /* args to calls, ala RISC */
|
||||||
|
reg_local = 0x00008, /* local vars, ala RISC */
|
||||||
|
reg_fpu = 0x00010, /* FPU data register */
|
||||||
|
reg_seg = 0x00020, /* segment register */
|
||||||
|
reg_simd = 0x00040, /* SIMD/MMX reg */
|
||||||
|
reg_sys = 0x00080, /* restricted/system register */
|
||||||
|
reg_sp = 0x00100, /* stack pointer */
|
||||||
|
reg_fp = 0x00200, /* frame pointer */
|
||||||
|
reg_pc = 0x00400, /* program counter */
|
||||||
|
reg_retaddr = 0x00800, /* return addr for func */
|
||||||
|
reg_cond = 0x01000, /* condition code / flags */
|
||||||
|
reg_zero = 0x02000, /* zero register, ala RISC */
|
||||||
|
reg_ret = 0x04000, /* return value */
|
||||||
|
reg_src = 0x10000, /* array/rep source */
|
||||||
|
reg_dest = 0x20000, /* array/rep destination */
|
||||||
|
reg_count = 0x40000 /* array/rep/loop counter */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* x86_reg_t : an X86 CPU register */
|
||||||
|
typedef struct {
|
||||||
|
char name[MAX_REGNAME];
|
||||||
|
enum x86_reg_type type; /* what register is used for */
|
||||||
|
unsigned int size; /* size of register in bytes */
|
||||||
|
unsigned int id; /* register ID #, for quick compares */
|
||||||
|
unsigned int alias; /* ID of reg this is an alias for */
|
||||||
|
unsigned int shift; /* amount to shift aliased reg by */
|
||||||
|
} x86_reg_t;
|
||||||
|
|
||||||
|
/* x86_ea_t : an X86 effective address (address expression) */
|
||||||
|
typedef struct {
|
||||||
|
unsigned int scale; /* scale factor */
|
||||||
|
x86_reg_t index, base; /* index, base registers */
|
||||||
|
int32_t disp; /* displacement */
|
||||||
|
char disp_sign; /* is negative? 1/0 */
|
||||||
|
char disp_size; /* 0, 1, 2, 4 */
|
||||||
|
} x86_ea_t;
|
||||||
|
|
||||||
|
/* x86_absolute_t : an X86 segment:offset address (descriptor) */
|
||||||
|
typedef struct {
|
||||||
|
unsigned short segment; /* loaded directly into CS */
|
||||||
|
union {
|
||||||
|
unsigned short off16; /* loaded directly into IP */
|
||||||
|
uint32_t off32; /* loaded directly into EIP */
|
||||||
|
} offset;
|
||||||
|
} x86_absolute_t;
|
||||||
|
|
||||||
|
enum x86_op_type { /* mutually exclusive */
|
||||||
|
op_unused = 0, /* empty/unused operand: should never occur */
|
||||||
|
op_register = 1, /* CPU register */
|
||||||
|
op_immediate = 2, /* Immediate Value */
|
||||||
|
op_relative_near = 3, /* Relative offset from IP */
|
||||||
|
op_relative_far = 4, /* Relative offset from IP */
|
||||||
|
op_absolute = 5, /* Absolute address (ptr16:32) */
|
||||||
|
op_expression = 6, /* Address expression (scale/index/base/disp) */
|
||||||
|
op_offset = 7, /* Offset from start of segment (m32) */
|
||||||
|
op_unknown
|
||||||
|
};
|
||||||
|
|
||||||
|
#define x86_optype_is_address( optype ) \
|
||||||
|
( optype == op_absolute || optype == op_offset )
|
||||||
|
#define x86_optype_is_relative( optype ) \
|
||||||
|
( optype == op_relative_near || optype == op_relative_far )
|
||||||
|
#define x86_optype_is_memory( optype ) \
|
||||||
|
( optype > op_immediate && optype < op_unknown )
|
||||||
|
|
||||||
|
enum x86_op_datatype { /* these use Intel's lame terminology */
|
||||||
|
op_byte = 1, /* 1 byte integer */
|
||||||
|
op_word = 2, /* 2 byte integer */
|
||||||
|
op_dword = 3, /* 4 byte integer */
|
||||||
|
op_qword = 4, /* 8 byte integer */
|
||||||
|
op_dqword = 5, /* 16 byte integer */
|
||||||
|
op_sreal = 6, /* 4 byte real (single real) */
|
||||||
|
op_dreal = 7, /* 8 byte real (double real) */
|
||||||
|
op_extreal = 8, /* 10 byte real (extended real) */
|
||||||
|
op_bcd = 9, /* 10 byte binary-coded decimal */
|
||||||
|
op_ssimd = 10, /* 16 byte : 4 packed single FP (SIMD, MMX) */
|
||||||
|
op_dsimd = 11, /* 16 byte : 2 packed double FP (SIMD, MMX) */
|
||||||
|
op_sssimd = 12, /* 4 byte : scalar single FP (SIMD, MMX) */
|
||||||
|
op_sdsimd = 13, /* 8 byte : scalar double FP (SIMD, MMX) */
|
||||||
|
op_descr32 = 14, /* 6 byte Intel descriptor 2:4 */
|
||||||
|
op_descr16 = 15, /* 4 byte Intel descriptor 2:2 */
|
||||||
|
op_pdescr32 = 16, /* 6 byte Intel pseudo-descriptor 32:16 */
|
||||||
|
op_pdescr16 = 17, /* 6 byte Intel pseudo-descriptor 8:24:16 */
|
||||||
|
op_bounds16 = 18, /* signed 16:16 lower:upper bounds */
|
||||||
|
op_bounds32 = 19, /* signed 32:32 lower:upper bounds */
|
||||||
|
op_fpuenv16 = 20, /* 14 byte FPU control/environment data */
|
||||||
|
op_fpuenv32 = 21, /* 28 byte FPU control/environment data */
|
||||||
|
op_fpustate16 = 22, /* 94 byte FPU state (env & reg stack) */
|
||||||
|
op_fpustate32 = 23, /* 108 byte FPU state (env & reg stack) */
|
||||||
|
op_fpregset = 24, /* 512 bytes: register set */
|
||||||
|
op_fpreg = 25, /* FPU register */
|
||||||
|
op_none = 0xFF, /* operand without a datatype (INVLPG) */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum x86_op_access { /* ORed together */
|
||||||
|
op_read = 1,
|
||||||
|
op_write = 2,
|
||||||
|
op_execute = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum x86_op_flags { /* ORed together, but segs are mutually exclusive */
|
||||||
|
op_signed = 1, /* signed integer */
|
||||||
|
op_string = 2, /* possible string or array */
|
||||||
|
op_constant = 4, /* symbolic constant */
|
||||||
|
op_pointer = 8, /* operand points to a memory address */
|
||||||
|
op_sysref = 0x010, /* operand is a syscall number */
|
||||||
|
op_implied = 0x020, /* operand is implicit in the insn */
|
||||||
|
op_hardcode = 0x40, /* operand is hardcoded in insn definition */
|
||||||
|
/* NOTE: an 'implied' operand is one which can be considered a side
|
||||||
|
* effect of the insn, e.g. %esp being modified by PUSH or POP. A
|
||||||
|
* 'hard-coded' operand is one which is specified in the instruction
|
||||||
|
* definition, e.g. %es:%edi in MOVSB or 1 in ROL Eb, 1. The difference
|
||||||
|
* is that hard-coded operands are printed by disassemblers and are
|
||||||
|
* required to re-assemble, while implicit operands are invisible. */
|
||||||
|
op_es_seg = 0x100, /* ES segment override */
|
||||||
|
op_cs_seg = 0x200, /* CS segment override */
|
||||||
|
op_ss_seg = 0x300, /* SS segment override */
|
||||||
|
op_ds_seg = 0x400, /* DS segment override */
|
||||||
|
op_fs_seg = 0x500, /* FS segment override */
|
||||||
|
op_gs_seg = 0x600 /* GS segment override */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* x86_op_t : an X86 instruction operand */
|
||||||
|
typedef struct {
|
||||||
|
enum x86_op_type type; /* operand type */
|
||||||
|
enum x86_op_datatype datatype; /* operand size */
|
||||||
|
enum x86_op_access access; /* operand access [RWX] */
|
||||||
|
enum x86_op_flags flags; /* misc flags */
|
||||||
|
union {
|
||||||
|
/* sizeof will have to work on these union members! */
|
||||||
|
/* immediate values */
|
||||||
|
char sbyte;
|
||||||
|
short sword;
|
||||||
|
int32_t sdword;
|
||||||
|
qword_t sqword;
|
||||||
|
unsigned char byte;
|
||||||
|
unsigned short word;
|
||||||
|
uint32_t dword;
|
||||||
|
qword_t qword;
|
||||||
|
float sreal;
|
||||||
|
double dreal;
|
||||||
|
/* misc large/non-native types */
|
||||||
|
unsigned char extreal[10];
|
||||||
|
unsigned char bcd[10];
|
||||||
|
qword_t dqword[2];
|
||||||
|
unsigned char simd[16];
|
||||||
|
unsigned char fpuenv[28];
|
||||||
|
/* offset from segment */
|
||||||
|
uint32_t offset;
|
||||||
|
/* ID of CPU register */
|
||||||
|
x86_reg_t reg;
|
||||||
|
/* offsets from current insn */
|
||||||
|
char relative_near;
|
||||||
|
int32_t relative_far;
|
||||||
|
/* segment:offset */
|
||||||
|
x86_absolute_t absolute;
|
||||||
|
/* effective address [expression] */
|
||||||
|
x86_ea_t expression;
|
||||||
|
} data;
|
||||||
|
/* this is needed to make formatting operands more sane */
|
||||||
|
void * insn; /* pointer to x86_insn_t owning operand */
|
||||||
|
} x86_op_t;
|
||||||
|
|
||||||
|
/* Linked list of x86_op_t; provided for manual traversal of the operand
|
||||||
|
* list in an insn. Users wishing to add operands to this list, e.g. to add
|
||||||
|
* implicit operands, should use x86_operand_new in x86_operand_list.h */
|
||||||
|
typedef struct x86_operand_list {
|
||||||
|
x86_op_t op;
|
||||||
|
struct x86_operand_list *next;
|
||||||
|
} x86_oplist_t;
|
||||||
|
|
||||||
|
enum x86_insn_group {
|
||||||
|
insn_none = 0, /* invalid instruction */
|
||||||
|
insn_controlflow = 1,
|
||||||
|
insn_arithmetic = 2,
|
||||||
|
insn_logic = 3,
|
||||||
|
insn_stack = 4,
|
||||||
|
insn_comparison = 5,
|
||||||
|
insn_move = 6,
|
||||||
|
insn_string = 7,
|
||||||
|
insn_bit_manip = 8,
|
||||||
|
insn_flag_manip = 9,
|
||||||
|
insn_fpu = 10,
|
||||||
|
insn_interrupt = 13,
|
||||||
|
insn_system = 14,
|
||||||
|
insn_other = 15
|
||||||
|
};
|
||||||
|
|
||||||
|
enum x86_insn_type {
|
||||||
|
insn_invalid = 0, /* invalid instruction */
|
||||||
|
/* insn_controlflow */
|
||||||
|
insn_jmp = 0x1001,
|
||||||
|
insn_jcc = 0x1002,
|
||||||
|
insn_call = 0x1003,
|
||||||
|
insn_callcc = 0x1004,
|
||||||
|
insn_return = 0x1005,
|
||||||
|
/* insn_arithmetic */
|
||||||
|
insn_add = 0x2001,
|
||||||
|
insn_sub = 0x2002,
|
||||||
|
insn_mul = 0x2003,
|
||||||
|
insn_div = 0x2004,
|
||||||
|
insn_inc = 0x2005,
|
||||||
|
insn_dec = 0x2006,
|
||||||
|
insn_shl = 0x2007,
|
||||||
|
insn_shr = 0x2008,
|
||||||
|
insn_rol = 0x2009,
|
||||||
|
insn_ror = 0x200A,
|
||||||
|
/* insn_logic */
|
||||||
|
insn_and = 0x3001,
|
||||||
|
insn_or = 0x3002,
|
||||||
|
insn_xor = 0x3003,
|
||||||
|
insn_not = 0x3004,
|
||||||
|
insn_neg = 0x3005,
|
||||||
|
/* insn_stack */
|
||||||
|
insn_push = 0x4001,
|
||||||
|
insn_pop = 0x4002,
|
||||||
|
insn_pushregs = 0x4003,
|
||||||
|
insn_popregs = 0x4004,
|
||||||
|
insn_pushflags = 0x4005,
|
||||||
|
insn_popflags = 0x4006,
|
||||||
|
insn_enter = 0x4007,
|
||||||
|
insn_leave = 0x4008,
|
||||||
|
/* insn_comparison */
|
||||||
|
insn_test = 0x5001,
|
||||||
|
insn_cmp = 0x5002,
|
||||||
|
/* insn_move */
|
||||||
|
insn_mov = 0x6001, /* move */
|
||||||
|
insn_movcc = 0x6002, /* conditional move */
|
||||||
|
insn_xchg = 0x6003, /* exchange */
|
||||||
|
insn_xchgcc = 0x6004, /* conditional exchange */
|
||||||
|
/* insn_string */
|
||||||
|
insn_strcmp = 0x7001,
|
||||||
|
insn_strload = 0x7002,
|
||||||
|
insn_strmov = 0x7003,
|
||||||
|
insn_strstore = 0x7004,
|
||||||
|
insn_translate = 0x7005, /* xlat */
|
||||||
|
/* insn_bit_manip */
|
||||||
|
insn_bittest = 0x8001,
|
||||||
|
insn_bitset = 0x8002,
|
||||||
|
insn_bitclear = 0x8003,
|
||||||
|
/* insn_flag_manip */
|
||||||
|
insn_clear_carry = 0x9001,
|
||||||
|
insn_clear_zero = 0x9002,
|
||||||
|
insn_clear_oflow = 0x9003,
|
||||||
|
insn_clear_dir = 0x9004,
|
||||||
|
insn_clear_sign = 0x9005,
|
||||||
|
insn_clear_parity = 0x9006,
|
||||||
|
insn_set_carry = 0x9007,
|
||||||
|
insn_set_zero = 0x9008,
|
||||||
|
insn_set_oflow = 0x9009,
|
||||||
|
insn_set_dir = 0x900A,
|
||||||
|
insn_set_sign = 0x900B,
|
||||||
|
insn_set_parity = 0x900C,
|
||||||
|
insn_tog_carry = 0x9010,
|
||||||
|
insn_tog_zero = 0x9020,
|
||||||
|
insn_tog_oflow = 0x9030,
|
||||||
|
insn_tog_dir = 0x9040,
|
||||||
|
insn_tog_sign = 0x9050,
|
||||||
|
insn_tog_parity = 0x9060,
|
||||||
|
/* insn_fpu */
|
||||||
|
insn_fmov = 0xA001,
|
||||||
|
insn_fmovcc = 0xA002,
|
||||||
|
insn_fneg = 0xA003,
|
||||||
|
insn_fabs = 0xA004,
|
||||||
|
insn_fadd = 0xA005,
|
||||||
|
insn_fsub = 0xA006,
|
||||||
|
insn_fmul = 0xA007,
|
||||||
|
insn_fdiv = 0xA008,
|
||||||
|
insn_fsqrt = 0xA009,
|
||||||
|
insn_fcmp = 0xA00A,
|
||||||
|
insn_fcos = 0xA00C,
|
||||||
|
insn_fldpi = 0xA00D,
|
||||||
|
insn_fldz = 0xA00E,
|
||||||
|
insn_ftan = 0xA00F,
|
||||||
|
insn_fsine = 0xA010,
|
||||||
|
insn_fsys = 0xA020,
|
||||||
|
/* insn_interrupt */
|
||||||
|
insn_int = 0xD001,
|
||||||
|
insn_intcc = 0xD002, /* not present in x86 ISA */
|
||||||
|
insn_iret = 0xD003,
|
||||||
|
insn_bound = 0xD004,
|
||||||
|
insn_debug = 0xD005,
|
||||||
|
insn_trace = 0xD006,
|
||||||
|
insn_invalid_op = 0xD007,
|
||||||
|
insn_oflow = 0xD008,
|
||||||
|
/* insn_system */
|
||||||
|
insn_halt = 0xE001,
|
||||||
|
insn_in = 0xE002, /* input from port/bus */
|
||||||
|
insn_out = 0xE003, /* output to port/bus */
|
||||||
|
insn_cpuid = 0xE004,
|
||||||
|
/* insn_other */
|
||||||
|
insn_nop = 0xF001,
|
||||||
|
insn_bcdconv = 0xF002, /* convert to or from BCD */
|
||||||
|
insn_szconv = 0xF003 /* change size of operand */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* These flags specify special characteristics of the instruction, such as
|
||||||
|
* whether the inatruction is privileged or whether it serializes the
|
||||||
|
* pipeline.
|
||||||
|
* NOTE : These may not be accurate for all instructions; updates to the
|
||||||
|
* opcode tables have not been completed. */
|
||||||
|
enum x86_insn_note {
|
||||||
|
insn_note_ring0 = 1, /* Only available in ring 0 */
|
||||||
|
insn_note_smm = 2, /* "" in System Management Mode */
|
||||||
|
insn_note_serial = 4, /* Serializing instruction */
|
||||||
|
insn_note_nonswap = 8, /* Does not swap arguments in att-style formatting */
|
||||||
|
insn_note_nosuffix = 16, /* Does not have size suffix in att-style formatting */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This specifies what effects the instruction has on the %eflags register */
|
||||||
|
enum x86_flag_status {
|
||||||
|
insn_carry_set = 0x1, /* CF */
|
||||||
|
insn_zero_set = 0x2, /* ZF */
|
||||||
|
insn_oflow_set = 0x4, /* OF */
|
||||||
|
insn_dir_set = 0x8, /* DF */
|
||||||
|
insn_sign_set = 0x10, /* SF */
|
||||||
|
insn_parity_set = 0x20, /* PF */
|
||||||
|
insn_carry_or_zero_set = 0x40,
|
||||||
|
insn_zero_set_or_sign_ne_oflow = 0x80,
|
||||||
|
insn_carry_clear = 0x100,
|
||||||
|
insn_zero_clear = 0x200,
|
||||||
|
insn_oflow_clear = 0x400,
|
||||||
|
insn_dir_clear = 0x800,
|
||||||
|
insn_sign_clear = 0x1000,
|
||||||
|
insn_parity_clear = 0x2000,
|
||||||
|
insn_sign_eq_oflow = 0x4000,
|
||||||
|
insn_sign_ne_oflow = 0x8000
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The CPU model in which the insturction first appeared; this can be used
|
||||||
|
* to mask out instructions appearing in earlier or later models or to
|
||||||
|
* check the portability of a binary.
|
||||||
|
* NOTE : These may not be accurate for all instructions; updates to the
|
||||||
|
* opcode tables have not been completed. */
|
||||||
|
enum x86_insn_cpu {
|
||||||
|
cpu_8086 = 1, /* Intel */
|
||||||
|
cpu_80286 = 2,
|
||||||
|
cpu_80386 = 3,
|
||||||
|
cpu_80387 = 4,
|
||||||
|
cpu_80486 = 5,
|
||||||
|
cpu_pentium = 6,
|
||||||
|
cpu_pentiumpro = 7,
|
||||||
|
cpu_pentium2 = 8,
|
||||||
|
cpu_pentium3 = 9,
|
||||||
|
cpu_pentium4 = 10,
|
||||||
|
cpu_k6 = 16, /* AMD */
|
||||||
|
cpu_k7 = 32,
|
||||||
|
cpu_athlon = 48
|
||||||
|
};
|
||||||
|
|
||||||
|
/* CPU ISA subsets: These are derived from the Instruction Groups in
|
||||||
|
* Intel Vol 1 Chapter 5; they represent subsets of the IA32 ISA but
|
||||||
|
* do not reflect the 'type' of the instruction in the same way that
|
||||||
|
* x86_insn_group does. In short, these are AMD/Intel's somewhat useless
|
||||||
|
* designations.
|
||||||
|
* NOTE : These may not be accurate for all instructions; updates to the
|
||||||
|
* opcode tables have not been completed. */
|
||||||
|
enum x86_insn_isa {
|
||||||
|
isa_gp = 1, /* general purpose */
|
||||||
|
isa_fp = 2, /* floating point */
|
||||||
|
isa_fpumgt = 3, /* FPU/SIMD management */
|
||||||
|
isa_mmx = 4, /* Intel MMX */
|
||||||
|
isa_sse1 = 5, /* Intel SSE SIMD */
|
||||||
|
isa_sse2 = 6, /* Intel SSE2 SIMD */
|
||||||
|
isa_sse3 = 7, /* Intel SSE3 SIMD */
|
||||||
|
isa_3dnow = 8, /* AMD 3DNow! SIMD */
|
||||||
|
isa_sys = 9 /* system instructions */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum x86_insn_prefix {
|
||||||
|
insn_no_prefix = 0,
|
||||||
|
insn_rep_zero = 1, /* REPZ and REPE */
|
||||||
|
insn_rep_notzero = 2, /* REPNZ and REPNZ */
|
||||||
|
insn_lock = 4 /* LOCK: */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TODO: maybe provide insn_new/free(), and have disasm return new insn_t */
|
||||||
|
/* x86_insn_t : an X86 instruction */
|
||||||
|
typedef struct {
|
||||||
|
/* information about the instruction */
|
||||||
|
uint32_t addr; /* load address */
|
||||||
|
uint32_t offset; /* offset into file/buffer */
|
||||||
|
enum x86_insn_group group; /* meta-type, e.g. INS_EXEC */
|
||||||
|
enum x86_insn_type type; /* type, e.g. INS_BRANCH */
|
||||||
|
enum x86_insn_note note; /* note, e.g. RING0 */
|
||||||
|
unsigned char bytes[MAX_INSN_SIZE];
|
||||||
|
unsigned char size; /* size of insn in bytes */
|
||||||
|
/* 16/32-bit mode settings */
|
||||||
|
unsigned char addr_size; /* default address size : 2 or 4 */
|
||||||
|
unsigned char op_size; /* default operand size : 2 or 4 */
|
||||||
|
/* CPU/instruction set */
|
||||||
|
enum x86_insn_cpu cpu;
|
||||||
|
enum x86_insn_isa isa;
|
||||||
|
/* flags */
|
||||||
|
enum x86_flag_status flags_set; /* flags set or tested by insn */
|
||||||
|
enum x86_flag_status flags_tested;
|
||||||
|
/* stack */
|
||||||
|
unsigned char stack_mod; /* 0 or 1 : is the stack modified? */
|
||||||
|
int32_t stack_mod_val; /* val stack is modified by if known */
|
||||||
|
|
||||||
|
/* the instruction proper */
|
||||||
|
enum x86_insn_prefix prefix; /* prefixes ORed together */
|
||||||
|
char prefix_string[MAX_PREFIX_STR]; /* prefixes [might be truncated] */
|
||||||
|
char mnemonic[MAX_MNEM_STR];
|
||||||
|
x86_oplist_t *operands; /* list of explicit/implicit operands */
|
||||||
|
size_t operand_count; /* total number of operands */
|
||||||
|
size_t explicit_count; /* number of explicit operands */
|
||||||
|
/* convenience fields for user */
|
||||||
|
void *block; /* code block containing this insn */
|
||||||
|
void *function; /* function containing this insn */
|
||||||
|
int tag; /* tag the insn as seen/processed */
|
||||||
|
} x86_insn_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* returns 0 if an instruction is invalid, 1 if valid */
|
||||||
|
int x86_insn_is_valid( x86_insn_t *insn );
|
||||||
|
|
||||||
|
/* DISASSEMBLY ROUTINES
|
||||||
|
* Canonical order of arguments is
|
||||||
|
* (buf, buf_len, buf_rva, offset, len, insn, func, arg, resolve_func)
|
||||||
|
* ...but of course all of these are not used at the same time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Function prototype for caller-supplied callback routine
|
||||||
|
* These callbacks are intended to process 'insn' further, e.g. by
|
||||||
|
* adding it to a linked list, database, etc */
|
||||||
|
typedef void (*DISASM_CALLBACK)( x86_insn_t *insn, void * arg );
|
||||||
|
|
||||||
|
/* Function prototype for caller-supplied address resolver.
|
||||||
|
* This routine is used to determine the rva to disassemble next, given
|
||||||
|
* the 'dest' operand of a jump/call. This allows the caller to resolve
|
||||||
|
* jump/call targets stored in a register or on the stack, and also allows
|
||||||
|
* the caller to prevent endless loops by checking if an address has
|
||||||
|
* already been disassembled. If an address cannot be resolved from the
|
||||||
|
* operand, or if the address has already been disassembled, this routine
|
||||||
|
* should return -1; in all other cases the RVA to be disassembled next
|
||||||
|
* should be returned. */
|
||||||
|
typedef int32_t (*DISASM_RESOLVER)( x86_op_t *op, x86_insn_t * current_insn,
|
||||||
|
void *arg );
|
||||||
|
|
||||||
|
|
||||||
|
/* x86_disasm: Disassemble a single instruction from a buffer of bytes.
|
||||||
|
* Returns size of instruction in bytes.
|
||||||
|
* Caller is responsible for calling x86_oplist_free() on
|
||||||
|
* a reused "insn" to avoid leaking memory when calling this
|
||||||
|
* function repeatedly.
|
||||||
|
* buf : Buffer of bytes to disassemble
|
||||||
|
* buf_len : Length of the buffer
|
||||||
|
* buf_rva : Load address of the start of the buffer
|
||||||
|
* offset : Offset in buffer to disassemble
|
||||||
|
* insn : Structure to fill with disassembled instruction
|
||||||
|
*/
|
||||||
|
unsigned int x86_disasm( unsigned char *buf, unsigned int buf_len,
|
||||||
|
uint32_t buf_rva, unsigned int offset,
|
||||||
|
x86_insn_t * insn );
|
||||||
|
|
||||||
|
/* x86_disasm_range: Sequential disassembly of a range of bytes in a buffer,
|
||||||
|
* invoking a callback function each time an instruction
|
||||||
|
* is successfully disassembled. The 'range' refers to the
|
||||||
|
* bytes between 'offset' and 'offset + len' in the buffer;
|
||||||
|
* 'len' is assumed to be less than the length of the buffer.
|
||||||
|
* Returns number of instructions processed.
|
||||||
|
* buf : Buffer of bytes to disassemble (e.g. .text section)
|
||||||
|
* buf_rva : Load address of buffer (e.g. ELF Virtual Address)
|
||||||
|
* offset : Offset in buffer to start disassembly at
|
||||||
|
* len : Number of bytes to disassemble
|
||||||
|
* func : Callback function to invoke (may be NULL)
|
||||||
|
* arg : Arbitrary data to pass to callback (may be NULL)
|
||||||
|
*/
|
||||||
|
unsigned int x86_disasm_range( unsigned char *buf, uint32_t buf_rva,
|
||||||
|
unsigned int offset, unsigned int len,
|
||||||
|
DISASM_CALLBACK func, void *arg );
|
||||||
|
|
||||||
|
/* x86_disasm_forward: Flow-of-execution disassembly of the bytes in a buffer,
|
||||||
|
* invoking a callback function each time an instruction
|
||||||
|
* is successfully disassembled.
|
||||||
|
* buf : Buffer to disassemble (e.g. .text section)
|
||||||
|
* buf_len : Number of bytes in buffer
|
||||||
|
* buf_rva : Load address of buffer (e.g. ELF Virtual Address)
|
||||||
|
* offset : Offset in buffer to start disassembly at (e.g. entry point)
|
||||||
|
* func : Callback function to invoke (may be NULL)
|
||||||
|
* arg : Arbitrary data to pass to callback (may be NULL)
|
||||||
|
* resolver: Caller-supplied address resolver. If no resolver is
|
||||||
|
* supplied, a default internal one is used -- however the
|
||||||
|
* internal resolver does NOT catch loops and could end up
|
||||||
|
* disassembling forever..
|
||||||
|
* r_arg : Arbitrary data to pass to resolver (may be NULL)
|
||||||
|
*/
|
||||||
|
unsigned int x86_disasm_forward( unsigned char *buf, unsigned int buf_len,
|
||||||
|
uint32_t buf_rva, unsigned int offset,
|
||||||
|
DISASM_CALLBACK func, void *arg,
|
||||||
|
DISASM_RESOLVER resolver, void *r_arg );
|
||||||
|
|
||||||
|
/* Instruction operands: these are stored as a list of explicit and
|
||||||
|
* implicit operands. It is recommended that the 'foreach' routines
|
||||||
|
* be used to when examining operands for purposes of data flow analysis */
|
||||||
|
|
||||||
|
/* Operand FOREACH callback: 'arg' is an abritrary parameter passed to the
|
||||||
|
* foreach routine, 'insn' is the x86_insn_t whose operands are being
|
||||||
|
* iterated over, and 'op' is the current x86_op_t */
|
||||||
|
typedef void (*x86_operand_fn)(x86_op_t *op, x86_insn_t *insn, void *arg);
|
||||||
|
|
||||||
|
/* FOREACH types: these are used to limit the foreach results to
|
||||||
|
* operands which match a certain "type" (implicit or explicit)
|
||||||
|
* or which are accessed in certain ways (e.g. read or write). Note
|
||||||
|
* that this operates on the operand list of single instruction, so
|
||||||
|
* specifying the 'real' operand type (register, memory, etc) is not
|
||||||
|
* useful. Note also that by definition Execute Access implies Read
|
||||||
|
* Access and implies Not Write Access.
|
||||||
|
* The "type" (implicit or explicit) and the access method can
|
||||||
|
* be ORed together, e.g. op_wo | op_explicit */
|
||||||
|
enum x86_op_foreach_type {
|
||||||
|
op_any = 0, /* ALL operands (explicit, implicit, rwx) */
|
||||||
|
op_dest = 1, /* operands with Write access */
|
||||||
|
op_src = 2, /* operands with Read access */
|
||||||
|
op_ro = 3, /* operands with Read but not Write access */
|
||||||
|
op_wo = 4, /* operands with Write but not Read access */
|
||||||
|
op_xo = 5, /* operands with Execute access */
|
||||||
|
op_rw = 6, /* operands with Read AND Write access */
|
||||||
|
op_implicit = 0x10, /* operands that are implied by the opcode */
|
||||||
|
op_explicit = 0x20 /* operands that are not side-effects */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* free the operand list associated with an instruction -- useful for
|
||||||
|
* preventing memory leaks when free()ing an x86_insn_t */
|
||||||
|
void x86_oplist_free( x86_insn_t *insn );
|
||||||
|
|
||||||
|
/* Operand foreach: invokes 'func' with 'insn' and 'arg' as arguments. The
|
||||||
|
* 'type' parameter is used to select only operands matching specific
|
||||||
|
* criteria. */
|
||||||
|
int x86_operand_foreach( x86_insn_t *insn, x86_operand_fn func, void *arg,
|
||||||
|
enum x86_op_foreach_type type);
|
||||||
|
|
||||||
|
/* convenience routine: returns count of operands matching 'type' */
|
||||||
|
size_t x86_operand_count( x86_insn_t *insn, enum x86_op_foreach_type type );
|
||||||
|
|
||||||
|
/* accessor functions for the operands */
|
||||||
|
x86_op_t * x86_operand_1st( x86_insn_t *insn );
|
||||||
|
x86_op_t * x86_operand_2nd( x86_insn_t *insn );
|
||||||
|
x86_op_t * x86_operand_3rd( x86_insn_t *insn );
|
||||||
|
|
||||||
|
/* these allow libdisasm 2.0 accessor functions to still be used */
|
||||||
|
#define x86_get_dest_operand( insn ) x86_operand_1st( insn )
|
||||||
|
#define x86_get_src_operand( insn ) x86_operand_2nd( insn )
|
||||||
|
#define x86_get_imm_operand( insn ) x86_operand_3rd( insn )
|
||||||
|
|
||||||
|
/* get size of operand data in bytes */
|
||||||
|
unsigned int x86_operand_size( x86_op_t *op );
|
||||||
|
|
||||||
|
/* Operand Convenience Routines: the following three routines are common
|
||||||
|
* operations on operands, intended to ease the burden of the programmer. */
|
||||||
|
|
||||||
|
/* Get Address: return the value of an offset operand, or the offset of
|
||||||
|
* a segment:offset absolute address */
|
||||||
|
uint32_t x86_get_address( x86_insn_t *insn );
|
||||||
|
|
||||||
|
/* Get Relative Offset: return as a sign-extended int32_t the near or far
|
||||||
|
* relative offset operand, or 0 if there is none. There can be only one
|
||||||
|
* relaive offset operand in an instruction. */
|
||||||
|
int32_t x86_get_rel_offset( x86_insn_t *insn );
|
||||||
|
|
||||||
|
/* Get Branch Target: return the x86_op_t containing the target of
|
||||||
|
* a jump or call operand, or NULL if there is no branch target.
|
||||||
|
* Internally, a 'branch target' is defined as any operand with
|
||||||
|
* Execute Access set. There can be only one branch target per instruction. */
|
||||||
|
x86_op_t * x86_get_branch_target( x86_insn_t *insn );
|
||||||
|
|
||||||
|
/* Get Immediate: return the x86_op_t containing the immediate operand
|
||||||
|
* for this instruction, or NULL if there is no immediate operand. There
|
||||||
|
* can be only one immediate operand per instruction */
|
||||||
|
x86_op_t * x86_get_imm( x86_insn_t *insn );
|
||||||
|
|
||||||
|
/* Get Raw Immediate Data: returns a pointer to the immediate data encoded
|
||||||
|
* in the instruction. This is useful for large data types [>32 bits] currently
|
||||||
|
* not supported by libdisasm, or for determining if the disassembler
|
||||||
|
* screwed up the conversion of the immediate data. Note that 'imm' in this
|
||||||
|
* context refers to immediate data encoded at the end of an instruction as
|
||||||
|
* detailed in the Intel Manual Vol II Chapter 2; it does not refer to the
|
||||||
|
* 'op_imm' operand (the third operand in instructions like 'mul' */
|
||||||
|
unsigned char * x86_get_raw_imm( x86_insn_t *insn );
|
||||||
|
|
||||||
|
|
||||||
|
/* More accessor fuctions, this time for user-defined info... */
|
||||||
|
/* set the address (usually RVA) of the insn */
|
||||||
|
void x86_set_insn_addr( x86_insn_t *insn, uint32_t addr );
|
||||||
|
|
||||||
|
/* set the offset (usually offset into file) of the insn */
|
||||||
|
void x86_set_insn_offset( x86_insn_t *insn, unsigned int offset );
|
||||||
|
|
||||||
|
/* set a pointer to the function owning the instruction. The
|
||||||
|
* type of 'func' is user-defined; libdisasm does not use the func field. */
|
||||||
|
void x86_set_insn_function( x86_insn_t *insn, void * func );
|
||||||
|
|
||||||
|
/* set a pointer to the block of code owning the instruction. The
|
||||||
|
* type of 'block' is user-defined; libdisasm does not use the block field. */
|
||||||
|
void x86_set_insn_block( x86_insn_t *insn, void * block );
|
||||||
|
|
||||||
|
/* instruction tagging: these routines allow the programmer to mark
|
||||||
|
* instructions as "seen" in a DFS, for example. libdisasm does not use
|
||||||
|
* the tag field.*/
|
||||||
|
/* set insn->tag to 1 */
|
||||||
|
void x86_tag_insn( x86_insn_t *insn );
|
||||||
|
/* set insn->tag to 0 */
|
||||||
|
void x86_untag_insn( x86_insn_t *insn );
|
||||||
|
/* return insn->tag */
|
||||||
|
int x86_insn_is_tagged( x86_insn_t *insn );
|
||||||
|
|
||||||
|
|
||||||
|
/* Disassembly formats:
|
||||||
|
* AT&T is standard AS/GAS-style: "mnemonic\tsrc, dest, imm"
|
||||||
|
* Intel is standard MASM/NASM/TASM: "mnemonic\tdest,src, imm"
|
||||||
|
* Native is tab-delimited: "RVA\tbytes\tmnemonic\tdest\tsrc\timm"
|
||||||
|
* XML is your typical <insn> ... </insn>
|
||||||
|
* Raw is addr|offset|size|bytes|prefix... see libdisasm_formats.7
|
||||||
|
*/
|
||||||
|
enum x86_asm_format {
|
||||||
|
unknown_syntax = 0, /* never use! */
|
||||||
|
native_syntax, /* header: 35 bytes */
|
||||||
|
intel_syntax, /* header: 23 bytes */
|
||||||
|
att_syntax, /* header: 23 bytes */
|
||||||
|
xml_syntax, /* header: 679 bytes */
|
||||||
|
raw_syntax /* header: 172 bytes */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* format (sprintf) an operand into 'buf' using specified syntax */
|
||||||
|
int x86_format_operand(x86_op_t *op, char *buf, int len,
|
||||||
|
enum x86_asm_format format);
|
||||||
|
|
||||||
|
/* format (sprintf) an instruction mnemonic into 'buf' using specified syntax */
|
||||||
|
int x86_format_mnemonic(x86_insn_t *insn, char *buf, int len,
|
||||||
|
enum x86_asm_format format);
|
||||||
|
|
||||||
|
/* format (sprintf) an instruction into 'buf' using specified syntax;
|
||||||
|
* this includes formatting all operands */
|
||||||
|
int x86_format_insn(x86_insn_t *insn, char *buf, int len, enum x86_asm_format);
|
||||||
|
|
||||||
|
/* fill 'buf' with a description of the format's syntax */
|
||||||
|
int x86_format_header( char *buf, int len, enum x86_asm_format format);
|
||||||
|
|
||||||
|
/* Endianness of an x86 CPU : 0 is big, 1 is little; always returns 1 */
|
||||||
|
unsigned int x86_endian(void);
|
||||||
|
|
||||||
|
/* Default address and operand size in bytes */
|
||||||
|
unsigned int x86_addr_size(void);
|
||||||
|
unsigned int x86_op_size(void);
|
||||||
|
|
||||||
|
/* Size of a machine word in bytes */
|
||||||
|
unsigned int x86_word_size(void);
|
||||||
|
|
||||||
|
/* maximum size of a code instruction */
|
||||||
|
#define x86_max_inst_size(x) x86_max_insn_size(x)
|
||||||
|
unsigned int x86_max_insn_size(void);
|
||||||
|
|
||||||
|
/* register IDs of Stack, Frame, Instruction pointer and Flags register */
|
||||||
|
unsigned int x86_sp_reg(void);
|
||||||
|
unsigned int x86_fp_reg(void);
|
||||||
|
unsigned int x86_ip_reg(void);
|
||||||
|
unsigned int x86_flag_reg(void);
|
||||||
|
|
||||||
|
/* fill 'reg' struct with details of register 'id' */
|
||||||
|
void x86_reg_from_id( unsigned int id, x86_reg_t * reg );
|
||||||
|
|
||||||
|
/* convenience macro demonstrating how to get an aliased register; proto is
|
||||||
|
* void x86_get_aliased_reg( x86_reg_t *alias_reg, x86_reg_t *output_reg )
|
||||||
|
* where 'alias_reg' is a reg operand and 'output_reg' is filled with the
|
||||||
|
* register that the operand is an alias for */
|
||||||
|
#define x86_get_aliased_reg( alias_reg, output_reg ) \
|
||||||
|
x86_reg_from_id( alias_reg->alias, output_reg )
|
||||||
|
|
||||||
|
|
||||||
|
/* ================================== Invariant Instruction Representation */
|
||||||
|
/* Invariant instructions are used for generating binary signatures;
|
||||||
|
* the instruction is modified so that all variant bytes in an instruction
|
||||||
|
* are replaced with a wildcard byte.
|
||||||
|
*
|
||||||
|
* A 'variant byte' is one that is expected to be modified by either the
|
||||||
|
* static or the dynamic linker: for example, an address encoded in an
|
||||||
|
* instruction.
|
||||||
|
*
|
||||||
|
* By comparing the invariant representation of one instruction [or of a
|
||||||
|
* sequence of instructions] with the invariant representation of another,
|
||||||
|
* one determine whether the two invariant representations are from the same
|
||||||
|
* relocatable object [.o] file. Thus one can use binary signatures [which
|
||||||
|
* are just sequences of invariant instruction representations] to look for
|
||||||
|
* library routines which have been statically-linked into a binary.
|
||||||
|
*
|
||||||
|
* The invariant routines are faster and smaller than the disassembly
|
||||||
|
* routines; they can be used to determine the size of an instruction
|
||||||
|
* without all of the overhead of a full instruction disassembly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This byte is used to replace variant bytes */
|
||||||
|
#define X86_WILDCARD_BYTE 0xF4
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum x86_op_type type; /* operand type */
|
||||||
|
enum x86_op_datatype datatype; /* operand size */
|
||||||
|
enum x86_op_access access; /* operand access [RWX] */
|
||||||
|
enum x86_op_flags flags; /* misc flags */
|
||||||
|
} x86_invariant_op_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char bytes[64]; /* invariant representation */
|
||||||
|
unsigned int size; /* number of bytes in insn */
|
||||||
|
enum x86_insn_group group; /* meta-type, e.g. INS_EXEC */
|
||||||
|
enum x86_insn_type type; /* type, e.g. INS_BRANCH */
|
||||||
|
x86_invariant_op_t operands[3]; /* operands: dest, src, imm */
|
||||||
|
} x86_invariant_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* return a version of the instruction with the variant bytes masked out */
|
||||||
|
size_t x86_invariant_disasm( unsigned char *buf, int buf_len,
|
||||||
|
x86_invariant_t *inv );
|
||||||
|
/* return the size in bytes of the intruction pointed to by 'buf';
|
||||||
|
* this used x86_invariant_disasm since it faster than x86_disasm */
|
||||||
|
size_t x86_size_disasm( unsigned char *buf, unsigned int buf_len );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
14
libdisasm/qword.h
Normal file
14
libdisasm/qword.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef LIBDISASM_QWORD_H
|
||||||
|
#define LIBDISASM_QWORD_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* platform independent data types */
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef __int64 qword_t;
|
||||||
|
#else
|
||||||
|
typedef int64_t qword_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
70
libdisasm/swig/Makefile
Normal file
70
libdisasm/swig/Makefile
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# change these values if you need to
|
||||||
|
SWIG = swig # apt-get install swig !
|
||||||
|
GCC = gcc
|
||||||
|
|
||||||
|
CC_FLAGS = -c -fPIC
|
||||||
|
LD_FLAGS = -shared -L../.. -ldisasm
|
||||||
|
|
||||||
|
BASE_NAME = x86disasm
|
||||||
|
|
||||||
|
export INTERFACE_FILE BASE_NAME SWIG GCC CC_FLAGS LD_FLAGS
|
||||||
|
|
||||||
|
#====================================================
|
||||||
|
# TARGETS
|
||||||
|
|
||||||
|
all: swig
|
||||||
|
dummy: swig swig-python swig-ruby swig-perl swig-tcl install uninstall clean
|
||||||
|
|
||||||
|
swig: swig-python swig-perl
|
||||||
|
# swig-rub swig-tcl
|
||||||
|
|
||||||
|
swig-python:
|
||||||
|
cd python && make -f Makefile-swig
|
||||||
|
|
||||||
|
swig-ruby:
|
||||||
|
cd ruby && make -f Makefile-swig
|
||||||
|
|
||||||
|
swig-perl:
|
||||||
|
cd perl && make -f Makefile-swig
|
||||||
|
|
||||||
|
swig-tcl:
|
||||||
|
cd tcl && make -f Makefile-swig
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
install: install-python install-perl
|
||||||
|
# install-ruby install-tcl
|
||||||
|
|
||||||
|
install-python:
|
||||||
|
cd python && sudo make -f Makefile-swig install
|
||||||
|
|
||||||
|
install-ruby:
|
||||||
|
cd ruby && sudo make -f Makefile-swig install
|
||||||
|
|
||||||
|
install-perl:
|
||||||
|
cd perl && sudo make -f Makefile-swig install
|
||||||
|
|
||||||
|
install-tcl:
|
||||||
|
cd tcl && sudo make -f Makefile-swig install
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
uninstall: uninstall-python
|
||||||
|
#uninstall-ruby uninstall-perl uninstall-tcl
|
||||||
|
|
||||||
|
uninstall-python:
|
||||||
|
cd python && sudo make -f Makefile-swig uninstall
|
||||||
|
|
||||||
|
uninstall-ruby:
|
||||||
|
cd ruby && sudo make -f Makefile-swig uninstall
|
||||||
|
|
||||||
|
uninstall-perl:
|
||||||
|
cd perl && sudo make -f Makefile-swig uninstall
|
||||||
|
|
||||||
|
uninstall-tcl:
|
||||||
|
cd tcl && sudo make -f Makefile-swig uninstall
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
clean:
|
||||||
|
cd python && make -f Makefile-swig clean
|
||||||
|
cd ruby && make -f Makefile-swig clean
|
||||||
|
cd perl && make -f Makefile-swig clean
|
||||||
|
cd tcl && make -f Makefile-swig clean
|
128
libdisasm/swig/README
Normal file
128
libdisasm/swig/README
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
Libdisasm SWIG README
|
||||||
|
|
||||||
|
The SWIG utility (www.swig.org) can be used to generate
|
||||||
|
|
||||||
|
|
||||||
|
Building SWIG Modules
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
|
||||||
|
Make and Install both build Python, Perl, Ruby, and Tcl modules. If you
|
||||||
|
do not have one of these languages installed, comment out the relevant
|
||||||
|
target in the main Makefile.
|
||||||
|
|
||||||
|
Install uses 'sudo' to put files in the correct locations; if you
|
||||||
|
do not have sudo installed, change the install targets.
|
||||||
|
|
||||||
|
The Module API
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The OOP API
|
||||||
|
-----------
|
||||||
|
|
||||||
|
|
||||||
|
The Python Module
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
To test that the module loads:
|
||||||
|
|
||||||
|
bash# python
|
||||||
|
>>> import x86disasm
|
||||||
|
>>> x86disasm.version_string()
|
||||||
|
'0.21-pre'
|
||||||
|
>>>^D
|
||||||
|
bash#
|
||||||
|
|
||||||
|
>>> import x86disasm
|
||||||
|
>>> import array
|
||||||
|
>>> disasm = x86disasm.X86_Disasm( )
|
||||||
|
>>> tgt = open( "/tmp/a.out", "rb" )
|
||||||
|
>>> tgt.seek( 0, 2 )
|
||||||
|
>>> size = tgt.tell()
|
||||||
|
>>> tgt.seek( 0, 0 )
|
||||||
|
>>> buf = array.array( 'B' )
|
||||||
|
>>> buf.fromfile( tgt, size )
|
||||||
|
>>> tgt.close()
|
||||||
|
>>> data = x86disasm.byteArray( size )
|
||||||
|
>>> for i in range( size ):
|
||||||
|
... data[i] = buf.pop(0)
|
||||||
|
...
|
||||||
|
>>> del buf
|
||||||
|
>>> del tgt
|
||||||
|
>>> insn = disasm.disasm( data, size - 1, 0, 0 )
|
||||||
|
>>> insn.format( x86disasm.att_syntax )
|
||||||
|
'jg\t0x00000047'
|
||||||
|
>>> insn.format( x86disasm.raw_syntax )
|
||||||
|
'0x00000000|0x00000000|2|7F 45 |||controlflow|jcc|jg|80386|General Purpose|||zero_clear sign_eq_oflow |0|0|relative|sbyte|00000047|'
|
||||||
|
>>> ops = insn.operand_list()
|
||||||
|
>>> node = ops.first()
|
||||||
|
>>> while node is not None:
|
||||||
|
... s = node.op.format(x86disasm.raw_syntax)
|
||||||
|
... print s
|
||||||
|
... node = ops.next()
|
||||||
|
...
|
||||||
|
relative|sbyte|00000047|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The Perl Module
|
||||||
|
---------------
|
||||||
|
|
||||||
|
To test that the module loads:
|
||||||
|
|
||||||
|
bash# perl
|
||||||
|
use x86disasm;
|
||||||
|
print x86disasm::version_string() . "\n";
|
||||||
|
^D
|
||||||
|
0.21-pre
|
||||||
|
bash#
|
||||||
|
|
||||||
|
The Ruby Module
|
||||||
|
---------------
|
||||||
|
|
||||||
|
To test that the module loads:
|
||||||
|
|
||||||
|
bash# irb
|
||||||
|
irb(main):001:0> require 'x86disasm'
|
||||||
|
=> true
|
||||||
|
irb(main):002:0> X86disasm.version_string()
|
||||||
|
=> "0.21-pre"
|
||||||
|
irb(main):003:0> x = X86disasm::X86_Disasm.new
|
||||||
|
=> #<X86disasm::X86_Disasm:0xb7d624a4>
|
||||||
|
irb(main):004:0> x.max_register_string()
|
||||||
|
=> 8
|
||||||
|
irb(main):003:0> ^D
|
||||||
|
bash#
|
||||||
|
|
||||||
|
The Tcl Module
|
||||||
|
---------------
|
||||||
|
|
||||||
|
To test that the module loads:
|
||||||
|
|
||||||
|
bash# tclsh
|
||||||
|
% load /usr/lib/tcl8.3/x86disasm.so X86disasm
|
||||||
|
% version_string
|
||||||
|
0.21-pre
|
||||||
|
% ^D
|
||||||
|
bash#
|
||||||
|
|
||||||
|
% x86_init 0 NULL NULL
|
||||||
|
OR
|
||||||
|
% x86disasm dis
|
||||||
|
_486b0708_p_x86disasm
|
||||||
|
% puts "[dis cget -last_error]"
|
||||||
|
0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The Interface Files
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
libdisasm.i -- interface file without shadow classes
|
||||||
|
libdisasm_oop.i -- interface file with shadow classes
|
508
libdisasm/swig/libdisasm.i
Normal file
508
libdisasm/swig/libdisasm.i
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
%module x86disasm
|
||||||
|
%{
|
||||||
|
#include "../../libdis.h"
|
||||||
|
#include "../../../config.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%rename(version_string) x86_version_string;
|
||||||
|
%include "../../libdis.h"
|
||||||
|
#include "../../../config.h"
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
const char * x86_version_string( void ) {
|
||||||
|
return PACKAGE_VERSION;
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
%rename(report_codes) x86_report_codes;
|
||||||
|
%rename(report_error) x86_report_error;
|
||||||
|
%rename(options) x86_options;
|
||||||
|
%rename(init) x86_init;
|
||||||
|
%rename(set_reporter) x86_set_reporter;
|
||||||
|
%rename(set_options) x86_set_options;
|
||||||
|
%rename(options) x86_get_options;
|
||||||
|
%rename(cleanup) x86_cleanup;
|
||||||
|
%rename(reg_type) x86_reg_type;
|
||||||
|
%rename(reg) x86_reg_t;
|
||||||
|
%rename(eaddr) x86_ea_t;
|
||||||
|
%rename(op_type) x86_op_type;
|
||||||
|
%rename(optype_is_address) x86_optype_is_address;
|
||||||
|
%rename(optype_is_relative) x86_optype_is_relative;
|
||||||
|
%rename(op_datatype) x86_op_datatype;
|
||||||
|
%rename(op_access) x86_op_access;
|
||||||
|
%rename(op_flags) x86_op_flags;
|
||||||
|
%rename(operand) x86_op_t;
|
||||||
|
%rename(insn_group) x86_insn_group;
|
||||||
|
%rename(insn_type) x86_insn_type;
|
||||||
|
%rename(insn_note) x86_insn_note ;
|
||||||
|
%rename(flag_status) x86_flag_status;
|
||||||
|
%rename(insn_cpu) x86_insn_cpu ;
|
||||||
|
%rename(insn_isa) x86_insn_isa ;
|
||||||
|
%rename(insn_prefix) x86_insn_prefix ;
|
||||||
|
%rename(insn) x86_insn_t;
|
||||||
|
%rename(insn_is_valid) x86_insn_is_valid;
|
||||||
|
%rename(i_disasm) x86_disasm;
|
||||||
|
%rename(i_disasm_range) x86_disasm_range;
|
||||||
|
%rename(i_disasm_forward) x86_disasm_forward;
|
||||||
|
%rename(insn_operand_count) x86_operand_count;
|
||||||
|
%rename(insn_operand_1st) x86_operand_1st;
|
||||||
|
%rename(insn_operand_2nd) x86_operand_2nd;
|
||||||
|
%rename(insn_operand_3rd) x86_operand_3rd;
|
||||||
|
%rename(insn_dest_operand) x86_get_dest_operand;
|
||||||
|
%rename(insn_src_operand) x86_get_src_operand;
|
||||||
|
%rename(insn_imm_operand) x86_get_imm_operand;
|
||||||
|
%rename(operand_size) x86_operand_size;
|
||||||
|
%rename(insn_rel_offset) x86_get_rel_offset;
|
||||||
|
%rename(insn_branch_target) x86_get_branch_target;
|
||||||
|
%rename(insn_imm) x86_get_imm;
|
||||||
|
%rename(insn_raw_imm) x86_get_raw_imm;
|
||||||
|
%rename(insn_set_addr) x86_set_insn_addr;
|
||||||
|
%rename(insn_set_offset) x86_set_insn_offset;
|
||||||
|
%rename(insn_set_function) x86_set_insn_function;
|
||||||
|
%rename(insn_set_block) x86_set_insn_block;
|
||||||
|
%rename(insn_tag) x86_tag_insn;
|
||||||
|
%rename(insn_untag) x86_untag_insn;
|
||||||
|
%rename(insn_is_tagged) x86_insn_is_tagged;
|
||||||
|
%rename(asm_format) x86_asm_format;
|
||||||
|
%rename(operand_format) x86_format_operand;
|
||||||
|
%rename(insn_format_mnemonic) x86_format_mnemonic;
|
||||||
|
%rename(insn_format) x86_format_insn;
|
||||||
|
%rename(header_format) x86_format_header;
|
||||||
|
%rename(endian) x86_endian;
|
||||||
|
%rename(size_default_address) x86_addr_size;
|
||||||
|
%rename(size_default_operand) x86_op_size;
|
||||||
|
%rename(size_machine_word) x86_word_size;
|
||||||
|
%rename(size_max_insn) x86_max_insn_size;
|
||||||
|
%rename(reg_sp) x86_sp_reg;
|
||||||
|
%rename(reg_fp) x86_fp_reg;
|
||||||
|
%rename(reg_ip) x86_ip_reg;
|
||||||
|
%rename(reg_from_id) x86_reg_from_id;
|
||||||
|
%rename(reg_from_alias) x86_get_aliased_reg;
|
||||||
|
%rename(invariant_op) x86_invariant_op_t;
|
||||||
|
%rename(invariant) x86_invariant_t;
|
||||||
|
%rename(disasm_invariant) x86_invariant_disasm;
|
||||||
|
%rename(disasm_size) x86_size_disasm;
|
||||||
|
|
||||||
|
%include "carrays.i"
|
||||||
|
|
||||||
|
%array_class( unsigned char, byteArray );
|
||||||
|
|
||||||
|
|
||||||
|
%apply (unsigned char *STRING, int LENGTH) {
|
||||||
|
(unsigned char *buf, size_t buf_len)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
%newobject x86_op_copy;
|
||||||
|
%inline %{
|
||||||
|
x86_op_t * x86_op_copy( x86_op_t * src ) {
|
||||||
|
x86_op_t *op;
|
||||||
|
|
||||||
|
if (! src ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
op = (x86_op_t *) calloc( sizeof(x86_op_t), 1 );
|
||||||
|
if ( op ) {
|
||||||
|
memcpy( op, src, sizeof(x86_op_t) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct x86_op_list_node {
|
||||||
|
x86_op_t *op;
|
||||||
|
struct x86_op_list_node *next, *prev;
|
||||||
|
} x86_op_list_node;
|
||||||
|
|
||||||
|
typedef struct x86_op_list {
|
||||||
|
size_t count;
|
||||||
|
x86_op_list_node *head, *tail, *curr;
|
||||||
|
} x86_op_list;
|
||||||
|
|
||||||
|
x86_op_list * x86_op_list_new () {
|
||||||
|
x86_op_list *list = (x86_op_list *)
|
||||||
|
calloc( sizeof(x86_op_list), 1 );
|
||||||
|
list->count = 0;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_op_list_free(x86_op_list *list) {
|
||||||
|
x86_op_list_node *node, *next;
|
||||||
|
|
||||||
|
node = list->head;
|
||||||
|
while ( node ) {
|
||||||
|
next = node->next;
|
||||||
|
/* free( node->insn ); */
|
||||||
|
free( node );
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free( list );
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_op_list_node * x86_op_list_first(x86_op_list *list) {
|
||||||
|
return list->head;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_op_list_node * x86_op_list_last(x86_op_list *list) {
|
||||||
|
return list->tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_op_list_node * x86_op_list_next(x86_op_list *list) {
|
||||||
|
if (! list->curr ) {
|
||||||
|
list->curr = list->head;
|
||||||
|
return list->head;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->curr = list->curr->next;
|
||||||
|
return list->curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_op_list_node * x86_op_list_prev(x86_op_list *list) {
|
||||||
|
if (! list->curr ) {
|
||||||
|
list->curr = list->tail;
|
||||||
|
return list->tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->curr = list->curr->prev;
|
||||||
|
return list->curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%newobject x86_op_list_append;
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
void x86_op_list_append( x86_op_list * list, x86_op_t *op ) {
|
||||||
|
x86_op_list_node *node = (x86_op_list_node *)
|
||||||
|
calloc( sizeof(x86_op_list_node) , 1 );
|
||||||
|
if (! node ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->count++;
|
||||||
|
if ( ! list->tail ) {
|
||||||
|
list->head = list->tail = node;
|
||||||
|
} else {
|
||||||
|
list->tail->next = node;
|
||||||
|
node->prev = list->tail;
|
||||||
|
list->tail = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->op = x86_op_copy( op );
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_oplist_t * x86_op_list_node_copy( x86_oplist_t * list ) {
|
||||||
|
x86_oplist_t *ptr;
|
||||||
|
ptr = (x86_oplist_t *) calloc( sizeof(x86_oplist_t), 1 );
|
||||||
|
if ( ptr ) {
|
||||||
|
memcpy( &ptr->op, &list->op, sizeof(x86_op_t) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_insn_t * x86_insn_new() {
|
||||||
|
x86_insn_t *insn = (x86_insn_t *)
|
||||||
|
calloc( sizeof(x86_insn_t), 1 );
|
||||||
|
return insn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_insn_free( x86_insn_t *insn ) {
|
||||||
|
x86_oplist_free( insn );
|
||||||
|
free( insn );
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
%newobject x86_insn_copy;
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
x86_insn_t * x86_insn_copy( x86_insn_t *src) {
|
||||||
|
x86_oplist_t *ptr, *list, *last = NULL;
|
||||||
|
x86_insn_t *insn = (x86_insn_t *)
|
||||||
|
calloc( sizeof(x86_insn_t), 1 );
|
||||||
|
|
||||||
|
if ( insn ) {
|
||||||
|
memcpy( insn, src, sizeof(x86_insn_t) );
|
||||||
|
insn->operands = NULL;
|
||||||
|
insn->block = NULL;
|
||||||
|
insn->function = NULL;
|
||||||
|
|
||||||
|
/* copy operand list */
|
||||||
|
for ( list = src->operands; list; list = list->next ) {
|
||||||
|
ptr = x86_op_list_node_copy( list );
|
||||||
|
|
||||||
|
if (! ptr ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( insn->operands ) {
|
||||||
|
last->next = ptr;
|
||||||
|
} else {
|
||||||
|
insn->operands = ptr;
|
||||||
|
}
|
||||||
|
last = ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return insn;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_op_list * x86_insn_op_list( x86_insn_t *insn ) {
|
||||||
|
x86_oplist_t *list = insn->operands;
|
||||||
|
x86_op_list *op_list = x86_op_list_new();
|
||||||
|
|
||||||
|
for ( list = insn->operands; list; list = list->next ) {
|
||||||
|
x86_op_list_append( op_list, &list->op );
|
||||||
|
}
|
||||||
|
|
||||||
|
return op_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct x86_insn_list_node {
|
||||||
|
x86_insn_t *insn;
|
||||||
|
struct x86_insn_list_node *next, *prev;
|
||||||
|
} x86_insn_list_node;
|
||||||
|
|
||||||
|
typedef struct x86_insn_list {
|
||||||
|
size_t count;
|
||||||
|
x86_insn_list_node *head, *tail, *curr;
|
||||||
|
} x86_insn_list;
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%newobject x86_insn_list_new;
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
x86_insn_list * x86_insn_list_new () {
|
||||||
|
x86_insn_list *list = (x86_insn_list *)
|
||||||
|
calloc( sizeof(x86_insn_list), 1 );
|
||||||
|
list->count = 0;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_insn_list_free( x86_insn_list * list ) {
|
||||||
|
x86_insn_list_node *node, *next;
|
||||||
|
|
||||||
|
if (! list ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = list->head;
|
||||||
|
while ( node ) {
|
||||||
|
next = node->next;
|
||||||
|
/* free( node->insn ); */
|
||||||
|
free( node );
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free( list );
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_insn_list_node * x86_insn_list_first( x86_insn_list *list ) {
|
||||||
|
if (! list ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return list->head;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_insn_list_node * x86_insn_list_last( x86_insn_list *list ) {
|
||||||
|
if (! list ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return list->tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_insn_list_node * x86_insn_list_next( x86_insn_list *list ) {
|
||||||
|
if (! list ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (! list->curr ) {
|
||||||
|
list->curr = list->head;
|
||||||
|
return list->head;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->curr = list->curr->next;
|
||||||
|
return list->curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_insn_list_node * x86_insn_list_prev( x86_insn_list *list ) {
|
||||||
|
if (! list ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (! list->curr ) {
|
||||||
|
list->curr = list->tail;
|
||||||
|
return list->tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->curr = list->curr->prev;
|
||||||
|
return list->curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%newobject x86_insn_list_append;
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
void x86_insn_list_append( x86_insn_list *list, x86_insn_t *insn ) {
|
||||||
|
x86_insn_list_node *node;
|
||||||
|
if (! list ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = (x86_insn_list_node *)
|
||||||
|
calloc( sizeof(x86_insn_list_node) , 1 );
|
||||||
|
|
||||||
|
if (! node ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->count++;
|
||||||
|
if ( ! list->tail ) {
|
||||||
|
list->head = list->tail = node;
|
||||||
|
} else {
|
||||||
|
list->tail->next = node;
|
||||||
|
node->prev = list->tail;
|
||||||
|
list->tail = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->insn = x86_insn_copy( insn );
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum x86_report_codes last_error;
|
||||||
|
void * last_error_data;
|
||||||
|
void * disasm_callback;
|
||||||
|
void * disasm_resolver;
|
||||||
|
} x86disasm;
|
||||||
|
|
||||||
|
void x86_default_reporter( enum x86_report_codes code,
|
||||||
|
void *data, void *arg ) {
|
||||||
|
x86disasm *dis = (x86disasm *) arg;
|
||||||
|
if ( dis ) {
|
||||||
|
dis->last_error = code;
|
||||||
|
dis->last_error_data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_default_callback( x86_insn_t *insn, void *arg ) {
|
||||||
|
x86_insn_list *list = (x86_insn_list *) arg;
|
||||||
|
if ( list ) {
|
||||||
|
x86_insn_list_append( list, insn );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: resolver stack, maybe a callback */
|
||||||
|
long x86_default_resolver( x86_op_t *op, x86_insn_t *insn, void *arg ) {
|
||||||
|
x86disasm *dis = (x86disasm *) arg;
|
||||||
|
if ( dis ) {
|
||||||
|
//return dis->resolver( op, insn );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%newobject x86disasm_new;
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
x86disasm * x86disasm_new ( enum x86_options options ) {
|
||||||
|
x86disasm * dis = (x86disasm *)
|
||||||
|
calloc( sizeof( x86disasm ), 1 );
|
||||||
|
x86_init( options, x86_default_reporter, dis );
|
||||||
|
return dis;
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86disasm_free( x86disasm * dis ) {
|
||||||
|
x86_cleanup();
|
||||||
|
free( dis );
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
%newobject x86_disasm;
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
x86_insn_t * disasm( unsigned char *buf, size_t buf_len,
|
||||||
|
unsigned long buf_rva, unsigned int offset ) {
|
||||||
|
x86_insn_t *insn = calloc( sizeof( x86_insn_t ), 1 );
|
||||||
|
x86_disasm( buf, buf_len, buf_rva, offset, insn );
|
||||||
|
return insn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int disasm_range( unsigned char *buf, size_t buf_len,
|
||||||
|
unsigned long buf_rva, unsigned int offset,
|
||||||
|
unsigned int len ) {
|
||||||
|
|
||||||
|
x86_insn_list *list = x86_insn_list_new();
|
||||||
|
|
||||||
|
if ( len > buf_len ) {
|
||||||
|
len = buf_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return x86_disasm_range( buf, buf_rva, offset, len,
|
||||||
|
x86_default_callback, list );
|
||||||
|
}
|
||||||
|
|
||||||
|
int disasm_forward( unsigned char *buf, size_t buf_len,
|
||||||
|
unsigned long buf_rva, unsigned int offset ) {
|
||||||
|
x86_insn_list *list = x86_insn_list_new();
|
||||||
|
|
||||||
|
/* use default resolver: damn SWIG callbacks! */
|
||||||
|
return x86_disasm_forward( buf, buf_len, buf_rva, offset,
|
||||||
|
x86_default_callback, list,
|
||||||
|
x86_default_resolver, NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t disasm_invariant( unsigned char *buf, size_t buf_len,
|
||||||
|
x86_invariant_t *inv ) {
|
||||||
|
return x86_invariant_disasm( buf, buf_len, inv );
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t disasm_size( unsigned char *buf, size_t buf_len ) {
|
||||||
|
return x86_size_disasm( buf, buf_len );
|
||||||
|
}
|
||||||
|
|
||||||
|
int x86_max_operand_string( enum x86_asm_format format ) {
|
||||||
|
switch ( format ) {
|
||||||
|
case xml_syntax:
|
||||||
|
return MAX_OP_XML_STRING;
|
||||||
|
break;
|
||||||
|
case raw_syntax:
|
||||||
|
return MAX_OP_RAW_STRING;
|
||||||
|
break;
|
||||||
|
case native_syntax:
|
||||||
|
case intel_syntax:
|
||||||
|
case att_syntax:
|
||||||
|
case unknown_syntax:
|
||||||
|
default:
|
||||||
|
return MAX_OP_STRING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int x86_max_insn_string( enum x86_asm_format format ) {
|
||||||
|
switch ( format ) {
|
||||||
|
case xml_syntax:
|
||||||
|
return MAX_INSN_XML_STRING;
|
||||||
|
break;
|
||||||
|
case raw_syntax:
|
||||||
|
return MAX_INSN_RAW_STRING;
|
||||||
|
break;
|
||||||
|
case native_syntax:
|
||||||
|
case intel_syntax:
|
||||||
|
case att_syntax:
|
||||||
|
case unknown_syntax:
|
||||||
|
default:
|
||||||
|
return MAX_INSN_STRING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int x86_max_num_operands( ) { return MAX_NUM_OPERANDS; }
|
||||||
|
%}
|
||||||
|
|
1114
libdisasm/swig/libdisasm_oop.i
Normal file
1114
libdisasm/swig/libdisasm_oop.i
Normal file
File diff suppressed because it is too large
Load Diff
65
libdisasm/swig/perl/Makefile-swig
Normal file
65
libdisasm/swig/perl/Makefile-swig
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
ifndef BASE_NAME
|
||||||
|
BASE_NAME = x86disasm
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef SWIG
|
||||||
|
SWIG = swig # apt-get install swig !
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef GCC
|
||||||
|
GCC = gcc
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef CC_FLAGS
|
||||||
|
CC_FLAGS = -c -fPIC
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef LD_FLAGS
|
||||||
|
LD_FLAGS = -shared -L.. -ldisasm
|
||||||
|
endif
|
||||||
|
|
||||||
|
INTERFACE_FILE = libdisasm_oop.i
|
||||||
|
|
||||||
|
SWIG_INTERFACE = ../$(INTERFACE_FILE)
|
||||||
|
|
||||||
|
# PERL rules
|
||||||
|
PERL_MOD = blib/arch/auto/$(BASE_NAME)/$(BASE_NAME).so
|
||||||
|
PERL_SHADOW = $(BASE_NAME)_wrap.c
|
||||||
|
PERL_SWIG = $(BASE_NAME).pl
|
||||||
|
PERL_OBJ = $(BASE_NAME)_wrap.o
|
||||||
|
PERL_INC = `perl -e 'use Config; print $$Config{archlib};'`/CORE
|
||||||
|
PERL_CC_FLAGS = `perl -e 'use Config; print $$Config{ccflags};'`
|
||||||
|
|
||||||
|
#====================================================
|
||||||
|
# TARGETS
|
||||||
|
|
||||||
|
all: swig-perl
|
||||||
|
|
||||||
|
dummy: swig-perl install uninstall clean
|
||||||
|
|
||||||
|
swig-perl: $(PERL_MOD)
|
||||||
|
|
||||||
|
$(PERL_MOD): $(PERL_OBJ)
|
||||||
|
perl Makefile.PL
|
||||||
|
make
|
||||||
|
#$(GCC) $(LD_FLAGS) $(PERL_OBJ) -o $@
|
||||||
|
|
||||||
|
$(PERL_OBJ): $(PERL_SHADOW)
|
||||||
|
$(GCC) $(CC_FLAGS) $(PERL_CC_FLAGS) -I$(PERL_INC) -o $@ $<
|
||||||
|
|
||||||
|
$(PERL_SHADOW): $(SWIG_INTERFACE)
|
||||||
|
swig -perl -shadow -o $(PERL_SHADOW) -outdir . $<
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
install: $(PERL_MOD)
|
||||||
|
make install
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
uninstall:
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
clean:
|
||||||
|
rm $(PERL_MOD) $(PERL_OBJ)
|
||||||
|
rm $(PERL_SHADOW)
|
||||||
|
rm -rf Makefile blib pm_to_blib
|
||||||
|
|
7
libdisasm/swig/perl/Makefile.PL
Normal file
7
libdisasm/swig/perl/Makefile.PL
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
use ExtUtils::MakeMaker;
|
||||||
|
|
||||||
|
WriteMakefile(
|
||||||
|
'NAME' => 'x86disasm',
|
||||||
|
'LIBS' => ['-ldisasm'],
|
||||||
|
'OBJECT' => 'x86disasm_wrap.o'
|
||||||
|
);
|
64
libdisasm/swig/python/Makefile-swig
Normal file
64
libdisasm/swig/python/Makefile-swig
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
ifndef BASE_NAME
|
||||||
|
BASE_NAME = x86disasm
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef SWIG
|
||||||
|
SWIG = swig # apt-get install swig !
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef GCC
|
||||||
|
GCC = gcc
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef CC_FLAGS
|
||||||
|
CC_FLAGS = -c -fPIC
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef LD_FLAGS
|
||||||
|
LD_FLAGS = -shared -L.. -ldisasm
|
||||||
|
endif
|
||||||
|
|
||||||
|
INTERFACE_FILE = libdisasm_oop.i
|
||||||
|
|
||||||
|
SWIG_INTERFACE = ../$(INTERFACE_FILE)
|
||||||
|
|
||||||
|
# PYTHON rules
|
||||||
|
PYTHON_MOD = $(BASE_NAME)-python.so
|
||||||
|
PYTHON_SHADOW = $(BASE_NAME)_wrap.c
|
||||||
|
PYTHON_SWIG = $(BASE_NAME).py
|
||||||
|
PYTHON_OBJ = $(BASE_NAME)_wrap.o
|
||||||
|
PYTHON_INC = `/bin/echo -e 'import sys\nprint sys.prefix + "/include/python" + sys.version[:3]' | python`
|
||||||
|
PYTHON_LIB = `/bin/echo -e 'import sys\nprint sys.prefix + "/lib/python" + sys.version[:3]' | python`
|
||||||
|
PYTHON_DEST = $(PYTHON_LIB)/lib-dynload/_$(BASE_NAME).so
|
||||||
|
|
||||||
|
#====================================================
|
||||||
|
# TARGETS
|
||||||
|
|
||||||
|
all: swig-python
|
||||||
|
|
||||||
|
dummy: swig-python install uninstall clean
|
||||||
|
|
||||||
|
swig-python: $(PYTHON_MOD)
|
||||||
|
|
||||||
|
$(PYTHON_MOD): $(PYTHON_OBJ)
|
||||||
|
$(GCC) $(LD_FLAGS) $(PYTHON_OBJ) -o $@
|
||||||
|
|
||||||
|
$(PYTHON_OBJ): $(PYTHON_SHADOW)
|
||||||
|
$(GCC) $(CC_FLAGS) -I$(PYTHON_INC) -I.. -o $@ $<
|
||||||
|
|
||||||
|
$(PYTHON_SHADOW): $(SWIG_INTERFACE)
|
||||||
|
swig -python -shadow -o $(PYTHON_SHADOW) -outdir . $<
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
install: $(PYTHON_MOD)
|
||||||
|
sudo cp $(PYTHON_MOD) $(PYTHON_DEST)
|
||||||
|
sudo cp $(PYTHON_SWIG) $(PYTHON_LIB)
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
uninstall:
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
clean:
|
||||||
|
rm $(PYTHON_MOD) $(PYTHON_SWIG) $(PYTHON_OBJ)
|
||||||
|
rm $(PYTHON_SHADOW)
|
||||||
|
|
68
libdisasm/swig/ruby/Makefile-swig
Normal file
68
libdisasm/swig/ruby/Makefile-swig
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
ifndef BASE_NAME
|
||||||
|
BASE_NAME = x86disasm
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef SWIG
|
||||||
|
SWIG = swig # apt-get install swig !
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef GCC
|
||||||
|
GCC = gcc
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef CC_FLAGS
|
||||||
|
CC_FLAGS = -c -fPIC
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef LD_FLAGS
|
||||||
|
LD_FLAGS = -shared -L../.. -ldisasm
|
||||||
|
endif
|
||||||
|
|
||||||
|
LIBDISASM_DIR = ../..
|
||||||
|
|
||||||
|
INTERFACE_FILE = libdisasm_oop.i
|
||||||
|
|
||||||
|
SWIG_INTERFACE = ../$(INTERFACE_FILE)
|
||||||
|
|
||||||
|
# RUBY rules
|
||||||
|
RUBY_MAKEFILE = Makefile
|
||||||
|
RUBY_MOD = $(BASE_NAME).so
|
||||||
|
RUBY_SHADOW = $(BASE_NAME)_wrap.c
|
||||||
|
#RUBY_SWIG = $(BASE_NAME).rb
|
||||||
|
RUBY_OBJ = $(BASE_NAME)_wrap.o
|
||||||
|
RUBY_INC = `ruby -e 'puts $$:.join("\n")' | tail -2 | head -1`
|
||||||
|
#RUBY_LIB =
|
||||||
|
#RUBY_DEST =
|
||||||
|
|
||||||
|
#====================================================
|
||||||
|
# TARGETS
|
||||||
|
|
||||||
|
all: swig-ruby
|
||||||
|
|
||||||
|
dummy: swig-ruby install uninstall clean
|
||||||
|
|
||||||
|
swig-ruby: $(RUBY_MOD)
|
||||||
|
|
||||||
|
$(RUBY_MOD): $(RUBY_MAKEFILE)
|
||||||
|
make
|
||||||
|
|
||||||
|
$(RUBY_MAKEFILE): $(RUBY_OBJ)
|
||||||
|
ruby extconf.rb
|
||||||
|
|
||||||
|
$(RUBY_OBJ):$(RUBY_SHADOW)
|
||||||
|
$(GCC) $(CC_FLAGS) -I$(RUBY_INC) -I.. -o $@ $<
|
||||||
|
|
||||||
|
$(RUBY_SHADOW): $(SWIG_INTERFACE)
|
||||||
|
swig -ruby -o $(RUBY_SHADOW) -outdir . $<
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
install: $(RUBY_MOD)
|
||||||
|
make install
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
uninstall:
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
clean:
|
||||||
|
make clean || true
|
||||||
|
rm $(RUBY_SHADOW) $(RUBY_MAKEFILE) $(RUBY_MOD) $(RUBY_OBJ)
|
4
libdisasm/swig/ruby/extconf.rb
Normal file
4
libdisasm/swig/ruby/extconf.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
require 'mkmf'
|
||||||
|
find_library('disasm', 'x86_init', "/usr/local/lib", "../..")
|
||||||
|
create_makefile('x86disasm')
|
||||||
|
|
63
libdisasm/swig/tcl/Makefile-swig
Normal file
63
libdisasm/swig/tcl/Makefile-swig
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
ifndef BASE_NAME
|
||||||
|
BASE_NAME = x86disasm
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef SWIG
|
||||||
|
SWIG = swig # apt-get install swig !
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef GCC
|
||||||
|
GCC = gcc
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef CC_FLAGS
|
||||||
|
CC_FLAGS = -c -fPIC
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef LD_FLAGS
|
||||||
|
LD_FLAGS = -shared -L../.. -ldisasm
|
||||||
|
endif
|
||||||
|
|
||||||
|
INTERFACE_FILE = libdisasm.i
|
||||||
|
|
||||||
|
SWIG_INTERFACE = ../$(INTERFACE_FILE)
|
||||||
|
|
||||||
|
# TCL rules
|
||||||
|
TCL_VERSION = 8.3
|
||||||
|
TCL_MOD = $(BASE_NAME)-tcl.so
|
||||||
|
TCL_SHADOW = $(BASE_NAME)_wrap.c
|
||||||
|
TCL_OBJ = $(BASE_NAME)_wrap.o
|
||||||
|
TCL_INC = /usr/include/tcl$(TCL_VERSION)
|
||||||
|
TCL_LIB = /usr/lib/tcl$(TCL_VERSION)
|
||||||
|
TCL_DEST = $(TCL_LIB)/$(BASE_NAME).so
|
||||||
|
|
||||||
|
#====================================================
|
||||||
|
# TARGETS
|
||||||
|
|
||||||
|
all: swig-tcl
|
||||||
|
|
||||||
|
dummy: swig-tcl install uninstall clean
|
||||||
|
|
||||||
|
swig-tcl: $(TCL_MOD)
|
||||||
|
|
||||||
|
$(TCL_MOD): $(TCL_OBJ)
|
||||||
|
$(GCC) $(LD_FLAGS) $(TCL_OBJ) -o $@
|
||||||
|
|
||||||
|
$(TCL_OBJ): $(TCL_SHADOW)
|
||||||
|
$(GCC) $(CC_FLAGS) -I$(TCL_INC) -I.. -o $@ $<
|
||||||
|
|
||||||
|
$(TCL_SHADOW): $(SWIG_INTERFACE)
|
||||||
|
swig -tcl -o $(TCL_SHADOW) -outdir . $<
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
install: $(TCL_MOD)
|
||||||
|
sudo cp $(TCL_MOD) $(TCL_DEST)
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
uninstall:
|
||||||
|
|
||||||
|
# ==================================================================
|
||||||
|
clean:
|
||||||
|
rm $(TCL_MOD) $(TCL_SWIG) $(TCL_OBJ)
|
||||||
|
rm $(TCL_SHADOW)
|
||||||
|
|
210
libdisasm/x86_disasm.c
Normal file
210
libdisasm/x86_disasm.c
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "libdis.h"
|
||||||
|
#include "ia32_insn.h"
|
||||||
|
#include "ia32_invariant.h"
|
||||||
|
#include "x86_operand_list.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define inline __inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned int x86_disasm( unsigned char *buf, unsigned int buf_len,
|
||||||
|
uint32_t buf_rva, unsigned int offset,
|
||||||
|
x86_insn_t *insn ){
|
||||||
|
int len, size;
|
||||||
|
unsigned char bytes[MAX_INSTRUCTION_SIZE];
|
||||||
|
|
||||||
|
if ( ! buf || ! insn || ! buf_len ) {
|
||||||
|
/* caller screwed up somehow */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ensure we are all NULLed up */
|
||||||
|
memset( insn, 0, sizeof(x86_insn_t) );
|
||||||
|
insn->addr = buf_rva + offset;
|
||||||
|
insn->offset = offset;
|
||||||
|
/* default to invalid insn */
|
||||||
|
insn->type = insn_invalid;
|
||||||
|
insn->group = insn_none;
|
||||||
|
|
||||||
|
if ( offset >= buf_len ) {
|
||||||
|
/* another caller screwup ;) */
|
||||||
|
x86_report_error(report_disasm_bounds, (void*)(long)buf_rva+offset);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = buf_len - offset;
|
||||||
|
|
||||||
|
/* copy enough bytes for disassembly into buffer : this
|
||||||
|
* helps prevent buffer overruns at the end of a file */
|
||||||
|
memset( bytes, 0, MAX_INSTRUCTION_SIZE );
|
||||||
|
memcpy( bytes, &buf[offset], (len < MAX_INSTRUCTION_SIZE) ? len :
|
||||||
|
MAX_INSTRUCTION_SIZE );
|
||||||
|
|
||||||
|
/* actually do the disassembly */
|
||||||
|
/* TODO: allow switching when more disassemblers are added */
|
||||||
|
size = ia32_disasm_addr( bytes, len, insn);
|
||||||
|
|
||||||
|
/* check and see if we had an invalid instruction */
|
||||||
|
if (! size ) {
|
||||||
|
x86_report_error(report_invalid_insn, (void*)(long)buf_rva+offset );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if we overran the end of the buffer */
|
||||||
|
if ( size > len ) {
|
||||||
|
x86_report_error( report_insn_bounds, (void*)(long)buf_rva + offset );
|
||||||
|
MAKE_INVALID( insn, bytes );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill bytes field of insn */
|
||||||
|
memcpy( insn->bytes, bytes, size );
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int x86_disasm_range( unsigned char *buf, uint32_t buf_rva,
|
||||||
|
unsigned int offset, unsigned int len,
|
||||||
|
DISASM_CALLBACK func, void *arg ) {
|
||||||
|
x86_insn_t insn;
|
||||||
|
unsigned int buf_len, size, count = 0, bytes = 0;
|
||||||
|
|
||||||
|
/* buf_len is implied by the arguments */
|
||||||
|
buf_len = len + offset;
|
||||||
|
|
||||||
|
while ( bytes < len ) {
|
||||||
|
size = x86_disasm( buf, buf_len, buf_rva, offset + bytes,
|
||||||
|
&insn );
|
||||||
|
if ( size ) {
|
||||||
|
/* invoke callback if it exists */
|
||||||
|
if ( func ) {
|
||||||
|
(*func)( &insn, arg );
|
||||||
|
}
|
||||||
|
bytes += size;
|
||||||
|
count ++;
|
||||||
|
} else {
|
||||||
|
/* error */
|
||||||
|
bytes++; /* try next byte */
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_oplist_free( &insn );
|
||||||
|
}
|
||||||
|
|
||||||
|
return( count );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int follow_insn_dest( x86_insn_t *insn ) {
|
||||||
|
if ( insn->type == insn_jmp || insn->type == insn_jcc ||
|
||||||
|
insn->type == insn_call || insn->type == insn_callcc ) {
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int insn_doesnt_return( x86_insn_t *insn ) {
|
||||||
|
return( (insn->type == insn_jmp || insn->type == insn_return) ? 1: 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t internal_resolver( x86_op_t *op, x86_insn_t *insn ){
|
||||||
|
int32_t next_addr = -1;
|
||||||
|
if ( x86_optype_is_address(op->type) ) {
|
||||||
|
next_addr = op->data.sdword;
|
||||||
|
} else if ( op->type == op_relative_near ) {
|
||||||
|
next_addr = insn->addr + insn->size + op->data.relative_near;
|
||||||
|
} else if ( op->type == op_relative_far ) {
|
||||||
|
next_addr = insn->addr + insn->size + op->data.relative_far;
|
||||||
|
}
|
||||||
|
return( next_addr );
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int x86_disasm_forward( unsigned char *buf, unsigned int buf_len,
|
||||||
|
uint32_t buf_rva, unsigned int offset,
|
||||||
|
DISASM_CALLBACK func, void *arg,
|
||||||
|
DISASM_RESOLVER resolver, void *r_arg ){
|
||||||
|
x86_insn_t insn;
|
||||||
|
x86_op_t *op;
|
||||||
|
int32_t next_addr;
|
||||||
|
uint32_t next_offset;
|
||||||
|
unsigned int size, count = 0, bytes = 0, cont = 1;
|
||||||
|
|
||||||
|
while ( cont && bytes < buf_len ) {
|
||||||
|
size = x86_disasm( buf, buf_len, buf_rva, offset + bytes,
|
||||||
|
&insn );
|
||||||
|
|
||||||
|
if ( size ) {
|
||||||
|
/* invoke callback if it exists */
|
||||||
|
if ( func ) {
|
||||||
|
(*func)( &insn, arg );
|
||||||
|
}
|
||||||
|
bytes += size;
|
||||||
|
count ++;
|
||||||
|
} else {
|
||||||
|
/* error */
|
||||||
|
bytes++; /* try next byte */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( follow_insn_dest(&insn) ) {
|
||||||
|
op = x86_get_dest_operand( &insn );
|
||||||
|
next_addr = -1;
|
||||||
|
|
||||||
|
/* if caller supplied a resolver, use it to determine
|
||||||
|
* the address to disassemble */
|
||||||
|
if ( resolver ) {
|
||||||
|
next_addr = resolver(op, &insn, r_arg);
|
||||||
|
} else {
|
||||||
|
next_addr = internal_resolver(op, &insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_addr != -1 ) {
|
||||||
|
next_offset = next_addr - buf_rva;
|
||||||
|
/* if offset is in this buffer... */
|
||||||
|
if ( next_offset >= 0 &&
|
||||||
|
next_offset < buf_len ) {
|
||||||
|
/* go ahead and disassemble */
|
||||||
|
count += x86_disasm_forward( buf,
|
||||||
|
buf_len,
|
||||||
|
buf_rva,
|
||||||
|
next_offset,
|
||||||
|
func, arg,
|
||||||
|
resolver, r_arg );
|
||||||
|
} else {
|
||||||
|
/* report unresolved address */
|
||||||
|
x86_report_error( report_disasm_bounds,
|
||||||
|
(void*)(long)next_addr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /* end follow_insn */
|
||||||
|
|
||||||
|
if ( insn_doesnt_return(&insn) ) {
|
||||||
|
/* stop disassembling */
|
||||||
|
cont = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_oplist_free( &insn );
|
||||||
|
}
|
||||||
|
return( count );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* invariant instruction representation */
|
||||||
|
size_t x86_invariant_disasm( unsigned char *buf, int buf_len,
|
||||||
|
x86_invariant_t *inv ){
|
||||||
|
if (! buf || ! buf_len || ! inv ) {
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ia32_disasm_invariant(buf, buf_len, inv);
|
||||||
|
}
|
||||||
|
size_t x86_size_disasm( unsigned char *buf, unsigned int buf_len ) {
|
||||||
|
if (! buf || ! buf_len ) {
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ia32_disasm_size(buf, buf_len);
|
||||||
|
}
|
1430
libdisasm/x86_format.c
Normal file
1430
libdisasm/x86_format.c
Normal file
File diff suppressed because it is too large
Load Diff
70
libdisasm/x86_imm.c
Normal file
70
libdisasm/x86_imm.c
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include "qword.h"
|
||||||
|
#include "x86_imm.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
unsigned int x86_imm_signsized( unsigned char * buf, size_t buf_len,
|
||||||
|
void *dest, unsigned int size ) {
|
||||||
|
signed char *cp = (signed char *) dest;
|
||||||
|
signed short *sp = (signed short *) dest;
|
||||||
|
int32_t *lp = (int32_t *) dest;
|
||||||
|
qword_t *qp = (qword_t *) dest;
|
||||||
|
|
||||||
|
if ( size > buf_len ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy 'size' bytes from *buf to *op
|
||||||
|
* return number of bytes copied */
|
||||||
|
switch (size) {
|
||||||
|
case 1: /* BYTE */
|
||||||
|
*cp = *((signed char *) buf);
|
||||||
|
break;
|
||||||
|
case 2: /* WORD */
|
||||||
|
*sp = *((signed short *) buf);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
case 8: /* QWORD */
|
||||||
|
*qp = *((qword_t *) buf);
|
||||||
|
break;
|
||||||
|
case 4: /* DWORD */
|
||||||
|
default:
|
||||||
|
*lp = *((int32_t *) buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int x86_imm_sized( unsigned char * buf, size_t buf_len, void *dest,
|
||||||
|
unsigned int size ) {
|
||||||
|
unsigned char *cp = (unsigned char *) dest;
|
||||||
|
unsigned short *sp = (unsigned short *) dest;
|
||||||
|
uint32_t *lp = (uint32_t *) dest;
|
||||||
|
qword_t *qp = (qword_t *) dest;
|
||||||
|
|
||||||
|
if ( size > buf_len ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy 'size' bytes from *buf to *op
|
||||||
|
* return number of bytes copied */
|
||||||
|
switch (size) {
|
||||||
|
case 1: /* BYTE */
|
||||||
|
*cp = *((unsigned char *) buf);
|
||||||
|
break;
|
||||||
|
case 2: /* WORD */
|
||||||
|
*sp = *((unsigned short *) buf);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
case 8: /* QWORD */
|
||||||
|
*qp = *((qword_t *) buf);
|
||||||
|
break;
|
||||||
|
case 4: /* DWORD */
|
||||||
|
default:
|
||||||
|
*lp = *((uint32_t *) buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (size);
|
||||||
|
}
|
||||||
|
|
18
libdisasm/x86_imm.h
Normal file
18
libdisasm/x86_imm.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef x86_IMM_H
|
||||||
|
#define x86_IMM_H
|
||||||
|
|
||||||
|
#include "./qword.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* these are in the global x86 namespace but are not a part of the
|
||||||
|
* official API */
|
||||||
|
unsigned int x86_imm_sized( unsigned char *buf, size_t buf_len, void *dest,
|
||||||
|
unsigned int size );
|
||||||
|
|
||||||
|
unsigned int x86_imm_signsized( unsigned char *buf, size_t buf_len, void *dest,
|
||||||
|
unsigned int size );
|
||||||
|
#endif
|
182
libdisasm/x86_insn.c
Normal file
182
libdisasm/x86_insn.c
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "libdis.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define inline __inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int x86_insn_is_valid( x86_insn_t *insn ) {
|
||||||
|
if ( insn && insn->type != insn_invalid && insn->size > 0 ) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t x86_get_address( x86_insn_t *insn ) {
|
||||||
|
x86_oplist_t *op_lst;
|
||||||
|
if (! insn || ! insn->operands ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (op_lst = insn->operands; op_lst; op_lst = op_lst->next ) {
|
||||||
|
if ( op_lst->op.type == op_offset ) {
|
||||||
|
return op_lst->op.data.offset;
|
||||||
|
} else if ( op_lst->op.type == op_absolute ) {
|
||||||
|
if ( op_lst->op.datatype == op_descr16 ) {
|
||||||
|
return (uint32_t)
|
||||||
|
op_lst->op.data.absolute.offset.off16;
|
||||||
|
}
|
||||||
|
return op_lst->op.data.absolute.offset.off32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t x86_get_rel_offset( x86_insn_t *insn ) {
|
||||||
|
x86_oplist_t *op_lst;
|
||||||
|
if (! insn || ! insn->operands ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (op_lst = insn->operands; op_lst; op_lst = op_lst->next ) {
|
||||||
|
if ( op_lst->op.type == op_relative_near ) {
|
||||||
|
return (int32_t) op_lst->op.data.relative_near;
|
||||||
|
} else if ( op_lst->op.type == op_relative_far ) {
|
||||||
|
return op_lst->op.data.relative_far;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_op_t * x86_get_branch_target( x86_insn_t *insn ) {
|
||||||
|
x86_oplist_t *op_lst;
|
||||||
|
if (! insn || ! insn->operands ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (op_lst = insn->operands; op_lst; op_lst = op_lst->next ) {
|
||||||
|
if ( op_lst->op.access & op_execute ) {
|
||||||
|
return &(op_lst->op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
x86_op_t * x86_get_imm( x86_insn_t *insn ) {
|
||||||
|
x86_oplist_t *op_lst;
|
||||||
|
if (! insn || ! insn->operands ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (op_lst = insn->operands; op_lst; op_lst = op_lst->next ) {
|
||||||
|
if ( op_lst->op.type == op_immediate ) {
|
||||||
|
return &(op_lst->op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IS_PROPER_IMM( x ) \
|
||||||
|
x->op.type == op_immediate && ! (x->op.flags & op_hardcode)
|
||||||
|
|
||||||
|
|
||||||
|
/* if there is an immediate value in the instruction, return a pointer to
|
||||||
|
* it */
|
||||||
|
unsigned char * x86_get_raw_imm( x86_insn_t *insn ) {
|
||||||
|
int size, offset;
|
||||||
|
x86_op_t *op = NULL;
|
||||||
|
|
||||||
|
if (! insn || ! insn->operands ) {
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a bit inelegant, but oh well... */
|
||||||
|
if ( IS_PROPER_IMM( insn->operands ) ) {
|
||||||
|
op = &insn->operands->op;
|
||||||
|
} else if ( insn->operands->next ) {
|
||||||
|
if ( IS_PROPER_IMM( insn->operands->next ) ) {
|
||||||
|
op = &insn->operands->next->op;
|
||||||
|
} else if ( insn->operands->next->next &&
|
||||||
|
IS_PROPER_IMM( insn->operands->next->next ) ) {
|
||||||
|
op = &insn->operands->next->next->op;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! op ) {
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* immediate data is at the end of the insn */
|
||||||
|
size = x86_operand_size( op );
|
||||||
|
offset = insn->size - size;
|
||||||
|
return( &insn->bytes[offset] );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int x86_operand_size( x86_op_t *op ) {
|
||||||
|
switch (op->datatype ) {
|
||||||
|
case op_byte: return 1;
|
||||||
|
case op_word: return 2;
|
||||||
|
case op_dword: return 4;
|
||||||
|
case op_qword: return 8;
|
||||||
|
case op_dqword: return 16;
|
||||||
|
case op_sreal: return 4;
|
||||||
|
case op_dreal: return 8;
|
||||||
|
case op_extreal: return 10;
|
||||||
|
case op_bcd: return 10;
|
||||||
|
case op_ssimd: return 16;
|
||||||
|
case op_dsimd: return 16;
|
||||||
|
case op_sssimd: return 4;
|
||||||
|
case op_sdsimd: return 8;
|
||||||
|
case op_descr32: return 6;
|
||||||
|
case op_descr16: return 4;
|
||||||
|
case op_pdescr32: return 6;
|
||||||
|
case op_pdescr16: return 6;
|
||||||
|
case op_bounds16: return 4;
|
||||||
|
case op_bounds32: return 8;
|
||||||
|
case op_fpuenv16: return 14;
|
||||||
|
case op_fpuenv32: return 28;
|
||||||
|
case op_fpustate16: return 94;
|
||||||
|
case op_fpustate32: return 108;
|
||||||
|
case op_fpregset: return 512;
|
||||||
|
case op_fpreg: return 10;
|
||||||
|
case op_none: return 0;
|
||||||
|
}
|
||||||
|
return(4); /* default size */
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_set_insn_addr( x86_insn_t *insn, uint32_t addr ) {
|
||||||
|
if ( insn ) insn->addr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_set_insn_offset( x86_insn_t *insn, unsigned int offset ){
|
||||||
|
if ( insn ) insn->offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_set_insn_function( x86_insn_t *insn, void * func ){
|
||||||
|
if ( insn ) insn->function = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_set_insn_block( x86_insn_t *insn, void * block ){
|
||||||
|
if ( insn ) insn->block = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_tag_insn( x86_insn_t *insn ){
|
||||||
|
if ( insn ) insn->tag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_untag_insn( x86_insn_t *insn ){
|
||||||
|
if ( insn ) insn->tag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x86_insn_is_tagged( x86_insn_t *insn ){
|
||||||
|
return insn->tag;
|
||||||
|
}
|
||||||
|
|
71
libdisasm/x86_misc.c
Normal file
71
libdisasm/x86_misc.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "libdis.h"
|
||||||
|
#include "ia32_insn.h"
|
||||||
|
#include "ia32_reg.h" /* for ia32_reg wrapper */
|
||||||
|
#include "ia32_settings.h"
|
||||||
|
extern ia32_settings_t ia32_settings;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define inline __inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* =========================================================== INIT/TERM */
|
||||||
|
static DISASM_REPORTER __x86_reporter_func = NULL;
|
||||||
|
static void * __x86_reporter_arg = NULL;
|
||||||
|
|
||||||
|
int x86_init( enum x86_options options, DISASM_REPORTER reporter, void * arg )
|
||||||
|
{
|
||||||
|
ia32_settings.options = options;
|
||||||
|
__x86_reporter_func = reporter;
|
||||||
|
__x86_reporter_arg = arg;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_set_reporter( DISASM_REPORTER reporter, void * arg ) {
|
||||||
|
__x86_reporter_func = reporter;
|
||||||
|
__x86_reporter_arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_set_options( enum x86_options options ){
|
||||||
|
ia32_settings.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum x86_options x86_get_options( void ) {
|
||||||
|
return ia32_settings.options;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x86_cleanup( void )
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================================================== ERRORS */
|
||||||
|
void x86_report_error( enum x86_report_codes code, void *data ) {
|
||||||
|
if ( __x86_reporter_func ) {
|
||||||
|
(*__x86_reporter_func)(code, data, __x86_reporter_arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* =========================================================== MISC */
|
||||||
|
unsigned int x86_endian(void) { return ia32_settings.endian; }
|
||||||
|
unsigned int x86_addr_size(void) { return ia32_settings.sz_addr; }
|
||||||
|
unsigned int x86_op_size(void) { return ia32_settings.sz_oper; }
|
||||||
|
unsigned int x86_word_size(void) { return ia32_settings.sz_word; }
|
||||||
|
unsigned int x86_max_insn_size(void) { return ia32_settings.max_insn; }
|
||||||
|
unsigned int x86_sp_reg(void) { return ia32_settings.id_sp_reg; }
|
||||||
|
unsigned int x86_fp_reg(void) { return ia32_settings.id_fp_reg; }
|
||||||
|
unsigned int x86_ip_reg(void) { return ia32_settings.id_ip_reg; }
|
||||||
|
unsigned int x86_flag_reg(void) { return ia32_settings.id_flag_reg; }
|
||||||
|
|
||||||
|
/* wrapper function to hide the IA32 register fn */
|
||||||
|
void x86_reg_from_id( unsigned int id, x86_reg_t * reg ) {
|
||||||
|
ia32_handle_register( reg, id );
|
||||||
|
return;
|
||||||
|
}
|
191
libdisasm/x86_operand_list.c
Normal file
191
libdisasm/x86_operand_list.c
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include "libdis.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void x86_oplist_append( x86_insn_t *insn, x86_oplist_t *op ) {
|
||||||
|
x86_oplist_t *list;
|
||||||
|
|
||||||
|
if (! insn ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list = insn->operands;
|
||||||
|
if (! list ) {
|
||||||
|
insn->operand_count = 1;
|
||||||
|
/* Note that we have no way of knowing if this is an
|
||||||
|
* exlicit operand or not, since the caller fills
|
||||||
|
* the x86_op_t after we return. We increase the
|
||||||
|
* explicit count automatically, and ia32_insn_implicit_ops
|
||||||
|
* decrements it */
|
||||||
|
insn->explicit_count = 1;
|
||||||
|
insn->operands = op;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get to end of list */
|
||||||
|
for ( ; list->next; list = list->next )
|
||||||
|
;
|
||||||
|
|
||||||
|
insn->operand_count = insn->operand_count + 1;
|
||||||
|
insn->explicit_count = insn->explicit_count + 1;
|
||||||
|
list->next = op;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_op_t * x86_operand_new( x86_insn_t *insn ) {
|
||||||
|
x86_oplist_t *op;
|
||||||
|
|
||||||
|
if (! insn ) {
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
op = calloc( sizeof(x86_oplist_t), 1 );
|
||||||
|
op->op.insn = insn;
|
||||||
|
x86_oplist_append( insn, op );
|
||||||
|
return( &(op->op) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void x86_oplist_free( x86_insn_t *insn ) {
|
||||||
|
x86_oplist_t *op, *list;
|
||||||
|
|
||||||
|
if (! insn ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( list = insn->operands; list; ) {
|
||||||
|
op = list;
|
||||||
|
list = list->next;
|
||||||
|
free(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
insn->operands = NULL;
|
||||||
|
insn->operand_count = 0;
|
||||||
|
insn->explicit_count = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== LIBDISASM API */
|
||||||
|
/* these could probably just be #defines, but that means exposing the
|
||||||
|
enum... yet one more confusing thing in the API */
|
||||||
|
int x86_operand_foreach( x86_insn_t *insn, x86_operand_fn func, void *arg,
|
||||||
|
enum x86_op_foreach_type type ){
|
||||||
|
x86_oplist_t *list;
|
||||||
|
char explicit = 1, implicit = 1;
|
||||||
|
|
||||||
|
if (! insn || ! func ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* note: explicit and implicit can be ORed together to
|
||||||
|
* allow an "all" limited by access type, even though the
|
||||||
|
* user is stupid to do this since it is default behavior :) */
|
||||||
|
if ( (type & op_explicit) && ! (type & op_implicit) ) {
|
||||||
|
implicit = 0;
|
||||||
|
}
|
||||||
|
if ( (type & op_implicit) && ! (type & op_explicit) ) {
|
||||||
|
explicit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = type & 0x0F; /* mask out explicit/implicit operands */
|
||||||
|
|
||||||
|
for ( list = insn->operands; list; list = list->next ) {
|
||||||
|
if (! implicit && (list->op.flags & op_implied) ) {
|
||||||
|
/* operand is implicit */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! explicit && ! (list->op.flags & op_implied) ) {
|
||||||
|
/* operand is not implicit */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( type ) {
|
||||||
|
case op_any:
|
||||||
|
break;
|
||||||
|
case op_dest:
|
||||||
|
if (! (list->op.access & op_write) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case op_src:
|
||||||
|
if (! (list->op.access & op_read) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case op_ro:
|
||||||
|
if (! (list->op.access & op_read) ||
|
||||||
|
(list->op.access & op_write ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case op_wo:
|
||||||
|
if (! (list->op.access & op_write) ||
|
||||||
|
(list->op.access & op_read ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case op_xo:
|
||||||
|
if (! (list->op.access & op_execute) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case op_rw:
|
||||||
|
if (! (list->op.access & op_write) ||
|
||||||
|
! (list->op.access & op_read ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case op_implicit: case op_explicit: /* make gcc happy */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* any non-continue ends up here: invoke the callback */
|
||||||
|
(*func)( &list->op, insn, arg );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void count_operand( x86_op_t *op, x86_insn_t *insn, void *arg ) {
|
||||||
|
size_t * count = (size_t *) arg;
|
||||||
|
*count = *count + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t x86_operand_count( x86_insn_t *insn, enum x86_op_foreach_type type ) {
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
/* save us a list traversal for common counts... */
|
||||||
|
if ( type == op_any ) {
|
||||||
|
return insn->operand_count;
|
||||||
|
} else if ( type == op_explicit ) {
|
||||||
|
return insn->explicit_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_operand_foreach( insn, count_operand, &count, type );
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* accessor functions */
|
||||||
|
x86_op_t * x86_operand_1st( x86_insn_t *insn ) {
|
||||||
|
if (! insn->explicit_count ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &(insn->operands->op);
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_op_t * x86_operand_2nd( x86_insn_t *insn ) {
|
||||||
|
if ( insn->explicit_count < 2 ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &(insn->operands->next->op);
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_op_t * x86_operand_3rd( x86_insn_t *insn ) {
|
||||||
|
if ( insn->explicit_count < 3 ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &(insn->operands->next->next->op);
|
||||||
|
}
|
8
libdisasm/x86_operand_list.h
Normal file
8
libdisasm/x86_operand_list.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef X86_OPERAND_LIST_H
|
||||||
|
#define X86_OPERAND_LIST_H
|
||||||
|
#include "libdis.h"
|
||||||
|
|
||||||
|
|
||||||
|
x86_op_t * x86_operand_new( x86_insn_t *insn );
|
||||||
|
|
||||||
|
#endif
|
@ -8,10 +8,14 @@ ldflags_popnhax := \
|
|||||||
|
|
||||||
libs_popnhax := \
|
libs_popnhax := \
|
||||||
util \
|
util \
|
||||||
minhook
|
minhook \
|
||||||
|
libdisasm
|
||||||
|
|
||||||
srcpp_popnhax := \
|
srcpp_popnhax := \
|
||||||
dllmain.cc \
|
dllmain.cc \
|
||||||
|
config.cc \
|
||||||
loader.cc \
|
loader.cc \
|
||||||
SearchFile.cc \
|
SearchFile.cc \
|
||||||
translation.cc
|
translation.cc \
|
||||||
|
omnimix_patch.cc \
|
||||||
|
custom_categs.cc
|
||||||
|
242
popnhax/config.cc
Normal file
242
popnhax/config.cc
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
#include "util/crc32.h"
|
||||||
|
#include "util/log.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define F_OK 0
|
||||||
|
|
||||||
|
static char *get_opt_filename(const char *xml_filename){
|
||||||
|
char *opt_filename = strdup(xml_filename);
|
||||||
|
if ( opt_filename != NULL )
|
||||||
|
strcpy(opt_filename+strlen(opt_filename)-3, "opt");
|
||||||
|
return opt_filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
//works for .opt and .xml
|
||||||
|
static char *get_option(FILE *handle, char *option_name){
|
||||||
|
if (handle == NULL || option_name == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
rewind(handle);
|
||||||
|
char line[256];
|
||||||
|
while (fgets(line, 256, handle))
|
||||||
|
{
|
||||||
|
char *ptr = strchr(line, '<');
|
||||||
|
if ( ptr == NULL )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( strncmp(option_name, ptr+1, strlen(option_name)) == 0
|
||||||
|
&& (*(ptr+1+strlen(option_name)) == ' ') ) //filter out common prefixes
|
||||||
|
{
|
||||||
|
rewind(handle);
|
||||||
|
return strdup(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check .xml crc-32 and compare to .opt entry
|
||||||
|
static bool config_check_crc(const char *filepath){
|
||||||
|
//retrieve xml crc
|
||||||
|
uint32_t xmlcrc = 0;
|
||||||
|
long charcnt = 0;
|
||||||
|
if ( crc32file(filepath, &xmlcrc, &charcnt) == false )
|
||||||
|
{
|
||||||
|
LOG("popnhax: config update: cannot compute %s CRC-32\n", filepath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LOG("popnhax: config update: %s CRC-32 is %08X\n", filepath, xmlcrc);
|
||||||
|
|
||||||
|
//retrieve opt crc
|
||||||
|
uint32_t optcrc = 0;
|
||||||
|
char *opt_filename = get_opt_filename(filepath);
|
||||||
|
FILE *opt = fopen(opt_filename, "r");
|
||||||
|
if (opt == NULL)
|
||||||
|
{
|
||||||
|
LOG("popnhax: config update: opt file not found.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char line[256];
|
||||||
|
fgets(line, 256, opt); //disclaimer line
|
||||||
|
fgets(line, 256, opt); //CRC line
|
||||||
|
sscanf(line, "<!-- %08X -->\n", &optcrc);
|
||||||
|
fclose(opt);
|
||||||
|
LOG("popnhax: config update: %s reference CRC is %08X (matching: %s)\n", opt_filename, optcrc, optcrc==xmlcrc? "true":"false");
|
||||||
|
free(opt_filename);
|
||||||
|
|
||||||
|
return (optcrc==xmlcrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *get_option_name(char *line)
|
||||||
|
{
|
||||||
|
if ( line == NULL )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char *ptr = line;
|
||||||
|
while ( *ptr == ' ' || *ptr == '\t' )
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
if ( *ptr != '<' )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ( *(++ptr) == '!' )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ( strchr(ptr, ' ') == NULL )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size_t opt_len = strchr(ptr, ' ') - ptr;
|
||||||
|
char *option_name = (char*)malloc(opt_len+1);
|
||||||
|
strncpy(option_name, ptr, opt_len);
|
||||||
|
option_name[opt_len] = '\0';
|
||||||
|
return option_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if _update file is present
|
||||||
|
static bool config_need_update()
|
||||||
|
{
|
||||||
|
return (access("_update", F_OK) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//for every entry in .opt, overwrite xml value
|
||||||
|
static bool config_update_xml(const char *xml_filename)
|
||||||
|
{
|
||||||
|
char *opt_filename = get_opt_filename(xml_filename);
|
||||||
|
FILE *opt = fopen(opt_filename, "r");
|
||||||
|
if ( opt == NULL )
|
||||||
|
{
|
||||||
|
LOG("popnhax: config_update_xml: cannot open opt file\n");
|
||||||
|
free(opt_filename);
|
||||||
|
return true; //not a problem if it doesn't exist
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *xml = fopen(xml_filename, "r");
|
||||||
|
if ( xml == NULL )
|
||||||
|
{
|
||||||
|
LOG("popnhax: config_update_xml: cannot open xml file\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *update = fopen("update.xml.tmp", "w");
|
||||||
|
if ( update == NULL )
|
||||||
|
{
|
||||||
|
LOG("popnhax: config_update_xml: create update.xml.tmp\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read each line from xml and copy to update unless opt has a value in which case copy from opt instead
|
||||||
|
char line[256];
|
||||||
|
while (fgets(line, 256, xml))
|
||||||
|
{
|
||||||
|
char *option_name = get_option_name(line);
|
||||||
|
char *option_line = get_option(opt, option_name); //will return NULL if option_name is NULL
|
||||||
|
|
||||||
|
if (option_line == NULL)
|
||||||
|
{
|
||||||
|
//not an option line, copy to dest
|
||||||
|
fprintf(update, "%s", line);
|
||||||
|
if (option_name)
|
||||||
|
free(option_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// opt file has an entry for it, take that one
|
||||||
|
fprintf(update, "%s", option_line);
|
||||||
|
free(option_line);
|
||||||
|
free(option_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(xml);
|
||||||
|
fclose(opt);
|
||||||
|
fclose(update);
|
||||||
|
free(opt_filename);
|
||||||
|
|
||||||
|
if ( remove(xml_filename) == -1 )
|
||||||
|
{
|
||||||
|
LOG("popnhax: config_update_xml: cannot remove %s (%d)\n", xml_filename, errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( rename("update.xml.tmp",xml_filename) == -1 )
|
||||||
|
{
|
||||||
|
LOG("popnhax: config_update_xml: cannot rename update.xml.tmp (%d)\n", errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//regen .opt file (comprised of disclaimer, crc, and all options from xml)
|
||||||
|
static bool config_make_opt(const char *xml_filename){
|
||||||
|
uint32_t crc = 0;
|
||||||
|
long charcnt = 0;
|
||||||
|
if ( crc32file(xml_filename, &crc, &charcnt) == false )
|
||||||
|
{
|
||||||
|
LOG("Cannot compute %s CRC-32\n", xml_filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *xml = fopen(xml_filename, "r");
|
||||||
|
if ( xml == NULL )
|
||||||
|
{
|
||||||
|
LOG("popnhax: config update: cannot open config xml file\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *opt_filename = get_opt_filename(xml_filename);
|
||||||
|
FILE *opt = fopen(opt_filename, "w");
|
||||||
|
free(opt_filename);
|
||||||
|
if ( opt == NULL )
|
||||||
|
{
|
||||||
|
LOG("popnhax: config update: cannot create config opt file\n");
|
||||||
|
free(opt_filename);
|
||||||
|
fclose(xml);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(opt, "<!-- GENERATED BY POPNHAX. DO NOT EDIT THIS FILE -->\n");
|
||||||
|
fprintf(opt, "<!-- %08X -->\n", crc);
|
||||||
|
|
||||||
|
char line[256];
|
||||||
|
while (fgets(line, 256, xml))
|
||||||
|
{
|
||||||
|
char *ptr = line;
|
||||||
|
while ( *ptr == ' ' || *ptr == '\t' )
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
if ( *ptr != '<' )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( *(ptr+1) == '!' )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fprintf(opt, "%s", line);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(opt);
|
||||||
|
fclose(xml);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// take care of updating .xml/.opt files if needed
|
||||||
|
bool config_process(const char *xml_filepath){
|
||||||
|
// look for _update marker file
|
||||||
|
if ( config_need_update() )
|
||||||
|
{
|
||||||
|
//update xml with values from opt
|
||||||
|
LOG("popnhax: config update: popnhax update detected. Updating xml with your previous settings\n");
|
||||||
|
config_update_xml(xml_filepath);
|
||||||
|
remove("_update");
|
||||||
|
} else if ( config_check_crc(xml_filepath) ) {
|
||||||
|
LOG("popnhax: config update: nothing to do.\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// regen opt from xml file
|
||||||
|
LOG("popnhax: config update: xml has changed. Regenerating opt file\n");
|
||||||
|
bool res = config_make_opt(xml_filepath);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
struct popnhax_config {
|
struct popnhax_config {
|
||||||
|
uint8_t game_version;
|
||||||
bool practice_mode;
|
bool practice_mode;
|
||||||
bool hidden_is_offset;
|
bool hidden_is_offset;
|
||||||
bool iidx_hard_gauge;
|
bool iidx_hard_gauge;
|
||||||
@ -14,6 +15,10 @@ struct popnhax_config {
|
|||||||
bool quick_retire;
|
bool quick_retire;
|
||||||
bool back_to_song_select;
|
bool back_to_song_select;
|
||||||
bool score_challenge;
|
bool score_challenge;
|
||||||
|
uint8_t custom_categ;
|
||||||
|
uint16_t custom_categ_min_songid;
|
||||||
|
bool custom_exclude_from_version;
|
||||||
|
bool custom_exclude_from_level;
|
||||||
bool force_hd_timing;
|
bool force_hd_timing;
|
||||||
uint8_t force_hd_resolution;
|
uint8_t force_hd_resolution;
|
||||||
bool force_unlocks;
|
bool force_unlocks;
|
||||||
@ -26,12 +31,12 @@ struct popnhax_config {
|
|||||||
bool force_full_opt;
|
bool force_full_opt;
|
||||||
bool netvs_off;
|
bool netvs_off;
|
||||||
bool guidese_off;
|
bool guidese_off;
|
||||||
|
bool local_favorites;
|
||||||
|
|
||||||
bool patch_db;
|
bool patch_db;
|
||||||
bool disable_expansions;
|
|
||||||
bool disable_redirection;
|
|
||||||
bool disable_multiboot;
|
bool disable_multiboot;
|
||||||
bool patch_xml_auto;
|
bool patch_xml_auto;
|
||||||
|
bool ignore_music_limit;
|
||||||
char patch_xml_filename[MAX_PATH];
|
char patch_xml_filename[MAX_PATH];
|
||||||
char force_datecode[11];
|
char force_datecode[11];
|
||||||
bool network_datecode;
|
bool network_datecode;
|
||||||
@ -41,16 +46,32 @@ struct popnhax_config {
|
|||||||
int8_t beam_brightness;
|
int8_t beam_brightness;
|
||||||
bool fps_uncap;
|
bool fps_uncap;
|
||||||
bool disable_translation;
|
bool disable_translation;
|
||||||
bool translation_debug;
|
|
||||||
bool enhanced_polling;
|
bool enhanced_polling;
|
||||||
uint8_t debounce;
|
uint8_t debounce;
|
||||||
bool enhanced_polling_stats;
|
bool enhanced_polling_stats;
|
||||||
int8_t enhanced_polling_priority;
|
int8_t enhanced_polling_priority;
|
||||||
uint8_t hispeed_auto;
|
uint8_t hispeed_auto;
|
||||||
uint16_t hispeed_default_bpm;
|
uint16_t hispeed_default_bpm;
|
||||||
|
int8_t base_offset;
|
||||||
|
char custom_category_title[16];
|
||||||
|
char custom_category_format[64];
|
||||||
|
char custom_track_title_format[64];
|
||||||
|
char custom_track_title_format2[64];
|
||||||
|
bool exclude_omni;
|
||||||
|
bool partial_entries;
|
||||||
|
bool high_framerate;
|
||||||
|
bool high_framerate_limiter;
|
||||||
|
uint16_t high_framerate_fps;
|
||||||
|
|
||||||
|
/* removed/hidden */
|
||||||
|
bool disable_expansions;
|
||||||
|
bool disable_redirection;
|
||||||
uint8_t survival_gauge;
|
uint8_t survival_gauge;
|
||||||
bool survival_iidx;
|
bool survival_iidx;
|
||||||
bool survival_spicy;
|
bool survival_spicy;
|
||||||
|
bool translation_debug;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool config_process(const char *filepath); // take care of updating .xml/.opt files if needed
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
1115
popnhax/custom_categs.cc
Normal file
1115
popnhax/custom_categs.cc
Normal file
File diff suppressed because it is too large
Load Diff
24
popnhax/custom_categs.h
Normal file
24
popnhax/custom_categs.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef __CUSTOM_CATEGS_H__
|
||||||
|
#define __CUSTOM_CATEGS_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "popnhax/config.h"
|
||||||
|
#include "util/bst.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t *songlist; //really is a (songlist_t *) pointer
|
||||||
|
} subcategory_s;
|
||||||
|
|
||||||
|
extern uint32_t g_max_id;
|
||||||
|
extern bst_t *g_customs_bst;
|
||||||
|
|
||||||
|
void init_subcategories();
|
||||||
|
void add_song_to_subcateg(uint32_t songid, subcategory_s* subcateg);
|
||||||
|
subcategory_s* get_subcateg(const char *title);
|
||||||
|
|
||||||
|
bool patch_custom_categs(const char *dllFilename, struct popnhax_config *config);
|
||||||
|
bool patch_local_favorites(const char *dllFilename, uint8_t version);
|
||||||
|
|
||||||
|
#endif
|
4585
popnhax/dllmain.cc
4585
popnhax/dllmain.cc
File diff suppressed because it is too large
Load Diff
@ -4,8 +4,11 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include "imports/avs.h"
|
#include "imports/avs.h"
|
||||||
|
#include "util/bst.h"
|
||||||
#include "util/patch.h"
|
#include "util/patch.h"
|
||||||
|
#include "util/log.h"
|
||||||
#include "xmlhelper.h"
|
#include "xmlhelper.h"
|
||||||
|
#include "custom_categs.h"
|
||||||
|
|
||||||
#include "tableinfo.h"
|
#include "tableinfo.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
@ -66,7 +69,7 @@ uint32_t add_chart(uint32_t cur_idx, uint8_t *folder, uint8_t *filename, int32_t
|
|||||||
uint32_t file_type, uint16_t used_keys, bool override_idx);
|
uint32_t file_type, uint16_t used_keys, bool override_idx);
|
||||||
|
|
||||||
void parse_charadb(const char *input_filename, const char *target);
|
void parse_charadb(const char *input_filename, const char *target);
|
||||||
void parse_musicdb(const char *input_filename, const char *target);
|
void parse_musicdb(const char *input_filename, const char *target, struct popnhax_config *config);
|
||||||
|
|
||||||
std::map<uint32_t, int8_t> chart_type_overrides;
|
std::map<uint32_t, int8_t> chart_type_overrides;
|
||||||
|
|
||||||
@ -818,12 +821,76 @@ void parse_charadb(const char *input_filename, const char *target) {
|
|||||||
free(config_xml);
|
free(config_xml);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_musicdb(const char *input_filename, const char *target) {
|
static char *get_subcateg_title(const char* path) {
|
||||||
|
char *categ_name = NULL;
|
||||||
|
char filename[64];
|
||||||
|
|
||||||
|
//try to open "folderpath/_name.txt"
|
||||||
|
size_t len = (size_t)(strchr(path+10, '\\')-(path));
|
||||||
|
strncpy(filename, path, len);
|
||||||
|
sprintf(filename+len, "\\_name.txt");
|
||||||
|
|
||||||
|
FILE *file = fopen(filename, "r");
|
||||||
|
if ( file != NULL ) {
|
||||||
|
//if it has a custom title, use it
|
||||||
|
char line[64];
|
||||||
|
if (fgets(line, sizeof(line), file)) {
|
||||||
|
//handle UTF-8 BOM since that could be common
|
||||||
|
categ_name = (memcmp(line, "\xEF\xBB\xBF", 3) == 0) ? strdup(line+3) : strdup(line);
|
||||||
|
LOG("%s sets subcategory name to %s\n", filename, categ_name);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
} else { // or just keep folder name by itself (cut "data_mods")
|
||||||
|
len = (size_t)(strchr(path+10, '\\')-(path+10));
|
||||||
|
categ_name = (char*) malloc(len+1);
|
||||||
|
strncpy(categ_name, path+10, len);
|
||||||
|
categ_name[len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return categ_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define F_OK 0
|
||||||
|
static bool is_excluded_folder(const char *path)
|
||||||
|
{
|
||||||
|
char filename[64];
|
||||||
|
|
||||||
|
//try to open "folderpath/_exclude"
|
||||||
|
size_t len = (size_t)(strchr(path+10, '\\')-(path));
|
||||||
|
strncpy(filename, path, len);
|
||||||
|
sprintf(filename+len, "\\_exclude");
|
||||||
|
if (access(filename, F_OK) == 0)
|
||||||
|
{
|
||||||
|
LOG("%s causes folder to be excluded from customs (contents will be treated as regular songs)\n", filename);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( path[strlen("data_mods/")] == '_' )
|
||||||
|
{
|
||||||
|
filename[strchr(path+10, '\\')-path] = '\0';
|
||||||
|
LOG("%s starting with _ causes folder to be excluded from customs (contents will be treated as regular songs)\n", filename);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_musicdb(const char *input_filename, const char *target, struct popnhax_config *config) {
|
||||||
if (!file_exists(input_filename)) {
|
if (!file_exists(input_filename)) {
|
||||||
printf("Couldn't find %s, skipping...\n", input_filename);
|
printf("Couldn't find %s, skipping...\n", input_filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool excluded = (config->custom_categ && is_excluded_folder(input_filename));
|
||||||
|
|
||||||
|
char *subcateg_title = NULL;
|
||||||
|
subcategory_s *subcateg = NULL;
|
||||||
|
if (config->custom_categ == 2 && !excluded)
|
||||||
|
{
|
||||||
|
subcateg_title = get_subcateg_title(input_filename);
|
||||||
|
subcateg = get_subcateg(subcateg_title); //will return a new one if not found
|
||||||
|
}
|
||||||
|
|
||||||
property *config_xml = load_prop_file(input_filename);
|
property *config_xml = load_prop_file(input_filename);
|
||||||
|
|
||||||
if (target && strlen(target) > 0) {
|
if (target && strlen(target) > 0) {
|
||||||
@ -859,7 +926,22 @@ void parse_musicdb(const char *input_filename, const char *target) {
|
|||||||
// If it doesn't exist, create a new entry in memory
|
// If it doesn't exist, create a new entry in memory
|
||||||
// Update the data in-place and make all parameters optional
|
// Update the data in-place and make all parameters optional
|
||||||
music_entry *m = get_music(idx);
|
music_entry *m = get_music(idx);
|
||||||
bool is_fresh = m == NULL;
|
bool is_fresh = m == NULL; // ie. not part of internal songdb
|
||||||
|
bool is_gone = ( m != NULL && strcmp((const char*) m->title_ptr, "\x81\x5D") == 0); // removed entries all have this title (SJIS "-")
|
||||||
|
|
||||||
|
// Update customs/omni songid list
|
||||||
|
if ( is_fresh || is_gone || config->partial_entries )
|
||||||
|
{
|
||||||
|
if ( idx >= config->custom_categ_min_songid && !excluded && bst_search(g_customs_bst, idx) == NULL )
|
||||||
|
{
|
||||||
|
g_customs_bst = bst_insert(g_customs_bst, idx);
|
||||||
|
//LOG("%d inserted into customs bst\n", idx);
|
||||||
|
if (config->custom_categ == 2)
|
||||||
|
{
|
||||||
|
add_song_to_subcateg(idx, subcateg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_fresh) {
|
if (is_fresh) {
|
||||||
// Default music entry
|
// Default music entry
|
||||||
@ -915,6 +997,16 @@ void parse_musicdb(const char *input_filename, const char *target) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( config->custom_categ
|
||||||
|
&& config->custom_exclude_from_version
|
||||||
|
&& !excluded
|
||||||
|
&& idx >= config->custom_categ_min_songid
|
||||||
|
&& ( is_fresh || config->exclude_omni ) )
|
||||||
|
{
|
||||||
|
m->cs_version = 0;
|
||||||
|
m->folder = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((prop_chart = property_search(config_xml, prop, "charts/chart"))) {
|
if ((prop_chart = property_search(config_xml, prop, "charts/chart"))) {
|
||||||
for (; prop_chart != NULL; prop_chart = property_node_traversal(
|
for (; prop_chart != NULL; prop_chart = property_node_traversal(
|
||||||
prop_chart, TRAVERSE_NEXT_SEARCH_RESULT)) {
|
prop_chart, TRAVERSE_NEXT_SEARCH_RESULT)) {
|
||||||
@ -990,9 +1082,14 @@ void parse_musicdb(const char *input_filename, const char *target) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
free(config_xml);
|
free(config_xml);
|
||||||
|
|
||||||
|
if (config->custom_categ == 2 && !excluded)
|
||||||
|
{
|
||||||
|
free(subcateg_title);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_databases(const char *target_datecode) {
|
void load_databases(const char *target_datecode, struct popnhax_config *config) {
|
||||||
|
|
||||||
SearchFile s;
|
SearchFile s;
|
||||||
printf("XML db files search...\n");
|
printf("XML db files search...\n");
|
||||||
@ -1008,16 +1105,19 @@ void load_databases(const char *target_datecode) {
|
|||||||
parse_charadb(result[i].c_str(), target_datecode);
|
parse_charadb(result[i].c_str(), target_datecode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config->custom_categ == 2)
|
||||||
|
init_subcategories();
|
||||||
|
|
||||||
for(uint16_t i=0;i<result.size();i++)
|
for(uint16_t i=0;i<result.size();i++)
|
||||||
{
|
{
|
||||||
if ( strstr(result[i].c_str(), "musicdb") == NULL )
|
if ( strstr(result[i].c_str(), "musicdb") == NULL )
|
||||||
continue;
|
continue;
|
||||||
printf("(musicdb) Loading %s...\n", result[i].c_str());
|
printf("(musicdb) Loading %s...\n", result[i].c_str());
|
||||||
parse_musicdb(result[i].c_str(), target_datecode);
|
parse_musicdb(result[i].c_str(), target_datecode, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void musichax_core_init(bool force_unlocks, bool is_expansion_allowed, bool is_redirection_allowed,
|
void musichax_core_init(struct popnhax_config *config,
|
||||||
char *target_datecode,
|
char *target_datecode,
|
||||||
|
|
||||||
char *base_data,
|
char *base_data,
|
||||||
@ -1036,6 +1136,10 @@ void musichax_core_init(bool force_unlocks, bool is_expansion_allowed, bool is_r
|
|||||||
|
|
||||||
uint64_t chara_size, uint64_t *new_chara_size, char *orig_chara_data,
|
uint64_t chara_size, uint64_t *new_chara_size, char *orig_chara_data,
|
||||||
uint8_t **new_chara_table) {
|
uint8_t **new_chara_table) {
|
||||||
|
bool force_unlocks = config->force_unlocks;
|
||||||
|
bool is_expansion_allowed = !config->disable_expansions;
|
||||||
|
bool is_redirection_allowed = !config->disable_redirection;
|
||||||
|
|
||||||
if (style_size > fontstyle_table_size) {
|
if (style_size > fontstyle_table_size) {
|
||||||
fontstyle_table_size = style_size;
|
fontstyle_table_size = style_size;
|
||||||
}
|
}
|
||||||
@ -1181,7 +1285,7 @@ void musichax_core_init(bool force_unlocks, bool is_expansion_allowed, bool is_r
|
|||||||
cur->chara_x, cur->chara_y, cur->unk1, cur->display_bpm, cur->hold_flags, true);
|
cur->chara_x, cur->chara_y, cur->unk1, cur->display_bpm, cur->hold_flags, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
load_databases((const char *)target_datecode);
|
load_databases((const char *)target_datecode, config);
|
||||||
|
|
||||||
// Add some filler charts to fix some bugs (hack)
|
// Add some filler charts to fix some bugs (hack)
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
|
@ -2,10 +2,11 @@
|
|||||||
#define __LOADER_H__
|
#define __LOADER_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "popnhax/config.h"
|
||||||
|
|
||||||
int8_t get_chart_type_override(uint8_t *, uint32_t, uint32_t);
|
int8_t get_chart_type_override(uint8_t *, uint32_t, uint32_t);
|
||||||
|
|
||||||
void musichax_core_init(bool force_unlocks, bool is_expansion_allowed, bool is_redirection_allowed,
|
void musichax_core_init(struct popnhax_config *config,
|
||||||
char *target_datecode, char *base_data, uint64_t music_size,
|
char *target_datecode, char *base_data, uint64_t music_size,
|
||||||
uint64_t *new_music_size, char *orig_music_data, uint8_t **new_music_table,
|
uint64_t *new_music_size, char *orig_music_data, uint8_t **new_music_table,
|
||||||
uint64_t chart_size, uint64_t *new_chart_size, char *orig_chart_data,
|
uint64_t chart_size, uint64_t *new_chart_size, char *orig_chart_data,
|
||||||
|
297
popnhax/omnimix_patch.cc
Normal file
297
popnhax/omnimix_patch.cc
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <io.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "util/bst.h"
|
||||||
|
#include "util/log.h"
|
||||||
|
#include "util/patch.h"
|
||||||
|
#include "util/search.h"
|
||||||
|
#include "libdisasm/libdis.h"
|
||||||
|
|
||||||
|
#include "omnimix_patch.h"
|
||||||
|
|
||||||
|
#define LINE_SIZE 512
|
||||||
|
|
||||||
|
|
||||||
|
#define MUSIC_IDX 0
|
||||||
|
#define CHART_IDX 1
|
||||||
|
#define STYLE_IDX 2
|
||||||
|
#define FLAVOR_IDX 3
|
||||||
|
#define CHARA_IDX 4
|
||||||
|
#define NUM_IDX 5
|
||||||
|
|
||||||
|
bst_t *g_xref_bst = NULL;
|
||||||
|
bst_t *g_data_xref_bst = NULL;
|
||||||
|
|
||||||
|
typedef struct table_s {
|
||||||
|
char *name;
|
||||||
|
uint32_t *addr;
|
||||||
|
uint32_t size; // size of one entry
|
||||||
|
uint32_t limit; // number of entries
|
||||||
|
} table_t;
|
||||||
|
|
||||||
|
table_t g_tables[NUM_IDX];
|
||||||
|
|
||||||
|
uint32_t *find_binary(char *data, DWORD dllSize, const char *search_pattern, uint32_t search_size, uint32_t search_head, int8_t search_idx)
|
||||||
|
{
|
||||||
|
//fprintf(stderr, "find binary %.*s\n", search_size, search_pattern);
|
||||||
|
uint32_t *ea = 0;
|
||||||
|
int8_t found = -1;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int64_t pattern_offset = search(data, dllSize -((uint32_t) ea)-1, search_pattern, search_size, ((uint32_t) ea)+1);
|
||||||
|
|
||||||
|
if (pattern_offset == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ea = (uint32_t *) (pattern_offset + search_head);
|
||||||
|
found++;
|
||||||
|
|
||||||
|
if (found != search_idx)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return (uint32_t *) ((int64_t) data + (int64_t) ea);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t *find_binary_xref(char *data, DWORD dllSize, const char *search_pattern, uint32_t search_size, uint32_t search_head, int8_t search_idx, int8_t xref_search_idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint32_t* ea = find_binary(data, dllSize, search_pattern, search_size, search_head, search_idx);
|
||||||
|
|
||||||
|
if (ea == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char *as_hex = (char *) &ea;
|
||||||
|
|
||||||
|
ea = find_binary(data, dllSize, as_hex, 4, 0, xref_search_idx);
|
||||||
|
|
||||||
|
return ea;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t get_table_size_by_xref(char *data, DWORD data_size, uint32_t *ea, uint32_t entry_size)
|
||||||
|
{
|
||||||
|
//fprintf(stderr, "get table size by xref\n");
|
||||||
|
uint32_t *orig_ea = ea;
|
||||||
|
// Skip 10 entries because why not. We're looking for the end anyway
|
||||||
|
ea = (uint32_t*)((uint32_t)ea+(entry_size*10));
|
||||||
|
|
||||||
|
//fprintf(stderr, "orig ea %p, entry size %u, ea %p\n", orig_ea, entry_size, ea);
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
while (!found)
|
||||||
|
{
|
||||||
|
uint32_t *as_int = (uint32_t*)&ea;
|
||||||
|
//uint32_t curr_limit = (((uint32_t)ea)-((uint32_t)orig_ea))/entry_size;
|
||||||
|
//fprintf(stderr, "limit candidate %u, looking for xref to %0X\n", curr_limit, *as_int);
|
||||||
|
|
||||||
|
if ( bst_search(g_xref_bst, *as_int) != NULL )
|
||||||
|
{
|
||||||
|
//fprintf(stderr, "found .text XREF in BST\n");
|
||||||
|
found = true;
|
||||||
|
} else if ( bst_search(g_data_xref_bst, *as_int) != NULL )
|
||||||
|
{
|
||||||
|
//fprintf(stderr, "found .data XREF at addr %p\n", xref);
|
||||||
|
found = true;
|
||||||
|
} /* else {
|
||||||
|
//look for Xref in data section
|
||||||
|
char *as_hex = (char*)&ea;
|
||||||
|
uint32_t *xref = find_binary(data, data_size, as_hex, 4, 0, 0);
|
||||||
|
if ( xref != NULL )
|
||||||
|
{
|
||||||
|
fprintf(stderr, "found .data XREF at addr %p\n", xref);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
ea = (uint32_t*)((uint32_t)ea+entry_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//fprintf(stderr, "found value %u (ea = %p, orig_ea = %p, entry size = %u)\n", ((((uint32_t)ea)-((uint32_t)orig_ea))/entry_size), ea, orig_ea, entry_size);
|
||||||
|
return (((uint32_t)ea)-((uint32_t)orig_ea))/entry_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_cb(x86_insn_t *insn, void *arg)
|
||||||
|
{
|
||||||
|
char line[LINE_SIZE]; /* buffer of line to print */
|
||||||
|
x86_format_insn(insn, line, LINE_SIZE, intel_syntax);
|
||||||
|
fprintf(stderr,"%s\n", line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_xref_to_bst(bst_t **bst, uint32_t addr)
|
||||||
|
{
|
||||||
|
if ( bst_search(*bst, addr) == NULL )
|
||||||
|
{
|
||||||
|
//LOG("added addr %0X to BST\n", addr);
|
||||||
|
*bst = bst_insert(*bst, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_xref(x86_insn_t *insn, void *arg)
|
||||||
|
{
|
||||||
|
uint32_t addr = x86_get_address(insn);
|
||||||
|
if ( addr != 0 )
|
||||||
|
{
|
||||||
|
add_xref_to_bst(&g_xref_bst, addr);
|
||||||
|
//LOG("found ref to %0X at ea %0X\n", addr, insn->addr);
|
||||||
|
//fprintf(stderr, "\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// doesn't have an address directly
|
||||||
|
x86_op_t *op = x86_operand_1st(insn);
|
||||||
|
if ( op != NULL && op->type == op_expression )
|
||||||
|
{
|
||||||
|
x86_ea_t exp = op->data.expression;
|
||||||
|
// LOG("(expression) disp is %0X\n", exp.disp);
|
||||||
|
add_xref_to_bst(&g_xref_bst, exp.disp);
|
||||||
|
}
|
||||||
|
|
||||||
|
op = x86_operand_2nd(insn);
|
||||||
|
if ( op != NULL && op->type == op_expression )
|
||||||
|
{
|
||||||
|
x86_ea_t exp = op->data.expression;
|
||||||
|
// LOG("(expression) disp is %0X\n", exp.disp);
|
||||||
|
add_xref_to_bst(&g_xref_bst, exp.disp);
|
||||||
|
}
|
||||||
|
|
||||||
|
op = x86_operand_3rd(insn);
|
||||||
|
if ( op != NULL && op->type == op_expression )
|
||||||
|
{
|
||||||
|
x86_ea_t exp = op->data.expression;
|
||||||
|
// LOG("(expression) disp is %0X\n", exp.disp);
|
||||||
|
add_xref_to_bst(&g_xref_bst, exp.disp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool make_omnimix_patch(const char *dllFilename){
|
||||||
|
|
||||||
|
DWORD dllSize = 0;
|
||||||
|
char *buf = getDllData(dllFilename, &dllSize);
|
||||||
|
|
||||||
|
char *text = NULL;
|
||||||
|
DWORD text_size = 0;
|
||||||
|
|
||||||
|
char *data = NULL;
|
||||||
|
DWORD data_size = 0;
|
||||||
|
|
||||||
|
char *rdata = NULL;
|
||||||
|
DWORD rdata_size = 0;
|
||||||
|
|
||||||
|
PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)(buf + ((PIMAGE_DOS_HEADER)buf)->e_lfanew);
|
||||||
|
PIMAGE_SECTION_HEADER section_header = IMAGE_FIRST_SECTION(headers);
|
||||||
|
|
||||||
|
for (WORD SectionIndex = 0; SectionIndex < headers->FileHeader.NumberOfSections; SectionIndex++)
|
||||||
|
{
|
||||||
|
PIMAGE_SECTION_HEADER curr_header = §ion_header[SectionIndex];
|
||||||
|
|
||||||
|
if ( strcmp( (const char*)curr_header->Name, ".text" ) == 0 || curr_header->Characteristics & IMAGE_SCN_CNT_CODE )
|
||||||
|
{
|
||||||
|
text = (char*) ((int64_t)buf + curr_header->VirtualAddress);
|
||||||
|
text_size = curr_header->Misc.VirtualSize;
|
||||||
|
}
|
||||||
|
if ( strcmp( (const char*)curr_header->Name, ".data" ) == 0 )
|
||||||
|
{
|
||||||
|
data = (char*) ((int64_t)buf + curr_header->VirtualAddress);
|
||||||
|
data_size = curr_header->Misc.VirtualSize;
|
||||||
|
}
|
||||||
|
if ( strcmp( (const char*)curr_header->Name, ".rdata" ) == 0 )
|
||||||
|
{
|
||||||
|
rdata = (char*) ((int64_t)buf + curr_header->VirtualAddress);
|
||||||
|
rdata_size = curr_header->Misc.VirtualSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG("buf addr is %p\n", buf);
|
||||||
|
LOG("text section size %lX, addr %p, beginning %02X %02X %02X %02X\n", text_size, text, text[0], text[1], text[2], text[3]);
|
||||||
|
LOG("data section size %lX, addr %p, beginning %02X %02X %02X %02X\n", data_size, data, data[0], data[1], data[2], data[3]);
|
||||||
|
LOG("rdata section size %lX, addr %p, beginning %02X %02X %02X %02X\n", rdata_size, rdata, rdata[0], rdata[1], rdata[2], rdata[3]);
|
||||||
|
|
||||||
|
//add all data xrefs to BST (take anything which looks like 0x10****** in .data section)
|
||||||
|
{
|
||||||
|
LOG("Parsing .data section... ");
|
||||||
|
uint32_t *data_ea = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int64_t pattern_offset = search(data, data_size -((uint32_t) data_ea)-1, "\x10", 1, ((uint32_t) data_ea)+1);
|
||||||
|
if (pattern_offset == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
data_ea = (uint32_t *) ((uint32_t)data + pattern_offset - 3);
|
||||||
|
uint32_t *as_int = (uint32_t*)data_ea;
|
||||||
|
|
||||||
|
//LOG("found %X at offset %p\n", *as_int, data_ea);
|
||||||
|
//LOG("adding %X to data bst\n", *as_int);
|
||||||
|
add_xref_to_bst(&g_data_xref_bst, *as_int);
|
||||||
|
data_ea = (uint32_t *) (pattern_offset);
|
||||||
|
}
|
||||||
|
LOG("done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// disassemble .text section and add all xrefs to BST
|
||||||
|
LOG("Disassemble .text section... ");
|
||||||
|
x86_init(opt_none, NULL, NULL);
|
||||||
|
unsigned int num_insn = x86_disasm_range( (unsigned char *)text, (uint32_t) buf, 0, text_size, &add_xref, NULL);
|
||||||
|
x86_cleanup();
|
||||||
|
LOG("done (%u instructions)\n", num_insn);
|
||||||
|
|
||||||
|
LOG("<?xml version='1.0' encoding='shift-jis'?>\n");
|
||||||
|
LOG("<patches target=\"20xxxxxx00\">\n");
|
||||||
|
|
||||||
|
/* init tables */
|
||||||
|
g_tables[MUSIC_IDX].name = strdup("music");
|
||||||
|
g_tables[CHART_IDX].name = strdup("chart");
|
||||||
|
g_tables[STYLE_IDX].name = strdup("style");
|
||||||
|
g_tables[FLAVOR_IDX].name = strdup("flavor");
|
||||||
|
g_tables[CHARA_IDX].name = strdup("chara");
|
||||||
|
|
||||||
|
// These all reference the first entry in their respective tables
|
||||||
|
g_tables[MUSIC_IDX].addr = find_binary_xref(buf, dllSize, "\x00\x83\x7C\x83\x62\x83\x76\x83\x58\x00", 10, 1, 0, 0);
|
||||||
|
g_tables[CHART_IDX].addr = find_binary_xref(buf, dllSize, "\x00\x70\x6F\x70\x6E\x31\x00\x00", 8, 1, 0, 1);
|
||||||
|
g_tables[STYLE_IDX].addr = find_binary(buf, dllSize, "\x01\x00\x00\x00\xFF\x54\x0C\x00\x1A\x00\x00\x00\x11\x00\x00\x00", 16, 0, 2);
|
||||||
|
g_tables[FLAVOR_IDX].addr = find_binary(buf, dllSize, "\x00\x82\xBB\x82\xEA\x82\xA2\x82\xAF\x81\x5B\x00\x00\x00\x82\xA4\x82", 17, 1, 0);
|
||||||
|
g_tables[CHARA_IDX].addr = find_binary_xref(buf, dllSize, "\x00\x62\x61\x6D\x62\x5F\x31\x61\x00", 9, 1, 0, 0);
|
||||||
|
|
||||||
|
fprintf(stderr, "buffer addresses ok\n");
|
||||||
|
// Modify the entry sizes as required
|
||||||
|
g_tables[MUSIC_IDX].size = 0xAC;
|
||||||
|
g_tables[CHART_IDX].size = 0x20; // Probably won't change?
|
||||||
|
g_tables[STYLE_IDX].size = 0x10; // Unlikely to change
|
||||||
|
g_tables[FLAVOR_IDX].size = 0x60;
|
||||||
|
g_tables[CHARA_IDX].size = 0x4C;
|
||||||
|
|
||||||
|
// buffer_addr + (buffer_entry_size * limit) should give you the very end of the array (after the last entry)
|
||||||
|
g_tables[MUSIC_IDX].limit = get_table_size_by_xref(data, data_size, g_tables[MUSIC_IDX].addr, g_tables[MUSIC_IDX].size);
|
||||||
|
g_tables[CHART_IDX].limit = get_table_size_by_xref(data, data_size, g_tables[CHART_IDX].addr, g_tables[CHART_IDX].size);
|
||||||
|
g_tables[STYLE_IDX].limit = get_table_size_by_xref(data, data_size, g_tables[STYLE_IDX].addr, g_tables[STYLE_IDX].size);
|
||||||
|
g_tables[FLAVOR_IDX].limit = get_table_size_by_xref(data, data_size, g_tables[FLAVOR_IDX].addr, g_tables[FLAVOR_IDX].size);
|
||||||
|
g_tables[CHARA_IDX].limit = get_table_size_by_xref(data, data_size, g_tables[CHARA_IDX].addr, g_tables[CHARA_IDX].size);
|
||||||
|
|
||||||
|
LOG("\t<limits>\n");
|
||||||
|
for (int i=0; i < NUM_IDX; i++)
|
||||||
|
{
|
||||||
|
//patch_target, buffer_addr, entry_size = buffer_info
|
||||||
|
LOG("\t\t<%s __type=\"u32\">%d</%s>\n", g_tables[i].name, g_tables[i].limit, g_tables[i].name);
|
||||||
|
}
|
||||||
|
LOG("\t</limits>\n");
|
||||||
|
|
||||||
|
LOG("\t<buffer_base_addrs>\n");
|
||||||
|
for (int i=0; i < NUM_IDX; i++)
|
||||||
|
{
|
||||||
|
//patch_target, buffer_addr, entry_size = buffer_info
|
||||||
|
LOG("\t\t<%s __type=\"str\">0x%p</%s>\n", g_tables[i].name, g_tables[i].addr, g_tables[i].name);
|
||||||
|
}
|
||||||
|
LOG("\t</buffer_base_addrs>\n");
|
||||||
|
|
||||||
|
|
||||||
|
getchar();
|
||||||
|
exit(0);
|
||||||
|
return false;
|
||||||
|
}
|
6
popnhax/omnimix_patch.h
Normal file
6
popnhax/omnimix_patch.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef __OMNIMIX_PATCH_H__
|
||||||
|
#define __OMNIMIX_PATCH_H__
|
||||||
|
|
||||||
|
bool make_omnimix_patch(const char *dllFilename);
|
||||||
|
|
||||||
|
#endif
|
@ -56,10 +56,10 @@ bool patch_sjis(const char *dllFilename, const char *find, uint8_t find_size, in
|
|||||||
} while (valid_sjis);
|
} while (valid_sjis);
|
||||||
|
|
||||||
if (dump_dict)
|
if (dump_dict)
|
||||||
{
|
{
|
||||||
//fprintf(g_dict_applied_fp,"0x%x;%s;%s\n",rva_to_offset(dllFilename, (uint32_t)*offset),(char*)find,(char*)replace);
|
//fprintf(g_dict_applied_fp,"0x%x;%s;%s\n",rva_to_offset(dllFilename, (uint32_t)*offset),(char*)find,(char*)replace);
|
||||||
fprintf(g_dict_applied_fp,";%s;%s\n",(char*)find,(char*)replace);
|
fprintf(g_dict_applied_fp,";%s;%s\n",(char*)find,(char*)replace);
|
||||||
}
|
}
|
||||||
/* safety check replace is not too big */
|
/* safety check replace is not too big */
|
||||||
uint8_t free_size = find_size-1;
|
uint8_t free_size = find_size-1;
|
||||||
do
|
do
|
||||||
@ -83,41 +83,41 @@ bool patch_sjis(const char *dllFilename, const char *find, uint8_t find_size, in
|
|||||||
|
|
||||||
#define RELOC_HIGHLOW 0x3
|
#define RELOC_HIGHLOW 0x3
|
||||||
static void perform_reloc(char *data, int32_t delta, uint32_t ext_base, uint32_t ext_delta)
|
static void perform_reloc(char *data, int32_t delta, uint32_t ext_base, uint32_t ext_delta)
|
||||||
{
|
{
|
||||||
PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((int64_t)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew);
|
PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((int64_t)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew);
|
||||||
PIMAGE_DATA_DIRECTORY datadir = &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
PIMAGE_DATA_DIRECTORY datadir = &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
||||||
PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)(data + datadir->VirtualAddress);
|
PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)(data + datadir->VirtualAddress);
|
||||||
|
|
||||||
while(reloc->VirtualAddress != 0)
|
while(reloc->VirtualAddress != 0)
|
||||||
{
|
{
|
||||||
if (reloc->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION))
|
if (reloc->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION))
|
||||||
{
|
{
|
||||||
DWORD relocDescNb = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
|
DWORD relocDescNb = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
|
||||||
LPWORD relocDescList = (LPWORD)((LPBYTE)reloc + sizeof(IMAGE_BASE_RELOCATION));
|
LPWORD relocDescList = (LPWORD)((LPBYTE)reloc + sizeof(IMAGE_BASE_RELOCATION));
|
||||||
|
|
||||||
for (DWORD i = 0; i < relocDescNb; i++)
|
for (DWORD i = 0; i < relocDescNb; i++)
|
||||||
{
|
{
|
||||||
if ( ((relocDescList[i])>>12) == RELOC_HIGHLOW )
|
if ( ((relocDescList[i])>>12) == RELOC_HIGHLOW )
|
||||||
{
|
{
|
||||||
DWORD_PTR *p = (DWORD_PTR *)( data + (reloc->VirtualAddress + ((relocDescList[i])&0x0FFF)) );
|
DWORD_PTR *p = (DWORD_PTR *)( data + (reloc->VirtualAddress + ((relocDescList[i])&0x0FFF)) );
|
||||||
/* Change the offset to adapt to injected module base address */
|
/* Change the offset to adapt to injected module base address */
|
||||||
|
|
||||||
DWORD old_prot;
|
DWORD old_prot;
|
||||||
VirtualProtect((LPVOID)p, 4, PAGE_EXECUTE_READWRITE, &old_prot);
|
VirtualProtect((LPVOID)p, 4, PAGE_EXECUTE_READWRITE, &old_prot);
|
||||||
*p += delta;
|
*p += delta;
|
||||||
if ( ext_base > 0 && *p >= ((int64_t)data+ext_base) )
|
if ( ext_base > 0 && *p >= ((int64_t)data+ext_base) )
|
||||||
{
|
{
|
||||||
//fprintf(stderr,"reloc rva %lx to ext ", *p);
|
//fprintf(stderr,"reloc rva %lx to ext ", *p);
|
||||||
*p += ext_delta;
|
*p += ext_delta;
|
||||||
//fprintf(stderr," %lx\n", *p);
|
//fprintf(stderr," %lx\n", *p);
|
||||||
}
|
}
|
||||||
VirtualProtect((LPVOID)p, 4, old_prot, &old_prot);
|
VirtualProtect((LPVOID)p, 4, old_prot, &old_prot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Set reloc pointer to the next relocation block */
|
/* Set reloc pointer to the next relocation block */
|
||||||
reloc = (PIMAGE_BASE_RELOCATION)((LPBYTE)reloc + reloc->SizeOfBlock);
|
reloc = (PIMAGE_BASE_RELOCATION)((LPBYTE)reloc + reloc->SizeOfBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BYTE3_TO_UINT(bp) \
|
#define BYTE3_TO_UINT(bp) \
|
||||||
@ -134,191 +134,191 @@ static void perform_reloc(char *data, int32_t delta, uint32_t ext_base, uint32_t
|
|||||||
static bool patch_translation_ips(const char *dllFilename, const char *foldername, bool dump_dll)
|
static bool patch_translation_ips(const char *dllFilename, const char *foldername, bool dump_dll)
|
||||||
{
|
{
|
||||||
#define IPS_READ(_ips_read_dest, _ips_read_size, _ips_read_name) do {\
|
#define IPS_READ(_ips_read_dest, _ips_read_size, _ips_read_name) do {\
|
||||||
if ( fread(_ips_read_dest, 1, _ips_read_size, ips_fp) != _ips_read_size )\
|
if ( fread(_ips_read_dest, 1, _ips_read_size, ips_fp) != _ips_read_size )\
|
||||||
{\
|
{\
|
||||||
LOG("CANNOT READ %s\n", _ips_read_name);\
|
LOG("CANNOT READ %s\n", _ips_read_name);\
|
||||||
return false;\
|
return false;\
|
||||||
}\
|
}\
|
||||||
} while (0)
|
} while (0)
|
||||||
DWORD dllSize = 0;
|
DWORD dllSize = 0;
|
||||||
char *data = getDllData(dllFilename, &dllSize);
|
char *data = getDllData(dllFilename, &dllSize);
|
||||||
|
|
||||||
char dict_filepath[64];
|
char dict_filepath[64];
|
||||||
sprintf(dict_filepath, "%s%s%s", "data_mods\\", foldername, "\\popn22.ips");
|
sprintf(dict_filepath, "%s%s%s", "data_mods\\", foldername, "\\popn22.ips");
|
||||||
FILE *ips_fp = fopen(dict_filepath, "rb");
|
FILE *ips_fp = fopen(dict_filepath, "rb");
|
||||||
|
|
||||||
if (ips_fp == NULL)
|
if (ips_fp == NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("popnhax: translation: popn22.ips found\n");
|
LOG("popnhax: translation: popn22.ips found\n");
|
||||||
|
|
||||||
/* check .ips header */
|
/* check .ips header */
|
||||||
uint8_t buffer[8];
|
uint8_t buffer[8];
|
||||||
if (fread(&buffer, 1, 5, ips_fp) != 5)
|
if (fread(&buffer, 1, 5, ips_fp) != 5)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (memcmp(buffer, "PATCH", 5) != 0)
|
|
||||||
{
|
|
||||||
LOG("popnhax: translation: invalid .ips header\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dump_dll)
|
if (memcmp(buffer, "PATCH", 5) != 0)
|
||||||
{
|
{
|
||||||
LOG("popnhax: translation debug: dump dll before patch\n");
|
LOG("popnhax: translation: invalid .ips header\n");
|
||||||
FILE* dllrtp = fopen("dllruntime.dll", "wb");
|
return false;
|
||||||
fwrite(data, 1, dllSize, dllrtp);
|
}
|
||||||
fclose(dllrtp);
|
|
||||||
LOG("popnhax: translation debug: dllruntime.dll generated\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* undo all relocation so you can apply ips patch with correct values, we'll reapply them later */
|
if (dump_dll)
|
||||||
PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((int64_t)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew);
|
{
|
||||||
DWORD_PTR reloc_delta = (DWORD_PTR)((int64_t)data - headers->OptionalHeader.ImageBase);
|
LOG("popnhax: translation debug: dump dll before patch\n");
|
||||||
perform_reloc(data, -1*reloc_delta, 0, 0);
|
FILE* dllrtp = fopen("dllruntime.dll", "wb");
|
||||||
|
fwrite(data, 1, dllSize, dllrtp);
|
||||||
|
fclose(dllrtp);
|
||||||
|
LOG("popnhax: translation debug: dllruntime.dll generated\n");
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t trans_base = 0; /* eclale patch adds new section header which I'm relocating */
|
/* undo all relocation so you can apply ips patch with correct values, we'll reapply them later */
|
||||||
uint32_t trans_base_offset = 0;
|
PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((int64_t)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew);
|
||||||
uint32_t trans_rebase = 0;
|
DWORD_PTR reloc_delta = (DWORD_PTR)((int64_t)data - headers->OptionalHeader.ImageBase);
|
||||||
|
perform_reloc(data, -1*reloc_delta, 0, 0);
|
||||||
|
|
||||||
uint32_t offset = 0;
|
uint32_t trans_base = 0; /* eclale patch adds new section header which I'm relocating */
|
||||||
uint16_t size = 0;
|
uint32_t trans_base_offset = 0;
|
||||||
uint16_t count = 0;
|
uint32_t trans_rebase = 0;
|
||||||
uint8_t replace[MAX_REPLACE_SIZE] = {0};
|
|
||||||
|
|
||||||
while ( fread(&offset, 1, 3, ips_fp) == 3 && offset != IPS_EOF )
|
|
||||||
{
|
|
||||||
bool skip = false;
|
|
||||||
|
|
||||||
/* need to convert offset to rva before applying patch since the dll is already in memory */
|
|
||||||
uint8_t *bp = (uint8_t *)&offset;
|
|
||||||
offset = BYTE3_TO_UINT(bp);
|
|
||||||
uint32_t rva;
|
|
||||||
|
|
||||||
if (offset < 0x400)
|
uint32_t offset = 0;
|
||||||
{
|
uint16_t size = 0;
|
||||||
rva = offset;
|
uint16_t count = 0;
|
||||||
}
|
uint8_t replace[MAX_REPLACE_SIZE] = {0};
|
||||||
else if ( !offset_to_rva(dllFilename, offset, &rva) )
|
|
||||||
{
|
|
||||||
LOG("Invalid offset %x conversion. Skip this patch\n", offset);
|
|
||||||
skip = true;
|
|
||||||
/* still need to go through the loop to increase read pointer accordingly */
|
|
||||||
}
|
|
||||||
|
|
||||||
IPS_READ(&size, 2, "SIZE");
|
|
||||||
bp = (uint8_t *)&size;
|
|
||||||
size = BYTE2_TO_UINT(bp);
|
|
||||||
++count;
|
|
||||||
|
|
||||||
//LOG("%03d: offset %x converted to %x\nsize %d\n", count, offset, rva,size);
|
|
||||||
if ( size == 0 )
|
|
||||||
{
|
|
||||||
uint8_t value;
|
|
||||||
|
|
||||||
IPS_READ(&size, 2, "RLE SIZE");
|
|
||||||
bp = (uint8_t *)&size;
|
|
||||||
size = BYTE2_TO_UINT(bp);
|
|
||||||
|
|
||||||
IPS_READ(&value, 1, "RLE VALUE");
|
while ( fread(&offset, 1, 3, ips_fp) == 3 && offset != IPS_EOF )
|
||||||
|
{
|
||||||
//LOG("RLE PATCH! size %d value %d\n", size, value);
|
bool skip = false;
|
||||||
//fprintf(stderr, "rle value %d (%d bytes)\n",value, size);
|
|
||||||
if ( size > MAX_REPLACE_SIZE )
|
|
||||||
{
|
|
||||||
LOG("RLE replacement too big.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
memset(replace, value, size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( size > MAX_REPLACE_SIZE )
|
|
||||||
{
|
|
||||||
|
|
||||||
uint16_t remaining = size;
|
|
||||||
uint32_t chunk_rva = rva;
|
|
||||||
|
|
||||||
do {
|
|
||||||
/* patch in multiple chunks */
|
|
||||||
LOG("multipart patch: rva %x, %d remaining\n", chunk_rva, remaining);
|
|
||||||
IPS_READ(&replace, MAX_REPLACE_SIZE, "DATA");
|
|
||||||
|
|
||||||
if ( !skip )
|
|
||||||
patch_memory((int64_t)data+chunk_rva, (char *)replace, MAX_REPLACE_SIZE);
|
|
||||||
|
|
||||||
remaining -= MAX_REPLACE_SIZE;
|
|
||||||
chunk_rva += MAX_REPLACE_SIZE;
|
|
||||||
|
|
||||||
} while (remaining > MAX_REPLACE_SIZE);
|
|
||||||
|
|
||||||
size = remaining;
|
|
||||||
rva = chunk_rva;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
IPS_READ(&replace, size, "DATA");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eclale woes */
|
|
||||||
if ( trans_base == 0 && rva < 0x400 )
|
|
||||||
{
|
|
||||||
if (memcmp(replace, ".trans", 6) == 0)
|
|
||||||
{
|
|
||||||
trans_base = *(uint32_t*)(replace+0x0C);
|
|
||||||
trans_base_offset = *(uint32_t*)(replace+0x14);
|
|
||||||
//LOG("found .trans section at offset %x rva %x\n", trans_base_offset, trans_base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( trans_base_offset != 0 && offset >= trans_base_offset )
|
/* need to convert offset to rva before applying patch since the dll is already in memory */
|
||||||
{
|
uint8_t *bp = (uint8_t *)&offset;
|
||||||
/* patching into new section */
|
offset = BYTE3_TO_UINT(bp);
|
||||||
if ( trans_rebase == 0 )
|
uint32_t rva;
|
||||||
{
|
|
||||||
HANDLE hProc = GetCurrentProcess();
|
|
||||||
LPVOID myAlloc = VirtualAllocEx(hProc, NULL, 16384, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
||||||
if (myAlloc == NULL)
|
|
||||||
{
|
|
||||||
LOG("Failed to allocate memory in target process. Error: 0x%lX\n", GetLastError());
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
trans_rebase = (uint32_t)myAlloc - (uint32_t)data;
|
|
||||||
//LOG( "virtualalloc worked; address %x (%p)\n", trans_rebase, myAlloc);
|
|
||||||
|
|
||||||
/* seems useless */
|
if (offset < 0x400)
|
||||||
//memcpy(replace, &trans_rebase, 4);
|
{
|
||||||
//patch_memory((int64_t)data+0x02d4, (char *)replace, 4);
|
rva = offset;
|
||||||
//LOG( "patched .trans section address to %02x %02x %02x %02x\n", replace[0], replace[1], replace[2], replace[3]);
|
}
|
||||||
}
|
else if ( !offset_to_rva(dllFilename, offset, &rva) )
|
||||||
rva = (offset - trans_base_offset) + trans_rebase;
|
{
|
||||||
//LOG( "off %x - base %x + rebase %x = %x\n\n", offset, trans_base_offset, trans_rebase, rva);
|
LOG("Invalid offset %x conversion. Skip this patch\n", offset);
|
||||||
//LOG( "offset %x relocated to rva %x.", offset, rva);
|
skip = true;
|
||||||
}
|
/* still need to go through the loop to increase read pointer accordingly */
|
||||||
|
}
|
||||||
if ( !skip )
|
|
||||||
{
|
|
||||||
patch_memory((int64_t)data+rva, (char *)replace, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* redo all relocation now the dll is patched */
|
IPS_READ(&size, 2, "SIZE");
|
||||||
perform_reloc(data, reloc_delta, trans_base, trans_rebase-trans_base);
|
bp = (uint8_t *)&size;
|
||||||
|
size = BYTE2_TO_UINT(bp);
|
||||||
|
++count;
|
||||||
|
|
||||||
LOG("popnhax: translation: IPS patch applied.\n");
|
//LOG("%03d: offset %x converted to %x\nsize %d\n", count, offset, rva,size);
|
||||||
|
if ( size == 0 )
|
||||||
if (dump_dll)
|
{
|
||||||
{
|
uint8_t value;
|
||||||
LOG("popnhax: translation debug: dump dll after patch\n");
|
|
||||||
FILE* dllrtp = fopen("dllruntime_patched.dll", "wb");
|
|
||||||
fwrite(data, 1, dllSize, dllrtp);
|
|
||||||
fclose(dllrtp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(ips_fp);
|
IPS_READ(&size, 2, "RLE SIZE");
|
||||||
return true;
|
bp = (uint8_t *)&size;
|
||||||
|
size = BYTE2_TO_UINT(bp);
|
||||||
|
|
||||||
|
IPS_READ(&value, 1, "RLE VALUE");
|
||||||
|
|
||||||
|
//LOG("RLE PATCH! size %d value %d\n", size, value);
|
||||||
|
//fprintf(stderr, "rle value %d (%d bytes)\n",value, size);
|
||||||
|
if ( size > MAX_REPLACE_SIZE )
|
||||||
|
{
|
||||||
|
LOG("RLE replacement too big.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(replace, value, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( size > MAX_REPLACE_SIZE )
|
||||||
|
{
|
||||||
|
|
||||||
|
uint16_t remaining = size;
|
||||||
|
uint32_t chunk_rva = rva;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* patch in multiple chunks */
|
||||||
|
LOG("multipart patch: rva %x, %d remaining\n", chunk_rva, remaining);
|
||||||
|
IPS_READ(&replace, MAX_REPLACE_SIZE, "DATA");
|
||||||
|
|
||||||
|
if ( !skip )
|
||||||
|
patch_memory((int64_t)data+chunk_rva, (char *)replace, MAX_REPLACE_SIZE);
|
||||||
|
|
||||||
|
remaining -= MAX_REPLACE_SIZE;
|
||||||
|
chunk_rva += MAX_REPLACE_SIZE;
|
||||||
|
|
||||||
|
} while (remaining > MAX_REPLACE_SIZE);
|
||||||
|
|
||||||
|
size = remaining;
|
||||||
|
rva = chunk_rva;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
IPS_READ(&replace, size, "DATA");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eclale woes */
|
||||||
|
if ( trans_base == 0 && rva < 0x400 )
|
||||||
|
{
|
||||||
|
if (memcmp(replace, ".trans", 6) == 0)
|
||||||
|
{
|
||||||
|
trans_base = *(uint32_t*)(replace+0x0C);
|
||||||
|
trans_base_offset = *(uint32_t*)(replace+0x14);
|
||||||
|
//LOG("found .trans section at offset %x rva %x\n", trans_base_offset, trans_base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( trans_base_offset != 0 && offset >= trans_base_offset )
|
||||||
|
{
|
||||||
|
/* patching into new section */
|
||||||
|
if ( trans_rebase == 0 )
|
||||||
|
{
|
||||||
|
HANDLE hProc = GetCurrentProcess();
|
||||||
|
LPVOID myAlloc = VirtualAllocEx(hProc, NULL, 16384, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||||
|
if (myAlloc == NULL)
|
||||||
|
{
|
||||||
|
LOG("Failed to allocate memory in target process. Error: 0x%lX\n", GetLastError());
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
trans_rebase = (uint32_t)myAlloc - (uint32_t)data;
|
||||||
|
//LOG( "virtualalloc worked; address %x (%p)\n", trans_rebase, myAlloc);
|
||||||
|
|
||||||
|
/* seems useless */
|
||||||
|
//memcpy(replace, &trans_rebase, 4);
|
||||||
|
//patch_memory((int64_t)data+0x02d4, (char *)replace, 4);
|
||||||
|
//LOG( "patched .trans section address to %02x %02x %02x %02x\n", replace[0], replace[1], replace[2], replace[3]);
|
||||||
|
}
|
||||||
|
rva = (offset - trans_base_offset) + trans_rebase;
|
||||||
|
//LOG( "off %x - base %x + rebase %x = %x\n\n", offset, trans_base_offset, trans_rebase, rva);
|
||||||
|
//LOG( "offset %x relocated to rva %x.", offset, rva);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !skip )
|
||||||
|
{
|
||||||
|
patch_memory((int64_t)data+rva, (char *)replace, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* redo all relocation now the dll is patched */
|
||||||
|
perform_reloc(data, reloc_delta, trans_base, trans_rebase-trans_base);
|
||||||
|
|
||||||
|
LOG("popnhax: translation: IPS patch applied.\n");
|
||||||
|
|
||||||
|
if (dump_dll)
|
||||||
|
{
|
||||||
|
LOG("popnhax: translation debug: dump dll after patch\n");
|
||||||
|
FILE* dllrtp = fopen("dllruntime_patched.dll", "wb");
|
||||||
|
fwrite(data, 1, dllSize, dllrtp);
|
||||||
|
fclose(dllrtp);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(ips_fp);
|
||||||
|
return true;
|
||||||
#undef IPS_READ
|
#undef IPS_READ
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,16 +331,16 @@ static bool patch_translation_dict(const char *dllFilename, const char *folderna
|
|||||||
uint8_t word_count = 0;
|
uint8_t word_count = 0;
|
||||||
uint8_t orig_size = 0;
|
uint8_t orig_size = 0;
|
||||||
|
|
||||||
char dict_filepath[64];
|
char dict_filepath[64];
|
||||||
sprintf(dict_filepath, "%s%s%s", "data_mods\\", foldername, "\\popn22.dict");
|
sprintf(dict_filepath, "%s%s%s", "data_mods\\", foldername, "\\popn22.dict");
|
||||||
FILE *dict_fp = fopen(dict_filepath, "rb");
|
FILE *dict_fp = fopen(dict_filepath, "rb");
|
||||||
|
|
||||||
if (dict_fp == NULL)
|
if (dict_fp == NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("popnhax: translation: popn22.dict file found\n");
|
LOG("popnhax: translation: popn22.dict file found\n");
|
||||||
|
|
||||||
#define STATE_WAITING 0
|
#define STATE_WAITING 0
|
||||||
#define STATE_ORIGINAL 1
|
#define STATE_ORIGINAL 1
|
||||||
@ -435,11 +435,11 @@ static bool patch_translation_dict(const char *dllFilename, const char *folderna
|
|||||||
|
|
||||||
bool patch_translate(const char *dllFilename, const char *folder, bool debug)
|
bool patch_translate(const char *dllFilename, const char *folder, bool debug)
|
||||||
{
|
{
|
||||||
bool ips_done = false;
|
bool ips_done = false;
|
||||||
bool dict_done = false;
|
bool dict_done = false;
|
||||||
|
|
||||||
ips_done = patch_translation_ips(dllFilename, folder, debug);
|
ips_done = patch_translation_ips(dllFilename, folder, debug);
|
||||||
dict_done = patch_translation_dict(dllFilename, folder, debug);
|
dict_done = patch_translation_dict(dllFilename, folder, debug);
|
||||||
|
|
||||||
return ips_done || dict_done;
|
return ips_done || dict_done;
|
||||||
}
|
}
|
@ -1,7 +1,8 @@
|
|||||||
libs += util
|
libs += util
|
||||||
|
|
||||||
srcpp_util := \
|
srcpp_util := \
|
||||||
fuzzy_search.cc \
|
bst.cc \
|
||||||
search.cc \
|
search.cc \
|
||||||
cmdline.cc \
|
cmdline.cc \
|
||||||
patch.cc \
|
patch.cc \
|
||||||
|
crc32.cc \
|
||||||
|
34
util/bst.cc
Normal file
34
util/bst.cc
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "bst.h"
|
||||||
|
|
||||||
|
bst_t* bst_search(bst_t *root, uint32_t val)
|
||||||
|
{
|
||||||
|
if( root == NULL || root->data == val )
|
||||||
|
return root;
|
||||||
|
else if( val > (root->data) )
|
||||||
|
return bst_search(root->right, val);
|
||||||
|
else
|
||||||
|
return bst_search(root->left,val);
|
||||||
|
}
|
||||||
|
|
||||||
|
bst_t* bst_insert(bst_t *root, uint32_t val)
|
||||||
|
{
|
||||||
|
if ( root == NULL )
|
||||||
|
{
|
||||||
|
bst_t *p;
|
||||||
|
p = (bst_t *)malloc(sizeof(bst_t));
|
||||||
|
p->data = val;
|
||||||
|
p->left = NULL;
|
||||||
|
p->right = NULL;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
else if ( val > root->data )
|
||||||
|
root->right = bst_insert(root->right, val);
|
||||||
|
else
|
||||||
|
root->left = bst_insert(root->left, val);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
16
util/bst.h
Normal file
16
util/bst.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef __BST_H__
|
||||||
|
#define __BST_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct bst_s
|
||||||
|
{
|
||||||
|
uint32_t data;
|
||||||
|
struct bst_s *right;
|
||||||
|
struct bst_s *left;
|
||||||
|
} bst_t;
|
||||||
|
|
||||||
|
bst_t* bst_search(bst_t *root, uint32_t val);
|
||||||
|
bst_t* bst_insert(bst_t *root, uint32_t val);
|
||||||
|
|
||||||
|
#endif
|
160
util/crc32.cc
Normal file
160
util/crc32.cc
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/* Crc - 32 BIT ANSI X3.66 CRC checksum files */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "crc32.h"
|
||||||
|
|
||||||
|
/**********************************************************************\
|
||||||
|
|* Demonstration program to compute the 32-bit CRC used as the frame *|
|
||||||
|
|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *|
|
||||||
|
|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *|
|
||||||
|
|* protocol). The 32-bit FCS was added via the Federal Register, *|
|
||||||
|
|* 1 June 1982, p.23798. I presume but don't know for certain that *|
|
||||||
|
|* this polynomial is or will be included in CCITT V.41, which *|
|
||||||
|
|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *|
|
||||||
|
|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *|
|
||||||
|
|* errors by a factor of 10^-5 over 16-bit FCS. *|
|
||||||
|
\**********************************************************************/
|
||||||
|
|
||||||
|
/* Need an unsigned type capable of holding 32 bits; */
|
||||||
|
|
||||||
|
typedef uint32_t UNS_32_BITS;
|
||||||
|
|
||||||
|
/* Copyright (C) 1986 Gary S. Brown. You may use this program, or
|
||||||
|
code or tables extracted from it, as desired without restriction.*/
|
||||||
|
|
||||||
|
/* First, the polynomial itself and its table of feedback terms. The */
|
||||||
|
/* polynomial is */
|
||||||
|
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
|
||||||
|
/* Note that we take it "backwards" and put the highest-order term in */
|
||||||
|
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
|
||||||
|
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
|
||||||
|
/* the MSB being 1. */
|
||||||
|
|
||||||
|
/* Note that the usual hardware shift register implementation, which */
|
||||||
|
/* is what we're using (we're merely optimizing it by doing eight-bit */
|
||||||
|
/* chunks at a time) shifts bits into the lowest-order term. In our */
|
||||||
|
/* implementation, that means shifting towards the right. Why do we */
|
||||||
|
/* do it this way? Because the calculated CRC must be transmitted in */
|
||||||
|
/* order from highest-order term to lowest-order term. UARTs transmit */
|
||||||
|
/* characters in order from LSB to MSB. By storing the CRC this way, */
|
||||||
|
/* we hand it to the UART in the order low-byte to high-byte; the UART */
|
||||||
|
/* sends each low-bit to hight-bit; and the result is transmission bit */
|
||||||
|
/* by bit from highest- to lowest-order term without requiring any bit */
|
||||||
|
/* shuffling on our part. Reception works similarly. */
|
||||||
|
|
||||||
|
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
|
||||||
|
/* */
|
||||||
|
/* 1. The table can be generated at runtime if desired; code to do so */
|
||||||
|
/* is shown later. It might not be obvious, but the feedback */
|
||||||
|
/* terms simply represent the results of eight shift/xor opera- */
|
||||||
|
/* tions for all combinations of data and CRC register values. */
|
||||||
|
/* */
|
||||||
|
/* 2. The CRC accumulation logic is the same for all CRC polynomials, */
|
||||||
|
/* be they sixteen or thirty-two bits wide. You simply choose the */
|
||||||
|
/* appropriate table. Alternatively, because the table can be */
|
||||||
|
/* generated at runtime, you can start by generating the table for */
|
||||||
|
/* the polynomial in question and use exactly the same "updcrc", */
|
||||||
|
/* if your application needn't simultaneously handle two CRC */
|
||||||
|
/* polynomials. (Note, however, that XMODEM is strange.) */
|
||||||
|
/* */
|
||||||
|
/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */
|
||||||
|
/* of course, 32-bit entries work OK if the high 16 bits are zero. */
|
||||||
|
/* */
|
||||||
|
/* 4. The values must be right-shifted by eight bits by the "updcrc" */
|
||||||
|
/* logic; the shift must be unsigned (bring in zeroes). On some */
|
||||||
|
/* hardware you could probably optimize the shift in assembler by */
|
||||||
|
/* using byte-swap instructions. */
|
||||||
|
|
||||||
|
static UNS_32_BITS crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
|
||||||
|
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||||
|
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||||
|
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||||
|
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||||
|
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||||
|
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||||
|
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||||
|
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||||
|
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||||
|
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||||
|
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||||
|
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||||
|
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||||
|
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||||
|
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||||
|
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||||
|
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||||
|
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||||
|
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||||
|
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||||
|
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||||
|
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||||
|
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||||
|
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||||
|
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||||
|
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||||
|
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||||
|
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||||
|
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||||
|
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||||
|
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||||
|
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||||
|
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||||
|
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||||
|
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||||
|
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||||
|
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||||
|
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||||
|
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||||
|
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||||
|
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||||
|
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||||
|
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t updateCRC32(unsigned char ch, uint32_t crc)
|
||||||
|
{
|
||||||
|
return UPDC32(ch, crc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool crc32file(const char *name, uint32_t *crc, long *charcnt)
|
||||||
|
{
|
||||||
|
register FILE *fin;
|
||||||
|
register uint32_t oldcrc32;
|
||||||
|
register int c;
|
||||||
|
|
||||||
|
oldcrc32 = 0xFFFFFFFF; *charcnt = 0;
|
||||||
|
if ((fin=fopen(name, "r"))==NULL)
|
||||||
|
{
|
||||||
|
perror(name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while ((c=getc(fin))!=EOF)
|
||||||
|
{
|
||||||
|
++*charcnt;
|
||||||
|
oldcrc32 = UPDC32(c, oldcrc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ferror(fin))
|
||||||
|
{
|
||||||
|
perror(name);
|
||||||
|
*charcnt = -1;
|
||||||
|
}
|
||||||
|
fclose(fin);
|
||||||
|
|
||||||
|
*crc = oldcrc32 = ~oldcrc32;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t crc32buf(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
register uint32_t oldcrc32;
|
||||||
|
|
||||||
|
oldcrc32 = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
for ( ; len; --len, ++buf)
|
||||||
|
{
|
||||||
|
oldcrc32 = UPDC32(*buf, oldcrc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ~oldcrc32;
|
||||||
|
}
|
16
util/crc32.h
Normal file
16
util/crc32.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/* taken from https://github.com/panzi/CRC-and-checksum-functions/ */
|
||||||
|
#ifndef __CRC32_H__
|
||||||
|
#define __CRC32_H__
|
||||||
|
|
||||||
|
#include <stdlib.h> /* For size_t */
|
||||||
|
#include <stdint.h> /* For uint8_t, uint16_t, uint32_t */
|
||||||
|
#include <stdbool.h> /* For bool, true, false */
|
||||||
|
|
||||||
|
#define UPDC32(octet,crc) (crc_32_tab[((crc)\
|
||||||
|
^ ((uint8_t)octet)) & 0xff] ^ ((crc) >> 8))
|
||||||
|
|
||||||
|
uint32_t updateCRC32(unsigned char ch, uint32_t crc);
|
||||||
|
bool crc32file(const char *name, uint32_t *crc, long *charcnt);
|
||||||
|
uint32_t crc32buf(char *buf, size_t len);
|
||||||
|
|
||||||
|
#endif
|
@ -1,62 +0,0 @@
|
|||||||
#include <memory.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "util/fuzzy_search.h"
|
|
||||||
|
|
||||||
int find_block_core(char *haystack, size_t haystack_size, fuzzy_search_task *needle,
|
|
||||||
size_t orig_offset, int dir) {
|
|
||||||
size_t offset = orig_offset;
|
|
||||||
haystack_size += orig_offset;
|
|
||||||
while (offset + 1 < haystack_size) {
|
|
||||||
size_t offset_temp = offset;
|
|
||||||
int found = 1;
|
|
||||||
|
|
||||||
if (needle->count <= 0) {
|
|
||||||
found = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < needle->count; i++) {
|
|
||||||
int subfound = -1;
|
|
||||||
|
|
||||||
if (needle->blocks[i].type == 1) {
|
|
||||||
offset_temp += needle->blocks[i].length;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = 0; j < needle->blocks[i].count; j++) {
|
|
||||||
if (haystack + offset_temp + needle->blocks[i].data[j].length <
|
|
||||||
haystack + haystack_size &&
|
|
||||||
memcmp(haystack + offset_temp, needle->blocks[i].data[j].block,
|
|
||||||
needle->blocks[i].data[j].length) == 0) {
|
|
||||||
subfound = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subfound == -1) {
|
|
||||||
found = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset_temp += needle->blocks[i].data[subfound].length;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found == 1) {
|
|
||||||
return offset;
|
|
||||||
} else {
|
|
||||||
offset += dir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int find_block(char *haystack, size_t haystack_size, fuzzy_search_task *needle,
|
|
||||||
size_t orig_offset) {
|
|
||||||
return find_block_core(haystack, haystack_size, needle, orig_offset, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int find_block_back(char *haystack, size_t haystack_size, fuzzy_search_task *needle,
|
|
||||||
size_t orig_offset) {
|
|
||||||
return find_block_core(haystack, haystack_size, needle, orig_offset, -1);
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
#ifndef __FUZZY_SEARCH_H__
|
|
||||||
#define __FUZZY_SEARCH_H__
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#define FUZZY_START(task, _count) \
|
|
||||||
{ \
|
|
||||||
task.count = _count; \
|
|
||||||
task.blocks = (fuzzy_search_block *)calloc(task.count, sizeof(fuzzy_search_block)); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FUZZY_CODE(task, id, code, len) \
|
|
||||||
{ \
|
|
||||||
task.blocks[id].count = 1; \
|
|
||||||
task.blocks[id].data[0].type = 0; \
|
|
||||||
task.blocks[id].data[0].length = len; \
|
|
||||||
task.blocks[id].data[0].block = \
|
|
||||||
(char *)calloc(task.blocks[id].data[0].length, sizeof(char)); \
|
|
||||||
memcpy(task.blocks[id].data[0].block, code, task.blocks[id].data[0].length); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FUZZY_WILDCARD(task, id, len) \
|
|
||||||
{ \
|
|
||||||
task.blocks[id].count = 1; \
|
|
||||||
task.blocks[id].type = 1; \
|
|
||||||
task.blocks[id].length = len; \
|
|
||||||
task.blocks[id].data[0].length = len; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FUZZY_SIZE(task, id) (task.blocks[id].data[0].length)
|
|
||||||
|
|
||||||
typedef struct fuzzy_search_block_data {
|
|
||||||
int type;
|
|
||||||
int length;
|
|
||||||
char *block;
|
|
||||||
} fuzzy_search_block_data;
|
|
||||||
|
|
||||||
typedef struct fuzzy_search_block {
|
|
||||||
int type;
|
|
||||||
int length;
|
|
||||||
int count;
|
|
||||||
fuzzy_search_block_data data[0x10];
|
|
||||||
} fuzzy_search_block;
|
|
||||||
|
|
||||||
typedef struct fuzzy_search_task {
|
|
||||||
int count;
|
|
||||||
fuzzy_search_block *blocks;
|
|
||||||
} fuzzy_search_task;
|
|
||||||
|
|
||||||
int find_block(char *haystack, size_t haystack_size, fuzzy_search_task *needle, size_t offset);
|
|
||||||
int find_block_back(char *haystack, size_t haystack_size, fuzzy_search_task *needle, size_t offset);
|
|
||||||
|
|
||||||
#endif
|
|
@ -26,7 +26,7 @@ static void badCharHeuristic(const unsigned char *str, int size, int* badchar) {
|
|||||||
|
|
||||||
#define DEBUG_SEARCH 0
|
#define DEBUG_SEARCH 0
|
||||||
|
|
||||||
int _search(unsigned char *haystack, size_t haystack_size, const unsigned char *needle, size_t needle_size, int orig_offset, int debug) {
|
int _search(unsigned char *haystack, size_t haystack_size, const unsigned char *needle, size_t needle_size, int orig_offset, bool wildcards, int debug) {
|
||||||
int badchar[NO_OF_CHARS];
|
int badchar[NO_OF_CHARS];
|
||||||
|
|
||||||
badCharHeuristic(needle, needle_size, badchar);
|
badCharHeuristic(needle, needle_size, badchar);
|
||||||
@ -46,12 +46,21 @@ int _search(unsigned char *haystack, size_t haystack_size, const unsigned char *
|
|||||||
LOG("pat...");
|
LOG("pat...");
|
||||||
for (size_t i = 0; i < needle_size; i++)
|
for (size_t i = 0; i < needle_size; i++)
|
||||||
{
|
{
|
||||||
LOG("%02x ", needle[i]);
|
if (wildcards && needle[i] == '?')
|
||||||
|
LOG("** ");
|
||||||
|
else
|
||||||
|
LOG("%02x ", needle[i]);
|
||||||
}
|
}
|
||||||
LOG("\n");
|
LOG("\n");
|
||||||
}
|
}
|
||||||
while (j >= 0 && needle[j] == haystack[orig_offset + s + j])
|
if ( wildcards )
|
||||||
j--;
|
{
|
||||||
|
while (j >= 0 && ( needle[j] == '?' || needle[j] == haystack[orig_offset + s + j]) )
|
||||||
|
j--;
|
||||||
|
} else {
|
||||||
|
while (j >= 0 && ( needle[j] == haystack[orig_offset + s + j]) )
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
|
||||||
if (j < 0) {
|
if (j < 0) {
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -70,6 +79,21 @@ int _search(unsigned char *haystack, size_t haystack_size, const unsigned char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
int search(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset) {
|
int search(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset) {
|
||||||
int res = _search((unsigned char*) haystack, haystack_size, (const unsigned char *)needle, needle_size, orig_offset, 0);
|
int res = _search((unsigned char*) haystack, haystack_size, (const unsigned char *)needle, needle_size, orig_offset, false, 0);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wildcard_search(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset) {
|
||||||
|
int res = _search((unsigned char*) haystack, haystack_size, (const unsigned char *)needle, needle_size, orig_offset, true, 0);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int search_debug(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset) {
|
||||||
|
int res = _search((unsigned char*) haystack, haystack_size, (const unsigned char *)needle, needle_size, orig_offset, false, 2);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wildcard_search_debug(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset) {
|
||||||
|
int res = _search((unsigned char*) haystack, haystack_size, (const unsigned char *)needle, needle_size, orig_offset, true, 2);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
@ -2,5 +2,8 @@
|
|||||||
#define __SEARCH_H__
|
#define __SEARCH_H__
|
||||||
|
|
||||||
int search(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset);
|
int search(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset);
|
||||||
|
int search_debug(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset);
|
||||||
|
int wildcard_search(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset);
|
||||||
|
int wildcard_search_debug(char *haystack, size_t haystack_size, const char *needle, size_t needle_size, size_t orig_offset);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user