xref: /haiku/src/bin/debug/ltrace/ltrace_stub.cpp (revision d25503d3dbd8e3f526fd0a9bdd884b8e43c1b794)
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