Skip to content

Commit 7d2f643

Browse files
committed
Implement -instrument_transitive
1 parent e651645 commit 7d2f643

9 files changed

Lines changed: 109 additions & 63 deletions

File tree

Linux/debugger.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,7 +1499,8 @@ void Debugger::ExtractCodeRanges(void *module_base,
14991499
size_t min_address,
15001500
size_t max_address,
15011501
std::list<AddressRange> *executable_ranges,
1502-
size_t *code_size)
1502+
size_t *code_size,
1503+
bool do_protect)
15031504
{
15041505
std::string elf_filename;
15051506
if(module_base) {
@@ -1531,12 +1532,14 @@ void Debugger::ExtractCodeRanges(void *module_base,
15311532
iter->addr_from = min_address;
15321533
}
15331534
}
1534-
1535-
int ret = RemoteMprotect((void *)iter->addr_from,
1536-
(iter->addr_to - iter->addr_from),
1537-
iter->permissions ^ PROT_EXEC);
1538-
if(ret) {
1539-
FATAL("Could not apply memory protection");
1535+
1536+
if(do_protect) {
1537+
int ret = RemoteMprotect((void *)iter->addr_from,
1538+
(iter->addr_to - iter->addr_from),
1539+
iter->permissions ^ PROT_EXEC);
1540+
if(ret) {
1541+
FATAL("Could not apply memory protection");
1542+
}
15401543
}
15411544

15421545
AddressRange range;

Linux/debugger.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ class Debugger {
162162
size_t min_address,
163163
size_t max_address,
164164
std::list<AddressRange> *executable_ranges,
165-
size_t *code_size);
165+
size_t *code_size,
166+
bool do_protect = true);
166167

167168
void ProtectCodeRanges(std::list<AddressRange> *executable_ranges);
168169

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ In addition to the general-purpose API documented above, TinyInst also implement
184184

185185
`-instrument_module [module name]` specifies which module to instrument, multiple `-instrument_module` options can be specified to instrument multiple modules.
186186

187+
`-instrument_transitive [module name]` similar to `-instrument_module` except only code entered from other instrumented modules will run instrumented. Primarily used as optimization for calls like module1->module2->module1 where it's not important to instrument the entire module2 module, but module2->module1 entries are causing slowdowns.
188+
187189
`-indirect_instrumentation [none|local|global|auto]` which instrumentation to use for indirect jump/calls
188190

189191
`-patch_return_addresses` - replaces return address with the original value, causes returns to be instrumented using whatever `-indirect_instrumentation` method is specified

Windows/debugger.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,8 @@ void Debugger::ExtractCodeRanges(void *module_base,
553553
size_t min_address,
554554
size_t max_address,
555555
std::list<AddressRange> *executable_ranges,
556-
size_t *code_size)
556+
size_t *code_size,
557+
bool do_protect)
557558
{
558559
LPCVOID end_address = (void *)max_address;
559560
LPCVOID cur_address = (void *)min_address;
@@ -593,17 +594,19 @@ void Debugger::ExtractCodeRanges(void *module_base,
593594
FATAL("Error in ReadProcessMemory");
594595
}
595596

596-
uint8_t low = meminfobuf.Protect & 0xFF;
597-
low = low >> 4;
598-
DWORD newProtect = (meminfobuf.Protect & 0xFFFFFF00) + low;
599-
DWORD oldProtect;
600-
if (!VirtualProtectEx(child_handle,
601-
meminfobuf.BaseAddress,
602-
meminfobuf.RegionSize,
603-
newProtect,
604-
&oldProtect))
605-
{
606-
FATAL("Error in VirtualProtectEx");
597+
if(do_protect) {
598+
uint8_t low = meminfobuf.Protect & 0xFF;
599+
low = low >> 4;
600+
DWORD newProtect = (meminfobuf.Protect & 0xFFFFFF00) + low;
601+
DWORD oldProtect;
602+
if (!VirtualProtectEx(child_handle,
603+
meminfobuf.BaseAddress,
604+
meminfobuf.RegionSize,
605+
newProtect,
606+
&oldProtect))
607+
{
608+
FATAL("Error in VirtualProtectEx");
609+
}
607610
}
608611

609612
newRange.from = (size_t)meminfobuf.BaseAddress;

Windows/debugger.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ class Debugger {
124124
size_t min_address,
125125
size_t max_address,
126126
std::list<AddressRange> *executable_ranges,
127-
size_t *code_size);
127+
size_t *code_size,
128+
bool do_protect = true);
128129

129130
void ProtectCodeRanges(std::list<AddressRange> *executable_ranges);
130131

macOS/debugger.cpp

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -815,8 +815,9 @@ void Debugger::ExtractCodeRanges(void *base_address,
815815
size_t min_address,
816816
size_t max_address,
817817
std::list<AddressRange> *executable_ranges,
818-
size_t *code_size) {
819-
818+
size_t *code_size,
819+
bool do_protect)
820+
{
820821
if(!base_address) {
821822
ExtractSegmentCodeRanges(min_address, max_address, executable_ranges, code_size);
822823
return;
@@ -876,7 +877,7 @@ void Debugger::ExtractCodeRanges(void *base_address,
876877
mach_vm_address_t segment_start_addr = (mach_vm_address_t)segment_cmd->vmaddr + file_vm_slide;
877878
mach_vm_address_t segment_end_addr = (mach_vm_address_t)segment_cmd->vmaddr + file_vm_slide + segment_cmd->vmsize;
878879

879-
ExtractSegmentCodeRanges(segment_start_addr, segment_end_addr, executable_ranges, code_size);
880+
ExtractSegmentCodeRanges(segment_start_addr, segment_end_addr, executable_ranges, code_size, do_protect);
880881
#endif
881882
}
882883

@@ -889,7 +890,9 @@ void Debugger::ExtractCodeRanges(void *base_address,
889890
void Debugger::ExtractSegmentCodeRanges(mach_vm_address_t segment_start_addr,
890891
mach_vm_address_t segment_end_addr,
891892
std::list<AddressRange> *executable_ranges,
892-
size_t *code_size) {
893+
size_t *code_size,
894+
bool do_protect)
895+
{
893896
mach_vm_address_t cur_address = segment_start_addr;
894897
while (cur_address < segment_end_addr) {
895898
mach_vm_size_t region_size = 0;
@@ -916,38 +919,42 @@ void Debugger::ExtractSegmentCodeRanges(mach_vm_address_t segment_start_addr,
916919
new_range.data = (char *)malloc(range_size);
917920
RemoteRead((void*)new_range.from, new_range.data, range_size);
918921

919-
retry_label:
920-
RemoteProtect((void*)new_range.from, range_size, info.protection ^ VM_PROT_EXECUTE);
921-
mach_vm_address_t region_addr = new_range.from;
922-
mach_vm_size_t region_sz = range_size;
923-
vm_region_submap_info_data_64_t region_info;
924-
mach_target->GetRegionSubmapInfo(&region_addr, (mach_vm_size_t*)&region_sz, &region_info);
925-
if (region_info.protection & VM_PROT_EXECUTE) {
926-
if (retried) {
927-
FATAL("Failed to mark the original code NON-EXECUTABLE\n");
928-
}
929-
930-
kern_return_t krt;
931-
krt = mach_vm_deallocate(mach_target->Task(),
932-
(mach_vm_address_t)new_range.from,
933-
range_size);
934-
935-
if (krt == KERN_SUCCESS) {
936-
mach_vm_address_t alloc_address = new_range.from;
937-
krt = mach_vm_allocate(mach_target->Task(),
938-
(mach_vm_address_t*)&alloc_address,
939-
range_size,
940-
VM_FLAGS_FIXED);
941-
942-
if (krt == KERN_SUCCESS && alloc_address && new_range.from) {
943-
RemoteWrite((void*)new_range.from, new_range.data, range_size);
944-
} else {
945-
FATAL("Unable to re-allocate memory after deallocate in ExtractSegmentCodeRanges\n");
922+
if(do_protect) {
923+
retry_label:
924+
RemoteProtect((void*)new_range.from, range_size, info.protection ^ VM_PROT_EXECUTE);
925+
mach_vm_address_t region_addr = new_range.from;
926+
mach_vm_size_t region_sz = range_size;
927+
vm_region_submap_info_data_64_t region_info;
928+
mach_target->GetRegionSubmapInfo(&region_addr, (mach_vm_size_t*)&region_sz, &region_info);
929+
if (region_info.protection & VM_PROT_EXECUTE) {
930+
if (retried) {
931+
FATAL("Failed to mark the original code NON-EXECUTABLE\n");
932+
}
933+
934+
kern_return_t krt;
935+
krt = mach_vm_deallocate(mach_target->Task(),
936+
(mach_vm_address_t)new_range.from,
937+
range_size);
938+
939+
if (krt == KERN_SUCCESS) {
940+
mach_vm_address_t alloc_address = new_range.from;
941+
krt = mach_vm_allocate(mach_target->Task(),
942+
(mach_vm_address_t*)&alloc_address,
943+
range_size,
944+
VM_FLAGS_FIXED);
945+
946+
if (krt == KERN_SUCCESS && alloc_address && new_range.from) {
947+
RemoteWrite((void*)new_range.from, new_range.data, range_size);
948+
} else {
949+
FATAL("Unable to re-allocate memory after deallocate in ExtractSegmentCodeRanges\n");
950+
}
946951
}
952+
953+
retried = true;
954+
goto retry_label;
947955
}
948-
949-
retried = true;
950-
goto retry_label;
956+
} else {
957+
//WARN("skipping memory protection");
951958
}
952959

953960
AddressRange *last_range = NULL;

macOS/debugger.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ friend kern_return_t catch_mach_exception_raise_state_identity(
156156
DebuggerStatus Kill();
157157
DebuggerStatus Continue(uint32_t timeout);
158158
DebuggerStatus Attach(unsigned int pid, uint32_t timeout);
159+
DebuggerStatus GetDebuggerStatus() {
160+
return dbg_last_status;
161+
}
159162

160163
bool IsTargetAlive();
161164
bool IsTargetFunctionDefined() { return target_function_defined; }
@@ -254,7 +257,8 @@ friend kern_return_t catch_mach_exception_raise_state_identity(
254257
size_t min_address,
255258
size_t max_address,
256259
std::list<AddressRange> *executable_ranges,
257-
size_t *code_size);
260+
size_t *code_size,
261+
bool do_protect = true);
258262

259263
void ProtectCodeRanges(std::list<AddressRange> *executable_ranges);
260264

@@ -398,7 +402,7 @@ friend kern_return_t catch_mach_exception_raise_state_identity(
398402
void ExtractSegmentCodeRanges(mach_vm_address_t segment_start_addr,
399403
mach_vm_address_t segment_end_addr,
400404
std::list<AddressRange> *executable_ranges,
401-
size_t *code_size);
405+
size_t *code_size, bool do_protect = true);
402406

403407
void HandleDyld(void *module);
404408

tinyinst.cpp

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ ModuleInfo::ModuleInfo() {
4949
instrumented_code_size = 0;
5050
unwind_data = NULL;
5151
client_data = NULL;
52+
do_protect = true;
5253
}
5354

5455
void ModuleInfo::ClearInstrumentation() {
@@ -900,16 +901,19 @@ void TinyInst::InstrumentModule(ModuleInfo *module) {
900901
printf("Module %s already instrumented, "
901902
"reusing instrumentation data\n",
902903
module->module_name.c_str());
903-
ProtectCodeRanges(&module->executable_ranges);
904+
if (module->do_protect) {
905+
ProtectCodeRanges(&module->executable_ranges);
906+
}
904907
FixCrossModuleLinks(module);
905908
return;
906909
}
907-
910+
908911
ExtractCodeRanges(module->module_header,
909912
module->min_address,
910913
module->max_address,
911914
&module->executable_ranges,
912-
&module->code_size);
915+
&module->code_size,
916+
module->do_protect);
913917

914918
// allocate buffer for instrumented code
915919
module->instrumented_code_size = module->code_size * CODE_SIZE_MULTIPLIER;
@@ -1213,6 +1217,18 @@ InstructionResult TinyInst::InstrumentInstruction(ModuleInfo *module,
12131217
return INST_NOTHANDLED;
12141218
}
12151219

1220+
void TinyInst::AddInstrumentedModule(char* name, bool do_protect) {
1221+
std::string module_name = name;
1222+
for(auto iter=instrumented_modules.begin(); iter!=instrumented_modules.end(); iter++) {
1223+
if((*iter)->module_name == module_name) {
1224+
FATAL("Duplicate instrumented modules, module %s is already being instrumented", name);
1225+
}
1226+
}
1227+
ModuleInfo *new_module = new ModuleInfo();
1228+
new_module->module_name = module_name;
1229+
new_module->do_protect = do_protect;
1230+
instrumented_modules.push_back(new_module);
1231+
}
12161232

12171233
// initializes instrumentation from command line options
12181234
void TinyInst::Init(int argc, char **argv) {
@@ -1298,9 +1314,15 @@ void TinyInst::Init(int argc, char **argv) {
12981314
#endif
12991315

13001316
for (const auto module_name: module_names) {
1301-
ModuleInfo *new_module = new ModuleInfo();
1302-
new_module->module_name = module_name;
1303-
instrumented_modules.push_back(new_module);
1317+
AddInstrumentedModule(module_name, true);
1318+
// SAY("--- %s\n", module_name);
1319+
}
1320+
1321+
std::list <char *> module_names_transitive;
1322+
GetOptionAll("-instrument_transitive", argc, argv, &module_names_transitive);
1323+
1324+
for (const auto module_name: module_names_transitive) {
1325+
AddInstrumentedModule(module_name, false);
13041326
// SAY("--- %s\n", module_name);
13051327
}
13061328

tinyinst.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ class TinyInst : public Debugger {
165165
void InstrumentAddressRange(const char *name, size_t min_address, size_t max_address);
166166

167167
private:
168+
void AddInstrumentedModule(char* name, bool do_protect);
168169
bool HandleBreakpoint(void *address);
169170
void OnInstrumentModuleLoaded(void *module, ModuleInfo *target_module);
170171
ModuleInfo *IsInstrumentModule(char *module_name);
@@ -321,6 +322,8 @@ class ModuleInfo {
321322
std::unordered_set<size_t> entry_offsets;
322323

323324
UnwindData *unwind_data;
325+
326+
bool do_protect;
324327

325328
// clients can use this to store additional data
326329
// about the module

0 commit comments

Comments
 (0)