mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2026-01-09 20:46:53 +00:00
补充某些必要的文件
This commit is contained in:
164
cocos2d-x/tools/cocos2d-console/bin/MultiLanguage.py
Normal file
164
cocos2d-x/tools/cocos2d-console/bin/MultiLanguage.py
Normal file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/python
|
||||
# ----------------------------------------------------------------------------
|
||||
# MultiLanguage: Get the multi-language strings for console.
|
||||
#
|
||||
# Author: Bin Zhang
|
||||
#
|
||||
# License: MIT
|
||||
# ----------------------------------------------------------------------------
|
||||
'''
|
||||
Get the multi-language strings for console.
|
||||
'''
|
||||
|
||||
import cocos
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import locale
|
||||
|
||||
def get_current_path():
|
||||
if getattr(sys, 'frozen', None):
|
||||
ret = os.path.realpath(os.path.dirname(sys.executable))
|
||||
else:
|
||||
ret = os.path.realpath(os.path.dirname(__file__))
|
||||
|
||||
return ret
|
||||
|
||||
class MultiLanguage(object):
|
||||
CONFIG_FILE_NAME = 'strings.json'
|
||||
DEFAULT_LANGUAGE = 'en'
|
||||
instance = None
|
||||
|
||||
@classmethod
|
||||
def get_available_langs(cls):
|
||||
info = cls.get_instance().cfg_info
|
||||
ret = []
|
||||
if info is not None:
|
||||
for key in info.keys():
|
||||
if isinstance(key, unicode):
|
||||
ret.append(key.encode('utf-8'))
|
||||
|
||||
return ret
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls):
|
||||
if cls.instance is None:
|
||||
cls.instance = MultiLanguage()
|
||||
|
||||
return cls.instance
|
||||
|
||||
@classmethod
|
||||
def get_string(cls, key, fmt_value=None):
|
||||
fmt = cls.get_instance().get_current_string(key)
|
||||
if fmt_value is None:
|
||||
ret = fmt
|
||||
else:
|
||||
if isinstance(fmt_value, tuple):
|
||||
dst_values = []
|
||||
for value in fmt_value:
|
||||
if isinstance(value, unicode):
|
||||
dst_values.append(value.encode(cls.get_instance().get_encoding()))
|
||||
else:
|
||||
dst_values.append(value)
|
||||
ret = fmt % tuple(dst_values)
|
||||
elif isinstance(fmt_value, unicode):
|
||||
ret = fmt % fmt_value.encode(cls.get_instance().get_encoding())
|
||||
else:
|
||||
ret = fmt % fmt_value
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@classmethod
|
||||
def set_language(cls, lang):
|
||||
cls.get_instance().set_current_language(lang)
|
||||
|
||||
def __init__(self):
|
||||
cfg_file_path = os.path.join(get_current_path(), MultiLanguage.CONFIG_FILE_NAME)
|
||||
|
||||
try:
|
||||
sys_lang, self.encoding = locale.getdefaultlocale()
|
||||
except:
|
||||
sys_lang = None
|
||||
self.encoding = None
|
||||
pass
|
||||
|
||||
if self.encoding is None:
|
||||
self.encoding = 'utf-8'
|
||||
|
||||
if sys_lang is None:
|
||||
cur_lang_key = MultiLanguage.DEFAULT_LANGUAGE
|
||||
else:
|
||||
cur_lang_key = self.get_lang_key(sys_lang)
|
||||
|
||||
# override lang & encoding
|
||||
self.encoding = 'utf-8'
|
||||
cur_lang_key = MultiLanguage.DEFAULT_LANGUAGE
|
||||
|
||||
# get the strings info
|
||||
if os.path.isfile(cfg_file_path):
|
||||
f = open(cfg_file_path)
|
||||
self.cfg_info = json.load(f, encoding='utf-8')
|
||||
f.close()
|
||||
|
||||
if self.cfg_info.has_key(cur_lang_key):
|
||||
self.cur_lang_strings = self.cfg_info[cur_lang_key]
|
||||
else:
|
||||
self.cur_lang_strings = None
|
||||
|
||||
if self.cfg_info.has_key(MultiLanguage.DEFAULT_LANGUAGE):
|
||||
self.default_lang_strings = self.cfg_info[MultiLanguage.DEFAULT_LANGUAGE]
|
||||
else:
|
||||
self.default_lang_strings = None
|
||||
else:
|
||||
self.cfg_info = None
|
||||
self.cur_lang_strings = None
|
||||
self.default_lang_strings = None
|
||||
|
||||
def get_lang_key(self, sys_lang):
|
||||
sys_lang_info = sys_lang.split('_')
|
||||
lang = sys_lang_info[0]
|
||||
lang = lang.lower()
|
||||
region = None
|
||||
if len(sys_lang_info) > 1:
|
||||
region = sys_lang_info[1]
|
||||
region = region.lower()
|
||||
|
||||
if lang == 'zh':
|
||||
if (region is None) or (region == 'cn'):
|
||||
ret = lang
|
||||
else:
|
||||
ret = 'zh_tr'
|
||||
else:
|
||||
ret = lang
|
||||
|
||||
return ret
|
||||
|
||||
def has_key(self, key, strings_info):
|
||||
ret = False
|
||||
if strings_info is not None and strings_info.has_key(key):
|
||||
ret = True
|
||||
|
||||
return ret
|
||||
|
||||
def set_current_language(self, lang):
|
||||
if (self.cfg_info is not None) and (self.cfg_info.has_key(lang)):
|
||||
self.cur_lang_strings = self.cfg_info[lang]
|
||||
else:
|
||||
cocos.Logging.warning(MultiLanguage.get_string('COCOS_WARNING_LANG_NOT_SUPPORT_FMT', lang))
|
||||
|
||||
def get_encoding(self):
|
||||
return self.encoding
|
||||
|
||||
def get_current_string(self, key):
|
||||
if self.has_key(key, self.cur_lang_strings):
|
||||
ret = self.cur_lang_strings[key]
|
||||
elif self.has_key(key, self.default_lang_strings):
|
||||
ret = self.default_lang_strings[key]
|
||||
else:
|
||||
ret= key
|
||||
|
||||
if isinstance(ret, unicode):
|
||||
ret = ret.encode(self.encoding)
|
||||
|
||||
return ret
|
||||
7
cocos2d-x/tools/cocos2d-console/bin/cocos
Executable file
7
cocos2d-x/tools/cocos2d-console/bin/cocos
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash -l
|
||||
|
||||
COCOS_CONSOLE_BIN_DIRECTORY=$(dirname "$0")
|
||||
COCOS_CONSOLE_BIN_DIRECTORY=$(cd "$COCOS_CONSOLE_BIN_DIRECTORY" && pwd -P)
|
||||
|
||||
python "$COCOS_CONSOLE_BIN_DIRECTORY/cocos.py" "$@"
|
||||
|
||||
3
cocos2d-x/tools/cocos2d-console/bin/cocos.bat
Normal file
3
cocos2d-x/tools/cocos2d-console/bin/cocos.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
@python "%~dp0/cocos.py" %*
|
||||
|
||||
1072
cocos2d-x/tools/cocos2d-console/bin/cocos.py
Normal file
1072
cocos2d-x/tools/cocos2d-console/bin/cocos.py
Normal file
File diff suppressed because it is too large
Load Diff
57
cocos2d-x/tools/cocos2d-console/bin/cocos2d.ini
Normal file
57
cocos2d-x/tools/cocos2d-console/bin/cocos2d.ini
Normal file
@@ -0,0 +1,57 @@
|
||||
#
|
||||
# cocos2d command line tool configuration file
|
||||
#
|
||||
|
||||
[global]
|
||||
# there are 3 modes
|
||||
# "source", which means that the cocos2d-x source code is being used for "new" and other plugins.
|
||||
# "precompiled", which means that cocos2d-x precompiled libraries and headers will be used for "new" and other plugins
|
||||
# "distro", which means that cocos2d-x precompiled libraries and headers won't be copied when using "new" and other plugins
|
||||
# Default: source. Distros and other installers must override this setting
|
||||
cocos2d_x_mode=source
|
||||
|
||||
# Enable/Disable the data statistics
|
||||
# If the value is 'false' or 'no', statistics is disabled.
|
||||
# Otherwise, it's enabled.
|
||||
enable_stat=true
|
||||
|
||||
[plugins]
|
||||
# What are the plugins that must be enabled
|
||||
plugin_new.CCPluginNew
|
||||
plugin_compile.CCPluginCompile
|
||||
plugin_run.CCPluginRun
|
||||
plugin_deploy.CCPluginDeploy
|
||||
plugin_jscompile.CCPluginJSCompile
|
||||
plugin_luacompile.CCPluginLuaCompile
|
||||
plugin_generate.LibsCompiler
|
||||
plugin_generate.SimulatorCompiler
|
||||
plugin_generate.TemplateGenerator
|
||||
plugin_package.CCPluginPackage
|
||||
plugin_framework.CCPluginFramework
|
||||
plugin_gui.CCPluginGUI
|
||||
#plugin_version.CCPluginVersion
|
||||
#plugin_install.CCPluginInstall
|
||||
#plugin_update.CCPluginUpdate
|
||||
#plugin_clean.CCPluginClean
|
||||
#plugin_dist.CCPluginDist
|
||||
#plugin_test.CCPluginTest
|
||||
# To add a new plugin add it's classname here
|
||||
|
||||
|
||||
[paths]
|
||||
# where cocos2d-x is installed
|
||||
# example: /usr/local/cocos2d-x
|
||||
# eg: this file must exist: /usr/local/cocos2d-x/cocos/cocos2d.h
|
||||
# Default: empty. Installers will populate it
|
||||
cocos2d_x=
|
||||
|
||||
# where are the cocos2d-x's templates installed
|
||||
# example: /home/user/templates
|
||||
# eg: this directory must exist: /home/user/templates/cpp-template-default
|
||||
# Default: empty. Installers will populate it
|
||||
templates=
|
||||
|
||||
# where are the plugins installed
|
||||
# but distros can override this directory
|
||||
# Default: ../plugins. Installers can replace it if needed
|
||||
plugins=../plugins
|
||||
698
cocos2d-x/tools/cocos2d-console/bin/cocos_project.py
Normal file
698
cocos2d-x/tools/cocos2d-console/bin/cocos_project.py
Normal file
@@ -0,0 +1,698 @@
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import cocos
|
||||
from MultiLanguage import MultiLanguage
|
||||
|
||||
class Project(object):
|
||||
CPP = 'cpp'
|
||||
LUA = 'lua'
|
||||
JS = 'js'
|
||||
|
||||
CONFIG = '.cocos-project.json'
|
||||
|
||||
KEY_PROJ_TYPE = 'project_type'
|
||||
KEY_HAS_NATIVE = 'has_native'
|
||||
KEY_CUSTOM_STEP_SCRIPT = "custom_step_script"
|
||||
KEY_ENGINE_VERSION = "engine_version"
|
||||
|
||||
CUSTOM_STEP_PRE_BUILD = "pre-build"
|
||||
CUSTOM_STEP_POST_BUILD = "post-build"
|
||||
|
||||
@staticmethod
|
||||
def list_for_display():
|
||||
return [x.lower() for x in Project.language_list()]
|
||||
|
||||
@staticmethod
|
||||
def language_list():
|
||||
return (Project.CPP, Project.LUA, Project.JS)
|
||||
|
||||
def __init__(self, project_dir):
|
||||
# parse the config file
|
||||
self.info = self._parse_project_json(project_dir)
|
||||
|
||||
def _parse_project_json(self, src_dir):
|
||||
proj_path = self._find_project_dir(src_dir)
|
||||
# config file is not found
|
||||
if proj_path == None:
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('PROJECT_CFG_NOT_FOUND_FMT',
|
||||
os.path.join(src_dir, Project.CONFIG)),
|
||||
cocos.CCPluginError.ERROR_PATH_NOT_FOUND)
|
||||
|
||||
project_json = os.path.join(proj_path, Project.CONFIG)
|
||||
try:
|
||||
f = open(project_json)
|
||||
project_info = json.load(f)
|
||||
f.close()
|
||||
except Exception:
|
||||
if f is not None:
|
||||
f.close()
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('PROJECT_CFG_BROKEN_FMT',
|
||||
project_json),
|
||||
cocos.CCPluginError.ERROR_PARSE_FILE)
|
||||
|
||||
if project_info is None:
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('PROJECT_CFG_PARSE_FAILED_FMT',
|
||||
Project.CONFIG), cocos.CCPluginError.ERROR_PARSE_FILE)
|
||||
|
||||
if not project_info.has_key(Project.KEY_PROJ_TYPE):
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('PROJECT_CFG_GET_VALUE_FAILED_FMT',
|
||||
(Project.KEY_PROJ_TYPE, Project.CONFIG)),
|
||||
cocos.CCPluginError.ERROR_WRONG_CONFIG)
|
||||
|
||||
lang = project_info[Project.KEY_PROJ_TYPE]
|
||||
lang = lang.lower()
|
||||
|
||||
# The config is invalid
|
||||
if not (lang in Project.language_list()):
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('PROJECT_CFG_INVALID_LANG_FMT',
|
||||
(Project.KEY_PROJ_TYPE, ', '.join(Project.list_for_display()))),
|
||||
cocos.CCPluginError.ERROR_WRONG_CONFIG)
|
||||
|
||||
# record the dir & language of the project
|
||||
self._project_dir = proj_path
|
||||
self._project_lang = lang
|
||||
|
||||
# if is script project, record whether it has native or not
|
||||
self._has_native = False
|
||||
if (self._is_script_project() and project_info.has_key(Project.KEY_HAS_NATIVE)):
|
||||
self._has_native = project_info[Project.KEY_HAS_NATIVE]
|
||||
|
||||
# if has custom step script, record it
|
||||
self._custom_step = None
|
||||
if (project_info.has_key(Project.KEY_CUSTOM_STEP_SCRIPT)):
|
||||
script_path = project_info[Project.KEY_CUSTOM_STEP_SCRIPT]
|
||||
if not os.path.isabs(script_path):
|
||||
script_path = os.path.join(self._project_dir, script_path)
|
||||
|
||||
if os.path.isfile(script_path):
|
||||
import sys
|
||||
script_dir, script_name = os.path.split(script_path)
|
||||
sys.path.append(script_dir)
|
||||
self._custom_step = __import__(os.path.splitext(script_name)[0])
|
||||
cocos.Logging.info(MultiLanguage.get_string('PROJECT_INFO_FOUND_CUSTOM_STEP_FMT', script_path))
|
||||
else:
|
||||
cocos.Logging.warning(MultiLanguage.get_string('PROJECT_WARNING_CUSTOM_SCRIPT_NOT_FOUND_FMT',
|
||||
script_path))
|
||||
self._custom_step = None
|
||||
|
||||
return project_info
|
||||
|
||||
def invoke_custom_step_script(self, event, tp, args):
|
||||
try:
|
||||
if self._custom_step is not None:
|
||||
self._custom_step.handle_event(event, tp, args)
|
||||
except Exception as e:
|
||||
cocos.Logging.warning(MultiLanguage.get_string('PROJECT_WARNING_CUSTOM_STEP_FAILED_FMT', e))
|
||||
raise e
|
||||
|
||||
def _find_project_dir(self, start_path):
|
||||
path = start_path
|
||||
while True:
|
||||
if cocos.os_is_win32():
|
||||
# windows root path, eg. c:\
|
||||
if re.match(".+:\\\\$", path):
|
||||
break
|
||||
else:
|
||||
# unix like use '/' as root path
|
||||
if path == '/' :
|
||||
break
|
||||
cfg_path = os.path.join(path, Project.CONFIG)
|
||||
if (os.path.exists(cfg_path) and os.path.isfile(cfg_path)):
|
||||
return path
|
||||
|
||||
path = os.path.dirname(path)
|
||||
|
||||
return None
|
||||
|
||||
def get_proj_config(self, key):
|
||||
project_json = os.path.join(self._project_dir, Project.CONFIG)
|
||||
f = open(project_json)
|
||||
project_info = json.load(f)
|
||||
f.close()
|
||||
|
||||
ret = None
|
||||
if project_info.has_key(key):
|
||||
ret = project_info[key]
|
||||
|
||||
return ret
|
||||
|
||||
def write_proj_config(self, key, value):
|
||||
project_json = os.path.join(self._project_dir, Project.CONFIG)
|
||||
|
||||
if os.path.isfile(project_json):
|
||||
f = open(project_json)
|
||||
project_info = json.load(f)
|
||||
f.close()
|
||||
|
||||
if project_info is None:
|
||||
project_info = {}
|
||||
|
||||
project_info[key] = value
|
||||
|
||||
outfile = open(project_json, "w")
|
||||
json.dump(project_info, outfile, sort_keys = True, indent = 4)
|
||||
outfile.close()
|
||||
|
||||
def get_project_dir(self):
|
||||
return self._project_dir
|
||||
|
||||
def get_language(self):
|
||||
return self._project_lang
|
||||
|
||||
def has_android_libs(self):
|
||||
if self._is_script_project():
|
||||
proj_android_path = os.path.join(self.get_project_dir(), "frameworks", "runtime-src", "proj.android", "libs")
|
||||
else:
|
||||
proj_android_path = os.path.join(self.get_project_dir(), "proj.android", "libs")
|
||||
|
||||
return os.path.isdir(proj_android_path)
|
||||
|
||||
def _is_native_support(self):
|
||||
return self._has_native
|
||||
|
||||
def _is_script_project(self):
|
||||
return self._is_lua_project() or self._is_js_project()
|
||||
|
||||
def _is_cpp_project(self):
|
||||
return self._project_lang == Project.CPP
|
||||
|
||||
def _is_lua_project(self):
|
||||
return self._project_lang == Project.LUA
|
||||
|
||||
def _is_js_project(self):
|
||||
return self._project_lang == Project.JS
|
||||
|
||||
class Platforms(object):
|
||||
ANDROID = 'android'
|
||||
IOS = 'ios'
|
||||
MAC = 'mac'
|
||||
WEB = 'web'
|
||||
WIN32 = 'win32'
|
||||
LINUX = 'linux'
|
||||
WP8 = "wp8"
|
||||
WP8_1 = "wp8_1"
|
||||
METRO = "metro"
|
||||
|
||||
CFG_CLASS_MAP = {
|
||||
ANDROID : "cocos_project.AndroidConfig",
|
||||
IOS : "cocos_project.iOSConfig",
|
||||
MAC : "cocos_project.MacConfig",
|
||||
WEB : "cocos_project.WebConfig",
|
||||
WIN32 : "cocos_project.Win32Config",
|
||||
LINUX : "cocos_project.LinuxConfig",
|
||||
WP8 : "cocos_project.Wp8Config",
|
||||
WP8_1 : "cocos_project.Wp8_1Config",
|
||||
METRO : "cocos_project.MetroConfig"
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def list_for_display():
|
||||
return [x.lower() for x in Platforms.list()]
|
||||
|
||||
@staticmethod
|
||||
def list():
|
||||
return Platforms.CFG_CLASS_MAP.keys()
|
||||
|
||||
def __init__(self, project, current, proj_dir = None):
|
||||
self._project = project
|
||||
|
||||
proj_info = self._project.info
|
||||
self._gen_available_platforms(proj_info, proj_dir)
|
||||
|
||||
self._current = None
|
||||
if current is not None:
|
||||
current_lower = current.lower()
|
||||
if current_lower in self._available_platforms.keys():
|
||||
self._current = current_lower
|
||||
else:
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('PROJECT_INVALID_PLATFORM_FMT',
|
||||
(self._available_platforms.keys(), current)),
|
||||
cocos.CCPluginError.ERROR_WRONG_ARGS)
|
||||
|
||||
def _filter_platforms(self, platforms):
|
||||
ret = []
|
||||
platforms_for_os = {
|
||||
"linux" : [ Platforms.WEB, Platforms.LINUX, Platforms.ANDROID ],
|
||||
"mac" : [ Platforms.WEB, Platforms.IOS, Platforms.MAC, Platforms.ANDROID ],
|
||||
"win32" : [ Platforms.WEB, Platforms.WIN32, Platforms.ANDROID, Platforms.WP8,
|
||||
Platforms.WP8_1, Platforms.METRO]
|
||||
}
|
||||
for p in platforms:
|
||||
if cocos.os_is_linux():
|
||||
if p in platforms_for_os["linux"]:
|
||||
ret.append(p)
|
||||
if cocos.os_is_mac():
|
||||
if p in platforms_for_os["mac"]:
|
||||
ret.append(p)
|
||||
if cocos.os_is_win32():
|
||||
if p in platforms_for_os["win32"]:
|
||||
ret.append(p)
|
||||
|
||||
return ret
|
||||
|
||||
def _gen_available_platforms(self, proj_info, proj_dir):
|
||||
# generate the platform list for different projects
|
||||
if self._project._is_lua_project():
|
||||
if self._project._is_native_support():
|
||||
platform_list = [ Platforms.ANDROID, Platforms.WIN32, Platforms.IOS, Platforms.MAC, Platforms.LINUX ]
|
||||
else:
|
||||
if self._project.has_android_libs():
|
||||
platform_list = [ Platforms.ANDROID ]
|
||||
else:
|
||||
platform_list = []
|
||||
elif self._project._is_js_project():
|
||||
if self._project._is_native_support():
|
||||
platform_list = [ Platforms.ANDROID, Platforms.WIN32, Platforms.IOS, Platforms.MAC, Platforms.WEB, Platforms.LINUX, Platforms.WP8, Platforms.WP8_1, Platforms.METRO ]
|
||||
else:
|
||||
if self._project.has_android_libs():
|
||||
platform_list = [ Platforms.ANDROID, Platforms.WEB ]
|
||||
else:
|
||||
platform_list = [ Platforms.WEB ]
|
||||
elif self._project._is_cpp_project():
|
||||
platform_list = [ Platforms.ANDROID, Platforms.WIN32, Platforms.IOS, Platforms.MAC, Platforms.LINUX, Platforms.WP8, Platforms.WP8_1, Platforms.METRO ]
|
||||
|
||||
# filter the available platform list
|
||||
platform_list = self._filter_platforms(platform_list)
|
||||
|
||||
# check the real available platforms
|
||||
self._available_platforms = {}
|
||||
root_path = self._project.get_project_dir()
|
||||
for p in platform_list:
|
||||
cfg_class = cocos.get_class(Platforms.CFG_CLASS_MAP[p])
|
||||
if cfg_class is None:
|
||||
continue
|
||||
|
||||
cfg_key = "%s_cfg" % p
|
||||
if proj_info.has_key(cfg_key):
|
||||
cfg_obj = cfg_class(root_path, self._project._is_script_project(), proj_info[cfg_key])
|
||||
else:
|
||||
cfg_obj = cfg_class(root_path, self._project._is_script_project())
|
||||
|
||||
if proj_dir is not None:
|
||||
cfg_obj.proj_path = os.path.join(root_path, proj_dir)
|
||||
|
||||
if cfg_obj._is_available():
|
||||
self._available_platforms[p] = cfg_obj
|
||||
|
||||
# don't have available platforms
|
||||
if len(self._available_platforms) == 0:
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('PROJECT_NO_AVAILABLE_PLATFORMS'),
|
||||
cocos.CCPluginError.ERROR_WRONG_CONFIG)
|
||||
|
||||
def get_current_platform(self):
|
||||
return self._current
|
||||
|
||||
def get_available_platforms(self):
|
||||
return self._available_platforms
|
||||
|
||||
def none_active(self):
|
||||
return self._current is None
|
||||
|
||||
def is_android_active(self):
|
||||
return self._current == Platforms.ANDROID
|
||||
|
||||
def is_ios_active(self):
|
||||
return self._current == Platforms.IOS
|
||||
|
||||
def is_mac_active(self):
|
||||
return self._current == Platforms.MAC
|
||||
|
||||
def is_web_active(self):
|
||||
return self._current == Platforms.WEB
|
||||
|
||||
def is_win32_active(self):
|
||||
return self._current == Platforms.WIN32
|
||||
|
||||
def is_linux_active(self):
|
||||
return self._current == Platforms.LINUX
|
||||
|
||||
def is_wp8_active(self):
|
||||
return self._current == Platforms.WP8
|
||||
|
||||
def is_wp8_1_active(self):
|
||||
return self._current == Platforms.WP8_1
|
||||
|
||||
def is_metro_active(self):
|
||||
return self._current == Platforms.METRO
|
||||
|
||||
def get_current_config(self):
|
||||
if self.none_active():
|
||||
return None
|
||||
|
||||
return self._available_platforms[self._current]
|
||||
|
||||
def project_path(self):
|
||||
if self._current is None:
|
||||
return None
|
||||
|
||||
cfg_obj = self._available_platforms[self._current]
|
||||
return cfg_obj.proj_path
|
||||
|
||||
def _has_one(self):
|
||||
return len(self._available_platforms) == 1
|
||||
|
||||
def select_one(self):
|
||||
if self._has_one():
|
||||
self._current = self._available_platforms.keys()[0]
|
||||
return
|
||||
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('PROJECT_SPECIFY_PLATFORM_FMT',
|
||||
str(self._available_platforms.keys())),
|
||||
cocos.CCPluginError.ERROR_WRONG_CONFIG)
|
||||
|
||||
class PlatformConfig(object):
|
||||
KEY_PROJ_PATH = "project_path"
|
||||
def __init__(self, proj_root_path, is_script, cfg_info = None):
|
||||
self._proj_root_path = proj_root_path
|
||||
self._is_script = is_script
|
||||
if cfg_info is None:
|
||||
self._use_default()
|
||||
else:
|
||||
self._parse_info(cfg_info)
|
||||
|
||||
def _use_default(self):
|
||||
pass
|
||||
|
||||
def _parse_info(self, cfg_info):
|
||||
if cfg_info.has_key(PlatformConfig.KEY_PROJ_PATH):
|
||||
self.proj_path = os.path.join(self._proj_root_path, cfg_info[PlatformConfig.KEY_PROJ_PATH])
|
||||
else:
|
||||
self.proj_path = None
|
||||
|
||||
def _is_available(self):
|
||||
ret = True
|
||||
if self.proj_path is None or not os.path.isdir(self.proj_path):
|
||||
ret = False
|
||||
|
||||
return ret
|
||||
|
||||
class AndroidConfig(PlatformConfig):
|
||||
KEY_STUDIO_PATH = "studio_proj_path"
|
||||
|
||||
def _use_default(self):
|
||||
if self._is_script:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "frameworks", "runtime-src", "proj.android-studio")
|
||||
else:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "proj.android-studio")
|
||||
|
||||
def _parse_info(self, cfg_info):
|
||||
super(AndroidConfig, self)._parse_info(cfg_info)
|
||||
|
||||
if cfg_info.has_key(AndroidConfig.KEY_STUDIO_PATH):
|
||||
self.proj_path = os.path.join(self._proj_root_path, cfg_info[AndroidConfig.KEY_STUDIO_PATH])
|
||||
|
||||
def _is_available(self):
|
||||
proj_android_existed = super(AndroidConfig, self)._is_available()
|
||||
proj_studio_existed = False
|
||||
if (self.proj_path is not None) and os.path.isdir(self.proj_path):
|
||||
proj_studio_existed = True
|
||||
|
||||
ret = (proj_android_existed or proj_studio_existed)
|
||||
return ret
|
||||
|
||||
class iOSConfig(PlatformConfig):
|
||||
KEY_PROJ_FILE = "project_file"
|
||||
KEY_TARGET_NAME = "target_name"
|
||||
|
||||
def _use_default(self):
|
||||
if self._is_script:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "frameworks", "runtime-src", "proj.ios_mac")
|
||||
else:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "proj.ios_mac")
|
||||
|
||||
self.proj_file = None
|
||||
self.target_name = None
|
||||
|
||||
def _parse_info(self, cfg_info):
|
||||
super(iOSConfig, self)._parse_info(cfg_info)
|
||||
if cfg_info.has_key(iOSConfig.KEY_PROJ_FILE):
|
||||
self.proj_file = cfg_info[iOSConfig.KEY_PROJ_FILE]
|
||||
else:
|
||||
self.proj_file = None
|
||||
|
||||
if cfg_info.has_key(iOSConfig.KEY_TARGET_NAME):
|
||||
self.target_name = cfg_info[iOSConfig.KEY_TARGET_NAME]
|
||||
else:
|
||||
self.target_name = None
|
||||
|
||||
def _is_available(self):
|
||||
ret = super(iOSConfig, self)._is_available()
|
||||
|
||||
return ret
|
||||
|
||||
class MacConfig(PlatformConfig):
|
||||
|
||||
def _use_default(self):
|
||||
if self._is_script:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "frameworks", "runtime-src", "proj.ios_mac")
|
||||
else:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "proj.ios_mac")
|
||||
|
||||
self.proj_file = None
|
||||
self.target_name = None
|
||||
|
||||
def _parse_info(self, cfg_info):
|
||||
super(MacConfig, self)._parse_info(cfg_info)
|
||||
if cfg_info.has_key(iOSConfig.KEY_PROJ_FILE):
|
||||
self.proj_file = cfg_info[iOSConfig.KEY_PROJ_FILE]
|
||||
else:
|
||||
self.proj_file = None
|
||||
|
||||
if cfg_info.has_key(iOSConfig.KEY_TARGET_NAME):
|
||||
self.target_name = cfg_info[iOSConfig.KEY_TARGET_NAME]
|
||||
else:
|
||||
self.target_name = None
|
||||
|
||||
def _is_available(self):
|
||||
ret = super(MacConfig, self)._is_available()
|
||||
|
||||
return ret
|
||||
|
||||
class Win32Config(PlatformConfig):
|
||||
KEY_SLN_FILE = "sln_file"
|
||||
KEY_PROJECT_NAME = "project_name"
|
||||
KEY_BUILD_CFG_PATH = "build_cfg_path"
|
||||
KEY_EXE_OUT_DIR = "exe_out_dir"
|
||||
|
||||
def _use_default(self):
|
||||
if self._is_script:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "frameworks", "runtime-src", "proj.win32")
|
||||
else:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "proj.win32")
|
||||
|
||||
self.sln_file = None
|
||||
self.project_name =None
|
||||
self.build_cfg_path = None
|
||||
self.exe_out_dir = None
|
||||
|
||||
def _parse_info(self, cfg_info):
|
||||
super(Win32Config, self)._parse_info(cfg_info)
|
||||
if cfg_info.has_key(Win32Config.KEY_SLN_FILE):
|
||||
self.sln_file = cfg_info[Win32Config.KEY_SLN_FILE]
|
||||
else:
|
||||
self.sln_file = None
|
||||
|
||||
if cfg_info.has_key(Win32Config.KEY_PROJECT_NAME):
|
||||
self.project_name = cfg_info[Win32Config.KEY_PROJECT_NAME]
|
||||
else:
|
||||
self.project_name = None
|
||||
|
||||
if cfg_info.has_key(Win32Config.KEY_BUILD_CFG_PATH):
|
||||
self.build_cfg_path = cfg_info[Win32Config.KEY_BUILD_CFG_PATH]
|
||||
else:
|
||||
self.build_cfg_path = None
|
||||
|
||||
if cfg_info.has_key(Win32Config.KEY_EXE_OUT_DIR):
|
||||
self.exe_out_dir = cfg_info[Win32Config.KEY_EXE_OUT_DIR]
|
||||
else:
|
||||
self.exe_out_dir = None
|
||||
|
||||
def _is_available(self):
|
||||
ret = super(Win32Config, self)._is_available()
|
||||
|
||||
return ret
|
||||
|
||||
class LinuxConfig(PlatformConfig):
|
||||
KEY_CMAKE_PATH = "cmake_path"
|
||||
KEY_BUILD_DIR = "build_dir"
|
||||
KEY_PROJECT_NAME = "project_name"
|
||||
KEY_BUILD_RESULT_DIR = "build_result_dir"
|
||||
|
||||
def _use_default(self):
|
||||
if self._is_script:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "frameworks", "runtime-src", "proj.linux")
|
||||
else:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "proj.linux")
|
||||
|
||||
self.cmake_path = None
|
||||
self.build_dir = None
|
||||
self.project_name = None
|
||||
self.build_result_dir = None
|
||||
|
||||
def _parse_info(self, cfg_info):
|
||||
super(LinuxConfig, self)._parse_info(cfg_info)
|
||||
if cfg_info.has_key(LinuxConfig.KEY_CMAKE_PATH):
|
||||
self.cmake_path = cfg_info[LinuxConfig.KEY_CMAKE_PATH]
|
||||
else:
|
||||
self.cmake_path = None
|
||||
|
||||
if cfg_info.has_key(LinuxConfig.KEY_BUILD_DIR):
|
||||
self.build_dir = cfg_info[LinuxConfig.KEY_BUILD_DIR]
|
||||
else:
|
||||
self.build_dir = None
|
||||
|
||||
if cfg_info.has_key(LinuxConfig.KEY_PROJECT_NAME):
|
||||
self.project_name = cfg_info[LinuxConfig.KEY_PROJECT_NAME]
|
||||
else:
|
||||
self.project_name = None
|
||||
|
||||
if cfg_info.has_key(LinuxConfig.KEY_BUILD_RESULT_DIR):
|
||||
self.build_result_dir = cfg_info[LinuxConfig.KEY_BUILD_RESULT_DIR]
|
||||
else:
|
||||
self.build_result_dir = None
|
||||
|
||||
def _is_available(self):
|
||||
ret = super(LinuxConfig, self)._is_available()
|
||||
|
||||
return ret
|
||||
|
||||
class WebConfig(PlatformConfig):
|
||||
KEY_SUB_URL = "sub_url"
|
||||
KEY_RUN_ROOT_DIR = "run_root_dir"
|
||||
KEY_COPY_RESOURCES = "copy_resources"
|
||||
|
||||
def _use_default(self):
|
||||
self.proj_path = self._proj_root_path
|
||||
self.run_root_dir = self._proj_root_path
|
||||
self.copy_res = None
|
||||
self.sub_url = None
|
||||
|
||||
def _parse_info(self, cfg_info):
|
||||
super(WebConfig, self)._parse_info(cfg_info)
|
||||
if cfg_info.has_key(WebConfig.KEY_SUB_URL):
|
||||
self.sub_url = cfg_info[WebConfig.KEY_SUB_URL]
|
||||
else:
|
||||
self.sub_url = None
|
||||
|
||||
if cfg_info.has_key(WebConfig.KEY_RUN_ROOT_DIR):
|
||||
self.run_root_dir = os.path.join(self._proj_root_path, cfg_info[WebConfig.KEY_RUN_ROOT_DIR])
|
||||
else:
|
||||
self.run_root_dir = None
|
||||
|
||||
if cfg_info.has_key(WebConfig.KEY_COPY_RESOURCES):
|
||||
self.copy_res = cfg_info[WebConfig.KEY_COPY_RESOURCES]
|
||||
else:
|
||||
self.copy_res = None
|
||||
|
||||
def _is_available(self):
|
||||
ret = super(WebConfig, self)._is_available()
|
||||
|
||||
if ret:
|
||||
index_path = os.path.join(self.proj_path, "index.html")
|
||||
ret = os.path.isfile(index_path)
|
||||
|
||||
return ret
|
||||
|
||||
class Wp8Config(PlatformConfig):
|
||||
KEY_BUILD_FOLDER_PATH = "build_folder_path"
|
||||
KEY_MANIFEST_PATH = "manifest_path"
|
||||
KEY_WP8_PROJ_PATH = 'wp8_proj_path'
|
||||
|
||||
def _use_default(self):
|
||||
if self._is_script:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "frameworks", "runtime-src", "proj.wp8-xaml")
|
||||
else:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "proj.wp8-xaml")
|
||||
|
||||
self.wp8_proj_path = self.proj_path
|
||||
self.sln_file = None
|
||||
self.project_name =None
|
||||
self.build_folder_path = "App/Bin/x86"
|
||||
self.manifest_path = "App/Properties/WMAppManifest.xml"
|
||||
|
||||
def _parse_info(self, cfg_info):
|
||||
super(Wp8Config, self)._parse_info(cfg_info)
|
||||
if cfg_info.has_key(Win32Config.KEY_SLN_FILE):
|
||||
self.sln_file = cfg_info[Win32Config.KEY_SLN_FILE]
|
||||
else:
|
||||
self.sln_file = None
|
||||
|
||||
if cfg_info.has_key(Wp8Config.KEY_WP8_PROJ_PATH):
|
||||
self.wp8_proj_path = os.path.join(self._proj_root_path, cfg_info[Wp8Config.KEY_WP8_PROJ_PATH])
|
||||
else:
|
||||
self.wp8_proj_path = self.proj_path
|
||||
|
||||
if cfg_info.has_key(Win32Config.KEY_PROJECT_NAME):
|
||||
self.project_name = cfg_info[Win32Config.KEY_PROJECT_NAME]
|
||||
else:
|
||||
self.project_name = None
|
||||
|
||||
if cfg_info.has_key(Wp8Config.KEY_BUILD_FOLDER_PATH):
|
||||
self.build_folder_path = cfg_info[Wp8Config.KEY_BUILD_FOLDER_PATH]
|
||||
else:
|
||||
self.build_folder_path = "App/Bin/x86"
|
||||
|
||||
if cfg_info.has_key(Wp8Config.KEY_MANIFEST_PATH):
|
||||
self.manifest_path = cfg_info[Wp8Config.KEY_MANIFEST_PATH]
|
||||
else:
|
||||
self.manifest_path = "App/Properties/WMAppManifest.xml"
|
||||
|
||||
def _is_available(self):
|
||||
ret = super(Wp8Config, self)._is_available()
|
||||
|
||||
return ret
|
||||
|
||||
class Wp8_1Config(PlatformConfig):
|
||||
def _use_default(self):
|
||||
if self._is_script:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "frameworks", "runtime-src", "proj.win8.1-universal")
|
||||
else:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "proj.win8.1-universal")
|
||||
|
||||
self.sln_file = None
|
||||
self.project_name =None
|
||||
|
||||
def _parse_info(self, cfg_info):
|
||||
super(Wp8_1Config, self)._parse_info(cfg_info)
|
||||
if cfg_info.has_key(Win32Config.KEY_SLN_FILE):
|
||||
self.sln_file = cfg_info[Win32Config.KEY_SLN_FILE]
|
||||
else:
|
||||
self.sln_file = None
|
||||
|
||||
if cfg_info.has_key(Win32Config.KEY_PROJECT_NAME):
|
||||
self.project_name = cfg_info[Win32Config.KEY_PROJECT_NAME]
|
||||
else:
|
||||
self.project_name = None
|
||||
|
||||
def _is_available(self):
|
||||
ret = super(Wp8_1Config, self)._is_available()
|
||||
|
||||
return ret
|
||||
|
||||
class MetroConfig(PlatformConfig):
|
||||
def _use_default(self):
|
||||
if self._is_script:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "frameworks", "runtime-src", "proj.win8.1-universal")
|
||||
else:
|
||||
self.proj_path = os.path.join(self._proj_root_path, "proj.win8.1-universal")
|
||||
|
||||
self.sln_file = None
|
||||
self.project_name =None
|
||||
|
||||
def _parse_info(self, cfg_info):
|
||||
super(MetroConfig, self)._parse_info(cfg_info)
|
||||
if cfg_info.has_key(Win32Config.KEY_SLN_FILE):
|
||||
self.sln_file = cfg_info[Win32Config.KEY_SLN_FILE]
|
||||
else:
|
||||
self.sln_file = None
|
||||
|
||||
if cfg_info.has_key(Win32Config.KEY_PROJECT_NAME):
|
||||
self.project_name = cfg_info[Win32Config.KEY_PROJECT_NAME]
|
||||
else:
|
||||
self.project_name = None
|
||||
|
||||
def _is_available(self):
|
||||
ret = super(MetroConfig, self)._is_available()
|
||||
|
||||
return ret
|
||||
560
cocos2d-x/tools/cocos2d-console/bin/cocos_stat.py
Normal file
560
cocos2d-x/tools/cocos2d-console/bin/cocos_stat.py
Normal file
@@ -0,0 +1,560 @@
|
||||
#!/usr/bin/python
|
||||
# ----------------------------------------------------------------------------
|
||||
# statistics: Statistics the user behaviors of cocos2d-console by google analytics
|
||||
#
|
||||
# Author: Bin Zhang
|
||||
#
|
||||
# License: MIT
|
||||
# ----------------------------------------------------------------------------
|
||||
'''
|
||||
Statistics the user behaviors of cocos2d-console by google analytics
|
||||
'''
|
||||
|
||||
import cocos
|
||||
import uuid
|
||||
import locale
|
||||
import httplib
|
||||
import urllib
|
||||
import platform
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import socket
|
||||
import hashlib
|
||||
import datetime
|
||||
import zlib
|
||||
|
||||
import multiprocessing
|
||||
|
||||
# GA related Constants
|
||||
|
||||
GA_HOST = 'www.google-analytics.com'
|
||||
GA_PATH = '/collect'
|
||||
GA_APIVERSION = '1'
|
||||
APPNAME = 'CocosConcole'
|
||||
|
||||
TIMEOUT_VALUE = 0.5
|
||||
|
||||
# formal tracker ID
|
||||
GA_TRACKERID = 'UA-60734607-3'
|
||||
|
||||
# debug tracker ID
|
||||
# GA_TRACKERID = 'UA-60530469-4'
|
||||
|
||||
# BI related Constants
|
||||
BI_HOST = 'ark.cocounion.com'
|
||||
BI_PATH = '/as'
|
||||
BI_APPID = '433748803'
|
||||
|
||||
GA_ENABLED = True
|
||||
BI_ENABLED = False
|
||||
|
||||
class Fields(object):
|
||||
API_VERSION = 'v'
|
||||
TRACKING_ID = 'tid'
|
||||
HIT_TYPE = 't'
|
||||
CLIENT_ID = 'cid'
|
||||
EVENT_CATEGORY = 'ec'
|
||||
EVENT_ACTION = 'ea'
|
||||
EVENT_LABEL = 'el'
|
||||
EVENT_VALUE = 'ev'
|
||||
APP_NAME = 'an'
|
||||
APP_VERSION = 'av'
|
||||
USER_LANGUAGE = 'ul'
|
||||
USER_AGENT = 'ua'
|
||||
SCREEN_NAME = "cd"
|
||||
SCREEN_RESOLUTION = "sr"
|
||||
|
||||
|
||||
GA_CACHE_EVENTS_FILE = 'cache_events'
|
||||
GA_CACHE_EVENTS_BAK_FILE = 'cache_event_bak'
|
||||
|
||||
local_cfg_path = os.path.expanduser('~/.cocos')
|
||||
local_cfg_file = os.path.join(local_cfg_path, GA_CACHE_EVENTS_FILE)
|
||||
local_cfg_bak_file = os.path.join(local_cfg_path, GA_CACHE_EVENTS_BAK_FILE)
|
||||
file_in_use_lock = multiprocessing.Lock()
|
||||
bak_file_in_use_lock = multiprocessing.Lock()
|
||||
|
||||
|
||||
BI_CACHE_EVENTS_FILE = 'bi_cache_events'
|
||||
bi_cfg_file = os.path.join(local_cfg_path, BI_CACHE_EVENTS_FILE)
|
||||
bi_file_in_use_lock = multiprocessing.Lock()
|
||||
|
||||
def get_user_id():
|
||||
node = uuid.getnode()
|
||||
mac = uuid.UUID(int = node).hex[-12:]
|
||||
|
||||
uid = hashlib.md5(mac).hexdigest()
|
||||
return uid
|
||||
|
||||
def get_language():
|
||||
lang, encoding = locale.getdefaultlocale()
|
||||
return lang
|
||||
|
||||
def get_user_agent():
|
||||
ret_str = None
|
||||
if cocos.os_is_win32():
|
||||
ver_info = sys.getwindowsversion()
|
||||
ver_str = '%d.%d' % (ver_info[0], ver_info[1])
|
||||
if cocos.os_is_32bit_windows():
|
||||
arch_str = "WOW32"
|
||||
else:
|
||||
arch_str = "WOW64"
|
||||
ret_str = "Mozilla/5.0 (Windows NT %s; %s) Chrome/33.0.1750.154 Safari/537.36" % (ver_str, arch_str)
|
||||
elif cocos.os_is_mac():
|
||||
ver_str = (platform.mac_ver()[0]).replace('.', '_')
|
||||
ret_str = "Mozilla/5.0 (Macintosh; Intel Mac OS X %s) Chrome/35.0.1916.153 Safari/537.36" % ver_str
|
||||
elif cocos.os_is_linux():
|
||||
arch_str = platform.machine()
|
||||
ret_str = "Mozilla/5.0 (X11; Linux %s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1636.0 Safari/537.36" % arch_str
|
||||
|
||||
return ret_str
|
||||
|
||||
def get_system_info():
|
||||
if cocos.os_is_win32():
|
||||
ret_str = "windows"
|
||||
ret_str += "_%s" % platform.release()
|
||||
if cocos.os_is_32bit_windows():
|
||||
ret_str += "_%s" % "32bit"
|
||||
else:
|
||||
ret_str += "_%s" % "64bit"
|
||||
elif cocos.os_is_mac():
|
||||
ret_str = "mac_%s" % (platform.mac_ver()[0]).replace('.', '_')
|
||||
elif cocos.os_is_linux():
|
||||
ret_str = "linux_%s" % platform.linux_distribution()[0]
|
||||
else:
|
||||
ret_str = "unknown"
|
||||
|
||||
return ret_str
|
||||
|
||||
def get_python_version():
|
||||
return "python_%s" % platform.python_version()
|
||||
|
||||
def get_time_stamp():
|
||||
utc_dt = datetime.datetime.utcnow()
|
||||
local_dt = utc_dt + datetime.timedelta(hours=8)
|
||||
epoch = datetime.datetime(1970,1,1)
|
||||
local_ts = (local_dt - epoch).total_seconds()
|
||||
ret = '%d' % int(local_ts)
|
||||
|
||||
return ret
|
||||
|
||||
def get_static_params(engine_version):
|
||||
static_params = {
|
||||
Fields.API_VERSION: GA_APIVERSION,
|
||||
Fields.TRACKING_ID: GA_TRACKERID,
|
||||
Fields.CLIENT_ID: get_user_id(),
|
||||
Fields.APP_NAME: APPNAME,
|
||||
Fields.HIT_TYPE: "event",
|
||||
Fields.USER_LANGUAGE: get_language(),
|
||||
Fields.APP_VERSION: engine_version,
|
||||
Fields.SCREEN_NAME: get_system_info(),
|
||||
Fields.SCREEN_RESOLUTION: get_python_version()
|
||||
}
|
||||
agent_str = get_user_agent()
|
||||
if agent_str is not None:
|
||||
static_params[Fields.USER_AGENT] = agent_str
|
||||
|
||||
return static_params
|
||||
|
||||
def gen_bi_event(event, event_value):
|
||||
time_stamp = get_time_stamp()
|
||||
if event_value == 0:
|
||||
is_cache_event = '1'
|
||||
else:
|
||||
is_cache_event = '0'
|
||||
|
||||
category = event[0]
|
||||
action = event[1]
|
||||
label = event[2]
|
||||
|
||||
event_name = category
|
||||
params = {
|
||||
'cached_event' : is_cache_event
|
||||
}
|
||||
if category == 'cocos':
|
||||
if action == 'start':
|
||||
event_name = 'cocos_invoked'
|
||||
elif action == 'running_command':
|
||||
event_name = 'running_command'
|
||||
params['command'] = label
|
||||
else:
|
||||
params['category'] = category
|
||||
params['action'] = action
|
||||
params['label'] = label
|
||||
elif category == 'new':
|
||||
event_name = 'new_project'
|
||||
params['language'] = action
|
||||
params['template'] = label
|
||||
elif category == 'new_engine_ver':
|
||||
event_name = 'engine_info'
|
||||
params['version'] = action
|
||||
params['engine_type'] = label
|
||||
elif category == 'compile':
|
||||
params['language'] = action
|
||||
params['target_platform'] = label
|
||||
else:
|
||||
params['category'] = category
|
||||
params['action'] = action
|
||||
params['label'] = label
|
||||
|
||||
if len(event) >= 4:
|
||||
appear_time = event[3]
|
||||
else:
|
||||
appear_time = time_stamp
|
||||
ret = {
|
||||
'u' : {
|
||||
'28' : get_user_id(),
|
||||
'34' : get_python_version()
|
||||
},
|
||||
'p' : params,
|
||||
's' : time_stamp,
|
||||
'e' : event_name,
|
||||
't' : appear_time
|
||||
}
|
||||
|
||||
return ret
|
||||
|
||||
def get_bi_params(events, event_value, multi_events=False, engine_versio=''):
|
||||
if cocos.os_is_win32():
|
||||
system_str = 'windows'
|
||||
ver_info = sys.getwindowsversion()
|
||||
ver_str = '%d.%d' % (ver_info[0], ver_info[1])
|
||||
if cocos.os_is_32bit_windows():
|
||||
arch_str = "_32bit"
|
||||
else:
|
||||
arch_str = "_64bit"
|
||||
system_ver = '%s%s' % (ver_str, arch_str)
|
||||
elif cocos.os_is_mac():
|
||||
system_str = 'mac'
|
||||
system_ver = (platform.mac_ver()[0])
|
||||
elif cocos.os_is_linux():
|
||||
system_str = 'linux'
|
||||
system_ver = platform.machine()
|
||||
else:
|
||||
system_str = 'unknown'
|
||||
system_ver = 'unknown'
|
||||
|
||||
events_param = []
|
||||
if multi_events:
|
||||
for e in events:
|
||||
events_param.append(gen_bi_event(e, event_value))
|
||||
else:
|
||||
events_param.append(gen_bi_event(events, event_value))
|
||||
|
||||
params = {
|
||||
'device': {
|
||||
'10' : system_ver,
|
||||
'11' : system_str
|
||||
},
|
||||
'app': {
|
||||
'7' : BI_APPID,
|
||||
'8' : engine_version,
|
||||
'9' : get_language()
|
||||
},
|
||||
'time' : get_time_stamp(),
|
||||
'events' : events_param
|
||||
}
|
||||
|
||||
return params
|
||||
|
||||
def cache_event(event, is_ga=True, multi_events=False):
|
||||
if is_ga:
|
||||
cache_ga_event(event)
|
||||
else:
|
||||
cache_bi_event(event, multi_events)
|
||||
|
||||
# BI cache events related methods
|
||||
def cache_bi_event(event, multi_events=False):
|
||||
bi_file_in_use_lock.acquire()
|
||||
|
||||
outFile = None
|
||||
try:
|
||||
# get current cached events
|
||||
cache_events = get_bi_cached_events(need_lock=False)
|
||||
|
||||
if multi_events:
|
||||
need_cache_size = len(event)
|
||||
else:
|
||||
need_cache_size = 1
|
||||
|
||||
# delete the oldest events if there are too many events.
|
||||
events_size = len(cache_events)
|
||||
if events_size >= Statistic.MAX_CACHE_EVENTS:
|
||||
start_idx = events_size - (Statistic.MAX_CACHE_EVENTS - need_cache_size)
|
||||
cache_events = cache_events[start_idx:]
|
||||
|
||||
# cache the new event
|
||||
if multi_events:
|
||||
for e in event:
|
||||
cache_events.append(e)
|
||||
else:
|
||||
cache_events.append(event)
|
||||
|
||||
# write file
|
||||
outFile = open(bi_cfg_file, 'w')
|
||||
json.dump(cache_events, outFile)
|
||||
outFile.close()
|
||||
except:
|
||||
if outFile is not None:
|
||||
outFile.close()
|
||||
finally:
|
||||
bi_file_in_use_lock.release()
|
||||
|
||||
def get_bi_cached_events(need_lock=True):
|
||||
if not os.path.isfile(bi_cfg_file):
|
||||
cached_events = []
|
||||
else:
|
||||
f = None
|
||||
try:
|
||||
if need_lock:
|
||||
bi_file_in_use_lock.acquire()
|
||||
|
||||
f = open(bi_cfg_file)
|
||||
cached_events = json.load(f)
|
||||
f.close()
|
||||
|
||||
if not isinstance(cached_events, list):
|
||||
cached_events = []
|
||||
except:
|
||||
cached_events = []
|
||||
finally:
|
||||
if f is not None:
|
||||
f.close()
|
||||
|
||||
if need_lock:
|
||||
bi_file_in_use_lock.release()
|
||||
|
||||
return cached_events
|
||||
|
||||
# GA cache events related methods
|
||||
def get_ga_cached_events(is_bak=False, need_lock=True):
|
||||
if is_bak:
|
||||
cfg_file = local_cfg_bak_file
|
||||
lock = bak_file_in_use_lock
|
||||
else:
|
||||
cfg_file = local_cfg_file
|
||||
lock = file_in_use_lock
|
||||
|
||||
if not os.path.isfile(cfg_file):
|
||||
cached_events = []
|
||||
else:
|
||||
f = None
|
||||
try:
|
||||
if need_lock:
|
||||
lock.acquire()
|
||||
|
||||
f = open(cfg_file)
|
||||
cached_events = json.load(f)
|
||||
f.close()
|
||||
|
||||
if not isinstance(cached_events, list):
|
||||
cached_events = []
|
||||
except:
|
||||
cached_events = []
|
||||
finally:
|
||||
if f is not None:
|
||||
f.close()
|
||||
if need_lock:
|
||||
lock.release()
|
||||
|
||||
return cached_events
|
||||
|
||||
def cache_ga_event(event):
|
||||
file_in_use_lock.acquire()
|
||||
|
||||
outFile = None
|
||||
try:
|
||||
# get current cached events
|
||||
cache_events = get_ga_cached_events(is_bak=False, need_lock=False)
|
||||
|
||||
# delete the oldest events if there are too many events.
|
||||
events_size = len(cache_events)
|
||||
if events_size >= Statistic.MAX_CACHE_EVENTS:
|
||||
start_idx = events_size - (Statistic.MAX_CACHE_EVENTS - 1)
|
||||
cache_events = cache_events[start_idx:]
|
||||
|
||||
# cache the new event
|
||||
cache_events.append(event)
|
||||
|
||||
# write file
|
||||
outFile = open(local_cfg_file, 'w')
|
||||
json.dump(cache_events, outFile)
|
||||
outFile.close()
|
||||
except:
|
||||
if outFile is not None:
|
||||
outFile.close()
|
||||
finally:
|
||||
file_in_use_lock.release()
|
||||
|
||||
def pop_bak_ga_cached_event():
|
||||
bak_file_in_use_lock.acquire()
|
||||
events = get_ga_cached_events(is_bak=True, need_lock=False)
|
||||
|
||||
if len(events) > 0:
|
||||
e = events[0]
|
||||
events = events[1:]
|
||||
outFile = None
|
||||
try:
|
||||
outFile = open(local_cfg_bak_file, 'w')
|
||||
json.dump(events, outFile)
|
||||
outFile.close()
|
||||
except:
|
||||
if outFile:
|
||||
outFile.close()
|
||||
else:
|
||||
e = None
|
||||
|
||||
bak_file_in_use_lock.release()
|
||||
|
||||
return e
|
||||
|
||||
def do_send_ga_cached_event(engine_version):
|
||||
e = pop_bak_ga_cached_event()
|
||||
while(e is not None):
|
||||
do_send(e, 0, is_ga=True, multi_events=False, engine_version=engine_version)
|
||||
e = pop_bak_ga_cached_event()
|
||||
|
||||
def get_params_str(event, event_value, is_ga=True, multi_events=False, engine_version=''):
|
||||
if is_ga:
|
||||
params = get_static_params(engine_version)
|
||||
params[Fields.EVENT_CATEGORY] = event[0]
|
||||
params[Fields.EVENT_ACTION] = event[1]
|
||||
params[Fields.EVENT_LABEL] = event[2]
|
||||
params[Fields.EVENT_VALUE] = '%d' % event_value
|
||||
params_str = urllib.urlencode(params)
|
||||
else:
|
||||
params = get_bi_params(event, event_value, multi_events, engine_version)
|
||||
strParam = json.dumps(params)
|
||||
params_str = zlib.compress(strParam, 9)
|
||||
|
||||
return params_str
|
||||
|
||||
def do_http_request(event, event_value, is_ga=True, multi_events=False, engine_version=''):
|
||||
ret = False
|
||||
conn = None
|
||||
try:
|
||||
params_str = get_params_str(event, event_value, is_ga, multi_events, engine_version)
|
||||
if is_ga:
|
||||
host_url = GA_HOST
|
||||
host_path = GA_PATH
|
||||
else:
|
||||
host_url = BI_HOST
|
||||
host_path = BI_PATH
|
||||
|
||||
socket.setdefaulttimeout(TIMEOUT_VALUE)
|
||||
|
||||
conn = httplib.HTTPConnection(host_url, timeout=TIMEOUT_VALUE)
|
||||
conn.request(method="POST", url=host_path, body=params_str)
|
||||
|
||||
response = conn.getresponse()
|
||||
res = response.status
|
||||
if res >= 200 and res < 300:
|
||||
# status is 2xx mean the request is success.
|
||||
ret = True
|
||||
else:
|
||||
ret = False
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
return ret
|
||||
|
||||
def do_send(event, event_value, is_ga=True, multi_events=False, engine_version=''):
|
||||
try:
|
||||
ret = do_http_request(event, event_value, is_ga, multi_events, engine_version)
|
||||
if not ret:
|
||||
# request failed, cache the event
|
||||
cache_event(event, is_ga, multi_events)
|
||||
except:
|
||||
pass
|
||||
|
||||
class Statistic(object):
|
||||
|
||||
MAX_CACHE_EVENTS = 50
|
||||
MAX_CACHE_PROC = 5
|
||||
|
||||
def __init__(self, engine_version):
|
||||
self.process_pool = []
|
||||
self.engine_version = engine_version
|
||||
if cocos.os_is_win32():
|
||||
multiprocessing.freeze_support()
|
||||
|
||||
def send_cached_events(self):
|
||||
try:
|
||||
# send GA cached events
|
||||
if GA_ENABLED:
|
||||
events = get_ga_cached_events()
|
||||
event_size = len(events)
|
||||
if event_size == 0:
|
||||
return
|
||||
|
||||
# rename the file
|
||||
if os.path.isfile(local_cfg_bak_file):
|
||||
os.remove(local_cfg_bak_file)
|
||||
os.rename(local_cfg_file, local_cfg_bak_file)
|
||||
|
||||
# create processes to handle the events
|
||||
proc_num = min(event_size, Statistic.MAX_CACHE_PROC)
|
||||
for i in range(proc_num):
|
||||
p = multiprocessing.Process(target=do_send_ga_cached_event, args=(self.engine_version,))
|
||||
p.start()
|
||||
self.process_pool.append(p)
|
||||
|
||||
# send BI cached events
|
||||
if BI_ENABLED:
|
||||
events = get_bi_cached_events()
|
||||
event_size = len(events)
|
||||
if event_size == 0:
|
||||
return
|
||||
|
||||
# remove the cached events file
|
||||
if os.path.isfile(bi_cfg_file):
|
||||
os.remove(bi_cfg_file)
|
||||
|
||||
p = multiprocessing.Process(target=do_send, args=(events, 0, False, True, self.engine_version,))
|
||||
p.start()
|
||||
self.process_pool.append(p)
|
||||
except:
|
||||
pass
|
||||
|
||||
def send_event(self, category, action, label):
|
||||
try:
|
||||
event = [ category, action, label ]
|
||||
|
||||
# send event to GA
|
||||
if GA_ENABLED:
|
||||
p = multiprocessing.Process(target=do_send, args=(event, 1, True, False, self.engine_version,))
|
||||
p.start()
|
||||
self.process_pool.append(p)
|
||||
|
||||
# send event to BI
|
||||
if BI_ENABLED:
|
||||
# add timestamp
|
||||
event.append(get_time_stamp())
|
||||
p = multiprocessing.Process(target=do_send, args=(event, 1, False, False, self.engine_version,))
|
||||
p.start()
|
||||
self.process_pool.append(p)
|
||||
except:
|
||||
pass
|
||||
|
||||
def terminate_stat(self):
|
||||
# terminate sub-processes
|
||||
if len(self.process_pool) > 0:
|
||||
alive_count = 0
|
||||
for p in self.process_pool:
|
||||
if p.is_alive():
|
||||
alive_count += 1
|
||||
|
||||
if alive_count > 0:
|
||||
time.sleep(1)
|
||||
for p in self.process_pool:
|
||||
if p.is_alive():
|
||||
p.terminate()
|
||||
|
||||
# remove the backup file
|
||||
if os.path.isfile(local_cfg_bak_file):
|
||||
os.remove(local_cfg_bak_file)
|
||||
94
cocos2d-x/tools/cocos2d-console/bin/install.py
Normal file
94
cocos2d-x/tools/cocos2d-console/bin/install.py
Normal file
@@ -0,0 +1,94 @@
|
||||
#
|
||||
# cocos console installation script.
|
||||
#
|
||||
# Script idea based on Homebrew installation script.
|
||||
# by Luis Parravicini.
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
import urllib
|
||||
from tarfile import TarFile
|
||||
import shutil
|
||||
|
||||
|
||||
COCOS2D_PREFIX = os.path.expanduser('~/.cocos2d')
|
||||
|
||||
|
||||
# TODO copied from cocos.py, refactor.
|
||||
class Logging:
|
||||
# TODO maybe the right way to do this is to use something like colorama?
|
||||
RED = '\033[31m'
|
||||
GREEN = '\033[32m'
|
||||
YELLOW = '\033[33m'
|
||||
MAGENTA = '\033[35m'
|
||||
RESET = '\033[0m'
|
||||
|
||||
@staticmethod
|
||||
def _print(s, color=None):
|
||||
if color and sys.stdout.isatty() and sys.platform != 'win32':
|
||||
print color + s + Logging.RESET
|
||||
else:
|
||||
print s
|
||||
|
||||
@staticmethod
|
||||
def debug(s):
|
||||
Logging._print(s, Logging.MAGENTA)
|
||||
|
||||
@staticmethod
|
||||
def info(s):
|
||||
Logging._print(s, Logging.GREEN)
|
||||
|
||||
@staticmethod
|
||||
def warning(s):
|
||||
Logging._print(s, Logging.YELLOW)
|
||||
|
||||
@staticmethod
|
||||
def error(s):
|
||||
Logging._print(s, Logging.RED)
|
||||
|
||||
|
||||
def die(msg):
|
||||
Logging.error(msg)
|
||||
sys.exit(1)
|
||||
|
||||
def touch(path):
|
||||
open(path, 'w').close()
|
||||
|
||||
|
||||
|
||||
Logging.info("Starting the installation for Cocos2D console")
|
||||
|
||||
console_path = os.path.join(COCOS2D_PREFIX, 'console')
|
||||
install_mark_path = os.path.join(console_path, 'installed')
|
||||
if os.path.exists(install_mark_path):
|
||||
die("""
|
||||
It appears cocos2d console is already installed. If you want to resintall you should
|
||||
delete the directory "%s" before running the installer again.
|
||||
""" % console_path)
|
||||
|
||||
Logging.info("Downloading...")
|
||||
download_path, _ = urllib.urlretrieve('https://github.com/cocos2d/cocos2d-console/tarball/master')
|
||||
|
||||
Logging.info("Installing...")
|
||||
with TarFile.open(download_path) as tar:
|
||||
tmp_path = os.path.join(COCOS2D_PREFIX, 'tmp')
|
||||
tar.extractall(tmp_path)
|
||||
# it's assumed the first entry is the directory containing all the other files
|
||||
dir = tar.getmembers()[0].name
|
||||
|
||||
extracted_path = os.path.join(tmp_path, dir)
|
||||
if os.path.exists(console_path):
|
||||
shutil.rmtree(console_path)
|
||||
shutil.move(extracted_path, console_path)
|
||||
|
||||
bin_path = os.path.join(console_path, 'console', 'bin')
|
||||
path = os.environ.get('PATH', '')
|
||||
if not bin_path in path.split(os.pathsep):
|
||||
Logging.warning("console path '%s' is not in PATH!" % bin_path)
|
||||
|
||||
touch(install_mark_path)
|
||||
|
||||
Logging.info("Cocos2D console installed successfully at %s" % console_path)
|
||||
Logging.info("Now type: cocos")
|
||||
|
||||
1038
cocos2d-x/tools/cocos2d-console/bin/strings.json
Normal file
1038
cocos2d-x/tools/cocos2d-console/bin/strings.json
Normal file
File diff suppressed because it is too large
Load Diff
284
cocos2d-x/tools/cocos2d-console/bin/utils.py
Normal file
284
cocos2d-x/tools/cocos2d-console/bin/utils.py
Normal file
@@ -0,0 +1,284 @@
|
||||
#!/usr/bin/python
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import cocos
|
||||
import re
|
||||
import zipfile
|
||||
|
||||
VS_VERSION_MAP = {
|
||||
2012 : "11.0",
|
||||
2013 : "12.0",
|
||||
2015 : "14.0",
|
||||
2017 : "15.0"
|
||||
}
|
||||
|
||||
def get_msbuild_path(vs_version):
|
||||
if cocos.os_is_win32():
|
||||
import _winreg
|
||||
else:
|
||||
return None
|
||||
|
||||
if isinstance(vs_version, int):
|
||||
# The value of vs_version is int. such as : 2017
|
||||
if vs_version in VS_VERSION_MAP.keys():
|
||||
vs_ver = VS_VERSION_MAP[vs_version]
|
||||
else:
|
||||
# not supported VS version
|
||||
return None
|
||||
elif isinstance(vs_version, str):
|
||||
# The value of vs_version is string. such as: "12.0", "14.0"
|
||||
vs_ver = vs_version
|
||||
else:
|
||||
return None
|
||||
|
||||
# If the system is 64bit, find VS in both 32bit & 64bit registry
|
||||
# If the system is 32bit, only find VS in 32bit registry
|
||||
if cocos.os_is_32bit_windows():
|
||||
reg_flag_list = [ _winreg.KEY_WOW64_32KEY ]
|
||||
else:
|
||||
reg_flag_list = [ _winreg.KEY_WOW64_64KEY, _winreg.KEY_WOW64_32KEY ]
|
||||
|
||||
# Find VS path
|
||||
msbuild_path = None
|
||||
for reg_flag in reg_flag_list:
|
||||
try:
|
||||
vs = _winreg.OpenKey(
|
||||
_winreg.HKEY_LOCAL_MACHINE,
|
||||
r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\%s" % vs_ver,
|
||||
0,
|
||||
_winreg.KEY_READ | reg_flag
|
||||
)
|
||||
msbuild_path, type = _winreg.QueryValueEx(vs, 'MSBuildToolsPath')
|
||||
except:
|
||||
continue
|
||||
|
||||
if msbuild_path is not None:
|
||||
msbuild_path = os.path.join(msbuild_path, "MSBuild.exe")
|
||||
if os.path.exists(msbuild_path):
|
||||
break
|
||||
else:
|
||||
msbuild_path = None
|
||||
|
||||
return msbuild_path
|
||||
|
||||
def get_devenv_path(vs_version):
|
||||
if cocos.os_is_win32():
|
||||
import _winreg
|
||||
else:
|
||||
return None
|
||||
|
||||
if isinstance(vs_version, int):
|
||||
# The value of vs_version is int. such as : 2017
|
||||
if vs_version in VS_VERSION_MAP.keys():
|
||||
vs_ver = VS_VERSION_MAP[vs_version]
|
||||
else:
|
||||
# not supported VS version
|
||||
return None
|
||||
elif isinstance(vs_version, str):
|
||||
# The value of vs_version is string. such as: "12.0", "14.0"
|
||||
vs_ver = vs_version
|
||||
else:
|
||||
return None
|
||||
|
||||
# If the system is 64bit, find VS in both 32bit & 64bit registry
|
||||
# If the system is 32bit, only find VS in 32bit registry
|
||||
if cocos.os_is_32bit_windows():
|
||||
reg_flag_list = [ _winreg.KEY_WOW64_32KEY ]
|
||||
else:
|
||||
reg_flag_list = [ _winreg.KEY_WOW64_64KEY, _winreg.KEY_WOW64_32KEY ]
|
||||
|
||||
devenv_path = None
|
||||
for reg_flag in reg_flag_list:
|
||||
try:
|
||||
vs = _winreg.OpenKey(
|
||||
_winreg.HKEY_LOCAL_MACHINE,
|
||||
r"SOFTWARE\Microsoft\VisualStudio",
|
||||
0,
|
||||
_winreg.KEY_READ | reg_flag
|
||||
)
|
||||
except:
|
||||
continue
|
||||
|
||||
# find specified VS
|
||||
try:
|
||||
key = _winreg.OpenKey(vs, r"SxS\VS7")
|
||||
devenv_path, type = _winreg.QueryValueEx(key, vs_ver)
|
||||
except:
|
||||
pass
|
||||
|
||||
if devenv_path is not None:
|
||||
devenv_path = os.path.join(devenv_path, "Common7", "IDE", "devenv.com")
|
||||
if os.path.exists(devenv_path):
|
||||
break
|
||||
else:
|
||||
devenv_path = None
|
||||
|
||||
return devenv_path
|
||||
|
||||
def get_vs_versions():
|
||||
# Get the VS versions
|
||||
ret = []
|
||||
if cocos.os_is_win32():
|
||||
import _winreg
|
||||
else:
|
||||
return ret
|
||||
|
||||
# If the system is 64bit, find VS in both 32bit & 64bit registry
|
||||
# If the system is 32bit, only find VS in 32bit registry
|
||||
if cocos.os_is_32bit_windows():
|
||||
reg_flag_list = [ _winreg.KEY_WOW64_32KEY ]
|
||||
else:
|
||||
reg_flag_list = [ _winreg.KEY_WOW64_64KEY, _winreg.KEY_WOW64_32KEY ]
|
||||
|
||||
version_pattern = re.compile(r'(\d+)\.(\d+)')
|
||||
for reg_flag in reg_flag_list:
|
||||
try:
|
||||
vs = _winreg.OpenKey(
|
||||
_winreg.HKEY_LOCAL_MACHINE,
|
||||
r"SOFTWARE\Microsoft\VisualStudio",
|
||||
0,
|
||||
_winreg.KEY_READ | reg_flag
|
||||
)
|
||||
except:
|
||||
continue
|
||||
|
||||
i = 0
|
||||
while True:
|
||||
# enum the keys in vs reg
|
||||
try:
|
||||
version = _winreg.EnumKey(vs, i)
|
||||
except:
|
||||
break
|
||||
i += 1
|
||||
|
||||
match = re.match(version_pattern, version)
|
||||
if match is None:
|
||||
continue
|
||||
|
||||
ver_str = '%s.%s' % (match.group(1), match.group(2))
|
||||
if ver_str not in ret:
|
||||
ret.append(ver_str)
|
||||
|
||||
return ret
|
||||
|
||||
def get_newest_msbuild(min_ver=None):
|
||||
versions = get_vs_versions()
|
||||
|
||||
min_ver_float = 0.0
|
||||
if isinstance(min_ver, str):
|
||||
# value of min_ver is string. such as : "12.0", "14.0"
|
||||
min_ver_float = float(min_ver)
|
||||
elif isinstance(min_ver, int) and min_ver in VS_VERSION_MAP.keys():
|
||||
# value of min_ver is int. such as : 2017
|
||||
min_ver_float = float(VS_VERSION_MAP[min_ver])
|
||||
|
||||
find_ver = None
|
||||
find_path = None
|
||||
for v in versions:
|
||||
cur_v = float(v)
|
||||
if cur_v < min_ver_float:
|
||||
continue
|
||||
|
||||
v_path = get_msbuild_path(v)
|
||||
if v_path is not None:
|
||||
if (find_ver is None) or (cur_v > find_ver):
|
||||
find_ver = cur_v
|
||||
find_path = v_path
|
||||
|
||||
return find_path
|
||||
|
||||
def get_newest_devenv(min_ver=None):
|
||||
versions = get_vs_versions()
|
||||
|
||||
min_ver_float = 0.0
|
||||
if isinstance(min_ver, str):
|
||||
# value of min_ver is string. such as : "12.0", "14.0"
|
||||
min_ver_float = float(min_ver)
|
||||
elif isinstance(min_ver, int) and min_ver in VS_VERSION_MAP.keys():
|
||||
# value of min_ver is int. such as : 2017
|
||||
min_ver_float = float(VS_VERSION_MAP[min_ver])
|
||||
|
||||
find_ver = None
|
||||
find_path = None
|
||||
for v in versions:
|
||||
cur_v = float(v)
|
||||
if cur_v < min_ver_float:
|
||||
continue
|
||||
|
||||
v_path = get_devenv_path(v)
|
||||
if v_path is not None:
|
||||
if (find_ver is None) or (cur_v > find_ver):
|
||||
find_ver = cur_v
|
||||
find_path = v_path
|
||||
|
||||
if min_ver_float > 0 and find_ver > min_ver_float:
|
||||
need_upgrade = True
|
||||
else:
|
||||
need_upgrade = False
|
||||
|
||||
return (need_upgrade, find_path)
|
||||
|
||||
def rmdir(folder):
|
||||
if os.path.exists(folder):
|
||||
if sys.platform == 'win32':
|
||||
cocos.CMDRunner.run_cmd("rd /s/q \"%s\"" % folder, verbose=True)
|
||||
else:
|
||||
shutil.rmtree(folder)
|
||||
|
||||
VERSION_FILE_PATH = 'cocos/cocos2d.cpp'
|
||||
VERSION_PATTERN = r".*return[ \t]+\"(.*)\";"
|
||||
def get_engine_version(engine_path):
|
||||
ret = None
|
||||
|
||||
try:
|
||||
version_file = os.path.join(engine_path, VERSION_FILE_PATH)
|
||||
if os.path.isfile(version_file):
|
||||
f = open(version_file)
|
||||
for line in f.readlines():
|
||||
match = re.match(VERSION_PATTERN, line)
|
||||
if match:
|
||||
ret = match.group(1)
|
||||
break
|
||||
f.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
return ret
|
||||
|
||||
def un_zip(file_name, output_dir):
|
||||
"""unzip zip file into output_dir"""
|
||||
zip_file = zipfile.ZipFile(file_name)
|
||||
for names in zip_file.namelist():
|
||||
zip_file.extract(names, output_dir)
|
||||
zip_file.close()
|
||||
|
||||
class ExtendEnv(object):
|
||||
extend_env = {}
|
||||
|
||||
@classmethod
|
||||
def parse_extend_env(cls, env):
|
||||
env_list = env.split(';')
|
||||
for item in env_list:
|
||||
index = item.find('=')
|
||||
if index > 0:
|
||||
key = item[:index]
|
||||
value = item[index+1:]
|
||||
cls.extend_env[key] = value
|
||||
|
||||
@classmethod
|
||||
def get_extend_env_value(cls, key):
|
||||
if (cls.extend_env.has_key(key)):
|
||||
return cls.extend_env[key]
|
||||
else:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_extend_env_str(cls):
|
||||
env_list = []
|
||||
for item in cls.extend_env:
|
||||
env_list.append("%s=%s" % (item, cls.extend_env[item]))
|
||||
|
||||
return ';'.join(env_list)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,325 @@
|
||||
#!/usr/bin/python
|
||||
# ----------------------------------------------------------------------------
|
||||
# cocos "jscompile" plugin
|
||||
#
|
||||
# Copyright 2013 (C) Intel
|
||||
#
|
||||
# License: MIT
|
||||
# ----------------------------------------------------------------------------
|
||||
'''
|
||||
"jscompile" plugin for cocos command line tool
|
||||
'''
|
||||
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import os
|
||||
import json
|
||||
import inspect
|
||||
import platform
|
||||
|
||||
import cocos
|
||||
from MultiLanguage import MultiLanguage
|
||||
|
||||
class CCPluginJSCompile(cocos.CCPlugin):
|
||||
"""
|
||||
compiles (encodes) and minifies JS files
|
||||
"""
|
||||
@staticmethod
|
||||
def plugin_name():
|
||||
return "jscompile"
|
||||
|
||||
@staticmethod
|
||||
def brief_description():
|
||||
# returns a short description of this module
|
||||
return MultiLanguage.get_string('JSCOMPILE_BRIEF')
|
||||
|
||||
# This is not the constructor, just an initializator
|
||||
def init(self, options, workingdir):
|
||||
"""
|
||||
Arguments:
|
||||
- `options`:
|
||||
"""
|
||||
self._current_src_dir = None
|
||||
self._src_dir_arr = self.normalize_path_in_list(options.src_dir_arr)
|
||||
self._dst_dir = options.dst_dir
|
||||
self._use_closure_compiler = options.use_closure_compiler
|
||||
self._verbose = not options.quiet
|
||||
self._config = None
|
||||
self._workingdir = workingdir
|
||||
self._closure_params = ''
|
||||
if options.compiler_config != None:
|
||||
f = open(options.compiler_config)
|
||||
self._config = json.load(f)
|
||||
f.close()
|
||||
|
||||
self._pre_order = self._config["pre_order"]
|
||||
self.normalize_path_in_list(self._pre_order)
|
||||
self._post_order = self._config["post_order"]
|
||||
self.normalize_path_in_list(self._post_order)
|
||||
self._skip = self._config["skip"]
|
||||
self.normalize_path_in_list(self._skip)
|
||||
self._closure_params = self._config["closure_params"]
|
||||
|
||||
|
||||
if options.closure_params is not None:
|
||||
self._closure_params = options.closure_params
|
||||
|
||||
self._js_files = {}
|
||||
self._compressed_js_path = os.path.join(self._dst_dir, options.compressed_filename)
|
||||
self._compressed_jsc_path = os.path.join(self._dst_dir, options.compressed_filename+"c")
|
||||
|
||||
if(cocos.os_is_linux()):
|
||||
if(platform.architecture()[0] == "32bit"):
|
||||
self.jsbcc_exe_path = os.path.join(self._workingdir, "bin", "linux", "jsbcc_x86")
|
||||
else:
|
||||
self.jsbcc_exe_path = os.path.join(self._workingdir, "bin", "linux", "jsbcc_x64")
|
||||
else:
|
||||
self.jsbcc_exe_path = os.path.join(self._workingdir, "bin", "jsbcc")
|
||||
|
||||
def normalize_path_in_list(self, list):
|
||||
for i in list:
|
||||
tmp = os.path.normpath(i)
|
||||
list[list.index(i)] = tmp
|
||||
return list
|
||||
|
||||
def get_relative_path(self, jsfile):
|
||||
try:
|
||||
# print "current src dir: "+self._current_src_dir)
|
||||
pos = jsfile.index(self._current_src_dir)
|
||||
if pos != 0:
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('LUACOMPILE_ERROR_SRCDIR_NAME_NOT_FOUND'),
|
||||
cocos.CCPluginError.ERROR_WRONG_ARGS)
|
||||
# print "origin js path: "+ jsfile
|
||||
# print "relative path: "+jsfile[len(self._current_src_dir)+1:]
|
||||
return jsfile[len(self._current_src_dir)+1:]
|
||||
except ValueError:
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('LUACOMPILE_ERROR_SRCDIR_NAME_NOT_FOUND'),
|
||||
cocos.CCPluginError.ERROR_WRONG_ARGS)
|
||||
|
||||
def get_output_file_path(self, jsfile):
|
||||
"""
|
||||
Gets output file path by source js file
|
||||
"""
|
||||
# create folder for generated file
|
||||
jsc_filepath = ""
|
||||
relative_path = self.get_relative_path(jsfile)+"c"
|
||||
jsc_filepath = os.path.join(self._dst_dir, relative_path)
|
||||
|
||||
dst_rootpath = os.path.split(jsc_filepath)[0]
|
||||
try:
|
||||
# print "creating dir (%s)" % (dst_rootpath)
|
||||
os.makedirs(dst_rootpath)
|
||||
except OSError:
|
||||
if os.path.exists(dst_rootpath) == False:
|
||||
# There was an error on creation, so make sure we know about it
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('LUACOMPILE_ERROR_MKDIR_FAILED_FMT', dst_rootpath),
|
||||
cocos.CCPluginError.ERROR_PATH_NOT_FOUND)
|
||||
|
||||
# print "return jsc path: "+jsc_filepath
|
||||
return jsc_filepath
|
||||
|
||||
def compile_js(self, jsfile, output_file):
|
||||
"""
|
||||
Compiles js file
|
||||
"""
|
||||
cocos.Logging.debug(MultiLanguage.get_string('JSCOMPILE_DEBUG_COMPILE_FILE_FMT', jsfile))
|
||||
|
||||
cmd_str = "\"%s\" \"%s\" \"%s\"" % (self.jsbcc_exe_path, jsfile, output_file)
|
||||
self._run_cmd(cmd_str)
|
||||
|
||||
def compress_js(self):
|
||||
"""
|
||||
Compress all js files into one big file.
|
||||
"""
|
||||
jsfiles = ""
|
||||
for src_dir in self._src_dir_arr:
|
||||
# print "\n----------src:"+src_dir
|
||||
jsfiles = jsfiles + " --js ".join(self._js_files[src_dir]) + " "
|
||||
|
||||
compiler_jar_path = os.path.join(self._workingdir, "bin", "compiler.jar")
|
||||
command = "java -jar \"%s\" %s --js %s --js_output_file \"%s\"" % (compiler_jar_path, self._closure_params, jsfiles, self._compressed_js_path)
|
||||
self._run_cmd(command)
|
||||
|
||||
def deep_iterate_dir(self, rootDir):
|
||||
for lists in os.listdir(rootDir):
|
||||
path = os.path.join(rootDir, lists)
|
||||
if os.path.isdir(path):
|
||||
self.deep_iterate_dir(path)
|
||||
elif os.path.isfile(path):
|
||||
if os.path.splitext(path)[1] == ".js":
|
||||
self._js_files[self._current_src_dir].append(path)
|
||||
|
||||
|
||||
def index_in_list(self, jsfile, l):
|
||||
"""
|
||||
Arguments:
|
||||
- `self`:
|
||||
- `jsfile`:
|
||||
- `l`:
|
||||
"""
|
||||
index = -1
|
||||
|
||||
for el in l:
|
||||
if jsfile.rfind(el) != -1:
|
||||
# print "index:"+str(index+1)+", el:"+el
|
||||
return index+1
|
||||
index = index + 1
|
||||
return -1
|
||||
|
||||
def js_filename_pre_order_compare(self, a, b):
|
||||
return self._js_filename_compare(a, b, self._pre_order, 1)
|
||||
|
||||
def js_filename_post_order_compare(self, a, b):
|
||||
return self._js_filename_compare(a, b, self._post_order, -1)
|
||||
|
||||
def _js_filename_compare(self, a, b, files, delta):
|
||||
index_a = self.index_in_list(a, files)
|
||||
index_b = self.index_in_list(b, files)
|
||||
is_a_in_list = index_a != -1
|
||||
is_b_in_list = index_b != -1
|
||||
|
||||
if is_a_in_list and not is_b_in_list:
|
||||
return -1 * delta
|
||||
elif not is_a_in_list and is_b_in_list:
|
||||
return 1 * delta
|
||||
elif is_a_in_list and is_b_in_list:
|
||||
if index_a > index_b:
|
||||
return 1
|
||||
elif index_a < index_b:
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
else:
|
||||
return 0
|
||||
|
||||
def reorder_js_files(self):
|
||||
if self._config == None:
|
||||
return
|
||||
|
||||
# print "before:"+str(self._js_files)
|
||||
|
||||
for src_dir in self._js_files:
|
||||
# Remove file in exclude list
|
||||
need_remove_arr = []
|
||||
for jsfile in self._js_files[src_dir]:
|
||||
for exclude_file in self._skip:
|
||||
if jsfile.rfind(exclude_file) != -1:
|
||||
# print "remove:" + jsfile
|
||||
need_remove_arr.append(jsfile)
|
||||
|
||||
for need_remove in need_remove_arr:
|
||||
self._js_files[src_dir].remove(need_remove)
|
||||
|
||||
self._js_files[src_dir].sort(cmp=self.js_filename_pre_order_compare)
|
||||
self._js_files[src_dir].sort(cmp=self.js_filename_post_order_compare)
|
||||
|
||||
# print '-------------------'
|
||||
# print "after:" + str(self._js_files)
|
||||
|
||||
def handle_all_js_files(self):
|
||||
"""
|
||||
Arguments:
|
||||
- `self`:
|
||||
"""
|
||||
if self._use_closure_compiler == True:
|
||||
cocos.Logging.info(MultiLanguage.get_string('JSCOMPILE_INFO_COMPRESS_TIP'))
|
||||
self.compress_js()
|
||||
self.compile_js(self._compressed_js_path, self._compressed_jsc_path)
|
||||
# remove tmp compressed file
|
||||
os.remove(self._compressed_js_path)
|
||||
else:
|
||||
cocos.Logging.info(MultiLanguage.get_string('JSCOMPILE_INFO_COMPILE_TO_BYTECODE'))
|
||||
for src_dir in self._src_dir_arr:
|
||||
for jsfile in self._js_files[src_dir]:
|
||||
self._current_src_dir = src_dir
|
||||
self.compile_js(jsfile, self.get_output_file_path(jsfile))
|
||||
|
||||
# will be called from the cocos.py script
|
||||
def run(self, argv, dependencies):
|
||||
"""
|
||||
"""
|
||||
self.parse_args(argv)
|
||||
|
||||
# create output directory
|
||||
try:
|
||||
os.makedirs(self._dst_dir)
|
||||
except OSError:
|
||||
if os.path.exists(self._dst_dir) == False:
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('LUACOMPILE_ERROR_MKDIR_FAILED_FMT', self._dst_dir),
|
||||
cocos.CCPluginError.ERROR_PATH_NOT_FOUND)
|
||||
|
||||
# download the bin folder
|
||||
if not os.path.exists(self.jsbcc_exe_path):
|
||||
download_cmd_path = os.path.join(self._workingdir, os.pardir, os.pardir)
|
||||
subprocess.call("python %s -f -r no" % (os.path.join(download_cmd_path, "download-bin.py")), shell=True, cwd=download_cmd_path)
|
||||
|
||||
# deep iterate the src directory
|
||||
for src_dir in self._src_dir_arr:
|
||||
self._current_src_dir = src_dir
|
||||
self._js_files[self._current_src_dir] = []
|
||||
self.deep_iterate_dir(src_dir)
|
||||
|
||||
self.reorder_js_files()
|
||||
self.handle_all_js_files()
|
||||
cocos.Logging.info(MultiLanguage.get_string('LUACOMPILE_INFO_FINISHED'))
|
||||
|
||||
def parse_args(self, argv):
|
||||
"""
|
||||
"""
|
||||
from argparse import ArgumentParser
|
||||
|
||||
parser = ArgumentParser(prog="cocos %s" % self.__class__.plugin_name(),
|
||||
description=self.__class__.brief_description())
|
||||
parser.add_argument("-q", "--quiet",
|
||||
action="store_true",
|
||||
dest="quiet",
|
||||
help=MultiLanguage.get_string('COCOS_HELP_ARG_QUIET'))
|
||||
parser.add_argument("-s", "--src",
|
||||
action="append", dest="src_dir_arr",
|
||||
help=MultiLanguage.get_string('JSCOMPILE_ARG_SRC'))
|
||||
|
||||
parser.add_argument("-d", "--dst",
|
||||
action="store", dest="dst_dir",
|
||||
help=MultiLanguage.get_string('JSCOMPILE_ARG_DST'))
|
||||
|
||||
parser.add_argument("-c", "--use_closure_compiler",
|
||||
action="store_true", dest="use_closure_compiler", default=False,
|
||||
help=MultiLanguage.get_string('JSCOMPILE_ARG_CLOSURE'))
|
||||
|
||||
parser.add_argument("-o", "--output_compressed_filename",
|
||||
action="store", dest="compressed_filename", default="game.min.js",
|
||||
help=MultiLanguage.get_string('JSCOMPILE_ARG_OUT_FILE_NAME'))
|
||||
|
||||
parser.add_argument("-j", "--compiler_config",
|
||||
action="store", dest="compiler_config",
|
||||
help=MultiLanguage.get_string('JSCOMPILE_ARG_JSON_FILE'))
|
||||
parser.add_argument("-m", "--closure_params",
|
||||
action="store", dest="closure_params",
|
||||
help=MultiLanguage.get_string('JSCOMPILE_ARG_EXTRA_PARAM'))
|
||||
|
||||
options = parser.parse_args(argv)
|
||||
|
||||
if options.src_dir_arr == None:
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('JSCOMPILE_ERROR_SRC_NOT_SPECIFIED'),
|
||||
cocos.CCPluginError.ERROR_WRONG_ARGS)
|
||||
elif options.dst_dir == None:
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('LUACOMPILE_ERROR_DST_NOT_SPECIFIED'),
|
||||
cocos.CCPluginError.ERROR_WRONG_ARGS)
|
||||
else:
|
||||
for src_dir in options.src_dir_arr:
|
||||
if os.path.exists(src_dir) == False:
|
||||
raise cocos.CCPluginError(MultiLanguage.get_string('LUACOMPILE_ERROR_DIR_NOT_EXISTED_FMT',
|
||||
(src_dir)),
|
||||
cocos.CCPluginError.ERROR_PATH_NOT_FOUND)
|
||||
|
||||
|
||||
# script directory
|
||||
if getattr(sys, 'frozen', None):
|
||||
workingdir = os.path.realpath(os.path.dirname(sys.executable))
|
||||
else:
|
||||
workingdir = os.path.realpath(os.path.dirname(__file__))
|
||||
|
||||
self.init(options, workingdir)
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"pre_order":
|
||||
[
|
||||
"script/jsb_cocos2d_constants.js",
|
||||
"script/jsb_cocos2d.js",
|
||||
"script/jsb_cocos2d_extension.js",
|
||||
"script/jsb_chipmunk_constants.js",
|
||||
"script/jsb_chipmunk.js",
|
||||
"script/jsb_opengl_constants.js",
|
||||
"script/jsb_opengl.js",
|
||||
"script/jsb_cocosbuilder.js",
|
||||
"script/jsb_sys.js",
|
||||
"script/jsb_cocos2d_studio.js",
|
||||
"script/jsb_cocos2d_gui.js",
|
||||
"script/jsb.js",
|
||||
"tests/tests_resources-jsb.js",
|
||||
"tests/tests-main.js",
|
||||
"tests/BaseTestLayer/BaseTestLayer.js",
|
||||
"tests/PerformanceTest/PerformanceTest.js",
|
||||
"tests/tests-boot-jsb.js"
|
||||
],
|
||||
"post_order":
|
||||
[
|
||||
|
||||
],
|
||||
"skip":
|
||||
[
|
||||
"tests/main.js",
|
||||
"tests/tests_resources-html5.js",
|
||||
"tests/tests-boot-html5.js",
|
||||
"tests/AdvanceCompiler",
|
||||
"script/jsb_debugger.js",
|
||||
"script/debugger/"
|
||||
],
|
||||
"closure_params": ""
|
||||
}
|
||||
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/jsbcc
Executable file
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/jsbcc
Executable file
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.apple.xcode.dsym.jsbcc</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>dSYM</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/jsbcc.exe
Executable file
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/jsbcc.exe
Executable file
Binary file not shown.
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/linux/jsbcc_x64
Executable file
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/linux/jsbcc_x64
Executable file
Binary file not shown.
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/linux/jsbcc_x86
Executable file
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/linux/jsbcc_x86
Executable file
Binary file not shown.
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/mozjs-52.dll
Executable file
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/mozjs-52.dll
Executable file
Binary file not shown.
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/nspr4.dll
Executable file
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_jscompile/bin/nspr4.dll
Executable file
Binary file not shown.
@@ -0,0 +1,191 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT bytecode listing module.
|
||||
--
|
||||
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- This module lists the bytecode of a Lua function. If it's loaded by -jbc
|
||||
-- it hooks into the parser and lists all functions of a chunk as they
|
||||
-- are parsed.
|
||||
--
|
||||
-- Example usage:
|
||||
--
|
||||
-- luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)'
|
||||
-- luajit -jbc=- foo.lua
|
||||
-- luajit -jbc=foo.list foo.lua
|
||||
--
|
||||
-- Default output is to stderr. To redirect the output to a file, pass a
|
||||
-- filename as an argument (use '-' for stdout) or set the environment
|
||||
-- variable LUAJIT_LISTFILE. The file is overwritten every time the module
|
||||
-- is started.
|
||||
--
|
||||
-- This module can also be used programmatically:
|
||||
--
|
||||
-- local bc = require("jit.bc")
|
||||
--
|
||||
-- local function foo() print("hello") end
|
||||
--
|
||||
-- bc.dump(foo) --> -- BYTECODE -- [...]
|
||||
-- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello"
|
||||
--
|
||||
-- local out = {
|
||||
-- -- Do something with each line:
|
||||
-- write = function(t, ...) io.write(...) end,
|
||||
-- close = function(t) end,
|
||||
-- flush = function(t) end,
|
||||
-- }
|
||||
-- bc.dump(foo, out)
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Cache some library functions and objects.
|
||||
local jit = require("jit")
|
||||
assert(jit.version_num == 20001, "LuaJIT core/library version mismatch")
|
||||
local jutil = require("jit.util")
|
||||
local vmdef = require("jit.vmdef")
|
||||
local bit = require("bit")
|
||||
local sub, gsub, format = string.sub, string.gsub, string.format
|
||||
local byte, band, shr = string.byte, bit.band, bit.rshift
|
||||
local funcinfo, funcbc, funck = jutil.funcinfo, jutil.funcbc, jutil.funck
|
||||
local funcuvname = jutil.funcuvname
|
||||
local bcnames = vmdef.bcnames
|
||||
local stdout, stderr = io.stdout, io.stderr
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local function ctlsub(c)
|
||||
if c == "\n" then return "\\n"
|
||||
elseif c == "\r" then return "\\r"
|
||||
elseif c == "\t" then return "\\t"
|
||||
else return format("\\%03d", byte(c))
|
||||
end
|
||||
end
|
||||
|
||||
-- Return one bytecode line.
|
||||
local function bcline(func, pc, prefix)
|
||||
local ins, m = funcbc(func, pc)
|
||||
if not ins then return end
|
||||
local ma, mb, mc = band(m, 7), band(m, 15*8), band(m, 15*128)
|
||||
local a = band(shr(ins, 8), 0xff)
|
||||
local oidx = 6*band(ins, 0xff)
|
||||
local op = sub(bcnames, oidx+1, oidx+6)
|
||||
local s = format("%04d %s %-6s %3s ",
|
||||
pc, prefix or " ", op, ma == 0 and "" or a)
|
||||
local d = shr(ins, 16)
|
||||
if mc == 13*128 then -- BCMjump
|
||||
return format("%s=> %04d\n", s, pc+d-0x7fff)
|
||||
end
|
||||
if mb ~= 0 then
|
||||
d = band(d, 0xff)
|
||||
elseif mc == 0 then
|
||||
return s.."\n"
|
||||
end
|
||||
local kc
|
||||
if mc == 10*128 then -- BCMstr
|
||||
kc = funck(func, -d-1)
|
||||
kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub))
|
||||
elseif mc == 9*128 then -- BCMnum
|
||||
kc = funck(func, d)
|
||||
if op == "TSETM " then kc = kc - 2^52 end
|
||||
elseif mc == 12*128 then -- BCMfunc
|
||||
local fi = funcinfo(funck(func, -d-1))
|
||||
if fi.ffid then
|
||||
kc = vmdef.ffnames[fi.ffid]
|
||||
else
|
||||
kc = fi.loc
|
||||
end
|
||||
elseif mc == 5*128 then -- BCMuv
|
||||
kc = funcuvname(func, d)
|
||||
end
|
||||
if ma == 5 then -- BCMuv
|
||||
local ka = funcuvname(func, a)
|
||||
if kc then kc = ka.." ; "..kc else kc = ka end
|
||||
end
|
||||
if mb ~= 0 then
|
||||
local b = shr(ins, 24)
|
||||
if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end
|
||||
return format("%s%3d %3d\n", s, b, d)
|
||||
end
|
||||
if kc then return format("%s%3d ; %s\n", s, d, kc) end
|
||||
if mc == 7*128 and d > 32767 then d = d - 65536 end -- BCMlits
|
||||
return format("%s%3d\n", s, d)
|
||||
end
|
||||
|
||||
-- Collect branch targets of a function.
|
||||
local function bctargets(func)
|
||||
local target = {}
|
||||
for pc=1,1000000000 do
|
||||
local ins, m = funcbc(func, pc)
|
||||
if not ins then break end
|
||||
if band(m, 15*128) == 13*128 then target[pc+shr(ins, 16)-0x7fff] = true end
|
||||
end
|
||||
return target
|
||||
end
|
||||
|
||||
-- Dump bytecode instructions of a function.
|
||||
local function bcdump(func, out, all)
|
||||
if not out then out = stdout end
|
||||
local fi = funcinfo(func)
|
||||
if all and fi.children then
|
||||
for n=-1,-1000000000,-1 do
|
||||
local k = funck(func, n)
|
||||
if not k then break end
|
||||
if type(k) == "proto" then bcdump(k, out, true) end
|
||||
end
|
||||
end
|
||||
out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined))
|
||||
local target = bctargets(func)
|
||||
for pc=1,1000000000 do
|
||||
local s = bcline(func, pc, target[pc] and "=>")
|
||||
if not s then break end
|
||||
out:write(s)
|
||||
end
|
||||
out:write("\n")
|
||||
out:flush()
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Active flag and output file handle.
|
||||
local active, out
|
||||
|
||||
-- List handler.
|
||||
local function h_list(func)
|
||||
return bcdump(func, out)
|
||||
end
|
||||
|
||||
-- Detach list handler.
|
||||
local function bclistoff()
|
||||
if active then
|
||||
active = false
|
||||
jit.attach(h_list)
|
||||
if out and out ~= stdout and out ~= stderr then out:close() end
|
||||
out = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Open the output file and attach list handler.
|
||||
local function bcliston(outfile)
|
||||
if active then bclistoff() end
|
||||
if not outfile then outfile = os.getenv("LUAJIT_LISTFILE") end
|
||||
if outfile then
|
||||
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
|
||||
else
|
||||
out = stderr
|
||||
end
|
||||
jit.attach(h_list, "bc")
|
||||
active = true
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
module(...)
|
||||
|
||||
line = bcline
|
||||
dump = bcdump
|
||||
targets = bctargets
|
||||
|
||||
on = bcliston
|
||||
off = bclistoff
|
||||
start = bcliston -- For -j command line option.
|
||||
|
||||
@@ -0,0 +1,659 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT module to save/list bytecode.
|
||||
--
|
||||
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- This module saves or lists the bytecode for an input file.
|
||||
-- It's run by the -b command line option.
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local jit = require("jit")
|
||||
assert(jit.version_num == 20001, "LuaJIT core/library version mismatch")
|
||||
local bit = require("bit")
|
||||
|
||||
-- Symbol name prefix for LuaJIT bytecode.
|
||||
local LJBC_PREFIX = "luaJIT_BC_"
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local function usage()
|
||||
io.stderr:write[[
|
||||
Save LuaJIT bytecode: luajit -b[options] input output
|
||||
-l Only list bytecode.
|
||||
-s Strip debug info (default).
|
||||
-g Keep debug info.
|
||||
-n name Set module name (default: auto-detect from input name).
|
||||
-t type Set output file type (default: auto-detect from output name).
|
||||
-a arch Override architecture for object files (default: native).
|
||||
-o os Override OS for object files (default: native).
|
||||
-e chunk Use chunk string as input.
|
||||
-- Stop handling options.
|
||||
- Use stdin as input and/or stdout as output.
|
||||
|
||||
File types: c h obj o raw (default)
|
||||
]]
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local function check(ok, ...)
|
||||
if ok then return ok, ... end
|
||||
io.stderr:write("luajit: ", ...)
|
||||
io.stderr:write("\n")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local function readfile(input)
|
||||
if type(input) == "function" then return input end
|
||||
if input == "-" then input = nil end
|
||||
return check(loadfile(input))
|
||||
end
|
||||
|
||||
local function savefile(name, mode)
|
||||
if name == "-" then return io.stdout end
|
||||
return check(io.open(name, mode))
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_type = {
|
||||
raw = "raw", c = "c", h = "h", o = "obj", obj = "obj",
|
||||
}
|
||||
|
||||
local map_arch = {
|
||||
x86 = true, x64 = true, arm = true, ppc = true, ppcspe = true,
|
||||
mips = true, mipsel = true,
|
||||
}
|
||||
|
||||
local map_os = {
|
||||
linux = true, windows = true, osx = true, freebsd = true, netbsd = true,
|
||||
openbsd = true, solaris = true,
|
||||
}
|
||||
|
||||
local function checkarg(str, map, err)
|
||||
str = string.lower(str)
|
||||
local s = check(map[str], "unknown ", err)
|
||||
return s == true and str or s
|
||||
end
|
||||
|
||||
local function detecttype(str)
|
||||
local ext = string.match(string.lower(str), "%.(%a+)$")
|
||||
return map_type[ext] or "raw"
|
||||
end
|
||||
|
||||
local function checkmodname(str)
|
||||
check(string.match(str, "^[%w_.%-]+$"), "bad module name")
|
||||
return string.gsub(str, "[%.%-]", "_")
|
||||
end
|
||||
|
||||
local function detectmodname(str)
|
||||
if type(str) == "string" then
|
||||
local tail = string.match(str, "[^/\\]+$")
|
||||
if tail then str = tail end
|
||||
local head = string.match(str, "^(.*)%.[^.]*$")
|
||||
if head then str = head end
|
||||
str = string.match(str, "^[%w_.%-]+")
|
||||
else
|
||||
str = nil
|
||||
end
|
||||
check(str, "cannot derive module name, use -n name")
|
||||
return string.gsub(str, "[%.%-]", "_")
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local function bcsave_tail(fp, output, s)
|
||||
local ok, err = fp:write(s)
|
||||
if ok and output ~= "-" then ok, err = fp:close() end
|
||||
check(ok, "cannot write ", output, ": ", err)
|
||||
end
|
||||
|
||||
local function bcsave_raw(output, s)
|
||||
local fp = savefile(output, "wb")
|
||||
bcsave_tail(fp, output, s)
|
||||
end
|
||||
|
||||
local function bcsave_c(ctx, output, s)
|
||||
local fp = savefile(output, "w")
|
||||
if ctx.type == "c" then
|
||||
fp:write(string.format([[
|
||||
#ifdef _cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
const char %s%s[] = {
|
||||
]], LJBC_PREFIX, ctx.modname))
|
||||
else
|
||||
fp:write(string.format([[
|
||||
#define %s%s_SIZE %d
|
||||
static const char %s%s[] = {
|
||||
]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname))
|
||||
end
|
||||
local t, n, m = {}, 0, 0
|
||||
for i=1,#s do
|
||||
local b = tostring(string.byte(s, i))
|
||||
m = m + #b + 1
|
||||
if m > 78 then
|
||||
fp:write(table.concat(t, ",", 1, n), ",\n")
|
||||
n, m = 0, #b + 1
|
||||
end
|
||||
n = n + 1
|
||||
t[n] = b
|
||||
end
|
||||
bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n")
|
||||
end
|
||||
|
||||
local function bcsave_elfobj(ctx, output, s, ffi)
|
||||
ffi.cdef[[
|
||||
typedef struct {
|
||||
uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
|
||||
uint16_t type, machine;
|
||||
uint32_t version;
|
||||
uint32_t entry, phofs, shofs;
|
||||
uint32_t flags;
|
||||
uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
|
||||
} ELF32header;
|
||||
typedef struct {
|
||||
uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
|
||||
uint16_t type, machine;
|
||||
uint32_t version;
|
||||
uint64_t entry, phofs, shofs;
|
||||
uint32_t flags;
|
||||
uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
|
||||
} ELF64header;
|
||||
typedef struct {
|
||||
uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize;
|
||||
} ELF32sectheader;
|
||||
typedef struct {
|
||||
uint32_t name, type;
|
||||
uint64_t flags, addr, ofs, size;
|
||||
uint32_t link, info;
|
||||
uint64_t align, entsize;
|
||||
} ELF64sectheader;
|
||||
typedef struct {
|
||||
uint32_t name, value, size;
|
||||
uint8_t info, other;
|
||||
uint16_t sectidx;
|
||||
} ELF32symbol;
|
||||
typedef struct {
|
||||
uint32_t name;
|
||||
uint8_t info, other;
|
||||
uint16_t sectidx;
|
||||
uint64_t value, size;
|
||||
} ELF64symbol;
|
||||
typedef struct {
|
||||
ELF32header hdr;
|
||||
ELF32sectheader sect[6];
|
||||
ELF32symbol sym[2];
|
||||
uint8_t space[4096];
|
||||
} ELF32obj;
|
||||
typedef struct {
|
||||
ELF64header hdr;
|
||||
ELF64sectheader sect[6];
|
||||
ELF64symbol sym[2];
|
||||
uint8_t space[4096];
|
||||
} ELF64obj;
|
||||
]]
|
||||
local symname = LJBC_PREFIX..ctx.modname
|
||||
local is64, isbe = false, false
|
||||
if ctx.arch == "x64" then
|
||||
is64 = true
|
||||
elseif ctx.arch == "ppc" or ctx.arch == "ppcspe" or ctx.arch == "mips" then
|
||||
isbe = true
|
||||
end
|
||||
|
||||
-- Handle different host/target endianess.
|
||||
local function f32(x) return x end
|
||||
local f16, fofs = f32, f32
|
||||
if ffi.abi("be") ~= isbe then
|
||||
f32 = bit.bswap
|
||||
function f16(x) return bit.rshift(bit.bswap(x), 16) end
|
||||
if is64 then
|
||||
local two32 = ffi.cast("int64_t", 2^32)
|
||||
function fofs(x) return bit.bswap(x)*two32 end
|
||||
else
|
||||
fofs = f32
|
||||
end
|
||||
end
|
||||
|
||||
-- Create ELF object and fill in header.
|
||||
local o = ffi.new(is64 and "ELF64obj" or "ELF32obj")
|
||||
local hdr = o.hdr
|
||||
if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi.
|
||||
local bf = assert(io.open("/bin/ls", "rb"))
|
||||
local bs = bf:read(9)
|
||||
bf:close()
|
||||
ffi.copy(o, bs, 9)
|
||||
check(hdr.emagic[0] == 127, "no support for writing native object files")
|
||||
else
|
||||
hdr.emagic = "\127ELF"
|
||||
hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0
|
||||
end
|
||||
hdr.eclass = is64 and 2 or 1
|
||||
hdr.eendian = isbe and 2 or 1
|
||||
hdr.eversion = 1
|
||||
hdr.type = f16(1)
|
||||
hdr.machine = f16(({ x86=3, x64=62, arm=40, ppc=20, ppcspe=20, mips=8, mipsel=8 })[ctx.arch])
|
||||
if ctx.arch == "mips" or ctx.arch == "mipsel" then
|
||||
hdr.flags = 0x50001006
|
||||
end
|
||||
hdr.version = f32(1)
|
||||
hdr.shofs = fofs(ffi.offsetof(o, "sect"))
|
||||
hdr.ehsize = f16(ffi.sizeof(hdr))
|
||||
hdr.shentsize = f16(ffi.sizeof(o.sect[0]))
|
||||
hdr.shnum = f16(6)
|
||||
hdr.shstridx = f16(2)
|
||||
|
||||
-- Fill in sections and symbols.
|
||||
local sofs, ofs = ffi.offsetof(o, "space"), 1
|
||||
for i,name in ipairs{
|
||||
".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack",
|
||||
} do
|
||||
local sect = o.sect[i]
|
||||
sect.align = fofs(1)
|
||||
sect.name = f32(ofs)
|
||||
ffi.copy(o.space+ofs, name)
|
||||
ofs = ofs + #name+1
|
||||
end
|
||||
o.sect[1].type = f32(2) -- .symtab
|
||||
o.sect[1].link = f32(3)
|
||||
o.sect[1].info = f32(1)
|
||||
o.sect[1].align = fofs(8)
|
||||
o.sect[1].ofs = fofs(ffi.offsetof(o, "sym"))
|
||||
o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0]))
|
||||
o.sect[1].size = fofs(ffi.sizeof(o.sym))
|
||||
o.sym[1].name = f32(1)
|
||||
o.sym[1].sectidx = f16(4)
|
||||
o.sym[1].size = fofs(#s)
|
||||
o.sym[1].info = 17
|
||||
o.sect[2].type = f32(3) -- .shstrtab
|
||||
o.sect[2].ofs = fofs(sofs)
|
||||
o.sect[2].size = fofs(ofs)
|
||||
o.sect[3].type = f32(3) -- .strtab
|
||||
o.sect[3].ofs = fofs(sofs + ofs)
|
||||
o.sect[3].size = fofs(#symname+1)
|
||||
ffi.copy(o.space+ofs+1, symname)
|
||||
ofs = ofs + #symname + 2
|
||||
o.sect[4].type = f32(1) -- .rodata
|
||||
o.sect[4].flags = fofs(2)
|
||||
o.sect[4].ofs = fofs(sofs + ofs)
|
||||
o.sect[4].size = fofs(#s)
|
||||
o.sect[5].type = f32(1) -- .note.GNU-stack
|
||||
o.sect[5].ofs = fofs(sofs + ofs + #s)
|
||||
|
||||
-- Write ELF object file.
|
||||
local fp = savefile(output, "wb")
|
||||
fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
|
||||
bcsave_tail(fp, output, s)
|
||||
end
|
||||
|
||||
local function bcsave_peobj(ctx, output, s, ffi)
|
||||
ffi.cdef[[
|
||||
typedef struct {
|
||||
uint16_t arch, nsects;
|
||||
uint32_t time, symtabofs, nsyms;
|
||||
uint16_t opthdrsz, flags;
|
||||
} PEheader;
|
||||
typedef struct {
|
||||
char name[8];
|
||||
uint32_t vsize, vaddr, size, ofs, relocofs, lineofs;
|
||||
uint16_t nreloc, nline;
|
||||
uint32_t flags;
|
||||
} PEsection;
|
||||
typedef struct __attribute((packed)) {
|
||||
union {
|
||||
char name[8];
|
||||
uint32_t nameref[2];
|
||||
};
|
||||
uint32_t value;
|
||||
int16_t sect;
|
||||
uint16_t type;
|
||||
uint8_t scl, naux;
|
||||
} PEsym;
|
||||
typedef struct __attribute((packed)) {
|
||||
uint32_t size;
|
||||
uint16_t nreloc, nline;
|
||||
uint32_t cksum;
|
||||
uint16_t assoc;
|
||||
uint8_t comdatsel, unused[3];
|
||||
} PEsymaux;
|
||||
typedef struct {
|
||||
PEheader hdr;
|
||||
PEsection sect[2];
|
||||
// Must be an even number of symbol structs.
|
||||
PEsym sym0;
|
||||
PEsymaux sym0aux;
|
||||
PEsym sym1;
|
||||
PEsymaux sym1aux;
|
||||
PEsym sym2;
|
||||
PEsym sym3;
|
||||
uint32_t strtabsize;
|
||||
uint8_t space[4096];
|
||||
} PEobj;
|
||||
]]
|
||||
local symname = LJBC_PREFIX..ctx.modname
|
||||
local is64 = false
|
||||
if ctx.arch == "x86" then
|
||||
symname = "_"..symname
|
||||
elseif ctx.arch == "x64" then
|
||||
is64 = true
|
||||
end
|
||||
local symexport = " /EXPORT:"..symname..",DATA "
|
||||
|
||||
-- The file format is always little-endian. Swap if the host is big-endian.
|
||||
local function f32(x) return x end
|
||||
local f16 = f32
|
||||
if ffi.abi("be") then
|
||||
f32 = bit.bswap
|
||||
function f16(x) return bit.rshift(bit.bswap(x), 16) end
|
||||
end
|
||||
|
||||
-- Create PE object and fill in header.
|
||||
local o = ffi.new("PEobj")
|
||||
local hdr = o.hdr
|
||||
hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch])
|
||||
hdr.nsects = f16(2)
|
||||
hdr.symtabofs = f32(ffi.offsetof(o, "sym0"))
|
||||
hdr.nsyms = f32(6)
|
||||
|
||||
-- Fill in sections and symbols.
|
||||
o.sect[0].name = ".drectve"
|
||||
o.sect[0].size = f32(#symexport)
|
||||
o.sect[0].flags = f32(0x00100a00)
|
||||
o.sym0.sect = f16(1)
|
||||
o.sym0.scl = 3
|
||||
o.sym0.name = ".drectve"
|
||||
o.sym0.naux = 1
|
||||
o.sym0aux.size = f32(#symexport)
|
||||
o.sect[1].name = ".rdata"
|
||||
o.sect[1].size = f32(#s)
|
||||
o.sect[1].flags = f32(0x40300040)
|
||||
o.sym1.sect = f16(2)
|
||||
o.sym1.scl = 3
|
||||
o.sym1.name = ".rdata"
|
||||
o.sym1.naux = 1
|
||||
o.sym1aux.size = f32(#s)
|
||||
o.sym2.sect = f16(2)
|
||||
o.sym2.scl = 2
|
||||
o.sym2.nameref[1] = f32(4)
|
||||
o.sym3.sect = f16(-1)
|
||||
o.sym3.scl = 2
|
||||
o.sym3.value = f32(1)
|
||||
o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant.
|
||||
ffi.copy(o.space, symname)
|
||||
local ofs = #symname + 1
|
||||
o.strtabsize = f32(ofs + 4)
|
||||
o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs)
|
||||
ffi.copy(o.space + ofs, symexport)
|
||||
ofs = ofs + #symexport
|
||||
o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs)
|
||||
|
||||
-- Write PE object file.
|
||||
local fp = savefile(output, "wb")
|
||||
fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
|
||||
bcsave_tail(fp, output, s)
|
||||
end
|
||||
|
||||
local function bcsave_machobj(ctx, output, s, ffi)
|
||||
ffi.cdef[[
|
||||
typedef struct
|
||||
{
|
||||
uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags;
|
||||
} mach_header;
|
||||
typedef struct
|
||||
{
|
||||
mach_header; uint32_t reserved;
|
||||
} mach_header_64;
|
||||
typedef struct {
|
||||
uint32_t cmd, cmdsize;
|
||||
char segname[16];
|
||||
uint32_t vmaddr, vmsize, fileoff, filesize;
|
||||
uint32_t maxprot, initprot, nsects, flags;
|
||||
} mach_segment_command;
|
||||
typedef struct {
|
||||
uint32_t cmd, cmdsize;
|
||||
char segname[16];
|
||||
uint64_t vmaddr, vmsize, fileoff, filesize;
|
||||
uint32_t maxprot, initprot, nsects, flags;
|
||||
} mach_segment_command_64;
|
||||
typedef struct {
|
||||
char sectname[16], segname[16];
|
||||
uint32_t addr, size;
|
||||
uint32_t offset, align, reloff, nreloc, flags;
|
||||
uint32_t reserved1, reserved2;
|
||||
} mach_section;
|
||||
typedef struct {
|
||||
char sectname[16], segname[16];
|
||||
uint64_t addr, size;
|
||||
uint32_t offset, align, reloff, nreloc, flags;
|
||||
uint32_t reserved1, reserved2, reserved3;
|
||||
} mach_section_64;
|
||||
typedef struct {
|
||||
uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize;
|
||||
} mach_symtab_command;
|
||||
typedef struct {
|
||||
int32_t strx;
|
||||
uint8_t type, sect;
|
||||
int16_t desc;
|
||||
uint32_t value;
|
||||
} mach_nlist;
|
||||
typedef struct {
|
||||
uint32_t strx;
|
||||
uint8_t type, sect;
|
||||
uint16_t desc;
|
||||
uint64_t value;
|
||||
} mach_nlist_64;
|
||||
typedef struct
|
||||
{
|
||||
uint32_t magic, nfat_arch;
|
||||
} mach_fat_header;
|
||||
typedef struct
|
||||
{
|
||||
uint32_t cputype, cpusubtype, offset, size, align;
|
||||
} mach_fat_arch;
|
||||
typedef struct {
|
||||
struct {
|
||||
mach_header hdr;
|
||||
mach_segment_command seg;
|
||||
mach_section sec;
|
||||
mach_symtab_command sym;
|
||||
} arch[1];
|
||||
mach_nlist sym_entry;
|
||||
uint8_t space[4096];
|
||||
} mach_obj;
|
||||
typedef struct {
|
||||
struct {
|
||||
mach_header_64 hdr;
|
||||
mach_segment_command_64 seg;
|
||||
mach_section_64 sec;
|
||||
mach_symtab_command sym;
|
||||
} arch[1];
|
||||
mach_nlist_64 sym_entry;
|
||||
uint8_t space[4096];
|
||||
} mach_obj_64;
|
||||
typedef struct {
|
||||
mach_fat_header fat;
|
||||
mach_fat_arch fat_arch[4];
|
||||
struct {
|
||||
mach_header hdr;
|
||||
mach_segment_command seg;
|
||||
mach_section sec;
|
||||
mach_symtab_command sym;
|
||||
} arch[4];
|
||||
mach_nlist sym_entry;
|
||||
uint8_t space[4096];
|
||||
} mach_fat_obj;
|
||||
]]
|
||||
local symname = '_'..LJBC_PREFIX..ctx.modname
|
||||
local isfat, is64, align, mobj = false, false, 4, "mach_obj"
|
||||
if ctx.arch == "x64" then
|
||||
is64, align, mobj = true, 8, "mach_obj_64"
|
||||
elseif ctx.arch == "arm" then
|
||||
isfat, mobj = true, "mach_fat_obj"
|
||||
else
|
||||
check(ctx.arch == "x86", "unsupported architecture for OSX")
|
||||
end
|
||||
local function aligned(v, a) return bit.band(v+a-1, -a) end
|
||||
local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE.
|
||||
|
||||
-- Create Mach-O object and fill in header.
|
||||
local o = ffi.new(mobj)
|
||||
local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align)
|
||||
local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12,12,12} })[ctx.arch]
|
||||
local cpusubtype = ({ x86={3}, x64={3}, arm={3,6,9,11} })[ctx.arch]
|
||||
if isfat then
|
||||
o.fat.magic = be32(0xcafebabe)
|
||||
o.fat.nfat_arch = be32(#cpusubtype)
|
||||
end
|
||||
|
||||
-- Fill in sections and symbols.
|
||||
for i=0,#cpusubtype-1 do
|
||||
local ofs = 0
|
||||
if isfat then
|
||||
local a = o.fat_arch[i]
|
||||
a.cputype = be32(cputype[i+1])
|
||||
a.cpusubtype = be32(cpusubtype[i+1])
|
||||
-- Subsequent slices overlap each other to share data.
|
||||
ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0])
|
||||
a.offset = be32(ofs)
|
||||
a.size = be32(mach_size-ofs+#s)
|
||||
end
|
||||
local a = o.arch[i]
|
||||
a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface
|
||||
a.hdr.cputype = cputype[i+1]
|
||||
a.hdr.cpusubtype = cpusubtype[i+1]
|
||||
a.hdr.filetype = 1
|
||||
a.hdr.ncmds = 2
|
||||
a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym)
|
||||
a.seg.cmd = is64 and 0x19 or 0x1
|
||||
a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)
|
||||
a.seg.vmsize = #s
|
||||
a.seg.fileoff = mach_size-ofs
|
||||
a.seg.filesize = #s
|
||||
a.seg.maxprot = 1
|
||||
a.seg.initprot = 1
|
||||
a.seg.nsects = 1
|
||||
ffi.copy(a.sec.sectname, "__data")
|
||||
ffi.copy(a.sec.segname, "__DATA")
|
||||
a.sec.size = #s
|
||||
a.sec.offset = mach_size-ofs
|
||||
a.sym.cmd = 2
|
||||
a.sym.cmdsize = ffi.sizeof(a.sym)
|
||||
a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs
|
||||
a.sym.nsyms = 1
|
||||
a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs
|
||||
a.sym.strsize = aligned(#symname+2, align)
|
||||
end
|
||||
o.sym_entry.type = 0xf
|
||||
o.sym_entry.sect = 1
|
||||
o.sym_entry.strx = 1
|
||||
ffi.copy(o.space+1, symname)
|
||||
|
||||
-- Write Macho-O object file.
|
||||
local fp = savefile(output, "wb")
|
||||
fp:write(ffi.string(o, mach_size))
|
||||
bcsave_tail(fp, output, s)
|
||||
end
|
||||
|
||||
local function bcsave_obj(ctx, output, s)
|
||||
local ok, ffi = pcall(require, "ffi")
|
||||
check(ok, "FFI library required to write this file type")
|
||||
if ctx.os == "windows" then
|
||||
return bcsave_peobj(ctx, output, s, ffi)
|
||||
elseif ctx.os == "osx" then
|
||||
return bcsave_machobj(ctx, output, s, ffi)
|
||||
else
|
||||
return bcsave_elfobj(ctx, output, s, ffi)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local function bclist(input, output)
|
||||
local f = readfile(input)
|
||||
require("jit.bc").dump(f, savefile(output, "w"), true)
|
||||
end
|
||||
|
||||
local function bcsave(ctx, input, output)
|
||||
local f = readfile(input)
|
||||
local s = string.dump(f, ctx.strip)
|
||||
local t = ctx.type
|
||||
if not t then
|
||||
t = detecttype(output)
|
||||
ctx.type = t
|
||||
end
|
||||
if t == "raw" then
|
||||
bcsave_raw(output, s)
|
||||
else
|
||||
if not ctx.modname then ctx.modname = detectmodname(input) end
|
||||
if t == "obj" then
|
||||
bcsave_obj(ctx, output, s)
|
||||
else
|
||||
bcsave_c(ctx, output, s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function docmd(...)
|
||||
local arg = {...}
|
||||
local n = 1
|
||||
local list = false
|
||||
local ctx = {
|
||||
strip = true, arch = jit.arch, os = string.lower(jit.os),
|
||||
type = false, modname = false,
|
||||
}
|
||||
while n <= #arg do
|
||||
local a = arg[n]
|
||||
if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then
|
||||
table.remove(arg, n)
|
||||
if a == "--" then break end
|
||||
for m=2,#a do
|
||||
local opt = string.sub(a, m, m)
|
||||
if opt == "l" then
|
||||
list = true
|
||||
elseif opt == "s" then
|
||||
ctx.strip = true
|
||||
elseif opt == "g" then
|
||||
ctx.strip = false
|
||||
else
|
||||
if arg[n] == nil or m ~= #a then usage() end
|
||||
if opt == "e" then
|
||||
if n ~= 1 then usage() end
|
||||
arg[1] = check(loadstring(arg[1]))
|
||||
elseif opt == "n" then
|
||||
ctx.modname = checkmodname(table.remove(arg, n))
|
||||
elseif opt == "t" then
|
||||
ctx.type = checkarg(table.remove(arg, n), map_type, "file type")
|
||||
elseif opt == "a" then
|
||||
ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture")
|
||||
elseif opt == "o" then
|
||||
ctx.os = checkarg(table.remove(arg, n), map_os, "OS name")
|
||||
else
|
||||
usage()
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
if list then
|
||||
if #arg == 0 or #arg > 2 then usage() end
|
||||
bclist(arg[1], arg[2] or "-")
|
||||
else
|
||||
if #arg ~= 2 then usage() end
|
||||
bcsave(ctx, arg[1], arg[2])
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Public module functions.
|
||||
module(...)
|
||||
|
||||
start = docmd -- Process -b command line option.
|
||||
|
||||
@@ -0,0 +1,689 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT ARM disassembler module.
|
||||
--
|
||||
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This is a helper module used by the LuaJIT machine code dumper module.
|
||||
--
|
||||
-- It disassembles most user-mode ARMv7 instructions
|
||||
-- NYI: Advanced SIMD and VFP instructions.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local type = type
|
||||
local sub, byte, format = string.sub, string.byte, string.format
|
||||
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
|
||||
local concat = table.concat
|
||||
local bit = require("bit")
|
||||
local band, bor, ror, tohex = bit.band, bit.bor, bit.ror, bit.tohex
|
||||
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Opcode maps
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_loadc = {
|
||||
shift = 8, mask = 15,
|
||||
[10] = {
|
||||
shift = 20, mask = 1,
|
||||
[0] = {
|
||||
shift = 23, mask = 3,
|
||||
[0] = "vmovFmDN", "vstmFNdr",
|
||||
_ = {
|
||||
shift = 21, mask = 1,
|
||||
[0] = "vstrFdl",
|
||||
{ shift = 16, mask = 15, [13] = "vpushFdr", _ = "vstmdbFNdr", }
|
||||
},
|
||||
},
|
||||
{
|
||||
shift = 23, mask = 3,
|
||||
[0] = "vmovFDNm",
|
||||
{ shift = 16, mask = 15, [13] = "vpopFdr", _ = "vldmFNdr", },
|
||||
_ = {
|
||||
shift = 21, mask = 1,
|
||||
[0] = "vldrFdl", "vldmdbFNdr",
|
||||
},
|
||||
},
|
||||
},
|
||||
[11] = {
|
||||
shift = 20, mask = 1,
|
||||
[0] = {
|
||||
shift = 23, mask = 3,
|
||||
[0] = "vmovGmDN", "vstmGNdr",
|
||||
_ = {
|
||||
shift = 21, mask = 1,
|
||||
[0] = "vstrGdl",
|
||||
{ shift = 16, mask = 15, [13] = "vpushGdr", _ = "vstmdbGNdr", }
|
||||
},
|
||||
},
|
||||
{
|
||||
shift = 23, mask = 3,
|
||||
[0] = "vmovGDNm",
|
||||
{ shift = 16, mask = 15, [13] = "vpopGdr", _ = "vldmGNdr", },
|
||||
_ = {
|
||||
shift = 21, mask = 1,
|
||||
[0] = "vldrGdl", "vldmdbGNdr",
|
||||
},
|
||||
},
|
||||
},
|
||||
_ = {
|
||||
shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc.
|
||||
},
|
||||
}
|
||||
|
||||
local map_vfps = {
|
||||
shift = 6, mask = 0x2c001,
|
||||
[0] = "vmlaF.dnm", "vmlsF.dnm",
|
||||
[0x04000] = "vnmlsF.dnm", [0x04001] = "vnmlaF.dnm",
|
||||
[0x08000] = "vmulF.dnm", [0x08001] = "vnmulF.dnm",
|
||||
[0x0c000] = "vaddF.dnm", [0x0c001] = "vsubF.dnm",
|
||||
[0x20000] = "vdivF.dnm",
|
||||
[0x24000] = "vfnmsF.dnm", [0x24001] = "vfnmaF.dnm",
|
||||
[0x28000] = "vfmaF.dnm", [0x28001] = "vfmsF.dnm",
|
||||
[0x2c000] = "vmovF.dY",
|
||||
[0x2c001] = {
|
||||
shift = 7, mask = 0x1e01,
|
||||
[0] = "vmovF.dm", "vabsF.dm",
|
||||
[0x0200] = "vnegF.dm", [0x0201] = "vsqrtF.dm",
|
||||
[0x0800] = "vcmpF.dm", [0x0801] = "vcmpeF.dm",
|
||||
[0x0a00] = "vcmpzF.d", [0x0a01] = "vcmpzeF.d",
|
||||
[0x0e01] = "vcvtG.dF.m",
|
||||
[0x1000] = "vcvt.f32.u32Fdm", [0x1001] = "vcvt.f32.s32Fdm",
|
||||
[0x1800] = "vcvtr.u32F.dm", [0x1801] = "vcvt.u32F.dm",
|
||||
[0x1a00] = "vcvtr.s32F.dm", [0x1a01] = "vcvt.s32F.dm",
|
||||
},
|
||||
}
|
||||
|
||||
local map_vfpd = {
|
||||
shift = 6, mask = 0x2c001,
|
||||
[0] = "vmlaG.dnm", "vmlsG.dnm",
|
||||
[0x04000] = "vnmlsG.dnm", [0x04001] = "vnmlaG.dnm",
|
||||
[0x08000] = "vmulG.dnm", [0x08001] = "vnmulG.dnm",
|
||||
[0x0c000] = "vaddG.dnm", [0x0c001] = "vsubG.dnm",
|
||||
[0x20000] = "vdivG.dnm",
|
||||
[0x24000] = "vfnmsG.dnm", [0x24001] = "vfnmaG.dnm",
|
||||
[0x28000] = "vfmaG.dnm", [0x28001] = "vfmsG.dnm",
|
||||
[0x2c000] = "vmovG.dY",
|
||||
[0x2c001] = {
|
||||
shift = 7, mask = 0x1e01,
|
||||
[0] = "vmovG.dm", "vabsG.dm",
|
||||
[0x0200] = "vnegG.dm", [0x0201] = "vsqrtG.dm",
|
||||
[0x0800] = "vcmpG.dm", [0x0801] = "vcmpeG.dm",
|
||||
[0x0a00] = "vcmpzG.d", [0x0a01] = "vcmpzeG.d",
|
||||
[0x0e01] = "vcvtF.dG.m",
|
||||
[0x1000] = "vcvt.f64.u32GdFm", [0x1001] = "vcvt.f64.s32GdFm",
|
||||
[0x1800] = "vcvtr.u32FdG.m", [0x1801] = "vcvt.u32FdG.m",
|
||||
[0x1a00] = "vcvtr.s32FdG.m", [0x1a01] = "vcvt.s32FdG.m",
|
||||
},
|
||||
}
|
||||
|
||||
local map_datac = {
|
||||
shift = 24, mask = 1,
|
||||
[0] = {
|
||||
shift = 4, mask = 1,
|
||||
[0] = {
|
||||
shift = 8, mask = 15,
|
||||
[10] = map_vfps,
|
||||
[11] = map_vfpd,
|
||||
-- NYI cdp, mcr, mrc.
|
||||
},
|
||||
{
|
||||
shift = 8, mask = 15,
|
||||
[10] = {
|
||||
shift = 20, mask = 15,
|
||||
[0] = "vmovFnD", "vmovFDn",
|
||||
[14] = "vmsrD",
|
||||
[15] = { shift = 12, mask = 15, [15] = "vmrs", _ = "vmrsD", },
|
||||
},
|
||||
},
|
||||
},
|
||||
"svcT",
|
||||
}
|
||||
|
||||
local map_loadcu = {
|
||||
shift = 0, mask = 0, -- NYI unconditional CP load/store.
|
||||
}
|
||||
|
||||
local map_datacu = {
|
||||
shift = 0, mask = 0, -- NYI unconditional CP data.
|
||||
}
|
||||
|
||||
local map_simddata = {
|
||||
shift = 0, mask = 0, -- NYI SIMD data.
|
||||
}
|
||||
|
||||
local map_simdload = {
|
||||
shift = 0, mask = 0, -- NYI SIMD load/store, preload.
|
||||
}
|
||||
|
||||
local map_preload = {
|
||||
shift = 0, mask = 0, -- NYI preload.
|
||||
}
|
||||
|
||||
local map_media = {
|
||||
shift = 20, mask = 31,
|
||||
[0] = false,
|
||||
{ --01
|
||||
shift = 5, mask = 7,
|
||||
[0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM",
|
||||
"sadd8DNM", false, false, "ssub8DNM",
|
||||
},
|
||||
{ --02
|
||||
shift = 5, mask = 7,
|
||||
[0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM",
|
||||
"qadd8DNM", false, false, "qsub8DNM",
|
||||
},
|
||||
{ --03
|
||||
shift = 5, mask = 7,
|
||||
[0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM",
|
||||
"shadd8DNM", false, false, "shsub8DNM",
|
||||
},
|
||||
false,
|
||||
{ --05
|
||||
shift = 5, mask = 7,
|
||||
[0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM",
|
||||
"uadd8DNM", false, false, "usub8DNM",
|
||||
},
|
||||
{ --06
|
||||
shift = 5, mask = 7,
|
||||
[0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM",
|
||||
"uqadd8DNM", false, false, "uqsub8DNM",
|
||||
},
|
||||
{ --07
|
||||
shift = 5, mask = 7,
|
||||
[0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM",
|
||||
"uhadd8DNM", false, false, "uhsub8DNM",
|
||||
},
|
||||
{ --08
|
||||
shift = 5, mask = 7,
|
||||
[0] = "pkhbtDNMU", false, "pkhtbDNMU",
|
||||
{ shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", },
|
||||
"pkhbtDNMU", "selDNM", "pkhtbDNMU",
|
||||
},
|
||||
false,
|
||||
{ --0a
|
||||
shift = 5, mask = 7,
|
||||
[0] = "ssatDxMu", "ssat16DxM", "ssatDxMu",
|
||||
{ shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", },
|
||||
"ssatDxMu", false, "ssatDxMu",
|
||||
},
|
||||
{ --0b
|
||||
shift = 5, mask = 7,
|
||||
[0] = "ssatDxMu", "revDM", "ssatDxMu",
|
||||
{ shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", },
|
||||
"ssatDxMu", "rev16DM", "ssatDxMu",
|
||||
},
|
||||
{ --0c
|
||||
shift = 5, mask = 7,
|
||||
[3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", },
|
||||
},
|
||||
false,
|
||||
{ --0e
|
||||
shift = 5, mask = 7,
|
||||
[0] = "usatDwMu", "usat16DwM", "usatDwMu",
|
||||
{ shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", },
|
||||
"usatDwMu", false, "usatDwMu",
|
||||
},
|
||||
{ --0f
|
||||
shift = 5, mask = 7,
|
||||
[0] = "usatDwMu", "rbitDM", "usatDwMu",
|
||||
{ shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", },
|
||||
"usatDwMu", "revshDM", "usatDwMu",
|
||||
},
|
||||
{ --10
|
||||
shift = 12, mask = 15,
|
||||
[15] = {
|
||||
shift = 5, mask = 7,
|
||||
"smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS",
|
||||
},
|
||||
_ = {
|
||||
shift = 5, mask = 7,
|
||||
[0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD",
|
||||
},
|
||||
},
|
||||
false, false, false,
|
||||
{ --14
|
||||
shift = 5, mask = 7,
|
||||
[0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS",
|
||||
},
|
||||
{ --15
|
||||
shift = 5, mask = 7,
|
||||
[0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", },
|
||||
{ shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", },
|
||||
false, false, false, false,
|
||||
"smmlsNMSD", "smmlsrNMSD",
|
||||
},
|
||||
false, false,
|
||||
{ --18
|
||||
shift = 5, mask = 7,
|
||||
[0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", },
|
||||
},
|
||||
false,
|
||||
{ --1a
|
||||
shift = 5, mask = 3, [2] = "sbfxDMvw",
|
||||
},
|
||||
{ --1b
|
||||
shift = 5, mask = 3, [2] = "sbfxDMvw",
|
||||
},
|
||||
{ --1c
|
||||
shift = 5, mask = 3,
|
||||
[0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
|
||||
},
|
||||
{ --1d
|
||||
shift = 5, mask = 3,
|
||||
[0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
|
||||
},
|
||||
{ --1e
|
||||
shift = 5, mask = 3, [2] = "ubfxDMvw",
|
||||
},
|
||||
{ --1f
|
||||
shift = 5, mask = 3, [2] = "ubfxDMvw",
|
||||
},
|
||||
}
|
||||
|
||||
local map_load = {
|
||||
shift = 21, mask = 9,
|
||||
{
|
||||
shift = 20, mask = 5,
|
||||
[0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL",
|
||||
},
|
||||
_ = {
|
||||
shift = 20, mask = 5,
|
||||
[0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL",
|
||||
}
|
||||
}
|
||||
|
||||
local map_load1 = {
|
||||
shift = 4, mask = 1,
|
||||
[0] = map_load, map_media,
|
||||
}
|
||||
|
||||
local map_loadm = {
|
||||
shift = 20, mask = 1,
|
||||
[0] = {
|
||||
shift = 23, mask = 3,
|
||||
[0] = "stmdaNR", "stmNR",
|
||||
{ shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR",
|
||||
},
|
||||
{
|
||||
shift = 23, mask = 3,
|
||||
[0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", },
|
||||
"ldmdbNR", "ldmibNR",
|
||||
},
|
||||
}
|
||||
|
||||
local map_data = {
|
||||
shift = 21, mask = 15,
|
||||
[0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs",
|
||||
"addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs",
|
||||
"tstNP", "teqNP", "cmpNP", "cmnNP",
|
||||
"orrDNPs", "movDPs", "bicDNPs", "mvnDPs",
|
||||
}
|
||||
|
||||
local map_mul = {
|
||||
shift = 21, mask = 7,
|
||||
[0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS",
|
||||
"umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs",
|
||||
}
|
||||
|
||||
local map_sync = {
|
||||
shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd.
|
||||
[0] = "swpDMN", false, false, false,
|
||||
"swpbDMN", false, false, false,
|
||||
"strexDMN", "ldrexDN", "strexdDN", "ldrexdDN",
|
||||
"strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN",
|
||||
}
|
||||
|
||||
local map_mulh = {
|
||||
shift = 21, mask = 3,
|
||||
[0] = { shift = 5, mask = 3,
|
||||
[0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", },
|
||||
{ shift = 5, mask = 3,
|
||||
[0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", },
|
||||
{ shift = 5, mask = 3,
|
||||
[0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", },
|
||||
{ shift = 5, mask = 3,
|
||||
[0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", },
|
||||
}
|
||||
|
||||
local map_misc = {
|
||||
shift = 4, mask = 7,
|
||||
-- NYI: decode PSR bits of msr.
|
||||
[0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", },
|
||||
{ shift = 21, mask = 3, "bxM", false, "clzDM", },
|
||||
{ shift = 21, mask = 3, "bxjM", },
|
||||
{ shift = 21, mask = 3, "blxM", },
|
||||
false,
|
||||
{ shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", },
|
||||
false,
|
||||
{ shift = 21, mask = 3, "bkptK", },
|
||||
}
|
||||
|
||||
local map_datar = {
|
||||
shift = 4, mask = 9,
|
||||
[9] = {
|
||||
shift = 5, mask = 3,
|
||||
[0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, },
|
||||
{ shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", },
|
||||
{ shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", },
|
||||
{ shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", },
|
||||
},
|
||||
_ = {
|
||||
shift = 20, mask = 25,
|
||||
[16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, },
|
||||
_ = {
|
||||
shift = 0, mask = 0xffffffff,
|
||||
[bor(0xe1a00000)] = "nop",
|
||||
_ = map_data,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
local map_datai = {
|
||||
shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12.
|
||||
[16] = "movwDW", [20] = "movtDW",
|
||||
[18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", },
|
||||
[22] = "msrNW",
|
||||
_ = map_data,
|
||||
}
|
||||
|
||||
local map_branch = {
|
||||
shift = 24, mask = 1,
|
||||
[0] = "bB", "blB"
|
||||
}
|
||||
|
||||
local map_condins = {
|
||||
[0] = map_datar, map_datai, map_load, map_load1,
|
||||
map_loadm, map_branch, map_loadc, map_datac
|
||||
}
|
||||
|
||||
-- NYI: setend.
|
||||
local map_uncondins = {
|
||||
[0] = false, map_simddata, map_simdload, map_preload,
|
||||
false, "blxB", map_loadcu, map_datacu,
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_gpr = {
|
||||
[0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
|
||||
}
|
||||
|
||||
local map_cond = {
|
||||
[0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
|
||||
"hi", "ls", "ge", "lt", "gt", "le", "al",
|
||||
}
|
||||
|
||||
local map_shift = { [0] = "lsl", "lsr", "asr", "ror", }
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Output a nicely formatted line with an opcode and operands.
|
||||
local function putop(ctx, text, operands)
|
||||
local pos = ctx.pos
|
||||
local extra = ""
|
||||
if ctx.rel then
|
||||
local sym = ctx.symtab[ctx.rel]
|
||||
if sym then
|
||||
extra = "\t->"..sym
|
||||
elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then
|
||||
extra = "\t; 0x"..tohex(ctx.rel)
|
||||
end
|
||||
end
|
||||
if ctx.hexdump > 0 then
|
||||
ctx.out(format("%08x %s %-5s %s%s\n",
|
||||
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
|
||||
else
|
||||
ctx.out(format("%08x %-5s %s%s\n",
|
||||
ctx.addr+pos, text, concat(operands, ", "), extra))
|
||||
end
|
||||
ctx.pos = pos + 4
|
||||
end
|
||||
|
||||
-- Fallback for unknown opcodes.
|
||||
local function unknown(ctx)
|
||||
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
|
||||
end
|
||||
|
||||
-- Format operand 2 of load/store opcodes.
|
||||
local function fmtload(ctx, op, pos)
|
||||
local base = map_gpr[band(rshift(op, 16), 15)]
|
||||
local x, ofs
|
||||
local ext = (band(op, 0x04000000) == 0)
|
||||
if not ext and band(op, 0x02000000) == 0 then
|
||||
ofs = band(op, 4095)
|
||||
if band(op, 0x00800000) == 0 then ofs = -ofs end
|
||||
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
|
||||
ofs = "#"..ofs
|
||||
elseif ext and band(op, 0x00400000) ~= 0 then
|
||||
ofs = band(op, 15) + band(rshift(op, 4), 0xf0)
|
||||
if band(op, 0x00800000) == 0 then ofs = -ofs end
|
||||
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
|
||||
ofs = "#"..ofs
|
||||
else
|
||||
ofs = map_gpr[band(op, 15)]
|
||||
if ext or band(op, 0xfe0) == 0 then
|
||||
elseif band(op, 0xfe0) == 0x60 then
|
||||
ofs = format("%s, rrx", ofs)
|
||||
else
|
||||
local sh = band(rshift(op, 7), 31)
|
||||
if sh == 0 then sh = 32 end
|
||||
ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh)
|
||||
end
|
||||
if band(op, 0x00800000) == 0 then ofs = "-"..ofs end
|
||||
end
|
||||
if ofs == "#0" then
|
||||
x = format("[%s]", base)
|
||||
elseif band(op, 0x01000000) == 0 then
|
||||
x = format("[%s], %s", base, ofs)
|
||||
else
|
||||
x = format("[%s, %s]", base, ofs)
|
||||
end
|
||||
if band(op, 0x01200000) == 0x01200000 then x = x.."!" end
|
||||
return x
|
||||
end
|
||||
|
||||
-- Format operand 2 of vector load/store opcodes.
|
||||
local function fmtvload(ctx, op, pos)
|
||||
local base = map_gpr[band(rshift(op, 16), 15)]
|
||||
local ofs = band(op, 255)*4
|
||||
if band(op, 0x00800000) == 0 then ofs = -ofs end
|
||||
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
|
||||
if ofs == 0 then
|
||||
return format("[%s]", base)
|
||||
else
|
||||
return format("[%s, #%d]", base, ofs)
|
||||
end
|
||||
end
|
||||
|
||||
local function fmtvr(op, vr, sh0, sh1)
|
||||
if vr == "s" then
|
||||
return format("s%d", 2*band(rshift(op, sh0), 15)+band(rshift(op, sh1), 1))
|
||||
else
|
||||
return format("d%d", band(rshift(op, sh0), 15)+band(rshift(op, sh1-4), 16))
|
||||
end
|
||||
end
|
||||
|
||||
-- Disassemble a single instruction.
|
||||
local function disass_ins(ctx)
|
||||
local pos = ctx.pos
|
||||
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
|
||||
local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
|
||||
local operands = {}
|
||||
local suffix = ""
|
||||
local last, name, pat
|
||||
local vr
|
||||
ctx.op = op
|
||||
ctx.rel = nil
|
||||
|
||||
local cond = rshift(op, 28)
|
||||
local opat
|
||||
if cond == 15 then
|
||||
opat = map_uncondins[band(rshift(op, 25), 7)]
|
||||
else
|
||||
if cond ~= 14 then suffix = map_cond[cond] end
|
||||
opat = map_condins[band(rshift(op, 25), 7)]
|
||||
end
|
||||
while type(opat) ~= "string" do
|
||||
if not opat then return unknown(ctx) end
|
||||
opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
|
||||
end
|
||||
name, pat = match(opat, "^([a-z0-9]*)(.*)")
|
||||
if sub(pat, 1, 1) == "." then
|
||||
local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)")
|
||||
suffix = suffix..s2
|
||||
pat = p2
|
||||
end
|
||||
|
||||
for p in gmatch(pat, ".") do
|
||||
local x = nil
|
||||
if p == "D" then
|
||||
x = map_gpr[band(rshift(op, 12), 15)]
|
||||
elseif p == "N" then
|
||||
x = map_gpr[band(rshift(op, 16), 15)]
|
||||
elseif p == "S" then
|
||||
x = map_gpr[band(rshift(op, 8), 15)]
|
||||
elseif p == "M" then
|
||||
x = map_gpr[band(op, 15)]
|
||||
elseif p == "d" then
|
||||
x = fmtvr(op, vr, 12, 22)
|
||||
elseif p == "n" then
|
||||
x = fmtvr(op, vr, 16, 7)
|
||||
elseif p == "m" then
|
||||
x = fmtvr(op, vr, 0, 5)
|
||||
elseif p == "P" then
|
||||
if band(op, 0x02000000) ~= 0 then
|
||||
x = ror(band(op, 255), 2*band(rshift(op, 8), 15))
|
||||
else
|
||||
x = map_gpr[band(op, 15)]
|
||||
if band(op, 0xff0) ~= 0 then
|
||||
operands[#operands+1] = x
|
||||
local s = map_shift[band(rshift(op, 5), 3)]
|
||||
local r = nil
|
||||
if band(op, 0xf90) == 0 then
|
||||
if s == "ror" then s = "rrx" else r = "#32" end
|
||||
elseif band(op, 0x10) == 0 then
|
||||
r = "#"..band(rshift(op, 7), 31)
|
||||
else
|
||||
r = map_gpr[band(rshift(op, 8), 15)]
|
||||
end
|
||||
if name == "mov" then name = s; x = r
|
||||
elseif r then x = format("%s %s", s, r)
|
||||
else x = s end
|
||||
end
|
||||
end
|
||||
elseif p == "L" then
|
||||
x = fmtload(ctx, op, pos)
|
||||
elseif p == "l" then
|
||||
x = fmtvload(ctx, op, pos)
|
||||
elseif p == "B" then
|
||||
local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6)
|
||||
if cond == 15 then addr = addr + band(rshift(op, 23), 2) end
|
||||
ctx.rel = addr
|
||||
x = "0x"..tohex(addr)
|
||||
elseif p == "F" then
|
||||
vr = "s"
|
||||
elseif p == "G" then
|
||||
vr = "d"
|
||||
elseif p == "." then
|
||||
suffix = suffix..(vr == "s" and ".f32" or ".f64")
|
||||
elseif p == "R" then
|
||||
if band(op, 0x00200000) ~= 0 and #operands == 1 then
|
||||
operands[1] = operands[1].."!"
|
||||
end
|
||||
local t = {}
|
||||
for i=0,15 do
|
||||
if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end
|
||||
end
|
||||
x = "{"..concat(t, ", ").."}"
|
||||
elseif p == "r" then
|
||||
if band(op, 0x00200000) ~= 0 and #operands == 2 then
|
||||
operands[1] = operands[1].."!"
|
||||
end
|
||||
local s = tonumber(sub(last, 2))
|
||||
local n = band(op, 255)
|
||||
if vr == "d" then n = rshift(n, 1) end
|
||||
operands[#operands] = format("{%s-%s%d}", last, vr, s+n-1)
|
||||
elseif p == "W" then
|
||||
x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000)
|
||||
elseif p == "T" then
|
||||
x = "#0x"..tohex(band(op, 0x00ffffff), 6)
|
||||
elseif p == "U" then
|
||||
x = band(rshift(op, 7), 31)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "u" then
|
||||
x = band(rshift(op, 7), 31)
|
||||
if band(op, 0x40) == 0 then
|
||||
if x == 0 then x = nil else x = "lsl #"..x end
|
||||
else
|
||||
if x == 0 then x = "asr #32" else x = "asr #"..x end
|
||||
end
|
||||
elseif p == "v" then
|
||||
x = band(rshift(op, 7), 31)
|
||||
elseif p == "w" then
|
||||
x = band(rshift(op, 16), 31)
|
||||
elseif p == "x" then
|
||||
x = band(rshift(op, 16), 31) + 1
|
||||
elseif p == "X" then
|
||||
x = band(rshift(op, 16), 31) - last + 1
|
||||
elseif p == "Y" then
|
||||
x = band(rshift(op, 12), 0xf0) + band(op, 0x0f)
|
||||
elseif p == "K" then
|
||||
x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4)
|
||||
elseif p == "s" then
|
||||
if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
if x then
|
||||
last = x
|
||||
if type(x) == "number" then x = "#"..x end
|
||||
operands[#operands+1] = x
|
||||
end
|
||||
end
|
||||
|
||||
return putop(ctx, name..suffix, operands)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Disassemble a block of code.
|
||||
local function disass_block(ctx, ofs, len)
|
||||
if not ofs then ofs = 0 end
|
||||
local stop = len and ofs+len or #ctx.code
|
||||
ctx.pos = ofs
|
||||
ctx.rel = nil
|
||||
while ctx.pos < stop do disass_ins(ctx) end
|
||||
end
|
||||
|
||||
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
|
||||
local function create_(code, addr, out)
|
||||
local ctx = {}
|
||||
ctx.code = code
|
||||
ctx.addr = addr or 0
|
||||
ctx.out = out or io.write
|
||||
ctx.symtab = {}
|
||||
ctx.disass = disass_block
|
||||
ctx.hexdump = 8
|
||||
return ctx
|
||||
end
|
||||
|
||||
-- Simple API: disassemble code (a string) at address and output via out.
|
||||
local function disass_(code, addr, out)
|
||||
create_(code, addr, out):disass()
|
||||
end
|
||||
|
||||
-- Return register name for RID.
|
||||
local function regname_(r)
|
||||
if r < 16 then return map_gpr[r] end
|
||||
return "d"..(r-16)
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
module(...)
|
||||
|
||||
create = create_
|
||||
disass = disass_
|
||||
regname = regname_
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT MIPS disassembler module.
|
||||
--
|
||||
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT/X license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This is a helper module used by the LuaJIT machine code dumper module.
|
||||
--
|
||||
-- It disassembles all standard MIPS32R1/R2 instructions.
|
||||
-- Default mode is big-endian, but see: dis_mipsel.lua
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local type = type
|
||||
local sub, byte, format = string.sub, string.byte, string.format
|
||||
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
|
||||
local concat = table.concat
|
||||
local bit = require("bit")
|
||||
local band, bor, tohex = bit.band, bit.bor, bit.tohex
|
||||
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Primary and extended opcode maps
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
|
||||
local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
|
||||
local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
|
||||
|
||||
local map_special = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
|
||||
map_movci, map_srl, "sraDTA",
|
||||
"sllvDTS", false, map_srlv, "sravDTS",
|
||||
"jrS", "jalrD1S", "movzDST", "movnDST",
|
||||
"syscallY", "breakY", false, "sync",
|
||||
"mfhiD", "mthiS", "mfloD", "mtloS",
|
||||
false, false, false, false,
|
||||
"multST", "multuST", "divST", "divuST",
|
||||
false, false, false, false,
|
||||
"addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
|
||||
"andDST", "orDST", "xorDST", "nor|notDST0",
|
||||
false, false, "sltDST", "sltuDST",
|
||||
false, false, false, false,
|
||||
"tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
|
||||
"teqSTZ", false, "tneSTZ",
|
||||
}
|
||||
|
||||
local map_special2 = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "maddST", "madduST", "mulDST", false,
|
||||
"msubST", "msubuST",
|
||||
[32] = "clzDS", [33] = "cloDS",
|
||||
[63] = "sdbbpY",
|
||||
}
|
||||
|
||||
local map_bshfl = {
|
||||
shift = 6, mask = 31,
|
||||
[2] = "wsbhDT",
|
||||
[16] = "sebDT",
|
||||
[24] = "sehDT",
|
||||
}
|
||||
|
||||
local map_special3 = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "extTSAK", [4] = "insTSAL",
|
||||
[32] = map_bshfl,
|
||||
[59] = "rdhwrTD",
|
||||
}
|
||||
|
||||
local map_regimm = {
|
||||
shift = 16, mask = 31,
|
||||
[0] = "bltzSB", "bgezSB", "bltzlSB", "bgezlSB",
|
||||
false, false, false, false,
|
||||
"tgeiSI", "tgeiuSI", "tltiSI", "tltiuSI",
|
||||
"teqiSI", false, "tneiSI", false,
|
||||
"bltzalSB", "bgezalSB", "bltzallSB", "bgezallSB",
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, "synciSO",
|
||||
}
|
||||
|
||||
local map_cop0 = {
|
||||
shift = 25, mask = 1,
|
||||
[0] = {
|
||||
shift = 21, mask = 15,
|
||||
[0] = "mfc0TDW", [4] = "mtc0TDW",
|
||||
[10] = "rdpgprDT",
|
||||
[11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", },
|
||||
[14] = "wrpgprDT",
|
||||
}, {
|
||||
shift = 0, mask = 63,
|
||||
[1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp",
|
||||
[24] = "eret", [31] = "deret",
|
||||
[32] = "wait",
|
||||
},
|
||||
}
|
||||
|
||||
local map_cop1s = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
|
||||
"sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG",
|
||||
"round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG",
|
||||
"round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG",
|
||||
false,
|
||||
{ shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" },
|
||||
"movz.sFGT", "movn.sFGT",
|
||||
false, "recip.sFG", "rsqrt.sFG", false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, "cvt.d.sFG", false, false,
|
||||
"cvt.w.sFG", "cvt.l.sFG", "cvt.ps.sFGH", false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
"c.f.sVGH", "c.un.sVGH", "c.eq.sVGH", "c.ueq.sVGH",
|
||||
"c.olt.sVGH", "c.ult.sVGH", "c.ole.sVGH", "c.ule.sVGH",
|
||||
"c.sf.sVGH", "c.ngle.sVGH", "c.seq.sVGH", "c.ngl.sVGH",
|
||||
"c.lt.sVGH", "c.nge.sVGH", "c.le.sVGH", "c.ngt.sVGH",
|
||||
}
|
||||
|
||||
local map_cop1d = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH",
|
||||
"sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG",
|
||||
"round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG",
|
||||
"round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG",
|
||||
false,
|
||||
{ shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" },
|
||||
"movz.dFGT", "movn.dFGT",
|
||||
false, "recip.dFG", "rsqrt.dFG", false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
"cvt.s.dFG", false, false, false,
|
||||
"cvt.w.dFG", "cvt.l.dFG", false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
"c.f.dVGH", "c.un.dVGH", "c.eq.dVGH", "c.ueq.dVGH",
|
||||
"c.olt.dVGH", "c.ult.dVGH", "c.ole.dVGH", "c.ule.dVGH",
|
||||
"c.df.dVGH", "c.ngle.dVGH", "c.deq.dVGH", "c.ngl.dVGH",
|
||||
"c.lt.dVGH", "c.nge.dVGH", "c.le.dVGH", "c.ngt.dVGH",
|
||||
}
|
||||
|
||||
local map_cop1ps = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "add.psFGH", "sub.psFGH", "mul.psFGH", false,
|
||||
false, "abs.psFG", "mov.psFG", "neg.psFG",
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false,
|
||||
{ shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" },
|
||||
"movz.psFGT", "movn.psFGT",
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
"cvt.s.puFG", false, false, false,
|
||||
false, false, false, false,
|
||||
"cvt.s.plFG", false, false, false,
|
||||
"pll.psFGH", "plu.psFGH", "pul.psFGH", "puu.psFGH",
|
||||
"c.f.psVGH", "c.un.psVGH", "c.eq.psVGH", "c.ueq.psVGH",
|
||||
"c.olt.psVGH", "c.ult.psVGH", "c.ole.psVGH", "c.ule.psVGH",
|
||||
"c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH",
|
||||
"c.lt.psVGH", "c.nge.psVGH", "c.le.psVGH", "c.ngt.psVGH",
|
||||
}
|
||||
|
||||
local map_cop1w = {
|
||||
shift = 0, mask = 63,
|
||||
[32] = "cvt.s.wFG", [33] = "cvt.d.wFG",
|
||||
}
|
||||
|
||||
local map_cop1l = {
|
||||
shift = 0, mask = 63,
|
||||
[32] = "cvt.s.lFG", [33] = "cvt.d.lFG",
|
||||
}
|
||||
|
||||
local map_cop1bc = {
|
||||
shift = 16, mask = 3,
|
||||
[0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB",
|
||||
}
|
||||
|
||||
local map_cop1 = {
|
||||
shift = 21, mask = 31,
|
||||
[0] = "mfc1TG", false, "cfc1TG", "mfhc1TG",
|
||||
"mtc1TG", false, "ctc1TG", "mthc1TG",
|
||||
map_cop1bc, false, false, false,
|
||||
false, false, false, false,
|
||||
map_cop1s, map_cop1d, false, false,
|
||||
map_cop1w, map_cop1l, map_cop1ps,
|
||||
}
|
||||
|
||||
local map_cop1x = {
|
||||
shift = 0, mask = 63,
|
||||
[0] = "lwxc1FSX", "ldxc1FSX", false, false,
|
||||
false, "luxc1FSX", false, false,
|
||||
"swxc1FSX", "sdxc1FSX", false, false,
|
||||
false, "suxc1FSX", false, "prefxMSX",
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, "alnv.psFGHS", false,
|
||||
"madd.sFRGH", "madd.dFRGH", false, false,
|
||||
false, false, "madd.psFRGH", false,
|
||||
"msub.sFRGH", "msub.dFRGH", false, false,
|
||||
false, false, "msub.psFRGH", false,
|
||||
"nmadd.sFRGH", "nmadd.dFRGH", false, false,
|
||||
false, false, "nmadd.psFRGH", false,
|
||||
"nmsub.sFRGH", "nmsub.dFRGH", false, false,
|
||||
false, false, "nmsub.psFRGH", false,
|
||||
}
|
||||
|
||||
local map_pri = {
|
||||
[0] = map_special, map_regimm, "jJ", "jalJ",
|
||||
"beq|beqz|bST00B", "bne|bnezST0B", "blezSB", "bgtzSB",
|
||||
"addiTSI", "addiu|liTS0I", "sltiTSI", "sltiuTSI",
|
||||
"andiTSU", "ori|liTS0U", "xoriTSU", "luiTU",
|
||||
map_cop0, map_cop1, false, map_cop1x,
|
||||
"beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB",
|
||||
false, false, false, false,
|
||||
map_special2, false, false, map_special3,
|
||||
"lbTSO", "lhTSO", "lwlTSO", "lwTSO",
|
||||
"lbuTSO", "lhuTSO", "lwrTSO", false,
|
||||
"sbTSO", "shTSO", "swlTSO", "swTSO",
|
||||
false, false, "swrTSO", "cacheNSO",
|
||||
"llTSO", "lwc1HSO", "lwc2TSO", "prefNSO",
|
||||
false, "ldc1HSO", "ldc2TSO", false,
|
||||
"scTSO", "swc1HSO", "swc2TSO", false,
|
||||
false, "sdc1HSO", "sdc2TSO", false,
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_gpr = {
|
||||
[0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra",
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Output a nicely formatted line with an opcode and operands.
|
||||
local function putop(ctx, text, operands)
|
||||
local pos = ctx.pos
|
||||
local extra = ""
|
||||
if ctx.rel then
|
||||
local sym = ctx.symtab[ctx.rel]
|
||||
if sym then extra = "\t->"..sym end
|
||||
end
|
||||
if ctx.hexdump > 0 then
|
||||
ctx.out(format("%08x %s %-7s %s%s\n",
|
||||
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
|
||||
else
|
||||
ctx.out(format("%08x %-7s %s%s\n",
|
||||
ctx.addr+pos, text, concat(operands, ", "), extra))
|
||||
end
|
||||
ctx.pos = pos + 4
|
||||
end
|
||||
|
||||
-- Fallback for unknown opcodes.
|
||||
local function unknown(ctx)
|
||||
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
|
||||
end
|
||||
|
||||
local function get_be(ctx)
|
||||
local pos = ctx.pos
|
||||
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
|
||||
return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
|
||||
end
|
||||
|
||||
local function get_le(ctx)
|
||||
local pos = ctx.pos
|
||||
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
|
||||
return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
|
||||
end
|
||||
|
||||
-- Disassemble a single instruction.
|
||||
local function disass_ins(ctx)
|
||||
local op = ctx:get()
|
||||
local operands = {}
|
||||
local last = nil
|
||||
ctx.op = op
|
||||
ctx.rel = nil
|
||||
|
||||
local opat = map_pri[rshift(op, 26)]
|
||||
while type(opat) ~= "string" do
|
||||
if not opat then return unknown(ctx) end
|
||||
opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
|
||||
end
|
||||
local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
|
||||
local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
|
||||
if altname then pat = pat2 end
|
||||
|
||||
for p in gmatch(pat, ".") do
|
||||
local x = nil
|
||||
if p == "S" then
|
||||
x = map_gpr[band(rshift(op, 21), 31)]
|
||||
elseif p == "T" then
|
||||
x = map_gpr[band(rshift(op, 16), 31)]
|
||||
elseif p == "D" then
|
||||
x = map_gpr[band(rshift(op, 11), 31)]
|
||||
elseif p == "F" then
|
||||
x = "f"..band(rshift(op, 6), 31)
|
||||
elseif p == "G" then
|
||||
x = "f"..band(rshift(op, 11), 31)
|
||||
elseif p == "H" then
|
||||
x = "f"..band(rshift(op, 16), 31)
|
||||
elseif p == "R" then
|
||||
x = "f"..band(rshift(op, 21), 31)
|
||||
elseif p == "A" then
|
||||
x = band(rshift(op, 6), 31)
|
||||
elseif p == "M" then
|
||||
x = band(rshift(op, 11), 31)
|
||||
elseif p == "N" then
|
||||
x = band(rshift(op, 16), 31)
|
||||
elseif p == "C" then
|
||||
x = band(rshift(op, 18), 7)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "K" then
|
||||
x = band(rshift(op, 11), 31) + 1
|
||||
elseif p == "L" then
|
||||
x = band(rshift(op, 11), 31) - last + 1
|
||||
elseif p == "I" then
|
||||
x = arshift(lshift(op, 16), 16)
|
||||
elseif p == "U" then
|
||||
x = band(op, 0xffff)
|
||||
elseif p == "O" then
|
||||
local disp = arshift(lshift(op, 16), 16)
|
||||
operands[#operands] = format("%d(%s)", disp, last)
|
||||
elseif p == "X" then
|
||||
local index = map_gpr[band(rshift(op, 16), 31)]
|
||||
operands[#operands] = format("%s(%s)", index, last)
|
||||
elseif p == "B" then
|
||||
x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 16)*4 + 4
|
||||
ctx.rel = x
|
||||
x = "0x"..tohex(x)
|
||||
elseif p == "J" then
|
||||
x = band(ctx.addr + ctx.pos, 0xf0000000) + band(op, 0x03ffffff)*4
|
||||
ctx.rel = x
|
||||
x = "0x"..tohex(x)
|
||||
elseif p == "V" then
|
||||
x = band(rshift(op, 8), 7)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "W" then
|
||||
x = band(op, 7)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "Y" then
|
||||
x = band(rshift(op, 6), 0x000fffff)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "Z" then
|
||||
x = band(rshift(op, 6), 1023)
|
||||
if x == 0 then x = nil end
|
||||
elseif p == "0" then
|
||||
if last == "r0" or last == 0 then
|
||||
local n = #operands
|
||||
operands[n] = nil
|
||||
last = operands[n-1]
|
||||
if altname then
|
||||
local a1, a2 = match(altname, "([^|]*)|(.*)")
|
||||
if a1 then name, altname = a1, a2
|
||||
else name = altname end
|
||||
end
|
||||
end
|
||||
elseif p == "1" then
|
||||
if last == "ra" then
|
||||
operands[#operands] = nil
|
||||
end
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
if x then operands[#operands+1] = x; last = x end
|
||||
end
|
||||
|
||||
return putop(ctx, name, operands)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Disassemble a block of code.
|
||||
local function disass_block(ctx, ofs, len)
|
||||
if not ofs then ofs = 0 end
|
||||
local stop = len and ofs+len or #ctx.code
|
||||
stop = stop - stop % 4
|
||||
ctx.pos = ofs - ofs % 4
|
||||
ctx.rel = nil
|
||||
while ctx.pos < stop do disass_ins(ctx) end
|
||||
end
|
||||
|
||||
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
|
||||
local function create_(code, addr, out)
|
||||
local ctx = {}
|
||||
ctx.code = code
|
||||
ctx.addr = addr or 0
|
||||
ctx.out = out or io.write
|
||||
ctx.symtab = {}
|
||||
ctx.disass = disass_block
|
||||
ctx.hexdump = 8
|
||||
ctx.get = get_be
|
||||
return ctx
|
||||
end
|
||||
|
||||
local function create_el_(code, addr, out)
|
||||
local ctx = create_(code, addr, out)
|
||||
ctx.get = get_le
|
||||
return ctx
|
||||
end
|
||||
|
||||
-- Simple API: disassemble code (a string) at address and output via out.
|
||||
local function disass_(code, addr, out)
|
||||
create_(code, addr, out):disass()
|
||||
end
|
||||
|
||||
local function disass_el_(code, addr, out)
|
||||
create_el_(code, addr, out):disass()
|
||||
end
|
||||
|
||||
-- Return register name for RID.
|
||||
local function regname_(r)
|
||||
if r < 32 then return map_gpr[r] end
|
||||
return "f"..(r-32)
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
module(...)
|
||||
|
||||
create = create_
|
||||
create_el = create_el_
|
||||
disass = disass_
|
||||
disass_el = disass_el_
|
||||
regname = regname_
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT MIPSEL disassembler wrapper module.
|
||||
--
|
||||
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This module just exports the little-endian functions from the
|
||||
-- MIPS disassembler module. All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local require = require
|
||||
|
||||
module(...)
|
||||
|
||||
local dis_mips = require(_PACKAGE.."dis_mips")
|
||||
|
||||
create = dis_mips.create_el
|
||||
disass = dis_mips.disass_el
|
||||
regname = dis_mips.regname
|
||||
|
||||
@@ -0,0 +1,591 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT PPC disassembler module.
|
||||
--
|
||||
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT/X license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This is a helper module used by the LuaJIT machine code dumper module.
|
||||
--
|
||||
-- It disassembles all common, non-privileged 32/64 bit PowerPC instructions
|
||||
-- plus the e500 SPE instructions and some Cell/Xenon extensions.
|
||||
--
|
||||
-- NYI: VMX, VMX128
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local type = type
|
||||
local sub, byte, format = string.sub, string.byte, string.format
|
||||
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
|
||||
local concat = table.concat
|
||||
local bit = require("bit")
|
||||
local band, bor, tohex = bit.band, bit.bor, bit.tohex
|
||||
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Primary and extended opcode maps
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_crops = {
|
||||
shift = 1, mask = 1023,
|
||||
[0] = "mcrfXX",
|
||||
[33] = "crnor|crnotCCC=", [129] = "crandcCCC",
|
||||
[193] = "crxor|crclrCCC%", [225] = "crnandCCC",
|
||||
[257] = "crandCCC", [289] = "creqv|crsetCCC%",
|
||||
[417] = "crorcCCC", [449] = "cror|crmoveCCC=",
|
||||
[16] = "b_lrKB", [528] = "b_ctrKB",
|
||||
[150] = "isync",
|
||||
}
|
||||
|
||||
local map_rlwinm = setmetatable({
|
||||
shift = 0, mask = -1,
|
||||
},
|
||||
{ __index = function(t, x)
|
||||
local rot = band(rshift(x, 11), 31)
|
||||
local mb = band(rshift(x, 6), 31)
|
||||
local me = band(rshift(x, 1), 31)
|
||||
if mb == 0 and me == 31-rot then
|
||||
return "slwiRR~A."
|
||||
elseif me == 31 and mb == 32-rot then
|
||||
return "srwiRR~-A."
|
||||
else
|
||||
return "rlwinmRR~AAA."
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
local map_rld = {
|
||||
shift = 2, mask = 7,
|
||||
[0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.",
|
||||
{
|
||||
shift = 1, mask = 1,
|
||||
[0] = "rldclRR~RM.", "rldcrRR~RM.",
|
||||
},
|
||||
}
|
||||
|
||||
local map_ext = setmetatable({
|
||||
shift = 1, mask = 1023,
|
||||
|
||||
[0] = "cmp_YLRR", [32] = "cmpl_YLRR",
|
||||
[4] = "twARR", [68] = "tdARR",
|
||||
|
||||
[8] = "subfcRRR.", [40] = "subfRRR.",
|
||||
[104] = "negRR.", [136] = "subfeRRR.",
|
||||
[200] = "subfzeRR.", [232] = "subfmeRR.",
|
||||
[520] = "subfcoRRR.", [552] = "subfoRRR.",
|
||||
[616] = "negoRR.", [648] = "subfeoRRR.",
|
||||
[712] = "subfzeoRR.", [744] = "subfmeoRR.",
|
||||
|
||||
[9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.",
|
||||
[457] = "divduRRR.", [489] = "divdRRR.",
|
||||
[745] = "mulldoRRR.",
|
||||
[969] = "divduoRRR.", [1001] = "divdoRRR.",
|
||||
|
||||
[10] = "addcRRR.", [138] = "addeRRR.",
|
||||
[202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.",
|
||||
[522] = "addcoRRR.", [650] = "addeoRRR.",
|
||||
[714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.",
|
||||
|
||||
[11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.",
|
||||
[459] = "divwuRRR.", [491] = "divwRRR.",
|
||||
[747] = "mullwoRRR.",
|
||||
[971] = "divwouRRR.", [1003] = "divwoRRR.",
|
||||
|
||||
[15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR",
|
||||
|
||||
[144] = { shift = 20, mask = 1, [0] = "mtcrfRZ~", "mtocrfRZ~", },
|
||||
[19] = { shift = 20, mask = 1, [0] = "mfcrR", "mfocrfRZ", },
|
||||
[371] = { shift = 11, mask = 1023, [392] = "mftbR", [424] = "mftbuR", },
|
||||
[339] = {
|
||||
shift = 11, mask = 1023,
|
||||
[32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR",
|
||||
},
|
||||
[467] = {
|
||||
shift = 11, mask = 1023,
|
||||
[32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR",
|
||||
},
|
||||
|
||||
[20] = "lwarxRR0R", [84] = "ldarxRR0R",
|
||||
|
||||
[21] = "ldxRR0R", [53] = "lduxRRR",
|
||||
[149] = "stdxRR0R", [181] = "stduxRRR",
|
||||
[341] = "lwaxRR0R", [373] = "lwauxRRR",
|
||||
|
||||
[23] = "lwzxRR0R", [55] = "lwzuxRRR",
|
||||
[87] = "lbzxRR0R", [119] = "lbzuxRRR",
|
||||
[151] = "stwxRR0R", [183] = "stwuxRRR",
|
||||
[215] = "stbxRR0R", [247] = "stbuxRRR",
|
||||
[279] = "lhzxRR0R", [311] = "lhzuxRRR",
|
||||
[343] = "lhaxRR0R", [375] = "lhauxRRR",
|
||||
[407] = "sthxRR0R", [439] = "sthuxRRR",
|
||||
|
||||
[54] = "dcbst-R0R", [86] = "dcbf-R0R",
|
||||
[150] = "stwcxRR0R.", [214] = "stdcxRR0R.",
|
||||
[246] = "dcbtst-R0R", [278] = "dcbt-R0R",
|
||||
[310] = "eciwxRR0R", [438] = "ecowxRR0R",
|
||||
[470] = "dcbi-RR",
|
||||
|
||||
[598] = {
|
||||
shift = 21, mask = 3,
|
||||
[0] = "sync", "lwsync", "ptesync",
|
||||
},
|
||||
[758] = "dcba-RR",
|
||||
[854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R",
|
||||
|
||||
[26] = "cntlzwRR~", [58] = "cntlzdRR~",
|
||||
[122] = "popcntbRR~",
|
||||
[154] = "prtywRR~", [186] = "prtydRR~",
|
||||
|
||||
[28] = "andRR~R.", [60] = "andcRR~R.", [124] = "nor|notRR~R=.",
|
||||
[284] = "eqvRR~R.", [316] = "xorRR~R.",
|
||||
[412] = "orcRR~R.", [444] = "or|mrRR~R=.", [476] = "nandRR~R.",
|
||||
[508] = "cmpbRR~R",
|
||||
|
||||
[512] = "mcrxrX",
|
||||
|
||||
[532] = "ldbrxRR0R", [660] = "stdbrxRR0R",
|
||||
|
||||
[533] = "lswxRR0R", [597] = "lswiRR0A",
|
||||
[661] = "stswxRR0R", [725] = "stswiRR0A",
|
||||
|
||||
[534] = "lwbrxRR0R", [662] = "stwbrxRR0R",
|
||||
[790] = "lhbrxRR0R", [918] = "sthbrxRR0R",
|
||||
|
||||
[535] = "lfsxFR0R", [567] = "lfsuxFRR",
|
||||
[599] = "lfdxFR0R", [631] = "lfduxFRR",
|
||||
[663] = "stfsxFR0R", [695] = "stfsuxFRR",
|
||||
[727] = "stfdxFR0R", [759] = "stfduxFR0R",
|
||||
[855] = "lfiwaxFR0R",
|
||||
[983] = "stfiwxFR0R",
|
||||
|
||||
[24] = "slwRR~R.",
|
||||
|
||||
[27] = "sldRR~R.", [536] = "srwRR~R.",
|
||||
[792] = "srawRR~R.", [824] = "srawiRR~A.",
|
||||
|
||||
[794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.",
|
||||
[922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.",
|
||||
|
||||
[539] = "srdRR~R.",
|
||||
},
|
||||
{ __index = function(t, x)
|
||||
if band(x, 31) == 15 then return "iselRRRC" end
|
||||
end
|
||||
})
|
||||
|
||||
local map_ld = {
|
||||
shift = 0, mask = 3,
|
||||
[0] = "ldRRE", "lduRRE", "lwaRRE",
|
||||
}
|
||||
|
||||
local map_std = {
|
||||
shift = 0, mask = 3,
|
||||
[0] = "stdRRE", "stduRRE",
|
||||
}
|
||||
|
||||
local map_fps = {
|
||||
shift = 5, mask = 1,
|
||||
{
|
||||
shift = 1, mask = 15,
|
||||
[0] = false, false, "fdivsFFF.", false,
|
||||
"fsubsFFF.", "faddsFFF.", "fsqrtsF-F.", false,
|
||||
"fresF-F.", "fmulsFF-F.", "frsqrtesF-F.", false,
|
||||
"fmsubsFFFF~.", "fmaddsFFFF~.", "fnmsubsFFFF~.", "fnmaddsFFFF~.",
|
||||
}
|
||||
}
|
||||
|
||||
local map_fpd = {
|
||||
shift = 5, mask = 1,
|
||||
[0] = {
|
||||
shift = 1, mask = 1023,
|
||||
[0] = "fcmpuXFF", [32] = "fcmpoXFF", [64] = "mcrfsXX",
|
||||
[38] = "mtfsb1A.", [70] = "mtfsb0A.", [134] = "mtfsfiA>>-A>",
|
||||
[8] = "fcpsgnFFF.", [40] = "fnegF-F.", [72] = "fmrF-F.",
|
||||
[136] = "fnabsF-F.", [264] = "fabsF-F.",
|
||||
[12] = "frspF-F.",
|
||||
[14] = "fctiwF-F.", [15] = "fctiwzF-F.",
|
||||
[583] = "mffsF.", [711] = "mtfsfZF.",
|
||||
[392] = "frinF-F.", [424] = "frizF-F.",
|
||||
[456] = "fripF-F.", [488] = "frimF-F.",
|
||||
[814] = "fctidF-F.", [815] = "fctidzF-F.", [846] = "fcfidF-F.",
|
||||
},
|
||||
{
|
||||
shift = 1, mask = 15,
|
||||
[0] = false, false, "fdivFFF.", false,
|
||||
"fsubFFF.", "faddFFF.", "fsqrtF-F.", "fselFFFF~.",
|
||||
"freF-F.", "fmulFF-F.", "frsqrteF-F.", false,
|
||||
"fmsubFFFF~.", "fmaddFFFF~.", "fnmsubFFFF~.", "fnmaddFFFF~.",
|
||||
}
|
||||
}
|
||||
|
||||
local map_spe = {
|
||||
shift = 0, mask = 2047,
|
||||
|
||||
[512] = "evaddwRRR", [514] = "evaddiwRAR~",
|
||||
[516] = "evsubwRRR~", [518] = "evsubiwRAR~",
|
||||
[520] = "evabsRR", [521] = "evnegRR",
|
||||
[522] = "evextsbRR", [523] = "evextshRR", [524] = "evrndwRR",
|
||||
[525] = "evcntlzwRR", [526] = "evcntlswRR",
|
||||
|
||||
[527] = "brincRRR",
|
||||
|
||||
[529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR",
|
||||
[535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=",
|
||||
[537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR",
|
||||
|
||||
[544] = "evsrwuRRR", [545] = "evsrwsRRR",
|
||||
[546] = "evsrwiuRRA", [547] = "evsrwisRRA",
|
||||
[548] = "evslwRRR", [550] = "evslwiRRA",
|
||||
[552] = "evrlwRRR", [553] = "evsplatiRS",
|
||||
[554] = "evrlwiRRA", [555] = "evsplatfiRS",
|
||||
[556] = "evmergehiRRR", [557] = "evmergeloRRR",
|
||||
[558] = "evmergehiloRRR", [559] = "evmergelohiRRR",
|
||||
|
||||
[560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR",
|
||||
[562] = "evcmpltuYRR", [563] = "evcmpltsYRR",
|
||||
[564] = "evcmpeqYRR",
|
||||
|
||||
[632] = "evselRRR", [633] = "evselRRRW",
|
||||
[634] = "evselRRRW", [635] = "evselRRRW",
|
||||
[636] = "evselRRRW", [637] = "evselRRRW",
|
||||
[638] = "evselRRRW", [639] = "evselRRRW",
|
||||
|
||||
[640] = "evfsaddRRR", [641] = "evfssubRRR",
|
||||
[644] = "evfsabsRR", [645] = "evfsnabsRR", [646] = "evfsnegRR",
|
||||
[648] = "evfsmulRRR", [649] = "evfsdivRRR",
|
||||
[652] = "evfscmpgtYRR", [653] = "evfscmpltYRR", [654] = "evfscmpeqYRR",
|
||||
[656] = "evfscfuiR-R", [657] = "evfscfsiR-R",
|
||||
[658] = "evfscfufR-R", [659] = "evfscfsfR-R",
|
||||
[660] = "evfsctuiR-R", [661] = "evfsctsiR-R",
|
||||
[662] = "evfsctufR-R", [663] = "evfsctsfR-R",
|
||||
[664] = "evfsctuizR-R", [666] = "evfsctsizR-R",
|
||||
[668] = "evfststgtYRR", [669] = "evfststltYRR", [670] = "evfststeqYRR",
|
||||
|
||||
[704] = "efsaddRRR", [705] = "efssubRRR",
|
||||
[708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR",
|
||||
[712] = "efsmulRRR", [713] = "efsdivRRR",
|
||||
[716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR",
|
||||
[719] = "efscfdR-R",
|
||||
[720] = "efscfuiR-R", [721] = "efscfsiR-R",
|
||||
[722] = "efscfufR-R", [723] = "efscfsfR-R",
|
||||
[724] = "efsctuiR-R", [725] = "efsctsiR-R",
|
||||
[726] = "efsctufR-R", [727] = "efsctsfR-R",
|
||||
[728] = "efsctuizR-R", [730] = "efsctsizR-R",
|
||||
[732] = "efststgtYRR", [733] = "efststltYRR", [734] = "efststeqYRR",
|
||||
|
||||
[736] = "efdaddRRR", [737] = "efdsubRRR",
|
||||
[738] = "efdcfuidR-R", [739] = "efdcfsidR-R",
|
||||
[740] = "efdabsRR", [741] = "efdnabsRR", [742] = "efdnegRR",
|
||||
[744] = "efdmulRRR", [745] = "efddivRRR",
|
||||
[746] = "efdctuidzR-R", [747] = "efdctsidzR-R",
|
||||
[748] = "efdcmpgtYRR", [749] = "efdcmpltYRR", [750] = "efdcmpeqYRR",
|
||||
[751] = "efdcfsR-R",
|
||||
[752] = "efdcfuiR-R", [753] = "efdcfsiR-R",
|
||||
[754] = "efdcfufR-R", [755] = "efdcfsfR-R",
|
||||
[756] = "efdctuiR-R", [757] = "efdctsiR-R",
|
||||
[758] = "efdctufR-R", [759] = "efdctsfR-R",
|
||||
[760] = "efdctuizR-R", [762] = "efdctsizR-R",
|
||||
[764] = "efdtstgtYRR", [765] = "efdtstltYRR", [766] = "efdtsteqYRR",
|
||||
|
||||
[768] = "evlddxRR0R", [769] = "evlddRR8",
|
||||
[770] = "evldwxRR0R", [771] = "evldwRR8",
|
||||
[772] = "evldhxRR0R", [773] = "evldhRR8",
|
||||
[776] = "evlhhesplatxRR0R", [777] = "evlhhesplatRR2",
|
||||
[780] = "evlhhousplatxRR0R", [781] = "evlhhousplatRR2",
|
||||
[782] = "evlhhossplatxRR0R", [783] = "evlhhossplatRR2",
|
||||
[784] = "evlwhexRR0R", [785] = "evlwheRR4",
|
||||
[788] = "evlwhouxRR0R", [789] = "evlwhouRR4",
|
||||
[790] = "evlwhosxRR0R", [791] = "evlwhosRR4",
|
||||
[792] = "evlwwsplatxRR0R", [793] = "evlwwsplatRR4",
|
||||
[796] = "evlwhsplatxRR0R", [797] = "evlwhsplatRR4",
|
||||
|
||||
[800] = "evstddxRR0R", [801] = "evstddRR8",
|
||||
[802] = "evstdwxRR0R", [803] = "evstdwRR8",
|
||||
[804] = "evstdhxRR0R", [805] = "evstdhRR8",
|
||||
[816] = "evstwhexRR0R", [817] = "evstwheRR4",
|
||||
[820] = "evstwhoxRR0R", [821] = "evstwhoRR4",
|
||||
[824] = "evstwwexRR0R", [825] = "evstwweRR4",
|
||||
[828] = "evstwwoxRR0R", [829] = "evstwwoRR4",
|
||||
|
||||
[1027] = "evmhessfRRR", [1031] = "evmhossfRRR", [1032] = "evmheumiRRR",
|
||||
[1033] = "evmhesmiRRR", [1035] = "evmhesmfRRR", [1036] = "evmhoumiRRR",
|
||||
[1037] = "evmhosmiRRR", [1039] = "evmhosmfRRR", [1059] = "evmhessfaRRR",
|
||||
[1063] = "evmhossfaRRR", [1064] = "evmheumiaRRR", [1065] = "evmhesmiaRRR",
|
||||
[1067] = "evmhesmfaRRR", [1068] = "evmhoumiaRRR", [1069] = "evmhosmiaRRR",
|
||||
[1071] = "evmhosmfaRRR", [1095] = "evmwhssfRRR", [1096] = "evmwlumiRRR",
|
||||
[1100] = "evmwhumiRRR", [1101] = "evmwhsmiRRR", [1103] = "evmwhsmfRRR",
|
||||
[1107] = "evmwssfRRR", [1112] = "evmwumiRRR", [1113] = "evmwsmiRRR",
|
||||
[1115] = "evmwsmfRRR", [1127] = "evmwhssfaRRR", [1128] = "evmwlumiaRRR",
|
||||
[1132] = "evmwhumiaRRR", [1133] = "evmwhsmiaRRR", [1135] = "evmwhsmfaRRR",
|
||||
[1139] = "evmwssfaRRR", [1144] = "evmwumiaRRR", [1145] = "evmwsmiaRRR",
|
||||
[1147] = "evmwsmfaRRR",
|
||||
|
||||
[1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR",
|
||||
[1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR",
|
||||
[1220] = "evmraRR",
|
||||
[1222] = "evdivwsRRR", [1223] = "evdivwuRRR",
|
||||
[1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR",
|
||||
[1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR",
|
||||
|
||||
[1280] = "evmheusiaawRRR", [1281] = "evmhessiaawRRR",
|
||||
[1283] = "evmhessfaawRRR", [1284] = "evmhousiaawRRR",
|
||||
[1285] = "evmhossiaawRRR", [1287] = "evmhossfaawRRR",
|
||||
[1288] = "evmheumiaawRRR", [1289] = "evmhesmiaawRRR",
|
||||
[1291] = "evmhesmfaawRRR", [1292] = "evmhoumiaawRRR",
|
||||
[1293] = "evmhosmiaawRRR", [1295] = "evmhosmfaawRRR",
|
||||
[1320] = "evmhegumiaaRRR", [1321] = "evmhegsmiaaRRR",
|
||||
[1323] = "evmhegsmfaaRRR", [1324] = "evmhogumiaaRRR",
|
||||
[1325] = "evmhogsmiaaRRR", [1327] = "evmhogsmfaaRRR",
|
||||
[1344] = "evmwlusiaawRRR", [1345] = "evmwlssiaawRRR",
|
||||
[1352] = "evmwlumiaawRRR", [1353] = "evmwlsmiaawRRR",
|
||||
[1363] = "evmwssfaaRRR", [1368] = "evmwumiaaRRR",
|
||||
[1369] = "evmwsmiaaRRR", [1371] = "evmwsmfaaRRR",
|
||||
[1408] = "evmheusianwRRR", [1409] = "evmhessianwRRR",
|
||||
[1411] = "evmhessfanwRRR", [1412] = "evmhousianwRRR",
|
||||
[1413] = "evmhossianwRRR", [1415] = "evmhossfanwRRR",
|
||||
[1416] = "evmheumianwRRR", [1417] = "evmhesmianwRRR",
|
||||
[1419] = "evmhesmfanwRRR", [1420] = "evmhoumianwRRR",
|
||||
[1421] = "evmhosmianwRRR", [1423] = "evmhosmfanwRRR",
|
||||
[1448] = "evmhegumianRRR", [1449] = "evmhegsmianRRR",
|
||||
[1451] = "evmhegsmfanRRR", [1452] = "evmhogumianRRR",
|
||||
[1453] = "evmhogsmianRRR", [1455] = "evmhogsmfanRRR",
|
||||
[1472] = "evmwlusianwRRR", [1473] = "evmwlssianwRRR",
|
||||
[1480] = "evmwlumianwRRR", [1481] = "evmwlsmianwRRR",
|
||||
[1491] = "evmwssfanRRR", [1496] = "evmwumianRRR",
|
||||
[1497] = "evmwsmianRRR", [1499] = "evmwsmfanRRR",
|
||||
}
|
||||
|
||||
local map_pri = {
|
||||
[0] = false, false, "tdiARI", "twiARI",
|
||||
map_spe, false, false, "mulliRRI",
|
||||
"subficRRI", false, "cmpl_iYLRU", "cmp_iYLRI",
|
||||
"addicRRI", "addic.RRI", "addi|liRR0I", "addis|lisRR0I",
|
||||
"b_KBJ", "sc", "bKJ", map_crops,
|
||||
"rlwimiRR~AAA.", map_rlwinm, false, "rlwnmRR~RAA.",
|
||||
"oriNRR~U", "orisRR~U", "xoriRR~U", "xorisRR~U",
|
||||
"andi.RR~U", "andis.RR~U", map_rld, map_ext,
|
||||
"lwzRRD", "lwzuRRD", "lbzRRD", "lbzuRRD",
|
||||
"stwRRD", "stwuRRD", "stbRRD", "stbuRRD",
|
||||
"lhzRRD", "lhzuRRD", "lhaRRD", "lhauRRD",
|
||||
"sthRRD", "sthuRRD", "lmwRRD", "stmwRRD",
|
||||
"lfsFRD", "lfsuFRD", "lfdFRD", "lfduFRD",
|
||||
"stfsFRD", "stfsuFRD", "stfdFRD", "stfduFRD",
|
||||
false, false, map_ld, map_fps,
|
||||
false, false, map_std, map_fpd,
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local map_gpr = {
|
||||
[0] = "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
|
||||
}
|
||||
|
||||
local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", }
|
||||
|
||||
-- Format a condition bit.
|
||||
local function condfmt(cond)
|
||||
if cond <= 3 then
|
||||
return map_cond[band(cond, 3)]
|
||||
else
|
||||
return format("4*cr%d+%s", rshift(cond, 2), map_cond[band(cond, 3)])
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Output a nicely formatted line with an opcode and operands.
|
||||
local function putop(ctx, text, operands)
|
||||
local pos = ctx.pos
|
||||
local extra = ""
|
||||
if ctx.rel then
|
||||
local sym = ctx.symtab[ctx.rel]
|
||||
if sym then extra = "\t->"..sym end
|
||||
end
|
||||
if ctx.hexdump > 0 then
|
||||
ctx.out(format("%08x %s %-7s %s%s\n",
|
||||
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
|
||||
else
|
||||
ctx.out(format("%08x %-7s %s%s\n",
|
||||
ctx.addr+pos, text, concat(operands, ", "), extra))
|
||||
end
|
||||
ctx.pos = pos + 4
|
||||
end
|
||||
|
||||
-- Fallback for unknown opcodes.
|
||||
local function unknown(ctx)
|
||||
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
|
||||
end
|
||||
|
||||
-- Disassemble a single instruction.
|
||||
local function disass_ins(ctx)
|
||||
local pos = ctx.pos
|
||||
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
|
||||
local op = bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
|
||||
local operands = {}
|
||||
local last = nil
|
||||
local rs = 21
|
||||
ctx.op = op
|
||||
ctx.rel = nil
|
||||
|
||||
local opat = map_pri[rshift(b0, 2)]
|
||||
while type(opat) ~= "string" do
|
||||
if not opat then return unknown(ctx) end
|
||||
opat = opat[band(rshift(op, opat.shift), opat.mask)]
|
||||
end
|
||||
local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
|
||||
local altname, pat2 = match(pat, "|([a-z0-9_.]*)(.*)")
|
||||
if altname then pat = pat2 end
|
||||
|
||||
for p in gmatch(pat, ".") do
|
||||
local x = nil
|
||||
if p == "R" then
|
||||
x = map_gpr[band(rshift(op, rs), 31)]
|
||||
rs = rs - 5
|
||||
elseif p == "F" then
|
||||
x = "f"..band(rshift(op, rs), 31)
|
||||
rs = rs - 5
|
||||
elseif p == "A" then
|
||||
x = band(rshift(op, rs), 31)
|
||||
rs = rs - 5
|
||||
elseif p == "S" then
|
||||
x = arshift(lshift(op, 27-rs), 27)
|
||||
rs = rs - 5
|
||||
elseif p == "I" then
|
||||
x = arshift(lshift(op, 16), 16)
|
||||
elseif p == "U" then
|
||||
x = band(op, 0xffff)
|
||||
elseif p == "D" or p == "E" then
|
||||
local disp = arshift(lshift(op, 16), 16)
|
||||
if p == "E" then disp = band(disp, -4) end
|
||||
if last == "r0" then last = "0" end
|
||||
operands[#operands] = format("%d(%s)", disp, last)
|
||||
elseif p >= "2" and p <= "8" then
|
||||
local disp = band(rshift(op, rs), 31) * p
|
||||
if last == "r0" then last = "0" end
|
||||
operands[#operands] = format("%d(%s)", disp, last)
|
||||
elseif p == "H" then
|
||||
x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4)
|
||||
rs = rs - 5
|
||||
elseif p == "M" then
|
||||
x = band(rshift(op, rs), 31) + band(op, 0x20)
|
||||
elseif p == "C" then
|
||||
x = condfmt(band(rshift(op, rs), 31))
|
||||
rs = rs - 5
|
||||
elseif p == "B" then
|
||||
local bo = rshift(op, 21)
|
||||
local cond = band(rshift(op, 16), 31)
|
||||
local cn = ""
|
||||
rs = rs - 10
|
||||
if band(bo, 4) == 0 then
|
||||
cn = band(bo, 2) == 0 and "dnz" or "dz"
|
||||
if band(bo, 0x10) == 0 then
|
||||
cn = cn..(band(bo, 8) == 0 and "f" or "t")
|
||||
end
|
||||
if band(bo, 0x10) == 0 then x = condfmt(cond) end
|
||||
name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+")
|
||||
elseif band(bo, 0x10) == 0 then
|
||||
cn = map_cond[band(cond, 3) + (band(bo, 8) == 0 and 4 or 0)]
|
||||
if cond > 3 then x = "cr"..rshift(cond, 2) end
|
||||
name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+")
|
||||
end
|
||||
name = gsub(name, "_", cn)
|
||||
elseif p == "J" then
|
||||
x = arshift(lshift(op, 27-rs), 29-rs)*4
|
||||
if band(op, 2) == 0 then x = ctx.addr + pos + x end
|
||||
ctx.rel = x
|
||||
x = "0x"..tohex(x)
|
||||
elseif p == "K" then
|
||||
if band(op, 1) ~= 0 then name = name.."l" end
|
||||
if band(op, 2) ~= 0 then name = name.."a" end
|
||||
elseif p == "X" or p == "Y" then
|
||||
x = band(rshift(op, rs+2), 7)
|
||||
if x == 0 and p == "Y" then x = nil else x = "cr"..x end
|
||||
rs = rs - 5
|
||||
elseif p == "W" then
|
||||
x = "cr"..band(op, 7)
|
||||
elseif p == "Z" then
|
||||
x = band(rshift(op, rs-4), 255)
|
||||
rs = rs - 10
|
||||
elseif p == ">" then
|
||||
operands[#operands] = rshift(operands[#operands], 1)
|
||||
elseif p == "0" then
|
||||
if last == "r0" then
|
||||
operands[#operands] = nil
|
||||
if altname then name = altname end
|
||||
end
|
||||
elseif p == "L" then
|
||||
name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w")
|
||||
elseif p == "." then
|
||||
if band(op, 1) == 1 then name = name.."." end
|
||||
elseif p == "N" then
|
||||
if op == 0x60000000 then name = "nop"; break end
|
||||
elseif p == "~" then
|
||||
local n = #operands
|
||||
operands[n-1], operands[n] = operands[n], operands[n-1]
|
||||
elseif p == "=" then
|
||||
local n = #operands
|
||||
if last == operands[n-1] then
|
||||
operands[n] = nil
|
||||
name = altname
|
||||
end
|
||||
elseif p == "%" then
|
||||
local n = #operands
|
||||
if last == operands[n-1] and last == operands[n-2] then
|
||||
operands[n] = nil
|
||||
operands[n-1] = nil
|
||||
name = altname
|
||||
end
|
||||
elseif p == "-" then
|
||||
rs = rs - 5
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
if x then operands[#operands+1] = x; last = x end
|
||||
end
|
||||
|
||||
return putop(ctx, name, operands)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Disassemble a block of code.
|
||||
local function disass_block(ctx, ofs, len)
|
||||
if not ofs then ofs = 0 end
|
||||
local stop = len and ofs+len or #ctx.code
|
||||
stop = stop - stop % 4
|
||||
ctx.pos = ofs - ofs % 4
|
||||
ctx.rel = nil
|
||||
while ctx.pos < stop do disass_ins(ctx) end
|
||||
end
|
||||
|
||||
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
|
||||
local function create_(code, addr, out)
|
||||
local ctx = {}
|
||||
ctx.code = code
|
||||
ctx.addr = addr or 0
|
||||
ctx.out = out or io.write
|
||||
ctx.symtab = {}
|
||||
ctx.disass = disass_block
|
||||
ctx.hexdump = 8
|
||||
return ctx
|
||||
end
|
||||
|
||||
-- Simple API: disassemble code (a string) at address and output via out.
|
||||
local function disass_(code, addr, out)
|
||||
create_(code, addr, out):disass()
|
||||
end
|
||||
|
||||
-- Return register name for RID.
|
||||
local function regname_(r)
|
||||
if r < 32 then return map_gpr[r] end
|
||||
return "f"..(r-32)
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
module(...)
|
||||
|
||||
create = create_
|
||||
disass = disass_
|
||||
regname = regname_
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT x64 disassembler wrapper module.
|
||||
--
|
||||
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This module just exports the 64 bit functions from the combined
|
||||
-- x86/x64 disassembler module. All the interesting stuff is there.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local require = require
|
||||
|
||||
module(...)
|
||||
|
||||
local dis_x86 = require(_PACKAGE.."dis_x86")
|
||||
|
||||
create = dis_x86.create64
|
||||
disass = dis_x86.disass64
|
||||
regname = dis_x86.regname64
|
||||
|
||||
@@ -0,0 +1,836 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT x86/x64 disassembler module.
|
||||
--
|
||||
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
-- This is a helper module used by the LuaJIT machine code dumper module.
|
||||
--
|
||||
-- Sending small code snippets to an external disassembler and mixing the
|
||||
-- output with our own stuff was too fragile. So I had to bite the bullet
|
||||
-- and write yet another x86 disassembler. Oh well ...
|
||||
--
|
||||
-- The output format is very similar to what ndisasm generates. But it has
|
||||
-- been developed independently by looking at the opcode tables from the
|
||||
-- Intel and AMD manuals. The supported instruction set is quite extensive
|
||||
-- and reflects what a current generation Intel or AMD CPU implements in
|
||||
-- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3,
|
||||
-- SSE4.1, SSE4.2, SSE4a and even privileged and hypervisor (VMX/SVM)
|
||||
-- instructions.
|
||||
--
|
||||
-- Notes:
|
||||
-- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported.
|
||||
-- * No attempt at optimization has been made -- it's fast enough for my needs.
|
||||
-- * The public API may change when more architectures are added.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local type = type
|
||||
local sub, byte, format = string.sub, string.byte, string.format
|
||||
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
|
||||
local lower, rep = string.lower, string.rep
|
||||
|
||||
-- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on.
|
||||
local map_opc1_32 = {
|
||||
--0x
|
||||
[0]="addBmr","addVmr","addBrm","addVrm","addBai","addVai","push es","pop es",
|
||||
"orBmr","orVmr","orBrm","orVrm","orBai","orVai","push cs","opc2*",
|
||||
--1x
|
||||
"adcBmr","adcVmr","adcBrm","adcVrm","adcBai","adcVai","push ss","pop ss",
|
||||
"sbbBmr","sbbVmr","sbbBrm","sbbVrm","sbbBai","sbbVai","push ds","pop ds",
|
||||
--2x
|
||||
"andBmr","andVmr","andBrm","andVrm","andBai","andVai","es:seg","daa",
|
||||
"subBmr","subVmr","subBrm","subVrm","subBai","subVai","cs:seg","das",
|
||||
--3x
|
||||
"xorBmr","xorVmr","xorBrm","xorVrm","xorBai","xorVai","ss:seg","aaa",
|
||||
"cmpBmr","cmpVmr","cmpBrm","cmpVrm","cmpBai","cmpVai","ds:seg","aas",
|
||||
--4x
|
||||
"incVR","incVR","incVR","incVR","incVR","incVR","incVR","incVR",
|
||||
"decVR","decVR","decVR","decVR","decVR","decVR","decVR","decVR",
|
||||
--5x
|
||||
"pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR",
|
||||
"popUR","popUR","popUR","popUR","popUR","popUR","popUR","popUR",
|
||||
--6x
|
||||
"sz*pushaw,pusha","sz*popaw,popa","boundVrm","arplWmr",
|
||||
"fs:seg","gs:seg","o16:","a16",
|
||||
"pushUi","imulVrmi","pushBs","imulVrms",
|
||||
"insb","insVS","outsb","outsVS",
|
||||
--7x
|
||||
"joBj","jnoBj","jbBj","jnbBj","jzBj","jnzBj","jbeBj","jaBj",
|
||||
"jsBj","jnsBj","jpeBj","jpoBj","jlBj","jgeBj","jleBj","jgBj",
|
||||
--8x
|
||||
"arith!Bmi","arith!Vmi","arith!Bmi","arith!Vms",
|
||||
"testBmr","testVmr","xchgBrm","xchgVrm",
|
||||
"movBmr","movVmr","movBrm","movVrm",
|
||||
"movVmg","leaVrm","movWgm","popUm",
|
||||
--9x
|
||||
"nop*xchgVaR|pause|xchgWaR|repne nop","xchgVaR","xchgVaR","xchgVaR",
|
||||
"xchgVaR","xchgVaR","xchgVaR","xchgVaR",
|
||||
"sz*cbw,cwde,cdqe","sz*cwd,cdq,cqo","call farViw","wait",
|
||||
"sz*pushfw,pushf","sz*popfw,popf","sahf","lahf",
|
||||
--Ax
|
||||
"movBao","movVao","movBoa","movVoa",
|
||||
"movsb","movsVS","cmpsb","cmpsVS",
|
||||
"testBai","testVai","stosb","stosVS",
|
||||
"lodsb","lodsVS","scasb","scasVS",
|
||||
--Bx
|
||||
"movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi",
|
||||
"movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI",
|
||||
--Cx
|
||||
"shift!Bmu","shift!Vmu","retBw","ret","$lesVrm","$ldsVrm","movBmi","movVmi",
|
||||
"enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS",
|
||||
--Dx
|
||||
"shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb",
|
||||
"fp*0","fp*1","fp*2","fp*3","fp*4","fp*5","fp*6","fp*7",
|
||||
--Ex
|
||||
"loopneBj","loopeBj","loopBj","sz*jcxzBj,jecxzBj,jrcxzBj",
|
||||
"inBau","inVau","outBua","outVua",
|
||||
"callVj","jmpVj","jmp farViw","jmpBj","inBad","inVad","outBda","outVda",
|
||||
--Fx
|
||||
"lock:","int1","repne:rep","rep:","hlt","cmc","testb!Bm","testv!Vm",
|
||||
"clc","stc","cli","sti","cld","std","incb!Bm","incd!Vm",
|
||||
}
|
||||
assert(#map_opc1_32 == 255)
|
||||
|
||||
-- Map for 1st opcode byte in 64 bit mode (overrides only).
|
||||
local map_opc1_64 = setmetatable({
|
||||
[0x06]=false, [0x07]=false, [0x0e]=false,
|
||||
[0x16]=false, [0x17]=false, [0x1e]=false, [0x1f]=false,
|
||||
[0x27]=false, [0x2f]=false, [0x37]=false, [0x3f]=false,
|
||||
[0x60]=false, [0x61]=false, [0x62]=false, [0x63]="movsxdVrDmt", [0x67]="a32:",
|
||||
[0x40]="rex*", [0x41]="rex*b", [0x42]="rex*x", [0x43]="rex*xb",
|
||||
[0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb",
|
||||
[0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb",
|
||||
[0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb",
|
||||
[0x82]=false, [0x9a]=false, [0xc4]=false, [0xc5]=false, [0xce]=false,
|
||||
[0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false,
|
||||
}, { __index = map_opc1_32 })
|
||||
|
||||
-- Map for 2nd opcode byte (0F xx). True CISC hell. Hey, I told you.
|
||||
-- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne, -|F3|66|F2
|
||||
local map_opc2 = {
|
||||
--0x
|
||||
[0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret",
|
||||
"invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu",
|
||||
--1x
|
||||
"movupsXrm|movssXrm|movupdXrm|movsdXrm",
|
||||
"movupsXmr|movssXmr|movupdXmr|movsdXmr",
|
||||
"movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm",
|
||||
"movlpsXmr||movlpdXmr",
|
||||
"unpcklpsXrm||unpcklpdXrm",
|
||||
"unpckhpsXrm||unpckhpdXrm",
|
||||
"movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm",
|
||||
"movhpsXmr||movhpdXmr",
|
||||
"$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm",
|
||||
"hintnopVm","hintnopVm","hintnopVm","hintnopVm",
|
||||
--2x
|
||||
"movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil,
|
||||
"movapsXrm||movapdXrm",
|
||||
"movapsXmr||movapdXmr",
|
||||
"cvtpi2psXrMm|cvtsi2ssXrVmt|cvtpi2pdXrMm|cvtsi2sdXrVmt",
|
||||
"movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr",
|
||||
"cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm",
|
||||
"cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm",
|
||||
"ucomissXrm||ucomisdXrm",
|
||||
"comissXrm||comisdXrm",
|
||||
--3x
|
||||
"wrmsr","rdtsc","rdmsr","rdpmc","sysenter","sysexit",nil,"getsec",
|
||||
"opc3*38",nil,"opc3*3a",nil,nil,nil,nil,nil,
|
||||
--4x
|
||||
"cmovoVrm","cmovnoVrm","cmovbVrm","cmovnbVrm",
|
||||
"cmovzVrm","cmovnzVrm","cmovbeVrm","cmovaVrm",
|
||||
"cmovsVrm","cmovnsVrm","cmovpeVrm","cmovpoVrm",
|
||||
"cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm",
|
||||
--5x
|
||||
"movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm",
|
||||
"rsqrtpsXrm|rsqrtssXrm","rcppsXrm|rcpssXrm",
|
||||
"andpsXrm||andpdXrm","andnpsXrm||andnpdXrm",
|
||||
"orpsXrm||orpdXrm","xorpsXrm||xorpdXrm",
|
||||
"addpsXrm|addssXrm|addpdXrm|addsdXrm","mulpsXrm|mulssXrm|mulpdXrm|mulsdXrm",
|
||||
"cvtps2pdXrm|cvtss2sdXrm|cvtpd2psXrm|cvtsd2ssXrm",
|
||||
"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm",
|
||||
"subpsXrm|subssXrm|subpdXrm|subsdXrm","minpsXrm|minssXrm|minpdXrm|minsdXrm",
|
||||
"divpsXrm|divssXrm|divpdXrm|divsdXrm","maxpsXrm|maxssXrm|maxpdXrm|maxsdXrm",
|
||||
--6x
|
||||
"punpcklbwPrm","punpcklwdPrm","punpckldqPrm","packsswbPrm",
|
||||
"pcmpgtbPrm","pcmpgtwPrm","pcmpgtdPrm","packuswbPrm",
|
||||
"punpckhbwPrm","punpckhwdPrm","punpckhdqPrm","packssdwPrm",
|
||||
"||punpcklqdqXrm","||punpckhqdqXrm",
|
||||
"movPrVSm","movqMrm|movdquXrm|movdqaXrm",
|
||||
--7x
|
||||
"pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pmu",
|
||||
"pshiftd!Pmu","pshiftq!Mmu||pshiftdq!Xmu",
|
||||
"pcmpeqbPrm","pcmpeqwPrm","pcmpeqdPrm","emms|",
|
||||
"vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$",
|
||||
nil,nil,
|
||||
"||haddpdXrm|haddpsXrm","||hsubpdXrm|hsubpsXrm",
|
||||
"movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr",
|
||||
--8x
|
||||
"joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj",
|
||||
"jsVj","jnsVj","jpeVj","jpoVj","jlVj","jgeVj","jleVj","jgVj",
|
||||
--9x
|
||||
"setoBm","setnoBm","setbBm","setnbBm","setzBm","setnzBm","setbeBm","setaBm",
|
||||
"setsBm","setnsBm","setpeBm","setpoBm","setlBm","setgeBm","setleBm","setgBm",
|
||||
--Ax
|
||||
"push fs","pop fs","cpuid","btVmr","shldVmru","shldVmrc",nil,nil,
|
||||
"push gs","pop gs","rsm","btsVmr","shrdVmru","shrdVmrc","fxsave!Dmp","imulVrm",
|
||||
--Bx
|
||||
"cmpxchgBmr","cmpxchgVmr","$lssVrm","btrVmr",
|
||||
"$lfsVrm","$lgsVrm","movzxVrBmt","movzxVrWmt",
|
||||
"|popcntVrm","ud2Dp","bt!Vmu","btcVmr",
|
||||
"bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt",
|
||||
--Cx
|
||||
"xaddBmr","xaddVmr",
|
||||
"cmppsXrmu|cmpssXrmu|cmppdXrmu|cmpsdXrmu","$movntiVmr|",
|
||||
"pinsrwPrWmu","pextrwDrPmu",
|
||||
"shufpsXrmu||shufpdXrmu","$cmpxchg!Qmp",
|
||||
"bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR",
|
||||
--Dx
|
||||
"||addsubpdXrm|addsubpsXrm","psrlwPrm","psrldPrm","psrlqPrm",
|
||||
"paddqPrm","pmullwPrm",
|
||||
"|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm",
|
||||
"psubusbPrm","psubuswPrm","pminubPrm","pandPrm",
|
||||
"paddusbPrm","padduswPrm","pmaxubPrm","pandnPrm",
|
||||
--Ex
|
||||
"pavgbPrm","psrawPrm","psradPrm","pavgwPrm",
|
||||
"pmulhuwPrm","pmulhwPrm",
|
||||
"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr",
|
||||
"psubsbPrm","psubswPrm","pminswPrm","porPrm",
|
||||
"paddsbPrm","paddswPrm","pmaxswPrm","pxorPrm",
|
||||
--Fx
|
||||
"|||lddquXrm","psllwPrm","pslldPrm","psllqPrm",
|
||||
"pmuludqPrm","pmaddwdPrm","psadbwPrm","maskmovqMrm||maskmovdquXrm$",
|
||||
"psubbPrm","psubwPrm","psubdPrm","psubqPrm",
|
||||
"paddbPrm","paddwPrm","padddPrm","ud",
|
||||
}
|
||||
assert(map_opc2[255] == "ud")
|
||||
|
||||
-- Map for three-byte opcodes. Can't wait for their next invention.
|
||||
local map_opc3 = {
|
||||
["38"] = { -- [66] 0f 38 xx
|
||||
--0x
|
||||
[0]="pshufbPrm","phaddwPrm","phadddPrm","phaddswPrm",
|
||||
"pmaddubswPrm","phsubwPrm","phsubdPrm","phsubswPrm",
|
||||
"psignbPrm","psignwPrm","psigndPrm","pmulhrswPrm",
|
||||
nil,nil,nil,nil,
|
||||
--1x
|
||||
"||pblendvbXrma",nil,nil,nil,
|
||||
"||blendvpsXrma","||blendvpdXrma",nil,"||ptestXrm",
|
||||
nil,nil,nil,nil,
|
||||
"pabsbPrm","pabswPrm","pabsdPrm",nil,
|
||||
--2x
|
||||
"||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm",
|
||||
"||pmovsxwqXrm","||pmovsxdqXrm",nil,nil,
|
||||
"||pmuldqXrm","||pcmpeqqXrm","||$movntdqaXrm","||packusdwXrm",
|
||||
nil,nil,nil,nil,
|
||||
--3x
|
||||
"||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm",
|
||||
"||pmovzxwqXrm","||pmovzxdqXrm",nil,"||pcmpgtqXrm",
|
||||
"||pminsbXrm","||pminsdXrm","||pminuwXrm","||pminudXrm",
|
||||
"||pmaxsbXrm","||pmaxsdXrm","||pmaxuwXrm","||pmaxudXrm",
|
||||
--4x
|
||||
"||pmulddXrm","||phminposuwXrm",
|
||||
--Fx
|
||||
[0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt",
|
||||
},
|
||||
|
||||
["3a"] = { -- [66] 0f 3a xx
|
||||
--0x
|
||||
[0x00]=nil,nil,nil,nil,nil,nil,nil,nil,
|
||||
"||roundpsXrmu","||roundpdXrmu","||roundssXrmu","||roundsdXrmu",
|
||||
"||blendpsXrmu","||blendpdXrmu","||pblendwXrmu","palignrPrmu",
|
||||
--1x
|
||||
nil,nil,nil,nil,
|
||||
"||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru",
|
||||
nil,nil,nil,nil,nil,nil,nil,nil,
|
||||
--2x
|
||||
"||pinsrbXrVmu","||insertpsXrmu","||pinsrXrVmuS",nil,
|
||||
--4x
|
||||
[0x40] = "||dppsXrmu",
|
||||
[0x41] = "||dppdXrmu",
|
||||
[0x42] = "||mpsadbwXrmu",
|
||||
--6x
|
||||
[0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu",
|
||||
[0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu",
|
||||
},
|
||||
}
|
||||
|
||||
-- Map for VMX/SVM opcodes 0F 01 C0-FF (sgdt group with register operands).
|
||||
local map_opcvm = {
|
||||
[0xc1]="vmcall",[0xc2]="vmlaunch",[0xc3]="vmresume",[0xc4]="vmxoff",
|
||||
[0xc8]="monitor",[0xc9]="mwait",
|
||||
[0xd8]="vmrun",[0xd9]="vmmcall",[0xda]="vmload",[0xdb]="vmsave",
|
||||
[0xdc]="stgi",[0xdd]="clgi",[0xde]="skinit",[0xdf]="invlpga",
|
||||
[0xf8]="swapgs",[0xf9]="rdtscp",
|
||||
}
|
||||
|
||||
-- Map for FP opcodes. And you thought stack machines are simple?
|
||||
local map_opcfp = {
|
||||
-- D8-DF 00-BF: opcodes with a memory operand.
|
||||
-- D8
|
||||
[0]="faddFm","fmulFm","fcomFm","fcompFm","fsubFm","fsubrFm","fdivFm","fdivrFm",
|
||||
"fldFm",nil,"fstFm","fstpFm","fldenvVm","fldcwWm","fnstenvVm","fnstcwWm",
|
||||
-- DA
|
||||
"fiaddDm","fimulDm","ficomDm","ficompDm",
|
||||
"fisubDm","fisubrDm","fidivDm","fidivrDm",
|
||||
-- DB
|
||||
"fildDm","fisttpDm","fistDm","fistpDm",nil,"fld twordFmp",nil,"fstp twordFmp",
|
||||
-- DC
|
||||
"faddGm","fmulGm","fcomGm","fcompGm","fsubGm","fsubrGm","fdivGm","fdivrGm",
|
||||
-- DD
|
||||
"fldGm","fisttpQm","fstGm","fstpGm","frstorDmp",nil,"fnsaveDmp","fnstswWm",
|
||||
-- DE
|
||||
"fiaddWm","fimulWm","ficomWm","ficompWm",
|
||||
"fisubWm","fisubrWm","fidivWm","fidivrWm",
|
||||
-- DF
|
||||
"fildWm","fisttpWm","fistWm","fistpWm",
|
||||
"fbld twordFmp","fildQm","fbstp twordFmp","fistpQm",
|
||||
-- xx C0-FF: opcodes with a pseudo-register operand.
|
||||
-- D8
|
||||
"faddFf","fmulFf","fcomFf","fcompFf","fsubFf","fsubrFf","fdivFf","fdivrFf",
|
||||
-- D9
|
||||
"fldFf","fxchFf",{"fnop"},nil,
|
||||
{"fchs","fabs",nil,nil,"ftst","fxam"},
|
||||
{"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz"},
|
||||
{"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp"},
|
||||
{"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"},
|
||||
-- DA
|
||||
"fcmovbFf","fcmoveFf","fcmovbeFf","fcmovuFf",nil,{nil,"fucompp"},nil,nil,
|
||||
-- DB
|
||||
"fcmovnbFf","fcmovneFf","fcmovnbeFf","fcmovnuFf",
|
||||
{nil,nil,"fnclex","fninit"},"fucomiFf","fcomiFf",nil,
|
||||
-- DC
|
||||
"fadd toFf","fmul toFf",nil,nil,
|
||||
"fsub toFf","fsubr toFf","fdivr toFf","fdiv toFf",
|
||||
-- DD
|
||||
"ffreeFf",nil,"fstFf","fstpFf","fucomFf","fucompFf",nil,nil,
|
||||
-- DE
|
||||
"faddpFf","fmulpFf",nil,{nil,"fcompp"},
|
||||
"fsubrpFf","fsubpFf","fdivrpFf","fdivpFf",
|
||||
-- DF
|
||||
nil,nil,nil,nil,{"fnstsw ax"},"fucomipFf","fcomipFf",nil,
|
||||
}
|
||||
assert(map_opcfp[126] == "fcomipFf")
|
||||
|
||||
-- Map for opcode groups. The subkey is sp from the ModRM byte.
|
||||
local map_opcgroup = {
|
||||
arith = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" },
|
||||
shift = { "rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar" },
|
||||
testb = { "testBmi", "testBmi", "not", "neg", "mul", "imul", "div", "idiv" },
|
||||
testv = { "testVmi", "testVmi", "not", "neg", "mul", "imul", "div", "idiv" },
|
||||
incb = { "inc", "dec" },
|
||||
incd = { "inc", "dec", "callUmp", "$call farDmp",
|
||||
"jmpUmp", "$jmp farDmp", "pushUm" },
|
||||
sldt = { "sldt", "str", "lldt", "ltr", "verr", "verw" },
|
||||
sgdt = { "vm*$sgdt", "vm*$sidt", "$lgdt", "vm*$lidt",
|
||||
"smsw", nil, "lmsw", "vm*$invlpg" },
|
||||
bt = { nil, nil, nil, nil, "bt", "bts", "btr", "btc" },
|
||||
cmpxchg = { nil, "sz*,cmpxchg8bQmp,cmpxchg16bXmp", nil, nil,
|
||||
nil, nil, "vmptrld|vmxon|vmclear", "vmptrst" },
|
||||
pshiftw = { nil, nil, "psrlw", nil, "psraw", nil, "psllw" },
|
||||
pshiftd = { nil, nil, "psrld", nil, "psrad", nil, "pslld" },
|
||||
pshiftq = { nil, nil, "psrlq", nil, nil, nil, "psllq" },
|
||||
pshiftdq = { nil, nil, "psrlq", "psrldq", nil, nil, "psllq", "pslldq" },
|
||||
fxsave = { "$fxsave", "$fxrstor", "$ldmxcsr", "$stmxcsr",
|
||||
nil, "lfenceDp$", "mfenceDp$", "sfenceDp$clflush" },
|
||||
prefetch = { "prefetch", "prefetchw" },
|
||||
prefetcht = { "prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2" },
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Maps for register names.
|
||||
local map_regs = {
|
||||
B = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
|
||||
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
|
||||
B64 = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
|
||||
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
|
||||
W = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
|
||||
"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" },
|
||||
D = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
|
||||
"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" },
|
||||
Q = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" },
|
||||
M = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
|
||||
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext!
|
||||
X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
|
||||
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" },
|
||||
}
|
||||
local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" }
|
||||
|
||||
-- Maps for size names.
|
||||
local map_sz2n = {
|
||||
B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16,
|
||||
}
|
||||
local map_sz2prefix = {
|
||||
B = "byte", W = "word", D = "dword",
|
||||
Q = "qword",
|
||||
M = "qword", X = "xword",
|
||||
F = "dword", G = "qword", -- No need for sizes/register names for these two.
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Output a nicely formatted line with an opcode and operands.
|
||||
local function putop(ctx, text, operands)
|
||||
local code, pos, hex = ctx.code, ctx.pos, ""
|
||||
local hmax = ctx.hexdump
|
||||
if hmax > 0 then
|
||||
for i=ctx.start,pos-1 do
|
||||
hex = hex..format("%02X", byte(code, i, i))
|
||||
end
|
||||
if #hex > hmax then hex = sub(hex, 1, hmax)..". "
|
||||
else hex = hex..rep(" ", hmax-#hex+2) end
|
||||
end
|
||||
if operands then text = text.." "..operands end
|
||||
if ctx.o16 then text = "o16 "..text; ctx.o16 = false end
|
||||
if ctx.a32 then text = "a32 "..text; ctx.a32 = false end
|
||||
if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end
|
||||
if ctx.rex then
|
||||
local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "")..
|
||||
(ctx.rexx and "x" or "")..(ctx.rexb and "b" or "")
|
||||
if t ~= "" then text = "rex."..t.." "..text end
|
||||
ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
|
||||
ctx.rex = false
|
||||
end
|
||||
if ctx.seg then
|
||||
local text2, n = gsub(text, "%[", "["..ctx.seg..":")
|
||||
if n == 0 then text = ctx.seg.." "..text else text = text2 end
|
||||
ctx.seg = false
|
||||
end
|
||||
if ctx.lock then text = "lock "..text; ctx.lock = false end
|
||||
local imm = ctx.imm
|
||||
if imm then
|
||||
local sym = ctx.symtab[imm]
|
||||
if sym then text = text.."\t->"..sym end
|
||||
end
|
||||
ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text))
|
||||
ctx.mrm = false
|
||||
ctx.start = pos
|
||||
ctx.imm = nil
|
||||
end
|
||||
|
||||
-- Clear all prefix flags.
|
||||
local function clearprefixes(ctx)
|
||||
ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false
|
||||
ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
|
||||
ctx.rex = false; ctx.a32 = false
|
||||
end
|
||||
|
||||
-- Fallback for incomplete opcodes at the end.
|
||||
local function incomplete(ctx)
|
||||
ctx.pos = ctx.stop+1
|
||||
clearprefixes(ctx)
|
||||
return putop(ctx, "(incomplete)")
|
||||
end
|
||||
|
||||
-- Fallback for unknown opcodes.
|
||||
local function unknown(ctx)
|
||||
clearprefixes(ctx)
|
||||
return putop(ctx, "(unknown)")
|
||||
end
|
||||
|
||||
-- Return an immediate of the specified size.
|
||||
local function getimm(ctx, pos, n)
|
||||
if pos+n-1 > ctx.stop then return incomplete(ctx) end
|
||||
local code = ctx.code
|
||||
if n == 1 then
|
||||
local b1 = byte(code, pos, pos)
|
||||
return b1
|
||||
elseif n == 2 then
|
||||
local b1, b2 = byte(code, pos, pos+1)
|
||||
return b1+b2*256
|
||||
else
|
||||
local b1, b2, b3, b4 = byte(code, pos, pos+3)
|
||||
local imm = b1+b2*256+b3*65536+b4*16777216
|
||||
ctx.imm = imm
|
||||
return imm
|
||||
end
|
||||
end
|
||||
|
||||
-- Process pattern string and generate the operands.
|
||||
local function putpat(ctx, name, pat)
|
||||
local operands, regs, sz, mode, sp, rm, sc, rx, sdisp
|
||||
local code, pos, stop = ctx.code, ctx.pos, ctx.stop
|
||||
|
||||
-- Chars used: 1DFGIMPQRSTUVWXacdfgijmoprstuwxyz
|
||||
for p in gmatch(pat, ".") do
|
||||
local x = nil
|
||||
if p == "V" or p == "U" then
|
||||
if ctx.rexw then sz = "Q"; ctx.rexw = false
|
||||
elseif ctx.o16 then sz = "W"; ctx.o16 = false
|
||||
elseif p == "U" and ctx.x64 then sz = "Q"
|
||||
else sz = "D" end
|
||||
regs = map_regs[sz]
|
||||
elseif p == "T" then
|
||||
if ctx.rexw then sz = "Q"; ctx.rexw = false else sz = "D" end
|
||||
regs = map_regs[sz]
|
||||
elseif p == "B" then
|
||||
sz = "B"
|
||||
regs = ctx.rex and map_regs.B64 or map_regs.B
|
||||
elseif match(p, "[WDQMXFG]") then
|
||||
sz = p
|
||||
regs = map_regs[sz]
|
||||
elseif p == "P" then
|
||||
sz = ctx.o16 and "X" or "M"; ctx.o16 = false
|
||||
regs = map_regs[sz]
|
||||
elseif p == "S" then
|
||||
name = name..lower(sz)
|
||||
elseif p == "s" then
|
||||
local imm = getimm(ctx, pos, 1); if not imm then return end
|
||||
x = imm <= 127 and format("+0x%02x", imm)
|
||||
or format("-0x%02x", 256-imm)
|
||||
pos = pos+1
|
||||
elseif p == "u" then
|
||||
local imm = getimm(ctx, pos, 1); if not imm then return end
|
||||
x = format("0x%02x", imm)
|
||||
pos = pos+1
|
||||
elseif p == "w" then
|
||||
local imm = getimm(ctx, pos, 2); if not imm then return end
|
||||
x = format("0x%x", imm)
|
||||
pos = pos+2
|
||||
elseif p == "o" then -- [offset]
|
||||
if ctx.x64 then
|
||||
local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
|
||||
local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
|
||||
x = format("[0x%08x%08x]", imm2, imm1)
|
||||
pos = pos+8
|
||||
else
|
||||
local imm = getimm(ctx, pos, 4); if not imm then return end
|
||||
x = format("[0x%08x]", imm)
|
||||
pos = pos+4
|
||||
end
|
||||
elseif p == "i" or p == "I" then
|
||||
local n = map_sz2n[sz]
|
||||
if n == 8 and ctx.x64 and p == "I" then
|
||||
local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
|
||||
local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
|
||||
x = format("0x%08x%08x", imm2, imm1)
|
||||
else
|
||||
if n == 8 then n = 4 end
|
||||
local imm = getimm(ctx, pos, n); if not imm then return end
|
||||
if sz == "Q" and (imm < 0 or imm > 0x7fffffff) then
|
||||
imm = (0xffffffff+1)-imm
|
||||
x = format(imm > 65535 and "-0x%08x" or "-0x%x", imm)
|
||||
else
|
||||
x = format(imm > 65535 and "0x%08x" or "0x%x", imm)
|
||||
end
|
||||
end
|
||||
pos = pos+n
|
||||
elseif p == "j" then
|
||||
local n = map_sz2n[sz]
|
||||
if n == 8 then n = 4 end
|
||||
local imm = getimm(ctx, pos, n); if not imm then return end
|
||||
if sz == "B" and imm > 127 then imm = imm-256
|
||||
elseif imm > 2147483647 then imm = imm-4294967296 end
|
||||
pos = pos+n
|
||||
imm = imm + pos + ctx.addr
|
||||
if imm > 4294967295 and not ctx.x64 then imm = imm-4294967296 end
|
||||
ctx.imm = imm
|
||||
if sz == "W" then
|
||||
x = format("word 0x%04x", imm%65536)
|
||||
elseif ctx.x64 then
|
||||
local lo = imm % 0x1000000
|
||||
x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo)
|
||||
else
|
||||
x = format("0x%08x", imm)
|
||||
end
|
||||
elseif p == "R" then
|
||||
local r = byte(code, pos-1, pos-1)%8
|
||||
if ctx.rexb then r = r + 8; ctx.rexb = false end
|
||||
x = regs[r+1]
|
||||
elseif p == "a" then x = regs[1]
|
||||
elseif p == "c" then x = "cl"
|
||||
elseif p == "d" then x = "dx"
|
||||
elseif p == "1" then x = "1"
|
||||
else
|
||||
if not mode then
|
||||
mode = ctx.mrm
|
||||
if not mode then
|
||||
if pos > stop then return incomplete(ctx) end
|
||||
mode = byte(code, pos, pos)
|
||||
pos = pos+1
|
||||
end
|
||||
rm = mode%8; mode = (mode-rm)/8
|
||||
sp = mode%8; mode = (mode-sp)/8
|
||||
sdisp = ""
|
||||
if mode < 3 then
|
||||
if rm == 4 then
|
||||
if pos > stop then return incomplete(ctx) end
|
||||
sc = byte(code, pos, pos)
|
||||
pos = pos+1
|
||||
rm = sc%8; sc = (sc-rm)/8
|
||||
rx = sc%8; sc = (sc-rx)/8
|
||||
if ctx.rexx then rx = rx + 8; ctx.rexx = false end
|
||||
if rx == 4 then rx = nil end
|
||||
end
|
||||
if mode > 0 or rm == 5 then
|
||||
local dsz = mode
|
||||
if dsz ~= 1 then dsz = 4 end
|
||||
local disp = getimm(ctx, pos, dsz); if not disp then return end
|
||||
if mode == 0 then rm = nil end
|
||||
if rm or rx or (not sc and ctx.x64 and not ctx.a32) then
|
||||
if dsz == 1 and disp > 127 then
|
||||
sdisp = format("-0x%x", 256-disp)
|
||||
elseif disp >= 0 and disp <= 0x7fffffff then
|
||||
sdisp = format("+0x%x", disp)
|
||||
else
|
||||
sdisp = format("-0x%x", (0xffffffff+1)-disp)
|
||||
end
|
||||
else
|
||||
sdisp = format(ctx.x64 and not ctx.a32 and
|
||||
not (disp >= 0 and disp <= 0x7fffffff)
|
||||
and "0xffffffff%08x" or "0x%08x", disp)
|
||||
end
|
||||
pos = pos+dsz
|
||||
end
|
||||
end
|
||||
if rm and ctx.rexb then rm = rm + 8; ctx.rexb = false end
|
||||
if ctx.rexr then sp = sp + 8; ctx.rexr = false end
|
||||
end
|
||||
if p == "m" then
|
||||
if mode == 3 then x = regs[rm+1]
|
||||
else
|
||||
local aregs = ctx.a32 and map_regs.D or ctx.aregs
|
||||
local srm, srx = "", ""
|
||||
if rm then srm = aregs[rm+1]
|
||||
elseif not sc and ctx.x64 and not ctx.a32 then srm = "rip" end
|
||||
ctx.a32 = false
|
||||
if rx then
|
||||
if rm then srm = srm.."+" end
|
||||
srx = aregs[rx+1]
|
||||
if sc > 0 then srx = srx.."*"..(2^sc) end
|
||||
end
|
||||
x = format("[%s%s%s]", srm, srx, sdisp)
|
||||
end
|
||||
if mode < 3 and
|
||||
(not match(pat, "[aRrgp]") or match(pat, "t")) then -- Yuck.
|
||||
x = map_sz2prefix[sz].." "..x
|
||||
end
|
||||
elseif p == "r" then x = regs[sp+1]
|
||||
elseif p == "g" then x = map_segregs[sp+1]
|
||||
elseif p == "p" then -- Suppress prefix.
|
||||
elseif p == "f" then x = "st"..rm
|
||||
elseif p == "x" then
|
||||
if sp == 0 and ctx.lock and not ctx.x64 then
|
||||
x = "CR8"; ctx.lock = false
|
||||
else
|
||||
x = "CR"..sp
|
||||
end
|
||||
elseif p == "y" then x = "DR"..sp
|
||||
elseif p == "z" then x = "TR"..sp
|
||||
elseif p == "t" then
|
||||
else
|
||||
error("bad pattern `"..pat.."'")
|
||||
end
|
||||
end
|
||||
if x then operands = operands and operands..", "..x or x end
|
||||
end
|
||||
ctx.pos = pos
|
||||
return putop(ctx, name, operands)
|
||||
end
|
||||
|
||||
-- Forward declaration.
|
||||
local map_act
|
||||
|
||||
-- Fetch and cache MRM byte.
|
||||
local function getmrm(ctx)
|
||||
local mrm = ctx.mrm
|
||||
if not mrm then
|
||||
local pos = ctx.pos
|
||||
if pos > ctx.stop then return nil end
|
||||
mrm = byte(ctx.code, pos, pos)
|
||||
ctx.pos = pos+1
|
||||
ctx.mrm = mrm
|
||||
end
|
||||
return mrm
|
||||
end
|
||||
|
||||
-- Dispatch to handler depending on pattern.
|
||||
local function dispatch(ctx, opat, patgrp)
|
||||
if not opat then return unknown(ctx) end
|
||||
if match(opat, "%|") then -- MMX/SSE variants depending on prefix.
|
||||
local p
|
||||
if ctx.rep then
|
||||
p = ctx.rep=="rep" and "%|([^%|]*)" or "%|[^%|]*%|[^%|]*%|([^%|]*)"
|
||||
ctx.rep = false
|
||||
elseif ctx.o16 then p = "%|[^%|]*%|([^%|]*)"; ctx.o16 = false
|
||||
else p = "^[^%|]*" end
|
||||
opat = match(opat, p)
|
||||
if not opat then return unknown(ctx) end
|
||||
-- ctx.rep = false; ctx.o16 = false
|
||||
--XXX fails for 66 f2 0f 38 f1 06 crc32 eax,WORD PTR [esi]
|
||||
--XXX remove in branches?
|
||||
end
|
||||
if match(opat, "%$") then -- reg$mem variants.
|
||||
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
|
||||
opat = match(opat, mrm >= 192 and "^[^%$]*" or "%$(.*)")
|
||||
if opat == "" then return unknown(ctx) end
|
||||
end
|
||||
if opat == "" then return unknown(ctx) end
|
||||
local name, pat = match(opat, "^([a-z0-9 ]*)(.*)")
|
||||
if pat == "" and patgrp then pat = patgrp end
|
||||
return map_act[sub(pat, 1, 1)](ctx, name, pat)
|
||||
end
|
||||
|
||||
-- Get a pattern from an opcode map and dispatch to handler.
|
||||
local function dispatchmap(ctx, opcmap)
|
||||
local pos = ctx.pos
|
||||
local opat = opcmap[byte(ctx.code, pos, pos)]
|
||||
pos = pos + 1
|
||||
ctx.pos = pos
|
||||
return dispatch(ctx, opat)
|
||||
end
|
||||
|
||||
-- Map for action codes. The key is the first char after the name.
|
||||
map_act = {
|
||||
-- Simple opcodes without operands.
|
||||
[""] = function(ctx, name, pat)
|
||||
return putop(ctx, name)
|
||||
end,
|
||||
|
||||
-- Operand size chars fall right through.
|
||||
B = putpat, W = putpat, D = putpat, Q = putpat,
|
||||
V = putpat, U = putpat, T = putpat,
|
||||
M = putpat, X = putpat, P = putpat,
|
||||
F = putpat, G = putpat,
|
||||
|
||||
-- Collect prefixes.
|
||||
[":"] = function(ctx, name, pat)
|
||||
ctx[pat == ":" and name or sub(pat, 2)] = name
|
||||
if ctx.pos - ctx.start > 5 then return unknown(ctx) end -- Limit #prefixes.
|
||||
end,
|
||||
|
||||
-- Chain to special handler specified by name.
|
||||
["*"] = function(ctx, name, pat)
|
||||
return map_act[name](ctx, name, sub(pat, 2))
|
||||
end,
|
||||
|
||||
-- Use named subtable for opcode group.
|
||||
["!"] = function(ctx, name, pat)
|
||||
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
|
||||
return dispatch(ctx, map_opcgroup[name][((mrm-(mrm%8))/8)%8+1], sub(pat, 2))
|
||||
end,
|
||||
|
||||
-- o16,o32[,o64] variants.
|
||||
sz = function(ctx, name, pat)
|
||||
if ctx.o16 then ctx.o16 = false
|
||||
else
|
||||
pat = match(pat, ",(.*)")
|
||||
if ctx.rexw then
|
||||
local p = match(pat, ",(.*)")
|
||||
if p then pat = p; ctx.rexw = false end
|
||||
end
|
||||
end
|
||||
pat = match(pat, "^[^,]*")
|
||||
return dispatch(ctx, pat)
|
||||
end,
|
||||
|
||||
-- Two-byte opcode dispatch.
|
||||
opc2 = function(ctx, name, pat)
|
||||
return dispatchmap(ctx, map_opc2)
|
||||
end,
|
||||
|
||||
-- Three-byte opcode dispatch.
|
||||
opc3 = function(ctx, name, pat)
|
||||
return dispatchmap(ctx, map_opc3[pat])
|
||||
end,
|
||||
|
||||
-- VMX/SVM dispatch.
|
||||
vm = function(ctx, name, pat)
|
||||
return dispatch(ctx, map_opcvm[ctx.mrm])
|
||||
end,
|
||||
|
||||
-- Floating point opcode dispatch.
|
||||
fp = function(ctx, name, pat)
|
||||
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
|
||||
local rm = mrm%8
|
||||
local idx = pat*8 + ((mrm-rm)/8)%8
|
||||
if mrm >= 192 then idx = idx + 64 end
|
||||
local opat = map_opcfp[idx]
|
||||
if type(opat) == "table" then opat = opat[rm+1] end
|
||||
return dispatch(ctx, opat)
|
||||
end,
|
||||
|
||||
-- REX prefix.
|
||||
rex = function(ctx, name, pat)
|
||||
if ctx.rex then return unknown(ctx) end -- Only 1 REX prefix allowed.
|
||||
for p in gmatch(pat, ".") do ctx["rex"..p] = true end
|
||||
ctx.rex = true
|
||||
end,
|
||||
|
||||
-- Special case for nop with REX prefix.
|
||||
nop = function(ctx, name, pat)
|
||||
return dispatch(ctx, ctx.rex and pat or "nop")
|
||||
end,
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Disassemble a block of code.
|
||||
local function disass_block(ctx, ofs, len)
|
||||
if not ofs then ofs = 0 end
|
||||
local stop = len and ofs+len or #ctx.code
|
||||
ofs = ofs + 1
|
||||
ctx.start = ofs
|
||||
ctx.pos = ofs
|
||||
ctx.stop = stop
|
||||
ctx.imm = nil
|
||||
ctx.mrm = false
|
||||
clearprefixes(ctx)
|
||||
while ctx.pos <= stop do dispatchmap(ctx, ctx.map1) end
|
||||
if ctx.pos ~= ctx.start then incomplete(ctx) end
|
||||
end
|
||||
|
||||
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
|
||||
local function create_(code, addr, out)
|
||||
local ctx = {}
|
||||
ctx.code = code
|
||||
ctx.addr = (addr or 0) - 1
|
||||
ctx.out = out or io.write
|
||||
ctx.symtab = {}
|
||||
ctx.disass = disass_block
|
||||
ctx.hexdump = 16
|
||||
ctx.x64 = false
|
||||
ctx.map1 = map_opc1_32
|
||||
ctx.aregs = map_regs.D
|
||||
return ctx
|
||||
end
|
||||
|
||||
local function create64_(code, addr, out)
|
||||
local ctx = create_(code, addr, out)
|
||||
ctx.x64 = true
|
||||
ctx.map1 = map_opc1_64
|
||||
ctx.aregs = map_regs.Q
|
||||
return ctx
|
||||
end
|
||||
|
||||
-- Simple API: disassemble code (a string) at address and output via out.
|
||||
local function disass_(code, addr, out)
|
||||
create_(code, addr, out):disass()
|
||||
end
|
||||
|
||||
local function disass64_(code, addr, out)
|
||||
create64_(code, addr, out):disass()
|
||||
end
|
||||
|
||||
-- Return register name for RID.
|
||||
local function regname_(r)
|
||||
if r < 8 then return map_regs.D[r+1] end
|
||||
return map_regs.X[r-7]
|
||||
end
|
||||
|
||||
local function regname64_(r)
|
||||
if r < 16 then return map_regs.Q[r+1] end
|
||||
return map_regs.X[r-15]
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
module(...)
|
||||
|
||||
create = create_
|
||||
create64 = create64_
|
||||
disass = disass_
|
||||
disass64 = disass64_
|
||||
regname = regname_
|
||||
regname64 = regname64_
|
||||
|
||||
@@ -0,0 +1,700 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaJIT compiler dump module.
|
||||
--
|
||||
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- This module can be used to debug the JIT compiler itself. It dumps the
|
||||
-- code representations and structures used in various compiler stages.
|
||||
--
|
||||
-- Example usage:
|
||||
--
|
||||
-- luajit -jdump -e "local x=0; for i=1,1e6 do x=x+i end; print(x)"
|
||||
-- luajit -jdump=im -e "for i=1,1000 do for j=1,1000 do end end" | less -R
|
||||
-- luajit -jdump=is myapp.lua | less -R
|
||||
-- luajit -jdump=-b myapp.lua
|
||||
-- luajit -jdump=+aH,myapp.html myapp.lua
|
||||
-- luajit -jdump=ixT,myapp.dump myapp.lua
|
||||
--
|
||||
-- The first argument specifies the dump mode. The second argument gives
|
||||
-- the output file name. Default output is to stdout, unless the environment
|
||||
-- variable LUAJIT_DUMPFILE is set. The file is overwritten every time the
|
||||
-- module is started.
|
||||
--
|
||||
-- Different features can be turned on or off with the dump mode. If the
|
||||
-- mode starts with a '+', the following features are added to the default
|
||||
-- set of features; a '-' removes them. Otherwise the features are replaced.
|
||||
--
|
||||
-- The following dump features are available (* marks the default):
|
||||
--
|
||||
-- * t Print a line for each started, ended or aborted trace (see also -jv).
|
||||
-- * b Dump the traced bytecode.
|
||||
-- * i Dump the IR (intermediate representation).
|
||||
-- r Augment the IR with register/stack slots.
|
||||
-- s Dump the snapshot map.
|
||||
-- * m Dump the generated machine code.
|
||||
-- x Print each taken trace exit.
|
||||
-- X Print each taken trace exit and the contents of all registers.
|
||||
--
|
||||
-- The output format can be set with the following characters:
|
||||
--
|
||||
-- T Plain text output.
|
||||
-- A ANSI-colored text output
|
||||
-- H Colorized HTML + CSS output.
|
||||
--
|
||||
-- The default output format is plain text. It's set to ANSI-colored text
|
||||
-- if the COLORTERM variable is set. Note: this is independent of any output
|
||||
-- redirection, which is actually considered a feature.
|
||||
--
|
||||
-- You probably want to use less -R to enjoy viewing ANSI-colored text from
|
||||
-- a pipe or a file. Add this to your ~/.bashrc: export LESS="-R"
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Cache some library functions and objects.
|
||||
local jit = require("jit")
|
||||
assert(jit.version_num == 20001, "LuaJIT core/library version mismatch")
|
||||
local jutil = require("jit.util")
|
||||
local vmdef = require("jit.vmdef")
|
||||
local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc
|
||||
local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek
|
||||
local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap
|
||||
local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr
|
||||
local bit = require("bit")
|
||||
local band, shl, shr = bit.band, bit.lshift, bit.rshift
|
||||
local sub, gsub, format = string.sub, string.gsub, string.format
|
||||
local byte, char, rep = string.byte, string.char, string.rep
|
||||
local type, tostring = type, tostring
|
||||
local stdout, stderr = io.stdout, io.stderr
|
||||
|
||||
-- Load other modules on-demand.
|
||||
local bcline, disass
|
||||
|
||||
-- Active flag, output file handle and dump mode.
|
||||
local active, out, dumpmode
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local symtabmt = { __index = false }
|
||||
local symtab = {}
|
||||
local nexitsym = 0
|
||||
|
||||
-- Fill nested symbol table with per-trace exit stub addresses.
|
||||
local function fillsymtab_tr(tr, nexit)
|
||||
local t = {}
|
||||
symtabmt.__index = t
|
||||
if jit.arch == "mips" or jit.arch == "mipsel" then
|
||||
t[traceexitstub(tr, 0)] = "exit"
|
||||
return
|
||||
end
|
||||
for i=0,nexit-1 do
|
||||
local addr = traceexitstub(tr, i)
|
||||
t[addr] = tostring(i)
|
||||
end
|
||||
local addr = traceexitstub(tr, nexit)
|
||||
if addr then t[addr] = "stack_check" end
|
||||
end
|
||||
|
||||
-- Fill symbol table with trace exit stub addresses.
|
||||
local function fillsymtab(tr, nexit)
|
||||
local t = symtab
|
||||
if nexitsym == 0 then
|
||||
local ircall = vmdef.ircall
|
||||
for i=0,#ircall do
|
||||
local addr = ircalladdr(i)
|
||||
if addr ~= 0 then t[addr] = ircall[i] end
|
||||
end
|
||||
end
|
||||
if nexitsym == 1000000 then -- Per-trace exit stubs.
|
||||
fillsymtab_tr(tr, nexit)
|
||||
elseif nexit > nexitsym then -- Shared exit stubs.
|
||||
for i=nexitsym,nexit-1 do
|
||||
local addr = traceexitstub(i)
|
||||
if addr == nil then -- Fall back to per-trace exit stubs.
|
||||
fillsymtab_tr(tr, nexit)
|
||||
setmetatable(symtab, symtabmt)
|
||||
nexit = 1000000
|
||||
break
|
||||
end
|
||||
t[addr] = tostring(i)
|
||||
end
|
||||
nexitsym = nexit
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local function dumpwrite(s)
|
||||
out:write(s)
|
||||
end
|
||||
|
||||
-- Disassemble machine code.
|
||||
local function dump_mcode(tr)
|
||||
local info = traceinfo(tr)
|
||||
if not info then return end
|
||||
local mcode, addr, loop = tracemc(tr)
|
||||
if not mcode then return end
|
||||
if not disass then disass = require("jit.dis_"..jit.arch) end
|
||||
out:write("---- TRACE ", tr, " mcode ", #mcode, "\n")
|
||||
local ctx = disass.create(mcode, addr, dumpwrite)
|
||||
ctx.hexdump = 0
|
||||
ctx.symtab = fillsymtab(tr, info.nexit)
|
||||
if loop ~= 0 then
|
||||
symtab[addr+loop] = "LOOP"
|
||||
ctx:disass(0, loop)
|
||||
out:write("->LOOP:\n")
|
||||
ctx:disass(loop, #mcode-loop)
|
||||
symtab[addr+loop] = nil
|
||||
else
|
||||
ctx:disass(0, #mcode)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local irtype_text = {
|
||||
[0] = "nil",
|
||||
"fal",
|
||||
"tru",
|
||||
"lud",
|
||||
"str",
|
||||
"p32",
|
||||
"thr",
|
||||
"pro",
|
||||
"fun",
|
||||
"p64",
|
||||
"cdt",
|
||||
"tab",
|
||||
"udt",
|
||||
"flt",
|
||||
"num",
|
||||
"i8 ",
|
||||
"u8 ",
|
||||
"i16",
|
||||
"u16",
|
||||
"int",
|
||||
"u32",
|
||||
"i64",
|
||||
"u64",
|
||||
"sfp",
|
||||
}
|
||||
|
||||
local colortype_ansi = {
|
||||
[0] = "%s",
|
||||
"%s",
|
||||
"%s",
|
||||
"\027[36m%s\027[m",
|
||||
"\027[32m%s\027[m",
|
||||
"%s",
|
||||
"\027[1m%s\027[m",
|
||||
"%s",
|
||||
"\027[1m%s\027[m",
|
||||
"%s",
|
||||
"\027[33m%s\027[m",
|
||||
"\027[31m%s\027[m",
|
||||
"\027[36m%s\027[m",
|
||||
"\027[34m%s\027[m",
|
||||
"\027[34m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
"\027[35m%s\027[m",
|
||||
}
|
||||
|
||||
local function colorize_text(s, t)
|
||||
return s
|
||||
end
|
||||
|
||||
local function colorize_ansi(s, t)
|
||||
return format(colortype_ansi[t], s)
|
||||
end
|
||||
|
||||
local irtype_ansi = setmetatable({},
|
||||
{ __index = function(tab, t)
|
||||
local s = colorize_ansi(irtype_text[t], t); tab[t] = s; return s; end })
|
||||
|
||||
local html_escape = { ["<"] = "<", [">"] = ">", ["&"] = "&", }
|
||||
|
||||
local function colorize_html(s, t)
|
||||
s = gsub(s, "[<>&]", html_escape)
|
||||
return format('<span class="irt_%s">%s</span>', irtype_text[t], s)
|
||||
end
|
||||
|
||||
local irtype_html = setmetatable({},
|
||||
{ __index = function(tab, t)
|
||||
local s = colorize_html(irtype_text[t], t); tab[t] = s; return s; end })
|
||||
|
||||
local header_html = [[
|
||||
<style type="text/css">
|
||||
background { background: #ffffff; color: #000000; }
|
||||
pre.ljdump {
|
||||
font-size: 10pt;
|
||||
background: #f0f4ff;
|
||||
color: #000000;
|
||||
border: 1px solid #bfcfff;
|
||||
padding: 0.5em;
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
span.irt_str { color: #00a000; }
|
||||
span.irt_thr, span.irt_fun { color: #404040; font-weight: bold; }
|
||||
span.irt_tab { color: #c00000; }
|
||||
span.irt_udt, span.irt_lud { color: #00c0c0; }
|
||||
span.irt_num { color: #4040c0; }
|
||||
span.irt_int, span.irt_i8, span.irt_u8, span.irt_i16, span.irt_u16 { color: #b040b0; }
|
||||
</style>
|
||||
]]
|
||||
|
||||
local colorize, irtype
|
||||
|
||||
-- Lookup tables to convert some literals into names.
|
||||
local litname = {
|
||||
["SLOAD "] = setmetatable({}, { __index = function(t, mode)
|
||||
local s = ""
|
||||
if band(mode, 1) ~= 0 then s = s.."P" end
|
||||
if band(mode, 2) ~= 0 then s = s.."F" end
|
||||
if band(mode, 4) ~= 0 then s = s.."T" end
|
||||
if band(mode, 8) ~= 0 then s = s.."C" end
|
||||
if band(mode, 16) ~= 0 then s = s.."R" end
|
||||
if band(mode, 32) ~= 0 then s = s.."I" end
|
||||
t[mode] = s
|
||||
return s
|
||||
end}),
|
||||
["XLOAD "] = { [0] = "", "R", "V", "RV", "U", "RU", "VU", "RVU", },
|
||||
["CONV "] = setmetatable({}, { __index = function(t, mode)
|
||||
local s = irtype[band(mode, 31)]
|
||||
s = irtype[band(shr(mode, 5), 31)].."."..s
|
||||
if band(mode, 0x400) ~= 0 then s = s.." trunc"
|
||||
elseif band(mode, 0x800) ~= 0 then s = s.." sext" end
|
||||
local c = shr(mode, 14)
|
||||
if c == 2 then s = s.." index" elseif c == 3 then s = s.." check" end
|
||||
t[mode] = s
|
||||
return s
|
||||
end}),
|
||||
["FLOAD "] = vmdef.irfield,
|
||||
["FREF "] = vmdef.irfield,
|
||||
["FPMATH"] = vmdef.irfpm,
|
||||
}
|
||||
|
||||
local function ctlsub(c)
|
||||
if c == "\n" then return "\\n"
|
||||
elseif c == "\r" then return "\\r"
|
||||
elseif c == "\t" then return "\\t"
|
||||
else return format("\\%03d", byte(c))
|
||||
end
|
||||
end
|
||||
|
||||
local function fmtfunc(func, pc)
|
||||
local fi = funcinfo(func, pc)
|
||||
if fi.loc then
|
||||
return fi.loc
|
||||
elseif fi.ffid then
|
||||
return vmdef.ffnames[fi.ffid]
|
||||
elseif fi.addr then
|
||||
return format("C:%x", fi.addr)
|
||||
else
|
||||
return "(?)"
|
||||
end
|
||||
end
|
||||
|
||||
local function formatk(tr, idx)
|
||||
local k, t, slot = tracek(tr, idx)
|
||||
local tn = type(k)
|
||||
local s
|
||||
if tn == "number" then
|
||||
if k == 2^52+2^51 then
|
||||
s = "bias"
|
||||
else
|
||||
s = format("%+.14g", k)
|
||||
end
|
||||
elseif tn == "string" then
|
||||
s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub))
|
||||
elseif tn == "function" then
|
||||
s = fmtfunc(k)
|
||||
elseif tn == "table" then
|
||||
s = format("{%p}", k)
|
||||
elseif tn == "userdata" then
|
||||
if t == 12 then
|
||||
s = format("userdata:%p", k)
|
||||
else
|
||||
s = format("[%p]", k)
|
||||
if s == "[0x00000000]" then s = "NULL" end
|
||||
end
|
||||
elseif t == 21 then -- int64_t
|
||||
s = sub(tostring(k), 1, -3)
|
||||
if sub(s, 1, 1) ~= "-" then s = "+"..s end
|
||||
else
|
||||
s = tostring(k) -- For primitives.
|
||||
end
|
||||
s = colorize(format("%-4s", s), t)
|
||||
if slot then
|
||||
s = format("%s @%d", s, slot)
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
local function printsnap(tr, snap)
|
||||
local n = 2
|
||||
for s=0,snap[1]-1 do
|
||||
local sn = snap[n]
|
||||
if shr(sn, 24) == s then
|
||||
n = n + 1
|
||||
local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS
|
||||
if ref < 0 then
|
||||
out:write(formatk(tr, ref))
|
||||
elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM
|
||||
out:write(colorize(format("%04d/%04d", ref, ref+1), 14))
|
||||
else
|
||||
local m, ot, op1, op2 = traceir(tr, ref)
|
||||
out:write(colorize(format("%04d", ref), band(ot, 31)))
|
||||
end
|
||||
out:write(band(sn, 0x10000) == 0 and " " or "|") -- SNAP_FRAME
|
||||
else
|
||||
out:write("---- ")
|
||||
end
|
||||
end
|
||||
out:write("]\n")
|
||||
end
|
||||
|
||||
-- Dump snapshots (not interleaved with IR).
|
||||
local function dump_snap(tr)
|
||||
out:write("---- TRACE ", tr, " snapshots\n")
|
||||
for i=0,1000000000 do
|
||||
local snap = tracesnap(tr, i)
|
||||
if not snap then break end
|
||||
out:write(format("#%-3d %04d [ ", i, snap[0]))
|
||||
printsnap(tr, snap)
|
||||
end
|
||||
end
|
||||
|
||||
-- Return a register name or stack slot for a rid/sp location.
|
||||
local function ridsp_name(ridsp, ins)
|
||||
if not disass then disass = require("jit.dis_"..jit.arch) end
|
||||
local rid, slot = band(ridsp, 0xff), shr(ridsp, 8)
|
||||
if rid == 253 or rid == 254 then
|
||||
return (slot == 0 or slot == 255) and " {sink" or format(" {%04d", ins-slot)
|
||||
end
|
||||
if ridsp > 255 then return format("[%x]", slot*4) end
|
||||
if rid < 128 then return disass.regname(rid) end
|
||||
return ""
|
||||
end
|
||||
|
||||
-- Dump CALL* function ref and return optional ctype.
|
||||
local function dumpcallfunc(tr, ins)
|
||||
local ctype
|
||||
if ins > 0 then
|
||||
local m, ot, op1, op2 = traceir(tr, ins)
|
||||
if band(ot, 31) == 0 then -- nil type means CARG(func, ctype).
|
||||
ins = op1
|
||||
ctype = formatk(tr, op2)
|
||||
end
|
||||
end
|
||||
if ins < 0 then
|
||||
out:write(format("[0x%x](", tonumber((tracek(tr, ins)))))
|
||||
else
|
||||
out:write(format("%04d (", ins))
|
||||
end
|
||||
return ctype
|
||||
end
|
||||
|
||||
-- Recursively gather CALL* args and dump them.
|
||||
local function dumpcallargs(tr, ins)
|
||||
if ins < 0 then
|
||||
out:write(formatk(tr, ins))
|
||||
else
|
||||
local m, ot, op1, op2 = traceir(tr, ins)
|
||||
local oidx = 6*shr(ot, 8)
|
||||
local op = sub(vmdef.irnames, oidx+1, oidx+6)
|
||||
if op == "CARG " then
|
||||
dumpcallargs(tr, op1)
|
||||
if op2 < 0 then
|
||||
out:write(" ", formatk(tr, op2))
|
||||
else
|
||||
out:write(" ", format("%04d", op2))
|
||||
end
|
||||
else
|
||||
out:write(format("%04d", ins))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Dump IR and interleaved snapshots.
|
||||
local function dump_ir(tr, dumpsnap, dumpreg)
|
||||
local info = traceinfo(tr)
|
||||
if not info then return end
|
||||
local nins = info.nins
|
||||
out:write("---- TRACE ", tr, " IR\n")
|
||||
local irnames = vmdef.irnames
|
||||
local snapref = 65536
|
||||
local snap, snapno
|
||||
if dumpsnap then
|
||||
snap = tracesnap(tr, 0)
|
||||
snapref = snap[0]
|
||||
snapno = 0
|
||||
end
|
||||
for ins=1,nins do
|
||||
if ins >= snapref then
|
||||
if dumpreg then
|
||||
out:write(format(".... SNAP #%-3d [ ", snapno))
|
||||
else
|
||||
out:write(format(".... SNAP #%-3d [ ", snapno))
|
||||
end
|
||||
printsnap(tr, snap)
|
||||
snapno = snapno + 1
|
||||
snap = tracesnap(tr, snapno)
|
||||
snapref = snap and snap[0] or 65536
|
||||
end
|
||||
local m, ot, op1, op2, ridsp = traceir(tr, ins)
|
||||
local oidx, t = 6*shr(ot, 8), band(ot, 31)
|
||||
local op = sub(irnames, oidx+1, oidx+6)
|
||||
if op == "LOOP " then
|
||||
if dumpreg then
|
||||
out:write(format("%04d ------------ LOOP ------------\n", ins))
|
||||
else
|
||||
out:write(format("%04d ------ LOOP ------------\n", ins))
|
||||
end
|
||||
elseif op ~= "NOP " and op ~= "CARG " and
|
||||
(dumpreg or op ~= "RENAME") then
|
||||
local rid = band(ridsp, 255)
|
||||
if dumpreg then
|
||||
out:write(format("%04d %-6s", ins, ridsp_name(ridsp, ins)))
|
||||
else
|
||||
out:write(format("%04d ", ins))
|
||||
end
|
||||
out:write(format("%s%s %s %s ",
|
||||
(rid == 254 or rid == 253) and "}" or
|
||||
(band(ot, 128) == 0 and " " or ">"),
|
||||
band(ot, 64) == 0 and " " or "+",
|
||||
irtype[t], op))
|
||||
local m1, m2 = band(m, 3), band(m, 3*4)
|
||||
if sub(op, 1, 4) == "CALL" then
|
||||
local ctype
|
||||
if m2 == 1*4 then -- op2 == IRMlit
|
||||
out:write(format("%-10s (", vmdef.ircall[op2]))
|
||||
else
|
||||
ctype = dumpcallfunc(tr, op2)
|
||||
end
|
||||
if op1 ~= -1 then dumpcallargs(tr, op1) end
|
||||
out:write(")")
|
||||
if ctype then out:write(" ctype ", ctype) end
|
||||
elseif op == "CNEW " and op2 == -1 then
|
||||
out:write(formatk(tr, op1))
|
||||
elseif m1 ~= 3 then -- op1 != IRMnone
|
||||
if op1 < 0 then
|
||||
out:write(formatk(tr, op1))
|
||||
else
|
||||
out:write(format(m1 == 0 and "%04d" or "#%-3d", op1))
|
||||
end
|
||||
if m2 ~= 3*4 then -- op2 != IRMnone
|
||||
if m2 == 1*4 then -- op2 == IRMlit
|
||||
local litn = litname[op]
|
||||
if litn and litn[op2] then
|
||||
out:write(" ", litn[op2])
|
||||
elseif op == "UREFO " or op == "UREFC " then
|
||||
out:write(format(" #%-3d", shr(op2, 8)))
|
||||
else
|
||||
out:write(format(" #%-3d", op2))
|
||||
end
|
||||
elseif op2 < 0 then
|
||||
out:write(" ", formatk(tr, op2))
|
||||
else
|
||||
out:write(format(" %04d", op2))
|
||||
end
|
||||
end
|
||||
end
|
||||
out:write("\n")
|
||||
end
|
||||
end
|
||||
if snap then
|
||||
if dumpreg then
|
||||
out:write(format(".... SNAP #%-3d [ ", snapno))
|
||||
else
|
||||
out:write(format(".... SNAP #%-3d [ ", snapno))
|
||||
end
|
||||
printsnap(tr, snap)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local recprefix = ""
|
||||
local recdepth = 0
|
||||
|
||||
-- Format trace error message.
|
||||
local function fmterr(err, info)
|
||||
if type(err) == "number" then
|
||||
if type(info) == "function" then info = fmtfunc(info) end
|
||||
err = format(vmdef.traceerr[err], info)
|
||||
end
|
||||
return err
|
||||
end
|
||||
|
||||
-- Dump trace states.
|
||||
local function dump_trace(what, tr, func, pc, otr, oex)
|
||||
if what == "stop" or (what == "abort" and dumpmode.a) then
|
||||
if dumpmode.i then dump_ir(tr, dumpmode.s, dumpmode.r and what == "stop")
|
||||
elseif dumpmode.s then dump_snap(tr) end
|
||||
if dumpmode.m then dump_mcode(tr) end
|
||||
end
|
||||
if what == "start" then
|
||||
if dumpmode.H then out:write('<pre class="ljdump">\n') end
|
||||
out:write("---- TRACE ", tr, " ", what)
|
||||
if otr then out:write(" ", otr, "/", oex) end
|
||||
out:write(" ", fmtfunc(func, pc), "\n")
|
||||
recprefix = ""
|
||||
elseif what == "stop" or what == "abort" then
|
||||
out:write("---- TRACE ", tr, " ", what)
|
||||
recprefix = nil
|
||||
if what == "abort" then
|
||||
out:write(" ", fmtfunc(func, pc), " -- ", fmterr(otr, oex), "\n")
|
||||
else
|
||||
local info = traceinfo(tr)
|
||||
local link, ltype = info.link, info.linktype
|
||||
if link == tr or link == 0 then
|
||||
out:write(" -> ", ltype, "\n")
|
||||
elseif ltype == "root" then
|
||||
out:write(" -> ", link, "\n")
|
||||
else
|
||||
out:write(" -> ", link, " ", ltype, "\n")
|
||||
end
|
||||
end
|
||||
if dumpmode.H then out:write("</pre>\n\n") else out:write("\n") end
|
||||
else
|
||||
out:write("---- TRACE ", what, "\n\n")
|
||||
end
|
||||
out:flush()
|
||||
end
|
||||
|
||||
-- Dump recorded bytecode.
|
||||
local function dump_record(tr, func, pc, depth, callee)
|
||||
if depth ~= recdepth then
|
||||
recdepth = depth
|
||||
recprefix = rep(" .", depth)
|
||||
end
|
||||
local line
|
||||
if pc >= 0 then
|
||||
line = bcline(func, pc, recprefix)
|
||||
if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end
|
||||
else
|
||||
line = "0000 "..recprefix.." FUNCC \n"
|
||||
callee = func
|
||||
end
|
||||
if pc <= 0 then
|
||||
out:write(sub(line, 1, -2), " ; ", fmtfunc(func), "\n")
|
||||
else
|
||||
out:write(line)
|
||||
end
|
||||
if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC
|
||||
out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond.
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Dump taken trace exits.
|
||||
local function dump_texit(tr, ex, ngpr, nfpr, ...)
|
||||
out:write("---- TRACE ", tr, " exit ", ex, "\n")
|
||||
if dumpmode.X then
|
||||
local regs = {...}
|
||||
if jit.arch == "x64" then
|
||||
for i=1,ngpr do
|
||||
out:write(format(" %016x", regs[i]))
|
||||
if i % 4 == 0 then out:write("\n") end
|
||||
end
|
||||
else
|
||||
for i=1,ngpr do
|
||||
out:write(format(" %08x", regs[i]))
|
||||
if i % 8 == 0 then out:write("\n") end
|
||||
end
|
||||
end
|
||||
if jit.arch == "mips" or jit.arch == "mipsel" then
|
||||
for i=1,nfpr,2 do
|
||||
out:write(format(" %+17.14g", regs[ngpr+i]))
|
||||
if i % 8 == 7 then out:write("\n") end
|
||||
end
|
||||
else
|
||||
for i=1,nfpr do
|
||||
out:write(format(" %+17.14g", regs[ngpr+i]))
|
||||
if i % 4 == 0 then out:write("\n") end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Detach dump handlers.
|
||||
local function dumpoff()
|
||||
if active then
|
||||
active = false
|
||||
jit.attach(dump_texit)
|
||||
jit.attach(dump_record)
|
||||
jit.attach(dump_trace)
|
||||
if out and out ~= stdout and out ~= stderr then out:close() end
|
||||
out = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Open the output file and attach dump handlers.
|
||||
local function dumpon(opt, outfile)
|
||||
if active then dumpoff() end
|
||||
|
||||
local colormode = os.getenv("COLORTERM") and "A" or "T"
|
||||
if opt then
|
||||
opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end)
|
||||
end
|
||||
|
||||
local m = { t=true, b=true, i=true, m=true, }
|
||||
if opt and opt ~= "" then
|
||||
local o = sub(opt, 1, 1)
|
||||
if o ~= "+" and o ~= "-" then m = {} end
|
||||
for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end
|
||||
end
|
||||
dumpmode = m
|
||||
|
||||
if m.t or m.b or m.i or m.s or m.m then
|
||||
jit.attach(dump_trace, "trace")
|
||||
end
|
||||
if m.b then
|
||||
jit.attach(dump_record, "record")
|
||||
if not bcline then bcline = require("jit.bc").line end
|
||||
end
|
||||
if m.x or m.X then
|
||||
jit.attach(dump_texit, "texit")
|
||||
end
|
||||
|
||||
if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end
|
||||
if outfile then
|
||||
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
|
||||
else
|
||||
out = stdout
|
||||
end
|
||||
|
||||
m[colormode] = true
|
||||
if colormode == "A" then
|
||||
colorize = colorize_ansi
|
||||
irtype = irtype_ansi
|
||||
elseif colormode == "H" then
|
||||
colorize = colorize_html
|
||||
irtype = irtype_html
|
||||
out:write(header_html)
|
||||
else
|
||||
colorize = colorize_text
|
||||
irtype = irtype_text
|
||||
end
|
||||
|
||||
active = true
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
module(...)
|
||||
|
||||
on = dumpon
|
||||
off = dumpoff
|
||||
start = dumpon -- For -j command line option.
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- Verbose mode of the LuaJIT compiler.
|
||||
--
|
||||
-- Copyright (C) 2005-2013 Mike Pall. All rights reserved.
|
||||
-- Released under the MIT license. See Copyright Notice in luajit.h
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- This module shows verbose information about the progress of the
|
||||
-- JIT compiler. It prints one line for each generated trace. This module
|
||||
-- is useful to see which code has been compiled or where the compiler
|
||||
-- punts and falls back to the interpreter.
|
||||
--
|
||||
-- Example usage:
|
||||
--
|
||||
-- luajit -jv -e "for i=1,1000 do for j=1,1000 do end end"
|
||||
-- luajit -jv=myapp.out myapp.lua
|
||||
--
|
||||
-- Default output is to stderr. To redirect the output to a file, pass a
|
||||
-- filename as an argument (use '-' for stdout) or set the environment
|
||||
-- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the
|
||||
-- module is started.
|
||||
--
|
||||
-- The output from the first example should look like this:
|
||||
--
|
||||
-- [TRACE 1 (command line):1 loop]
|
||||
-- [TRACE 2 (1/3) (command line):1 -> 1]
|
||||
--
|
||||
-- The first number in each line is the internal trace number. Next are
|
||||
-- the file name ('(command line)') and the line number (':1') where the
|
||||
-- trace has started. Side traces also show the parent trace number and
|
||||
-- the exit number where they are attached to in parentheses ('(1/3)').
|
||||
-- An arrow at the end shows where the trace links to ('-> 1'), unless
|
||||
-- it loops to itself.
|
||||
--
|
||||
-- In this case the inner loop gets hot and is traced first, generating
|
||||
-- a root trace. Then the last exit from the 1st trace gets hot, too,
|
||||
-- and triggers generation of the 2nd trace. The side trace follows the
|
||||
-- path along the outer loop and *around* the inner loop, back to its
|
||||
-- start, and then links to the 1st trace. Yes, this may seem unusual,
|
||||
-- if you know how traditional compilers work. Trace compilers are full
|
||||
-- of surprises like this -- have fun! :-)
|
||||
--
|
||||
-- Aborted traces are shown like this:
|
||||
--
|
||||
-- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50]
|
||||
--
|
||||
-- Don't worry -- trace aborts are quite common, even in programs which
|
||||
-- can be fully compiled. The compiler may retry several times until it
|
||||
-- finds a suitable trace.
|
||||
--
|
||||
-- Of course this doesn't work with features that are not-yet-implemented
|
||||
-- (NYI error messages). The VM simply falls back to the interpreter. This
|
||||
-- may not matter at all if the particular trace is not very high up in
|
||||
-- the CPU usage profile. Oh, and the interpreter is quite fast, too.
|
||||
--
|
||||
-- Also check out the -jdump module, which prints all the gory details.
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Cache some library functions and objects.
|
||||
local jit = require("jit")
|
||||
assert(jit.version_num == 20001, "LuaJIT core/library version mismatch")
|
||||
local jutil = require("jit.util")
|
||||
local vmdef = require("jit.vmdef")
|
||||
local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo
|
||||
local type, format = type, string.format
|
||||
local stdout, stderr = io.stdout, io.stderr
|
||||
|
||||
-- Active flag and output file handle.
|
||||
local active, out
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
local startloc, startex
|
||||
|
||||
local function fmtfunc(func, pc)
|
||||
local fi = funcinfo(func, pc)
|
||||
if fi.loc then
|
||||
return fi.loc
|
||||
elseif fi.ffid then
|
||||
return vmdef.ffnames[fi.ffid]
|
||||
elseif fi.addr then
|
||||
return format("C:%x", fi.addr)
|
||||
else
|
||||
return "(?)"
|
||||
end
|
||||
end
|
||||
|
||||
-- Format trace error message.
|
||||
local function fmterr(err, info)
|
||||
if type(err) == "number" then
|
||||
if type(info) == "function" then info = fmtfunc(info) end
|
||||
err = format(vmdef.traceerr[err], info)
|
||||
end
|
||||
return err
|
||||
end
|
||||
|
||||
-- Dump trace states.
|
||||
local function dump_trace(what, tr, func, pc, otr, oex)
|
||||
if what == "start" then
|
||||
startloc = fmtfunc(func, pc)
|
||||
startex = otr and "("..otr.."/"..oex..") " or ""
|
||||
else
|
||||
if what == "abort" then
|
||||
local loc = fmtfunc(func, pc)
|
||||
if loc ~= startloc then
|
||||
out:write(format("[TRACE --- %s%s -- %s at %s]\n",
|
||||
startex, startloc, fmterr(otr, oex), loc))
|
||||
else
|
||||
out:write(format("[TRACE --- %s%s -- %s]\n",
|
||||
startex, startloc, fmterr(otr, oex)))
|
||||
end
|
||||
elseif what == "stop" then
|
||||
local info = traceinfo(tr)
|
||||
local link, ltype = info.link, info.linktype
|
||||
if ltype == "interpreter" then
|
||||
out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n",
|
||||
tr, startex, startloc))
|
||||
elseif link == tr or link == 0 then
|
||||
out:write(format("[TRACE %3s %s%s %s]\n",
|
||||
tr, startex, startloc, ltype))
|
||||
elseif ltype == "root" then
|
||||
out:write(format("[TRACE %3s %s%s -> %d]\n",
|
||||
tr, startex, startloc, link))
|
||||
else
|
||||
out:write(format("[TRACE %3s %s%s -> %d %s]\n",
|
||||
tr, startex, startloc, link, ltype))
|
||||
end
|
||||
else
|
||||
out:write(format("[TRACE %s]\n", what))
|
||||
end
|
||||
out:flush()
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
-- Detach dump handlers.
|
||||
local function dumpoff()
|
||||
if active then
|
||||
active = false
|
||||
jit.attach(dump_trace)
|
||||
if out and out ~= stdout and out ~= stderr then out:close() end
|
||||
out = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Open the output file and attach dump handlers.
|
||||
local function dumpon(outfile)
|
||||
if active then dumpoff() end
|
||||
if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end
|
||||
if outfile then
|
||||
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
|
||||
else
|
||||
out = stderr
|
||||
end
|
||||
jit.attach(dump_trace, "trace")
|
||||
active = true
|
||||
end
|
||||
|
||||
-- Public module functions.
|
||||
module(...)
|
||||
|
||||
on = dumpon
|
||||
off = dumpoff
|
||||
start = dumpon -- For -j command line option.
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
-- This is a generated file. DO NOT EDIT!
|
||||
|
||||
module(...)
|
||||
|
||||
bcnames = "ISLT ISGE ISLE ISGT ISEQV ISNEV ISEQS ISNES ISEQN ISNEN ISEQP ISNEP ISTC ISFC IST ISF MOV NOT UNM LEN ADDVN SUBVN MULVN DIVVN MODVN ADDNV SUBNV MULNV DIVNV MODNV ADDVV SUBVV MULVV DIVVV MODVV POW CAT KSTR KCDATAKSHORTKNUM KPRI KNIL UGET USETV USETS USETN USETP UCLO FNEW TNEW TDUP GGET GSET TGETV TGETS TGETB TSETV TSETS TSETB TSETM CALLM CALL CALLMTCALLT ITERC ITERN VARG ISNEXTRETM RET RET0 RET1 FORI JFORI FORL IFORL JFORL ITERL IITERLJITERLLOOP ILOOP JLOOP JMP FUNCF IFUNCFJFUNCFFUNCV IFUNCVJFUNCVFUNCC FUNCCW"
|
||||
|
||||
irnames = "LT GE LE GT ULT UGE ULE UGT EQ NE ABC RETF NOP BASE PVAL GCSTEPHIOP LOOP USE PHI RENAMEKPRI KINT KGC KPTR KKPTR KNULL KNUM KINT64KSLOT BNOT BSWAP BAND BOR BXOR BSHL BSHR BSAR BROL BROR ADD SUB MUL DIV MOD POW NEG ABS ATAN2 LDEXP MIN MAX FPMATHADDOV SUBOV MULOV AREF HREFK HREF NEWREFUREFO UREFC FREF STRREFALOAD HLOAD ULOAD FLOAD XLOAD SLOAD VLOAD ASTOREHSTOREUSTOREFSTOREXSTORESNEW XSNEW TNEW TDUP CNEW CNEWI TBAR OBAR XBAR CONV TOBIT TOSTR STRTO CALLN CALLL CALLS CALLXSCARG "
|
||||
|
||||
irfpm = { [0]="floor", "ceil", "trunc", "sqrt", "exp", "exp2", "log", "log2", "log10", "sin", "cos", "tan", "other", }
|
||||
|
||||
irfield = { [0]="str.len", "func.env", "func.pc", "tab.meta", "tab.array", "tab.node", "tab.asize", "tab.hmask", "tab.nomm", "udata.meta", "udata.udtype", "udata.file", "cdata.ctypeid", "cdata.ptr", "cdata.int", "cdata.int64", "cdata.int64_4", }
|
||||
|
||||
ircall = {
|
||||
[0]="lj_str_cmp",
|
||||
"lj_str_new",
|
||||
"lj_strscan_num",
|
||||
"lj_str_fromint",
|
||||
"lj_str_fromnum",
|
||||
"lj_tab_new1",
|
||||
"lj_tab_dup",
|
||||
"lj_tab_newkey",
|
||||
"lj_tab_len",
|
||||
"lj_gc_step_jit",
|
||||
"lj_gc_barrieruv",
|
||||
"lj_mem_newgco",
|
||||
"lj_math_random_step",
|
||||
"lj_vm_modi",
|
||||
"sinh",
|
||||
"cosh",
|
||||
"tanh",
|
||||
"fputc",
|
||||
"fwrite",
|
||||
"fflush",
|
||||
"lj_vm_floor",
|
||||
"lj_vm_ceil",
|
||||
"lj_vm_trunc",
|
||||
"sqrt",
|
||||
"exp",
|
||||
"lj_vm_exp2",
|
||||
"log",
|
||||
"lj_vm_log2",
|
||||
"log10",
|
||||
"sin",
|
||||
"cos",
|
||||
"tan",
|
||||
"lj_vm_powi",
|
||||
"pow",
|
||||
"atan2",
|
||||
"ldexp",
|
||||
"lj_vm_tobit",
|
||||
"softfp_add",
|
||||
"softfp_sub",
|
||||
"softfp_mul",
|
||||
"softfp_div",
|
||||
"softfp_cmp",
|
||||
"softfp_i2d",
|
||||
"softfp_d2i",
|
||||
"softfp_ui2d",
|
||||
"softfp_f2d",
|
||||
"softfp_d2ui",
|
||||
"softfp_d2f",
|
||||
"softfp_i2f",
|
||||
"softfp_ui2f",
|
||||
"softfp_f2i",
|
||||
"softfp_f2ui",
|
||||
"fp64_l2d",
|
||||
"fp64_ul2d",
|
||||
"fp64_l2f",
|
||||
"fp64_ul2f",
|
||||
"fp64_d2l",
|
||||
"fp64_d2ul",
|
||||
"fp64_f2l",
|
||||
"fp64_f2ul",
|
||||
"lj_carith_divi64",
|
||||
"lj_carith_divu64",
|
||||
"lj_carith_modi64",
|
||||
"lj_carith_modu64",
|
||||
"lj_carith_powi64",
|
||||
"lj_carith_powu64",
|
||||
"lj_cdata_setfin",
|
||||
"strlen",
|
||||
"memcpy",
|
||||
"memset",
|
||||
"lj_vm_errno",
|
||||
"lj_carith_mul64",
|
||||
}
|
||||
|
||||
traceerr = {
|
||||
[0]="error thrown or hook called during recording",
|
||||
"trace too long",
|
||||
"trace too deep",
|
||||
"too many snapshots",
|
||||
"blacklisted",
|
||||
"NYI: bytecode %d",
|
||||
"leaving loop in root trace",
|
||||
"inner loop in root trace",
|
||||
"loop unroll limit reached",
|
||||
"bad argument type",
|
||||
"call to JIT-disabled function",
|
||||
"call unroll limit reached",
|
||||
"down-recursion, restarting",
|
||||
"NYI: C function %p",
|
||||
"NYI: FastFunc %s",
|
||||
"NYI: unsupported variant of FastFunc %s",
|
||||
"NYI: return to lower frame",
|
||||
"store with nil or NaN key",
|
||||
"missing metamethod",
|
||||
"looping index lookup",
|
||||
"NYI: mixed sparse/dense table",
|
||||
"symbol not in cache",
|
||||
"NYI: unsupported C type conversion",
|
||||
"NYI: unsupported C function type",
|
||||
"guard would always fail",
|
||||
"too many PHIs",
|
||||
"persistent type instability",
|
||||
"failed to allocate mcode memory",
|
||||
"machine code too long",
|
||||
"hit mcode limit (retrying)",
|
||||
"too many spill slots",
|
||||
"inconsistent register allocation",
|
||||
"NYI: cannot assemble IR instruction %d",
|
||||
"NYI: PHI shuffling too complex",
|
||||
"NYI: register coalescing too complex",
|
||||
}
|
||||
|
||||
ffnames = {
|
||||
[0]="Lua",
|
||||
"C",
|
||||
"assert",
|
||||
"type",
|
||||
"next",
|
||||
"pairs",
|
||||
"ipairs_aux",
|
||||
"ipairs",
|
||||
"getmetatable",
|
||||
"setmetatable",
|
||||
"getfenv",
|
||||
"setfenv",
|
||||
"rawget",
|
||||
"rawset",
|
||||
"rawequal",
|
||||
"unpack",
|
||||
"select",
|
||||
"tonumber",
|
||||
"tostring",
|
||||
"error",
|
||||
"pcall",
|
||||
"xpcall",
|
||||
"loadfile",
|
||||
"load",
|
||||
"loadstring",
|
||||
"dofile",
|
||||
"gcinfo",
|
||||
"collectgarbage",
|
||||
"newproxy",
|
||||
"print",
|
||||
"coroutine.status",
|
||||
"coroutine.running",
|
||||
"coroutine.create",
|
||||
"coroutine.yield",
|
||||
"coroutine.resume",
|
||||
"coroutine.wrap_aux",
|
||||
"coroutine.wrap",
|
||||
"math.abs",
|
||||
"math.floor",
|
||||
"math.ceil",
|
||||
"math.sqrt",
|
||||
"math.log10",
|
||||
"math.exp",
|
||||
"math.sin",
|
||||
"math.cos",
|
||||
"math.tan",
|
||||
"math.asin",
|
||||
"math.acos",
|
||||
"math.atan",
|
||||
"math.sinh",
|
||||
"math.cosh",
|
||||
"math.tanh",
|
||||
"math.frexp",
|
||||
"math.modf",
|
||||
"math.log",
|
||||
"math.deg",
|
||||
"math.rad",
|
||||
"math.atan2",
|
||||
"math.pow",
|
||||
"math.fmod",
|
||||
"math.ldexp",
|
||||
"math.min",
|
||||
"math.max",
|
||||
"math.random",
|
||||
"math.randomseed",
|
||||
"bit.tobit",
|
||||
"bit.bnot",
|
||||
"bit.bswap",
|
||||
"bit.lshift",
|
||||
"bit.rshift",
|
||||
"bit.arshift",
|
||||
"bit.rol",
|
||||
"bit.ror",
|
||||
"bit.band",
|
||||
"bit.bor",
|
||||
"bit.bxor",
|
||||
"bit.tohex",
|
||||
"string.len",
|
||||
"string.byte",
|
||||
"string.char",
|
||||
"string.sub",
|
||||
"string.rep",
|
||||
"string.reverse",
|
||||
"string.lower",
|
||||
"string.upper",
|
||||
"string.dump",
|
||||
"string.find",
|
||||
"string.match",
|
||||
"string.gmatch_aux",
|
||||
"string.gmatch",
|
||||
"string.gsub",
|
||||
"string.format",
|
||||
"table.foreachi",
|
||||
"table.foreach",
|
||||
"table.getn",
|
||||
"table.maxn",
|
||||
"table.insert",
|
||||
"table.remove",
|
||||
"table.concat",
|
||||
"table.sort",
|
||||
"io.method.close",
|
||||
"io.method.read",
|
||||
"io.method.write",
|
||||
"io.method.flush",
|
||||
"io.method.seek",
|
||||
"io.method.setvbuf",
|
||||
"io.method.lines",
|
||||
"io.method.__gc",
|
||||
"io.method.__tostring",
|
||||
"io.open",
|
||||
"io.popen",
|
||||
"io.tmpfile",
|
||||
"io.close",
|
||||
"io.read",
|
||||
"io.write",
|
||||
"io.flush",
|
||||
"io.input",
|
||||
"io.output",
|
||||
"io.lines",
|
||||
"io.type",
|
||||
"os.execute",
|
||||
"os.remove",
|
||||
"os.rename",
|
||||
"os.tmpname",
|
||||
"os.getenv",
|
||||
"os.exit",
|
||||
"os.clock",
|
||||
"os.date",
|
||||
"os.time",
|
||||
"os.difftime",
|
||||
"os.setlocale",
|
||||
"debug.getregistry",
|
||||
"debug.getmetatable",
|
||||
"debug.setmetatable",
|
||||
"debug.getfenv",
|
||||
"debug.setfenv",
|
||||
"debug.getinfo",
|
||||
"debug.getlocal",
|
||||
"debug.setlocal",
|
||||
"debug.getupvalue",
|
||||
"debug.setupvalue",
|
||||
"debug.upvalueid",
|
||||
"debug.upvaluejoin",
|
||||
"debug.sethook",
|
||||
"debug.gethook",
|
||||
"debug.debug",
|
||||
"debug.traceback",
|
||||
"jit.on",
|
||||
"jit.off",
|
||||
"jit.flush",
|
||||
"jit.status",
|
||||
"jit.attach",
|
||||
"jit.util.funcinfo",
|
||||
"jit.util.funcbc",
|
||||
"jit.util.funck",
|
||||
"jit.util.funcuvname",
|
||||
"jit.util.traceinfo",
|
||||
"jit.util.traceir",
|
||||
"jit.util.tracek",
|
||||
"jit.util.tracesnap",
|
||||
"jit.util.tracemc",
|
||||
"jit.util.traceexitstub",
|
||||
"jit.util.ircalladdr",
|
||||
"jit.opt.start",
|
||||
"ffi.meta.__index",
|
||||
"ffi.meta.__newindex",
|
||||
"ffi.meta.__eq",
|
||||
"ffi.meta.__len",
|
||||
"ffi.meta.__lt",
|
||||
"ffi.meta.__le",
|
||||
"ffi.meta.__concat",
|
||||
"ffi.meta.__call",
|
||||
"ffi.meta.__add",
|
||||
"ffi.meta.__sub",
|
||||
"ffi.meta.__mul",
|
||||
"ffi.meta.__div",
|
||||
"ffi.meta.__mod",
|
||||
"ffi.meta.__pow",
|
||||
"ffi.meta.__unm",
|
||||
"ffi.meta.__tostring",
|
||||
"ffi.meta.__pairs",
|
||||
"ffi.meta.__ipairs",
|
||||
"ffi.clib.__index",
|
||||
"ffi.clib.__newindex",
|
||||
"ffi.clib.__gc",
|
||||
"ffi.callback.free",
|
||||
"ffi.callback.set",
|
||||
"ffi.cdef",
|
||||
"ffi.new",
|
||||
"ffi.cast",
|
||||
"ffi.typeof",
|
||||
"ffi.istype",
|
||||
"ffi.sizeof",
|
||||
"ffi.alignof",
|
||||
"ffi.offsetof",
|
||||
"ffi.errno",
|
||||
"ffi.string",
|
||||
"ffi.copy",
|
||||
"ffi.fill",
|
||||
"ffi.abi",
|
||||
"ffi.metatype",
|
||||
"ffi.gc",
|
||||
"ffi.load",
|
||||
}
|
||||
|
||||
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_luacompile/bin/lua/luajit-linux
Executable file
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_luacompile/bin/lua/luajit-linux
Executable file
Binary file not shown.
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_luacompile/bin/lua/luajit-mac
Executable file
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_luacompile/bin/lua/luajit-mac
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_luacompile/bin/msvcr110.dll
Executable file
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_luacompile/bin/msvcr110.dll
Executable file
Binary file not shown.
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_run/bin/ios-sim-xcode5
Executable file
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_run/bin/ios-sim-xcode5
Executable file
Binary file not shown.
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_run/bin/ios-sim-xcode6
Executable file
BIN
cocos2d-x/tools/cocos2d-console/plugins/plugin_run/bin/ios-sim-xcode6
Executable file
Binary file not shown.
4
cocos2d-x/tools/cocos2d-console/version.json
Normal file
4
cocos2d-x/tools/cocos2d-console/version.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"version":"v3-console-16",
|
||||
"spidermonkey":"33"
|
||||
}
|
||||
Reference in New Issue
Block a user