Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set Default Behavior to Skip Re-Instrumentation of Duplicate Modules #86

Merged
merged 9 commits into from
Dec 17, 2024
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ In addition to the general-purpose API documented above, TinyInst also implement

`-indirect_instrumentation [none|local|global|auto]` which instrumentation to use for indirect jump/calls

`-ignore_duplicates_module [module name]` Ensures only the first loaded instance of `[module name]` is instrumented, ignoring subsequent duplicates. Useful when instrumenting system libraries (e.g., `CoreAudio`) on macOS Sequoia and later, where multiple distinct libraries with the same name may be loaded.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think having a flag for this is not needed; TinyInst will not currently work correctly with duplicate module names, so the current ignore_duplicates behavior should just be the default implementation for all modules. Just issuing a warning on duplicate module and not instrumenting it is completely sufficient.

Later we need to think how to resolve this e.g. if the user wants to instrument the second module with the same name (or multiple modules with the same name). For that, there should probably be an option to specify instrumented_module by full path, but we can figure that out later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good! I will go ahead and remove the flag and implement ignoring duplicate modules as the default behavior :)


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

`-generate_unwind` - Generates stack unwinding data for instrumented code (for faster C++ exception handling). Note that it might not work correctly on some older Windows versions.
Expand Down
2 changes: 1 addition & 1 deletion hook.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ It is expected that most hooking operations can be performed just using the brea

If a hook needs to add additional assembly code, this can be done by implementing `WriteCodeBefore`/`WriteCodeAfter` methods of the hook class. Assembly code can be inserted by calling the `WriteCode` function with the buffer containing the assembly to be inserted. Note that both `WriteCodeBefore`/`WriteCodeAfter` get called during instrumentation time (before the function gets run) and, due to how `HookBeginEnd` is implemented, `WriteCodeAfter` can be called multiple times for a single hooked function.

Once the hook classes have been implemented for each function the user wants to hook, the user can register them by calling `RegisterHook` method inside their clien's constructor.
Once the hook classes have been implemented for each function the user wants to hook, the user can register them by calling `RegisterHook` method inside their client's constructor.

### Example

Expand Down
26 changes: 22 additions & 4 deletions tinyinst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ ModuleInfo::ModuleInfo() {
max_address = 0;
loaded = false;
instrumented = false;
ignore_duplicates = false;
instrumented_code_local = NULL;
instrumented_code_remote = NULL;
instrumented_code_remote_previous = NULL;
Expand Down Expand Up @@ -850,6 +851,8 @@ void TinyInst::OnModuleInstrumented(ModuleInfo* module) {
}
if(address) {
resolved_hooks[address] = hook;
} else {
FATAL("Could not resolve function %s in module %s", hook->GetFunctionName().c_str(), hook->GetModuleName().c_str());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to FATAL() here because hook's module name could be "*" so it searches for the function in all modules.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that makes good sense. Do you foresee a better way to alert the user if a hook function is unable to be resolved? Or do you think it's not necessary?

Copy link
Contributor Author

@dillonfranke dillonfranke Dec 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose I could just change it to WARN()

}
}
}
Expand Down Expand Up @@ -1075,9 +1078,14 @@ void TinyInst::OnInstrumentModuleLoaded(void *module, ModuleInfo *target_module)
target_module->module_header &&
(target_module->module_header != (void *)module))
{
WARN("Instrumented module loaded on a different address than seen previously\n"
"Module will need to be re-instrumented. Expect a drop in performance.");
ClearInstrumentation(target_module);
if (target_module->ignore_duplicates) {
WARN("Skipping duplicate module %s.", target_module->module_name.c_str());
return;
} else {
WARN("Instrumented module loaded on a different address than seen previously\n"
"Module will need to be re-instrumented. Expect a drop in performance.");
ClearInstrumentation(target_module);
}
}

target_module->module_header = (void *)module;
Expand All @@ -1095,7 +1103,7 @@ void TinyInst::OnInstrumentModuleLoaded(void *module, ModuleInfo *target_module)
}
}

// called when a potentialy interesting module gets loaded
// called when a potentially interesting module gets loaded
void TinyInst::OnModuleLoaded(void *module, char *module_name) {
Debugger::OnModuleLoaded(module, module_name);

Expand Down Expand Up @@ -1277,6 +1285,9 @@ void TinyInst::Init(int argc, char **argv) {
std::list <char *> module_names;
GetOptionAll("-instrument_module", argc, argv, &module_names);

std::list <char *> ignored_duplicate_modules;
GetOptionAll("-ignore_duplicates_module", argc, argv, &ignored_duplicate_modules);

#if defined(__APPLE__) && defined(ARM64)
std::set <std::string> orig_uniq_mod_names;
std::set <std::string> new_uniq_mod_names;
Expand Down Expand Up @@ -1314,6 +1325,13 @@ void TinyInst::Init(int argc, char **argv) {
#endif

for (const auto module_name: module_names) {
ModuleInfo *new_module = new ModuleInfo();
new_module->module_name = module_name;
for (const auto& ignored_module : ignored_duplicate_modules) {
if (strcmp(ignored_module, module_name) == 0) {
new_module->ignore_duplicates = true;
}
}
AddInstrumentedModule(module_name, true);
// SAY("--- %s\n", module_name);
}
Expand Down
1 change: 1 addition & 0 deletions tinyinst.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ class ModuleInfo {
size_t code_size;
bool loaded;
bool instrumented;
bool ignore_duplicates;
std::list<AddressRange> executable_ranges;

size_t instrumented_code_size;
Expand Down