fix: scripts runtime code and docs clean up

This commit is contained in:
Skylot
2022-11-14 12:09:07 +00:00
parent 17574ee554
commit 9a6dec0dbd
17 changed files with 146 additions and 155 deletions
@@ -4,7 +4,6 @@ import jadx.api.plugins.JadxPlugin
import jadx.api.plugins.JadxPluginContext
import jadx.api.plugins.JadxPluginInfo
import jadx.plugins.script.passes.JadxScriptAfterLoadPass
import jadx.plugins.script.runner.ScriptEval
import jadx.plugins.script.runtime.data.JadxScriptAllOptions
class JadxScriptPlugin : JadxPlugin {
@@ -14,7 +13,9 @@ class JadxScriptPlugin : JadxPlugin {
override fun init(init: JadxPluginContext) {
init.registerOptions(scriptOptions)
val scriptStates = ScriptEval().process(init, scriptOptions) ?: return
init.addPass(JadxScriptAfterLoadPass(scriptStates))
val scripts = ScriptEval().process(init, scriptOptions)
if (scripts.isNotEmpty()) {
init.addPass(JadxScriptAfterLoadPass(scripts))
}
}
}
@@ -0,0 +1,91 @@
package jadx.plugins.script
import jadx.api.JadxDecompiler
import jadx.api.plugins.JadxPluginContext
import jadx.plugins.script.runtime.JadxScriptData
import jadx.plugins.script.runtime.JadxScriptTemplate
import jadx.plugins.script.runtime.data.JadxScriptAllOptions
import kotlin.script.experimental.api.EvaluationResult
import kotlin.script.experimental.api.ResultValue
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptDiagnostic.Severity
import kotlin.script.experimental.api.ScriptEvaluationConfiguration
import kotlin.script.experimental.api.compilerOptions
import kotlin.script.experimental.api.constructorArgs
import kotlin.script.experimental.host.toScriptSource
import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate
import kotlin.script.experimental.jvmhost.createJvmEvaluationConfigurationFromTemplate
import kotlin.system.measureTimeMillis
class ScriptEval {
private val scriptingHost = BasicJvmScriptingHost()
fun process(init: JadxPluginContext, scriptOptions: JadxScriptAllOptions): List<JadxScriptData> {
val jadx = init.decompiler as JadxDecompiler
val scripts = jadx.args.inputFiles.filter { f -> f.name.endsWith(".jadx.kts") }
if (scripts.isEmpty()) {
return emptyList()
}
val scriptDataList = mutableListOf<JadxScriptData>()
for (scriptFile in scripts) {
val scriptData = JadxScriptData(jadx, init, scriptOptions, scriptFile)
scriptDataList.add(scriptData)
eval(scriptData)
}
return scriptDataList
}
fun buildCompileConf(): ScriptCompilationConfiguration {
return createJvmCompilationConfigurationFromTemplate<JadxScriptTemplate>() {
compilerOptions(listOf("-Xuse-k2"))
}
}
fun buildEvalConf(scriptData: JadxScriptData): ScriptEvaluationConfiguration {
return createJvmEvaluationConfigurationFromTemplate<JadxScriptTemplate> {
constructorArgs(scriptData)
}
}
private fun eval(scriptData: JadxScriptData) {
scriptData.log.debug { "Loading script: ${scriptData.scriptFile.absolutePath}" }
val execTime = measureTimeMillis {
val compilationConf = buildCompileConf()
val evalConf = buildEvalConf(scriptData)
val result = scriptingHost.eval(scriptData.scriptFile.toScriptSource(), compilationConf, evalConf)
processEvalResult(result, scriptData)
}
scriptData.log.debug { "Script '${scriptData.scriptName}' executed in $execTime ms" }
}
private fun processEvalResult(res: ResultWithDiagnostics<EvaluationResult>, scriptData: JadxScriptData) {
val log = scriptData.log
for (r in res.reports) {
val msg = r.render(withSeverity = false)
when (r.severity) {
Severity.FATAL, Severity.ERROR -> log.error(r.exception) { "Script execution error: $msg" }
Severity.WARNING -> log.warn { "Script execution issue: $msg" }
Severity.INFO -> log.info { "Script report: $msg" }
Severity.DEBUG -> log.debug { "Script report: $msg" }
}
}
when (res) {
is ResultWithDiagnostics.Success -> {
when (val retVal = res.value.returnValue) {
is ResultValue.Error -> log.error(retVal.error) { "Script execution error:" }
is ResultValue.Value -> log.info { "Script execution result: $retVal" }
is ResultValue.Unit -> {}
ResultValue.NotEvaluated -> {}
}
}
is ResultWithDiagnostics.Failure -> {
scriptData.error = true
log.error { "Script execution failed: ${scriptData.scriptName}" }
}
}
}
}
@@ -3,27 +3,24 @@ package jadx.plugins.script.passes
import jadx.api.JadxDecompiler
import jadx.api.plugins.pass.impl.SimpleJadxPassInfo
import jadx.api.plugins.pass.types.JadxAfterLoadPass
import jadx.plugins.script.runner.ScriptStates
import mu.KotlinLogging
import jadx.plugins.script.runtime.JadxScriptData
private val LOG = KotlinLogging.logger {}
class JadxScriptAfterLoadPass(private val scriptStates: ScriptStates) : JadxAfterLoadPass {
class JadxScriptAfterLoadPass(private val scripts: List<JadxScriptData>) : JadxAfterLoadPass {
override fun getInfo() = SimpleJadxPassInfo("JadxScriptAfterLoad", "Execute scripts 'afterLoad' block")
override fun init(decompiler: JadxDecompiler) {
for (script in scriptStates.getScripts()) {
for (script in scripts) {
if (script.error) {
continue
}
try {
for (b in script.scriptData.afterLoad) {
for (b in script.afterLoad) {
b.invoke()
}
} catch (e: Throwable) {
script.error = true
LOG.error(e) { "Error executing 'afterLoad' block in script: ${script.scriptFile.name}" }
script.log.error(e) { "Error executing 'afterLoad' block in script: ${script.scriptFile.name}" }
}
}
}
@@ -1,78 +0,0 @@
package jadx.plugins.script.runner
import jadx.api.JadxDecompiler
import jadx.api.plugins.JadxPluginContext
import jadx.plugins.script.runtime.JadxScriptData
import jadx.plugins.script.runtime.JadxScriptTemplate
import jadx.plugins.script.runtime.data.JadxScriptAllOptions
import mu.KotlinLogging
import java.io.File
import kotlin.script.experimental.api.EvaluationResult
import kotlin.script.experimental.api.ResultValue
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptDiagnostic
import kotlin.script.experimental.api.ScriptEvaluationConfiguration
import kotlin.script.experimental.api.constructorArgs
import kotlin.script.experimental.host.toScriptSource
import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate
import kotlin.script.experimental.jvmhost.createJvmEvaluationConfigurationFromTemplate
private val LOG = KotlinLogging.logger {}
class ScriptEval {
fun process(init: JadxPluginContext, scriptOptions: JadxScriptAllOptions): ScriptStates? {
val jadx = init.decompiler as JadxDecompiler
val scripts = jadx.args.inputFiles.filter { f -> f.name.endsWith(".jadx.kts") }
if (scripts.isEmpty()) {
return null
}
val scriptStates = ScriptStates()
for (scriptFile in scripts) {
val scriptData = JadxScriptData(jadx, init, scriptOptions, scriptFile)
load(scriptFile, scriptData)
scriptStates.add(scriptFile, scriptData)
}
return scriptStates
}
private fun load(scriptFile: File, scriptData: JadxScriptData) {
LOG.debug { "Loading script: ${scriptFile.absolutePath}" }
val result = eval(scriptFile, scriptData)
processEvalResult(result, scriptFile)
}
fun buildCompileConf() = createJvmCompilationConfigurationFromTemplate<JadxScriptTemplate>()
fun buildEvalConf(scriptData: JadxScriptData): ScriptEvaluationConfiguration {
return createJvmEvaluationConfigurationFromTemplate<JadxScriptTemplate> {
constructorArgs(scriptData)
}
}
private fun eval(scriptFile: File, scriptData: JadxScriptData): ResultWithDiagnostics<EvaluationResult> {
val compilationConf = buildCompileConf()
val evalConf = buildEvalConf(scriptData)
return BasicJvmScriptingHost().eval(scriptFile.toScriptSource(), compilationConf, evalConf)
}
private fun processEvalResult(res: ResultWithDiagnostics<EvaluationResult>, scriptFile: File) {
when (res) {
is ResultWithDiagnostics.Success -> {
val result = res.value.returnValue
if (result is ResultValue.Error) {
result.error.printStackTrace()
}
}
is ResultWithDiagnostics.Failure -> {
LOG.error { "Script execution failed: ${scriptFile.name}" }
res.reports
.filter { it.severity >= ScriptDiagnostic.Severity.ERROR }
.forEach { r ->
LOG.error(r.exception) { r.render(withSeverity = false) }
}
}
}
}
}
@@ -1,21 +1 @@
package jadx.plugins.script.runner
import jadx.plugins.script.runtime.JadxScriptData
import java.io.File
data class ScriptStateData(
val scriptFile: File,
val scriptData: JadxScriptData,
var error: Boolean = false,
)
class ScriptStates {
private val data: MutableList<ScriptStateData> = ArrayList()
fun add(scriptFile: File, scriptData: JadxScriptData) {
data.add(ScriptStateData(scriptFile, scriptData))
}
fun getScripts() = data
}