diff --git a/lib/android.js b/lib/android.js index 161de93..7b352dd 100644 --- a/lib/android.js +++ b/lib/android.js @@ -464,6 +464,11 @@ function _getApi () { const instrumentationOffset = runtimeOffset.instrumentation; temporaryApi.artInstrumentation = (instrumentationOffset !== null) ? artRuntime.add(instrumentationOffset) : null; + const instrumentationIsPointer = getArtApexVersion() >= 360_000_000; + if (instrumentationIsPointer && temporaryApi.artInstrumentation != null) { + temporaryApi.artInstrumentation = temporaryApi.artInstrumentation.readPointer(); + } + temporaryApi.artHeap = artRuntime.add(runtimeOffset.heap).readPointer(); temporaryApi.artThreadList = artRuntime.add(runtimeOffset.threadList).readPointer(); @@ -694,7 +699,11 @@ function _getArtRuntimeSpec (api) { throw new Error('Unable to determine Runtime field offsets'); } - spec.offset.instrumentation = tryDetectInstrumentationOffset(api); + const instrumentationIsPointer = getArtApexVersion() >= 360_000_000; + spec.offset.instrumentation = instrumentationIsPointer + ? tryDetectInstrumentationPointer(api) + : tryDetectInstrumentationOffset(api); + spec.offset.jniIdsIndirection = tryDetectJniIdsIndirectionOffset(api); return spec; @@ -774,6 +783,78 @@ function parseArm64InstrumentationOffset (insn) { return offset; } +const instrumentationPointerParser = { + ia32: parsex86InstrumentationPointer, + x64: parsex86InstrumentationPointer, + arm: parseArmInstrumentationPointer, + arm64: parseArm64InstrumentationPointer +}; + +function tryDetectInstrumentationPointer (api) { + const impl = api['art::Runtime::DeoptimizeBootImage']; + if (impl === undefined) { + return null; + } + + return parseInstructionsAt(impl, instrumentationPointerParser[Process.arch], { limit: 30 }); +} + +function parsex86InstrumentationPointer (insn) { + if (insn.mnemonic !== 'mov') { + return null; + } + + const ops = insn.operands; + + const dst = ops[0]; + if (dst.value !== 'rax') { + return null; + } + + const src = ops[1]; + if (src.type !== 'mem') { + return null; + } + + const mem = src.value; + if (mem.base !== 'rdi') { + return null; + } + + const offset = mem.disp; + if (offset < 0x100 || offset > 0x400) { + return null; + } + return offset; +} + +function parseArmInstrumentationPointer (insn) { + return null; +} + +function parseArm64InstrumentationPointer (insn) { + if (insn.mnemonic !== 'ldr') { + return null; + } + + const ops = insn.operands; + + if (ops[0].value === 'x0') { + return null; + } + + const mem = ops[1].value; + if (mem.base !== 'x0') { + return null; + } + + const offset = mem.disp; + if (offset < 0x100 || offset > 0x400) { + return null; + } + return offset; +} + const jniIdsIndirectionOffsetParsers = { ia32: parsex86JniIdsIndirectionOffset, x64: parsex86JniIdsIndirectionOffset,