1 /* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 9 #include <new> 10 11 #include <OS.h> 12 13 #include <runtime_loader.h> 14 #include <util/OpenHashTable.h> 15 16 #include "arch/ltrace_stub.h" 17 18 19 //#define TRACE_PRINTF debug_printf 20 #define TRACE_PRINTF ktrace_printf 21 22 23 static void* function_call_callback(const void* stub, const void* args); 24 25 26 struct PatchEntry { 27 PatchEntry* originalTableLink; 28 PatchEntry* patchedTableLink; 29 30 void* originalFunction; 31 void* patchedFunction; 32 const char* functionName; 33 34 static PatchEntry* Create(const char* name, void* function) 35 { 36 void* memory = malloc(_ALIGN(sizeof(PatchEntry)) 37 + arch_call_stub_size()); 38 if (memory == NULL) 39 return NULL; 40 41 PatchEntry* entry = new(memory) PatchEntry; 42 43 void* stub = (uint8*)memory + _ALIGN(sizeof(PatchEntry)); 44 arch_init_call_stub(stub, &function_call_callback, function); 45 46 entry->originalFunction = function; 47 entry->patchedFunction = stub; 48 entry->functionName = name; 49 50 return entry; 51 } 52 }; 53 54 55 struct OriginalTableDefinition { 56 typedef const void* KeyType; 57 typedef PatchEntry ValueType; 58 59 size_t HashKey(const void* key) const 60 { 61 return (addr_t)key >> 2; 62 } 63 64 size_t Hash(PatchEntry* value) const 65 { 66 return HashKey(value->originalFunction); 67 } 68 69 bool Compare(const void* key, PatchEntry* value) const 70 { 71 return value->originalFunction == key; 72 } 73 74 PatchEntry*& GetLink(PatchEntry* value) const 75 { 76 return value->originalTableLink; 77 } 78 }; 79 80 81 struct PatchedTableDefinition { 82 typedef const void* KeyType; 83 typedef PatchEntry ValueType; 84 85 size_t HashKey(const void* key) const 86 { 87 return (addr_t)key >> 2; 88 } 89 90 size_t Hash(PatchEntry* value) const 91 { 92 return HashKey(value->patchedFunction); 93 } 94 95 bool Compare(const void* key, PatchEntry* value) const 96 { 97 return value->patchedFunction == key; 98 } 99 100 PatchEntry*& GetLink(PatchEntry* value) const 101 { 102 return value->patchedTableLink; 103 } 104 }; 105 106 107 static rld_export* sRuntimeLoaderInterface; 108 static runtime_loader_add_on_export* sRuntimeLoaderAddOnInterface; 109 110 static BOpenHashTable<OriginalTableDefinition> sOriginalTable; 111 static BOpenHashTable<PatchedTableDefinition> sPatchedTable; 112 113 114 static void* 115 function_call_callback(const void* stub, const void* _args) 116 { 117 PatchEntry* entry = sPatchedTable.Lookup(stub); 118 if (entry == NULL) 119 { 120 TRACE_PRINTF("function_call_callback(): CALLED FOR UNKNOWN FUNCTION!\n"); 121 return NULL; 122 } 123 124 char buffer[1024]; 125 size_t bufferSize = sizeof(buffer); 126 size_t written = 0; 127 128 const uint32* args = (const uint32*)_args; 129 written += snprintf(buffer, bufferSize, "ltrace: %s(", 130 entry->functionName); 131 for (int32 i = 0; i < 5; i++) { 132 written += snprintf(buffer + written, bufferSize - written, "%s%#lx", 133 i == 0 ? "" : ", ", args[i]); 134 } 135 written += snprintf(buffer + written, bufferSize - written, ")"); 136 TRACE_PRINTF("%s\n", buffer); 137 138 return entry->originalFunction; 139 } 140 141 142 static void 143 symbol_patcher(void* cookie, image_t* rootImage, image_t* image, 144 const char* name, image_t** foundInImage, void** symbol, int32* type) 145 { 146 TRACE_PRINTF("symbol_patcher(%p, %p, %p, \"%s\", %p, %p, %ld)\n", 147 cookie, rootImage, image, name, *foundInImage, *symbol, *type); 148 149 // patch functions only 150 if (*type != B_SYMBOL_TYPE_TEXT) 151 return; 152 153 // already patched? 154 PatchEntry* entry = sOriginalTable.Lookup(*symbol); 155 if (entry != NULL) { 156 *foundInImage = NULL; 157 *symbol = entry->patchedFunction; 158 return; 159 } 160 161 entry = PatchEntry::Create(name, *symbol); 162 if (entry == NULL) 163 return; 164 165 sOriginalTable.Insert(entry); 166 sPatchedTable.Insert(entry); 167 168 TRACE_PRINTF(" -> patching to %p\n", entry->patchedFunction); 169 170 *foundInImage = NULL; 171 *symbol = entry->patchedFunction; 172 } 173 174 175 static void 176 ltrace_stub_init(rld_export* standardInterface, 177 runtime_loader_add_on_export* addOnInterface) 178 { 179 TRACE_PRINTF("ltrace_stub_init(%p, %p)\n", standardInterface, addOnInterface); 180 sRuntimeLoaderInterface = standardInterface; 181 sRuntimeLoaderAddOnInterface = addOnInterface; 182 183 sOriginalTable.Init(); 184 sPatchedTable.Init(); 185 } 186 187 188 static void 189 ltrace_stub_image_loaded(image_t* image) 190 { 191 TRACE_PRINTF("ltrace_stub_image_loaded(%p): \"%s\" (%ld)\n", image, image->path, 192 image->id); 193 194 if (sRuntimeLoaderAddOnInterface->register_undefined_symbol_patcher(image, 195 symbol_patcher, (void*)(addr_t)0xc0011eaf) != B_OK) { 196 TRACE_PRINTF(" failed to install symbol patcher\n"); 197 } 198 } 199 200 201 static void 202 ltrace_stub_image_relocated(image_t* image) 203 { 204 TRACE_PRINTF("ltrace_stub_image_relocated(%p): \"%s\" (%ld)\n", image, 205 image->path, image->id); 206 } 207 208 209 static void 210 ltrace_stub_image_initialized(image_t* image) 211 { 212 TRACE_PRINTF("ltrace_stub_image_initialized(%p): \"%s\" (%ld)\n", image, 213 image->path, image->id); 214 } 215 216 217 static void 218 ltrace_stub_image_uninitializing(image_t* image) 219 { 220 TRACE_PRINTF("ltrace_stub_image_uninitializing(%p): \"%s\" (%ld)\n", image, 221 image->path, image->id); 222 } 223 224 225 static void 226 ltrace_stub_image_unloading(image_t* image) 227 { 228 TRACE_PRINTF("ltrace_stub_image_unloading(%p): \"%s\" (%ld)\n", image, 229 image->path, image->id); 230 } 231 232 233 // interface for the runtime loader 234 runtime_loader_add_on __gRuntimeLoaderAddOn = { 235 RUNTIME_LOADER_ADD_ON_VERSION, // version 236 0, // flags 237 238 ltrace_stub_init, 239 240 ltrace_stub_image_loaded, 241 ltrace_stub_image_relocated, 242 ltrace_stub_image_initialized, 243 ltrace_stub_image_uninitializing, 244 ltrace_stub_image_unloading 245 }; 246