aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--slicer/instrumentation.cc144
-rw-r--r--testdata/expected/mi.array_entry_hook52
2 files changed, 115 insertions, 81 deletions
diff --git a/slicer/instrumentation.cc b/slicer/instrumentation.cc
index 7c93791..f0dfbdf 100644
--- a/slicer/instrumentation.cc
+++ b/slicer/instrumentation.cc
@@ -158,6 +158,54 @@ bool EntryHook::Apply(lir::CodeIr* code_ir) {
return true;
}
+void GenerateShiftParamsCode(lir::CodeIr* code_ir, lir::Instruction* position, dex::u4 shift) {
+ const auto ir_method = code_ir->ir_method;
+ SLICER_CHECK(ir_method->code->ins_count > 0);
+
+ // build a param list with the explicit "this" argument for non-static methods
+ std::vector<ir::Type*> param_types;
+ if ((ir_method->access_flags & dex::kAccStatic) == 0) {
+ param_types.push_back(ir_method->decl->parent);
+ }
+ if (ir_method->decl->prototype->param_types != nullptr) {
+ const auto& orig_param_types = ir_method->decl->prototype->param_types->types;
+ param_types.insert(param_types.end(), orig_param_types.begin(), orig_param_types.end());
+ }
+
+ const dex::u4 regs = ir_method->code->registers;
+ const dex::u4 ins_count = ir_method->code->ins_count;
+ SLICER_CHECK(regs >= ins_count);
+
+ // generate the args "relocation" instructions
+ dex::u4 reg = regs - ins_count;
+ for (const auto& type : param_types) {
+ auto move = code_ir->Alloc<lir::Bytecode>();
+ switch (type->GetCategory()) {
+ case ir::Type::Category::Reference:
+ move->opcode = dex::OP_MOVE_OBJECT_16;
+ move->operands.push_back(code_ir->Alloc<lir::VReg>(reg - shift));
+ move->operands.push_back(code_ir->Alloc<lir::VReg>(reg));
+ reg += 1;
+ break;
+ case ir::Type::Category::Scalar:
+ move->opcode = dex::OP_MOVE_16;
+ move->operands.push_back(code_ir->Alloc<lir::VReg>(reg - shift));
+ move->operands.push_back(code_ir->Alloc<lir::VReg>(reg));
+ reg += 1;
+ break;
+ case ir::Type::Category::WideScalar:
+ move->opcode = dex::OP_MOVE_WIDE_16;
+ move->operands.push_back(code_ir->Alloc<lir::VRegPair>(reg - shift));
+ move->operands.push_back(code_ir->Alloc<lir::VRegPair>(reg));
+ reg += 2;
+ break;
+ case ir::Type::Category::Void:
+ SLICER_FATAL("void parameter type");
+ }
+ code_ir->instructions.InsertBefore(position, move);
+ }
+}
+
bool EntryHook::InjectArrayParamsHook(lir::CodeIr* code_ir, lir::Bytecode* bytecode) {
ir::Builder builder(code_ir->dex_ir);
const auto ir_method = code_ir->ir_method;
@@ -170,28 +218,28 @@ bool EntryHook::InjectArrayParamsHook(lir::CodeIr* code_ir, lir::Bytecode* bytec
needsBoxingReg |= type->GetCategory() != ir::Type::Category::Reference;
}
- // allocate scract registers
- slicer::AllocateScratchRegs alloc_regs(2 + needsBoxingReg);
- alloc_regs.Apply(code_ir);
- auto reg_iterator = alloc_regs.ScratchRegs().begin();
+ // number of registers that we need to operate
+ dex::u2 regs_count = 2 + needsBoxingReg;
+ auto non_param_regs = ir_method->code->registers - ir_method->code->ins_count;
+
+ // do we have enough registers to operate?
+ bool needsExtraRegs = non_param_regs < regs_count;
+ if (needsExtraRegs) {
+ // we don't have enough registers, so we allocate more, we will shift
+ // params to their original registers later.
+ code_ir->ir_method->code->registers += regs_count - non_param_regs;
+ }
+
+ // simply use three first registry now
+
// register that will store size of during allocation
// later will be reused to store index when do "aput"
- dex::u4 array_size_reg = *(reg_iterator);
+ dex::u4 array_size_reg = 0;
// register that will store an array that will be passed
// as a parameter in entry hook
- dex::u4 array_reg = *(++reg_iterator);
+ dex::u4 array_reg = 1;
// if we need to boxing, this register stores result of boxing
- dex::u4 boxing_reg = needsBoxingReg ? *(++reg_iterator) : 0;
-
- // TODO: handle very "high" registers
- if (boxing_reg > 0xff) {
- printf("WARNING: can't instrument method %s.%s%s\n",
- ir_method->decl->parent->Decl().c_str(),
- ir_method->decl->name->c_str(),
- ir_method->decl->prototype->Signature().c_str());
- return false;
- }
-
+ dex::u4 boxing_reg = needsBoxingReg ? 2 : 0;
// array size bytecode
auto const_size_op = code_ir->Alloc<lir::Bytecode>();
const_size_op->opcode = dex::OP_CONST;
@@ -265,6 +313,22 @@ bool EntryHook::InjectArrayParamsHook(lir::CodeIr* code_ir, lir::Bytecode* bytec
hook_invoke->operands.push_back(args);
hook_invoke->operands.push_back(hook_method);
code_ir->instructions.InsertBefore(bytecode, hook_invoke);
+
+ // clean up registries used by us
+ // registers are assigned to a marker value 0xFE_FE_FE_FE (decimal
+ // value: -16843010) to help identify use of uninitialized registers.
+ for (dex::u2 i = 0; i < regs_count; ++i) {
+ auto cleanup = code_ir->Alloc<lir::Bytecode>();
+ cleanup->opcode = dex::OP_CONST;
+ cleanup->operands.push_back(code_ir->Alloc<lir::VReg>(i));
+ cleanup->operands.push_back(code_ir->Alloc<lir::Const32>(0xFEFEFEFE));
+ code_ir->instructions.InsertBefore(bytecode, cleanup);
+ }
+
+ // now we have to shift params to their original registers
+ if (needsExtraRegs) {
+ GenerateShiftParamsCode(code_ir, bytecode, regs_count - non_param_regs);
+ }
return true;
}
@@ -532,57 +596,15 @@ void AllocateScratchRegs::RegsRenumbering(lir::CodeIr* code_ir) {
//
void AllocateScratchRegs::ShiftParams(lir::CodeIr* code_ir) {
const auto ir_method = code_ir->ir_method;
- SLICER_CHECK(ir_method->code->ins_count > 0);
SLICER_CHECK(left_to_allocate_ > 0);
- // build a param list with the explicit "this" argument for non-static methods
- std::vector<ir::Type*> param_types;
- if ((ir_method->access_flags & dex::kAccStatic) == 0) {
- param_types.push_back(ir_method->decl->parent);
- }
- if (ir_method->decl->prototype->param_types != nullptr) {
- const auto& orig_param_types = ir_method->decl->prototype->param_types->types;
- param_types.insert(param_types.end(), orig_param_types.begin(), orig_param_types.end());
- }
-
const dex::u4 shift = left_to_allocate_;
-
Allocate(code_ir, ir_method->code->registers, left_to_allocate_);
assert(left_to_allocate_ == 0);
- const dex::u4 regs = ir_method->code->registers;
- const dex::u4 ins_count = ir_method->code->ins_count;
- SLICER_CHECK(regs >= ins_count);
-
// generate the args "relocation" instructions
- auto first_instr = code_ir->instructions.begin();
- dex::u4 reg = regs - ins_count;
- for (const auto& type : param_types) {
- auto move = code_ir->Alloc<lir::Bytecode>();
- switch (type->GetCategory()) {
- case ir::Type::Category::Reference:
- move->opcode = dex::OP_MOVE_OBJECT_16;
- move->operands.push_back(code_ir->Alloc<lir::VReg>(reg - shift));
- move->operands.push_back(code_ir->Alloc<lir::VReg>(reg));
- reg += 1;
- break;
- case ir::Type::Category::Scalar:
- move->opcode = dex::OP_MOVE_16;
- move->operands.push_back(code_ir->Alloc<lir::VReg>(reg - shift));
- move->operands.push_back(code_ir->Alloc<lir::VReg>(reg));
- reg += 1;
- break;
- case ir::Type::Category::WideScalar:
- move->opcode = dex::OP_MOVE_WIDE_16;
- move->operands.push_back(code_ir->Alloc<lir::VRegPair>(reg - shift));
- move->operands.push_back(code_ir->Alloc<lir::VRegPair>(reg));
- reg += 2;
- break;
- case ir::Type::Category::Void:
- SLICER_FATAL("void parameter type");
- }
- code_ir->instructions.insert(first_instr, move);
- }
+ auto first_instr = *(code_ir->instructions.begin());
+ GenerateShiftParamsCode(code_ir, first_instr, shift);
}
// Mark [first_reg, first_reg + count) as scratch registers
diff --git a/testdata/expected/mi.array_entry_hook b/testdata/expected/mi.array_entry_hook
index 8f2a5e3..48eea67 100644
--- a/testdata/expected/mi.array_entry_hook
+++ b/testdata/expected/mi.array_entry_hook
@@ -50,22 +50,28 @@ method Target.foo(int, java.lang.String):int
0| const v0, #+3 (0x00000003 | 4.20390e-45)
3| new-array v1, v0, java.lang.Object[]
5| const v0, #+0 (0x00000000 | 0.00000)
- 8| aput-object v5, v1, v0
- 10| invoke-static/range {v6..v6}, java.lang.Integer.valueOf(int):java.lang.Integer
+ 8| aput-object v3, v1, v0
+ 10| invoke-static/range {v4..v4}, java.lang.Integer.valueOf(int):java.lang.Integer
13| move-result-object v2
14| const v0, #+1 (0x00000001 | 1.40130e-45)
17| aput-object v2, v1, v0
19| const v0, #+2 (0x00000002 | 2.80260e-45)
- 22| aput-object v7, v1, v0
+ 22| aput-object v5, v1, v0
24| invoke-static/range {v1..v1}, Tracer.onFooEntry(java.lang.Object[]):void
- 27| iget-object v3, v5, Target.base
- 29| invoke-virtual {v3,v6,v7}, Base.foo(int, java.lang.String):int
- 32| move-result v3
+ 27| const v0, #-16843010 (0xfefefefe | -1.69474e+38)
+ 30| const v1, #-16843010 (0xfefefefe | -1.69474e+38)
+ 33| const v2, #-16843010 (0xfefefefe | -1.69474e+38)
+ 36| move-object/16 v2, v3
+ 39| move/16 v3, v4
+ 42| move-object/16 v4, v5
+ 45| iget-object v0, v2, Target.base
+ 47| invoke-virtual {v0,v3,v4}, Base.foo(int, java.lang.String):int
+ 50| move-result v0
.line 22
- 33| iget-object v4, v5, Target.iBase
- 35| invoke-interface {v4,v7}, IBase.bar(java.lang.String):void
+ 51| iget-object v1, v2, Target.iBase
+ 53| invoke-interface {v1,v4}, IBase.bar(java.lang.String):void
.line 23
- 38| return v3
+ 56| return v0
}
method Target.foo(int, java.lang.String[][]):java.lang.Integer
@@ -78,22 +84,28 @@ method Target.foo(int, java.lang.String[][]):java.lang.Integer
0| const v0, #+3 (0x00000003 | 4.20390e-45)
3| new-array v1, v0, java.lang.Object[]
5| const v0, #+0 (0x00000000 | 0.00000)
- 8| aput-object v5, v1, v0
- 10| invoke-static/range {v6..v6}, java.lang.Integer.valueOf(int):java.lang.Integer
+ 8| aput-object v3, v1, v0
+ 10| invoke-static/range {v4..v4}, java.lang.Integer.valueOf(int):java.lang.Integer
13| move-result-object v2
14| const v0, #+1 (0x00000001 | 1.40130e-45)
17| aput-object v2, v1, v0
19| const v0, #+2 (0x00000002 | 2.80260e-45)
- 22| aput-object v7, v1, v0
+ 22| aput-object v5, v1, v0
24| invoke-static/range {v1..v1}, Tracer.onFooEntry(java.lang.Object[]):void
- 27| iget-object v3, v5, Target.base
- 29| const-string v4, "foo"
- 31| invoke-virtual {v3,v6,v4}, Base.foo(int, java.lang.String):int
+ 27| const v0, #-16843010 (0xfefefefe | -1.69474e+38)
+ 30| const v1, #-16843010 (0xfefefefe | -1.69474e+38)
+ 33| const v2, #-16843010 (0xfefefefe | -1.69474e+38)
+ 36| move-object/16 v2, v3
+ 39| move/16 v3, v4
+ 42| move-object/16 v4, v5
+ 45| iget-object v0, v2, Target.base
+ 47| const-string v1, "foo"
+ 49| invoke-virtual {v0,v3,v1}, Base.foo(int, java.lang.String):int
.line 28
- 34| iget-object v3, v5, Target.iBase
- 36| const-string v4, "bar"
- 38| invoke-interface {v3,v4}, IBase.bar(java.lang.String):void
+ 52| iget-object v0, v2, Target.iBase
+ 54| const-string v1, "bar"
+ 56| invoke-interface {v0,v1}, IBase.bar(java.lang.String):void
.line 29
- 41| const/4 v3, #+0 (0x00000000 | 0.00000)
- 42| return-object v3
+ 59| const/4 v0, #+0 (0x00000000 | 0.00000)
+ 60| return-object v0
}