interpreter.cc
ps:Android7.0有三种解释模式
如果想查看函数的调用,可以通过hook如下函数,并通过ShadowFrame参数使用shadow_frame.GetMethod()->PrettyMethod()
获取函数信息
interpreter模式
:由ART下的解释器解释执行
。对于任何一个运行在Interpreter模式
下的java函数
,最终都会走到ART下的解释器
中运行。
流程:
从ArtMethod
类中的EnterInterpreterFromInvoke
开始分析Execute->ExecuteMterImpl
或者ExecuteSwitchImpl
。
interpreter.cc#Execute
interpreter_switch_impl.cc
interpreter_common.h
Instruction
类有一个DumpString
函数,可以输出当前指令的解析信息
dex_instruction.h
dex_instruction.cc
1、解释器改为switch模式
interpreter.cc
2、修改TraceExecution函数,针对感兴趣的函数筛选trace
interpreter_common.h
1、使用解释模式
runtime.cc里面有个Runtime::Init函数, 搜GetInstrumentation()->ForceInterpretOnly();, 在Runtime初始化的时候,调用一下ForceInterpretOnly就走解释模式了
runtime.cc
2、hook TraceExecution函数
interpreter_common.h
231
enum InterpreterImplKind {
232
kSwitchImplKind,
/
/
Switch
-
based interpreter implementation.
233
kMterpImplKind
/
/
Assembly interpreter
234
};
235
236
static constexpr InterpreterImplKind kInterpreterImplKind
=
kMterpImplKind;
/
/
解释器的实现模式由该全局变量控制,默认汇编实现
237
231
enum InterpreterImplKind {
232
kSwitchImplKind,
/
/
Switch
-
based interpreter implementation.
233
kMterpImplKind
/
/
Assembly interpreter
234
};
235
236
static constexpr InterpreterImplKind kInterpreterImplKind
=
kMterpImplKind;
/
/
解释器的实现模式由该全局变量控制,默认汇编实现
237
229
enum InterpreterImplKind {
230
kSwitchImplKind,
/
/
Switch
-
based interpreter implementation.
231
kComputedGotoImplKind,
/
/
Computed
-
goto
-
based interpreter implementation. goto跳转表模式
232
kMterpImplKind
/
/
Assembly interpreter
233
};
234
static std::ostream& operator<<(std::ostream& os, const InterpreterImplKind& rhs) {
235
os << ((rhs
=
=
kSwitchImplKind)
236
?
"Switch-based interpreter"
237
: (rhs
=
=
kComputedGotoImplKind)
238
?
"Computed-goto-based interpreter"
239
:
"Asm interpreter"
);
240
return
os;
241
}
229
enum InterpreterImplKind {
230
kSwitchImplKind,
/
/
Switch
-
based interpreter implementation.
231
kComputedGotoImplKind,
/
/
Computed
-
goto
-
based interpreter implementation. goto跳转表模式
232
kMterpImplKind
/
/
Assembly interpreter
233
};
234
static std::ostream& operator<<(std::ostream& os, const InterpreterImplKind& rhs) {
235
os << ((rhs
=
=
kSwitchImplKind)
236
?
"Switch-based interpreter"
237
: (rhs
=
=
kComputedGotoImplKind)
238
?
"Computed-goto-based interpreter"
239
:
"Asm interpreter"
);
240
return
os;
241
}
template<
bool
do_access_check,
bool
transaction_active>
extern JValue ExecuteSwitchImpl(Thread
*
self
, const DexFile::CodeItem
*
code_item,
ShadowFrame& shadow_frame, JValue result_register,
bool
interpret_one_instruction);
template<
bool
do_access_check,
bool
transaction_active>
extern JValue ExecuteGotoImpl(Thread
*
self
, const DexFile::CodeItem
*
code_item,
ShadowFrame& shadow_frame, JValue result_register);
/
/
Mterp does
not
support transactions
or
access check, thus no templated versions.
extern
"C"
bool
ExecuteMterpImpl(Thread
*
self
, const DexFile::CodeItem
*
code_item,
ShadowFrame
*
shadow_frame, JValue
*
result_register);
template<
bool
do_access_check,
bool
transaction_active>
extern JValue ExecuteSwitchImpl(Thread
*
self
, const DexFile::CodeItem
*
code_item,
ShadowFrame& shadow_frame, JValue result_register,
bool
interpret_one_instruction);
template<
bool
do_access_check,
bool
transaction_active>
extern JValue ExecuteGotoImpl(Thread
*
self
, const DexFile::CodeItem
*
code_item,
ShadowFrame& shadow_frame, JValue result_register);
/
/
Mterp does
not
support transactions
or
access check, thus no templated versions.
extern
"C"
bool
ExecuteMterpImpl(Thread
*
self
, const DexFile::CodeItem
*
code_item,
ShadowFrame
*
shadow_frame, JValue
*
result_register);
function hook_Impl() {
var module_libart
=
Process.findModuleByName(
"libart.so"
);
var symbols
=
module_libart.enumerateSymbols();
var ArtMethod_ExecuteSwitchImpltt
=
null;
var ArtMethod_ExecuteSwitchImpltf
=
null;
var ArtMethod_ExecuteSwitchImplff
=
null;
var ArtMethod_ExecuteMterpImpl
=
null;
/
/
_ZN3art11interpreter17ExecuteSwitchImplILb1ELb1EEENS_6JValueEPNS_6ThreadEPKNS_7DexFile8CodeItemERNS_11ShadowFrameES2_b ; art::interpreter::ExecuteSwitchImpl<true,true>(art::Thread
*
,art::DexFile::CodeItem const
*
,art::ShadowFrame &,art::JValue,
bool
)
/
/
_ZN3art11interpreter17ExecuteSwitchImplILb1ELb0EEENS_6JValueEPNS_6ThreadEPKNS_7DexFile8CodeItemERNS_11ShadowFrameES2_b ; art::interpreter::ExecuteSwitchImpl<true,false>(art::Thread
*
,art::DexFile::CodeItem const
*
,art::ShadowFrame &,art::JValue,
bool
)
/
/
_ZN3art11interpreter17ExecuteSwitchImplILb0ELb0EEENS_6JValueEPNS_6ThreadEPKNS_7DexFile8CodeItemERNS_11ShadowFrameES2_b ; art::interpreter::ExecuteSwitchImpl<false,false>(art::Thread
*
,art::DexFile::CodeItem const
*
,art::ShadowFrame &,art::JValue,
bool
)
for
(var i
=
0
; i < symbols.length; i
+
+
) {
var symbol
=
symbols[i];
var address
=
symbol.address;
var name
=
symbol.name;
var indexinterpreter
=
name.indexOf(
"interpreter"
);
var indexExecuteSwitchImpl
=
name.indexOf(
"ExecuteSwitchImpl"
);
var indexExecuteMterpImpl
=
name.indexOf(
"ExecuteMterpImpl"
);
var indexShadowFrame
=
name.indexOf(
"ShadowFrame"
);
var indextt
=
name.indexOf(
"b1ELb1"
);
var indextf
=
name.indexOf(
"b1ELb0"
);
var indexff
=
name.indexOf(
"b0ELb0"
);
var ArtMethod_PrettyMethod
=
null;
if
(name.indexOf(
"ArtMethod"
) >
=
0
&& name.indexOf(
"PrettyMethod"
) >
=
0
&& name.indexOf(
"Eb"
) >
=
0
) {
console.log(name);
ArtMethod_PrettyMethod
=
address;
}
if
(indexinterpreter >
=
0
&& indexExecuteSwitchImpl >
=
0
&& indexShadowFrame >
=
0
&& indextt >
=
0
) {
console.log(name);
ArtMethod_ExecuteSwitchImpltt
=
address;
}
if
(indexinterpreter >
=
0
&& indexExecuteSwitchImpl >
=
0
&& indexShadowFrame >
=
0
&& indextf >
=
0
) {
console.log(name);
ArtMethod_ExecuteSwitchImpltf
=
address;
}
if
(indexinterpreter >
=
0
&& indexExecuteSwitchImpl >
=
0
&& indexShadowFrame >
=
0
&& indexff >
=
0
) {
console.log(name);
ArtMethod_ExecuteSwitchImplff
=
address;
}
if
(indexExecuteMterpImpl >
=
0
) {
console.log(name);
ArtMethod_ExecuteMterpImpl
=
address;
}
}
var module_libext
=
null;
if
(Process.arch
=
=
=
"arm64"
) {
module_libext
=
Module.load(
"/data/app/libext64.so"
);
}
else
if
(Process.arch
=
=
=
"arm"
) {
module_libext
=
Module.load(
"/data/app/libext.so"
);
}
if
(ArtMethod_ExecuteSwitchImpltt !
=
null) {
Interceptor.attach(ArtMethod_ExecuteSwitchImpltt, {
onEnter: function (args) {
}, onLeave: function (retval) {
}
});
}
if
(ArtMethod_ExecuteSwitchImpltf !
=
null) {
Interceptor.attach(ArtMethod_ExecuteSwitchImpltf, {
onEnter: function (args) {
}, onLeave: function (retval) {
}
});
}
if
(ArtMethod_ExecuteSwitchImplff !
=
null) {
Interceptor.attach(ArtMethod_ExecuteSwitchImplff, {
onEnter: function (args) {
var shadow_frame
=
args[
2
];
var artMethodObj
=
ptr(shadow_frame).add(Process.pointerSize);
if
(module_libext !
=
null) {
var addr_PrettyMethod
=
module_libext.findExportByName(
"PrettyMethod"
);
var PrettyMethod
=
new NativeFunction(addr_PrettyMethod,
"void"
, [
"pointer"
,
"pointer"
,
"pointer"
,
"int"
])
var result
=
Memory.alloc(
0x100
);
try
{
PrettyMethod(ArtMethod_PrettyMethod, artMethodObj, result,
0x100
);
/
/
console.log(result.readCString());
console.log(
"ArtMethod_ExecuteSwitchImplff java_class:"
, result.readCString());
} catch (error) {
console.log(
"ArtMethod_ExecuteSwitchImplff"
+
error);
}
}
}, onLeave: function (retval) {
}
});
}
if
(ArtMethod_ExecuteMterpImpl !
=
null) {
Interceptor.attach(ArtMethod_ExecuteMterpImpl, {
onEnter: function (args) {
}, onLeave: function (retval) {
}
});
}
}
function hook_Impl() {
var module_libart
=
Process.findModuleByName(
"libart.so"
);
var symbols
=
module_libart.enumerateSymbols();
var ArtMethod_ExecuteSwitchImpltt
=
null;
var ArtMethod_ExecuteSwitchImpltf
=
null;
var ArtMethod_ExecuteSwitchImplff
=
null;
var ArtMethod_ExecuteMterpImpl
=
null;
/
/
_ZN3art11interpreter17ExecuteSwitchImplILb1ELb1EEENS_6JValueEPNS_6ThreadEPKNS_7DexFile8CodeItemERNS_11ShadowFrameES2_b ; art::interpreter::ExecuteSwitchImpl<true,true>(art::Thread
*
,art::DexFile::CodeItem const
*
,art::ShadowFrame &,art::JValue,
bool
)
/
/
_ZN3art11interpreter17ExecuteSwitchImplILb1ELb0EEENS_6JValueEPNS_6ThreadEPKNS_7DexFile8CodeItemERNS_11ShadowFrameES2_b ; art::interpreter::ExecuteSwitchImpl<true,false>(art::Thread
*
,art::DexFile::CodeItem const
*
,art::ShadowFrame &,art::JValue,
bool
)
/
/
_ZN3art11interpreter17ExecuteSwitchImplILb0ELb0EEENS_6JValueEPNS_6ThreadEPKNS_7DexFile8CodeItemERNS_11ShadowFrameES2_b ; art::interpreter::ExecuteSwitchImpl<false,false>(art::Thread
*
,art::DexFile::CodeItem const
*
,art::ShadowFrame &,art::JValue,
bool
)
for
(var i
=
0
; i < symbols.length; i
+
+
) {
var symbol
=
symbols[i];
var address
=
symbol.address;
var name
=
symbol.name;
var indexinterpreter
=
name.indexOf(
"interpreter"
);
var indexExecuteSwitchImpl
=
name.indexOf(
"ExecuteSwitchImpl"
);
var indexExecuteMterpImpl
=
name.indexOf(
"ExecuteMterpImpl"
);
var indexShadowFrame
=
name.indexOf(
"ShadowFrame"
);
var indextt
=
name.indexOf(
"b1ELb1"
);
var indextf
=
name.indexOf(
"b1ELb0"
);
var indexff
=
name.indexOf(
"b0ELb0"
);
var ArtMethod_PrettyMethod
=
null;
if
(name.indexOf(
"ArtMethod"
) >
=
0
&& name.indexOf(
"PrettyMethod"
) >
=
0
&& name.indexOf(
"Eb"
) >
=
0
) {
console.log(name);
ArtMethod_PrettyMethod
=
address;
}
if
(indexinterpreter >
=
0
&& indexExecuteSwitchImpl >
=
0
&& indexShadowFrame >
=
0
&& indextt >
=
0
) {
console.log(name);
ArtMethod_ExecuteSwitchImpltt
=
address;
}
if
(indexinterpreter >
=
0
&& indexExecuteSwitchImpl >
=
0
&& indexShadowFrame >
=
0
&& indextf >
=
0
) {
console.log(name);
ArtMethod_ExecuteSwitchImpltf
=
address;
}
if
(indexinterpreter >
=
0
&& indexExecuteSwitchImpl >
=
0
&& indexShadowFrame >
=
0
&& indexff >
=
0
) {
console.log(name);
ArtMethod_ExecuteSwitchImplff
=
address;
}
if
(indexExecuteMterpImpl >
=
0
) {
console.log(name);
ArtMethod_ExecuteMterpImpl
=
address;
}
}
var module_libext
=
null;
if
(Process.arch
=
=
=
"arm64"
) {
module_libext
=
Module.load(
"/data/app/libext64.so"
);
}
else
if
(Process.arch
=
=
=
"arm"
) {
module_libext
=
Module.load(
"/data/app/libext.so"
);
}
if
(ArtMethod_ExecuteSwitchImpltt !
=
null) {
Interceptor.attach(ArtMethod_ExecuteSwitchImpltt, {
onEnter: function (args) {
}, onLeave: function (retval) {
}
});
}
if
(ArtMethod_ExecuteSwitchImpltf !
=
null) {
Interceptor.attach(ArtMethod_ExecuteSwitchImpltf, {
onEnter: function (args) {
}, onLeave: function (retval) {
}
});
}
if
(ArtMethod_ExecuteSwitchImplff !
=
null) {
Interceptor.attach(ArtMethod_ExecuteSwitchImplff, {
onEnter: function (args) {
var shadow_frame
=
args[
2
];
var artMethodObj
=
ptr(shadow_frame).add(Process.pointerSize);
if
(module_libext !
=
null) {
var addr_PrettyMethod
=
module_libext.findExportByName(
"PrettyMethod"
);
var PrettyMethod
=
new NativeFunction(addr_PrettyMethod,
"void"
, [
"pointer"
,
"pointer"
,
"pointer"
,
"int"
])
var result
=
Memory.alloc(
0x100
);
try
{
PrettyMethod(ArtMethod_PrettyMethod, artMethodObj, result,
0x100
);
/
/
console.log(result.readCString());
console.log(
"ArtMethod_ExecuteSwitchImplff java_class:"
, result.readCString());
} catch (error) {
console.log(
"ArtMethod_ExecuteSwitchImplff"
+
error);
}
}
}, onLeave: function (retval) {
}
});
}
if
(ArtMethod_ExecuteMterpImpl !
=
null) {
Interceptor.attach(ArtMethod_ExecuteMterpImpl, {
onEnter: function (args) {
}, onLeave: function (retval) {
}
});
}
}
238
static inline JValue Execute(
239
Thread
*
self
,
240
const DexFile::CodeItem
*
code_item,
241
ShadowFrame& shadow_frame,
242
JValue result_register,
243
bool
stay_in_interpreter
=
false) REQUIRES_SHARED(Locks::mutator_lock_) {
244
DCHECK(!shadow_frame.GetMethod()
-
>IsAbstract());
245
DCHECK(!shadow_frame.GetMethod()
-
>IsNative());
246
if
(LIKELY(shadow_frame.GetDexPC()
=
=
0
)) {
/
/
Entering the method, but
not
via deoptimization.
247
if
(kIsDebugBuild) {
248
self
-
>AssertNoPendingException();
249
}
250
instrumentation::Instrumentation
*
instrumentation
=
Runtime::Current()
-
>GetInstrumentation();
251
ArtMethod
*
method
=
shadow_frame.GetMethod();
252
253
if
(UNLIKELY(instrumentation
-
>HasMethodEntryListeners())) {
254
instrumentation
-
>MethodEnterEvent(
self
, shadow_frame.GetThisObject(code_item
-
>ins_size_),
255
method,
0
);
256
}
257
258
if
(!stay_in_interpreter) {
259
jit::Jit
*
jit
=
Runtime::Current()
-
>GetJit();
260
if
(jit !
=
nullptr) {
261
jit
-
>MethodEntered(
self
, shadow_frame.GetMethod());
262
if
(jit
-
>CanInvokeCompiledCode(method)) {
263
JValue result;
264
265
/
/
Pop the shadow frame before calling into compiled code.
266
self
-
>PopShadowFrame();
267
ArtInterpreterToCompiledCodeBridge(
self
, nullptr, code_item, &shadow_frame, &result);
268
/
/
Push the shadow frame back as the caller will expect it.
269
self
-
>PushShadowFrame(&shadow_frame);
270
271
return
result;
272
}
273
}
274
}
275
}
276
277
shadow_frame.GetMethod()
-
>GetDeclaringClass()
-
>AssertInitializedOrInitializingInThread(
self
);
278
279
/
/
Lock counting
is
a special version of accessibility checks,
and
for
simplicity
and
280
/
/
reduction of template parameters, we gate it behind access
-
checks mode.
281
ArtMethod
*
method
=
shadow_frame.GetMethod();
282
DCHECK(!method
-
>SkipAccessChecks() || !method
-
>MustCountLocks());
283
284
bool
transaction_active
=
Runtime::Current()
-
>IsActiveTransaction();
285
if
(LIKELY(method
-
>SkipAccessChecks())) {
286
/
/
Enter the
"without access check"
interpreter.
287
if
(kInterpreterImplKind
=
=
kMterpImplKind) {
288
if
(transaction_active) {
289
/
/
No Mterp variant
-
just use the switch interpreter.
290
return
ExecuteSwitchImpl<false, true>(
self
, code_item, shadow_frame, result_register,
291
false);
292
}
else
if
(UNLIKELY(!Runtime::Current()
-
>IsStarted())) {
293
return
ExecuteSwitchImpl<false, false>(
self
, code_item, shadow_frame, result_register,
294
false);
295
}
else
{
296
while
(true) {
297
/
/
Mterp does
not
support
all
instrumentation
/
debugging.
298
if
(MterpShouldSwitchInterpreters() !
=
0
) {
299
return
ExecuteSwitchImpl<false, false>(
self
, code_item, shadow_frame, result_register,
300
false);
301
}
302
bool
returned
=
ExecuteMterpImpl(
self
, code_item, &shadow_frame, &result_register);
303
if
(returned) {
304
return
result_register;
305
}
else
{
306
/
/
Mterp didn't like that instruction. Single
-
step it with the reference interpreter.
307
result_register
=
ExecuteSwitchImpl<false, false>(
self
, code_item, shadow_frame,
308
result_register, true);
309
if
(shadow_frame.GetDexPC()
=
=
DexFile::kDexNoIndex) {
310
/
/
Single
-
stepped a
return
or
an exception
not
handled locally. Return to caller.
311
return
result_register;
312
}
313
}
314
}
315
}
316
}
else
{
317
DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
318
if
(transaction_active) {
319
return
ExecuteSwitchImpl<false, true>(
self
, code_item, shadow_frame, result_register,
320
false);
321
}
else
{
322
return
ExecuteSwitchImpl<false, false>(
self
, code_item, shadow_frame, result_register,
323
false);
324
}
325
}
326
}
else
{
327
/
/
Enter the
"with access check"
interpreter.
328
if
(kInterpreterImplKind
=
=
kMterpImplKind) {
329
/
/
No access check variants
for
Mterp. Just use the switch version.
330
if
(transaction_active) {
331
return
ExecuteSwitchImpl<true, true>(
self
, code_item, shadow_frame, result_register,
332
false);
333
}
else
{
334
return
ExecuteSwitchImpl<true, false>(
self
, code_item, shadow_frame, result_register,
335
false);
336
}
337
}
else
{
338
DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
339
if
(transaction_active) {
340
return
ExecuteSwitchImpl<true, true>(
self
, code_item, shadow_frame, result_register,
341
false);
342
}
else
{
343
return
ExecuteSwitchImpl<true, false>(
self
, code_item, shadow_frame, result_register,
344
false);
345
}
346
}
347
}
348
}
238
static inline JValue Execute(
239
Thread
*
self
,
240
const DexFile::CodeItem
*
code_item,
241
ShadowFrame& shadow_frame,
242
JValue result_register,
243
bool
stay_in_interpreter
=
false) REQUIRES_SHARED(Locks::mutator_lock_) {
244
DCHECK(!shadow_frame.GetMethod()
-
>IsAbstract());
245
DCHECK(!shadow_frame.GetMethod()
-
>IsNative());
246
if
(LIKELY(shadow_frame.GetDexPC()
=
=
0
)) {
/
/
Entering the method, but
not
via deoptimization.
247
if
(kIsDebugBuild) {
248
self
-
>AssertNoPendingException();
249
}
250
instrumentation::Instrumentation
*
instrumentation
=
Runtime::Current()
-
>GetInstrumentation();
251
ArtMethod
*
method
=
shadow_frame.GetMethod();
252
253
if
(UNLIKELY(instrumentation
-
>HasMethodEntryListeners())) {
254
instrumentation
-
>MethodEnterEvent(
self
, shadow_frame.GetThisObject(code_item
-
>ins_size_),
255
method,
0
);
256
}
257
258
if
(!stay_in_interpreter) {
259
jit::Jit
*
jit
=
Runtime::Current()
-
>GetJit();
260
if
(jit !
=
nullptr) {
261
jit
-
>MethodEntered(
self
, shadow_frame.GetMethod());
262
if
(jit
-
>CanInvokeCompiledCode(method)) {
263
JValue result;
264
265
/
/
Pop the shadow frame before calling into compiled code.
266
self
-
>PopShadowFrame();
267
ArtInterpreterToCompiledCodeBridge(
self
, nullptr, code_item, &shadow_frame, &result);
268
/
/
Push the shadow frame back as the caller will expect it.
269
self
-
>PushShadowFrame(&shadow_frame);
270
271
return
result;
272
}
273
}
274
}
275
}
276
277
shadow_frame.GetMethod()
-
>GetDeclaringClass()
-
>AssertInitializedOrInitializingInThread(
self
);
278
279
/
/
Lock counting
is
a special version of accessibility checks,
and
for
simplicity
and
280
/
/
reduction of template parameters, we gate it behind access
-
checks mode.
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课