1/*
2 * Copyright 2005-2007, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * 		Ingo Weinhold <bonefish@cs.tu-berlin.de>
7 * 		Hugo Santos <hugosantos@gmail.com>
8 */
9
10#include "TypeHandler.h"
11
12#include <string.h>
13#include <String.h>
14
15#include "Context.h"
16#include "MemoryReader.h"
17#include "Syscall.h"
18
19template<typename value_t>
20static inline value_t
21get_value(const void *address)
22{
23	if (sizeof(align_t) > sizeof(value_t))
24		return value_t(*(align_t*)address);
25	else
26		return *(value_t*)address;
27}
28
29// #pragma mark -
30
31// create_pointer_type_handler
32TypeHandler *
33create_pointer_type_handler()
34{
35	return new TypeHandlerImpl<const void*>();
36}
37
38// create_string_type_handler
39TypeHandler *
40create_string_type_handler()
41{
42	return new TypeHandlerImpl<const char*>();
43}
44
45// #pragma mark -
46
47// complete specializations
48
49// void
50template<>
51string
52TypeHandlerImpl<void>::GetParameterValue(Context &, Parameter *, const void *)
53{
54	return "void";
55}
56
57template<>
58string
59TypeHandlerImpl<void>::GetReturnValue(Context &, uint64 value)
60{
61	return "";
62}
63
64template<>
65TypeHandler *
66TypeHandlerFactory<void>::Create()
67{
68	return new TypeHandlerImpl<void>();
69}
70
71// bool
72template<>
73string
74TypeHandlerImpl<bool>::GetParameterValue(Context &, Parameter *,
75					 const void *address)
76{
77	return (*(const align_t*)address ? "true" : "false");
78}
79
80template<>
81string
82TypeHandlerImpl<bool>::GetReturnValue(Context &, uint64 value)
83{
84	return (value ? "true" : "false");
85}
86
87template<>
88TypeHandler *
89TypeHandlerFactory<bool>::Create()
90{
91	return new TypeHandlerImpl<bool>();
92}
93
94// status_t
95class StatusTypeHandler : public TypeHandler {
96public:
97	StatusTypeHandler() {}
98
99	string GetParameterValue(Context &context, Parameter *, const void *address)
100	{
101		return RenderValue(context, get_value<status_t>(address));
102	}
103
104	string GetReturnValue(Context &context, uint64 value)
105	{
106		return RenderValue(context, value);
107	}
108
109private:
110	string RenderValue(Context &context, uint64 value) const
111	{
112		string rendered = context.FormatUnsigned(value);
113		if (value <= UINT32_MAX && (status_t)value <= 0) {
114			rendered += " ";
115			rendered += strerror(value);
116		}
117		return rendered;
118	}
119};
120
121TypeHandler *
122create_status_t_type_handler()
123{
124	return new StatusTypeHandler;
125}
126
127// read_string
128static
129string
130read_string(Context &context, void *data)
131{
132	if (data == NULL || !context.GetContents(Context::STRINGS))
133		return context.FormatPointer(data);
134
135	char buffer[256];
136	int32 bytesRead;
137	status_t error = context.Reader().Read(data, buffer, sizeof(buffer), bytesRead);
138	if (error == B_OK) {
139		string result("\"");
140		result += string(buffer, strnlen(buffer, sizeof(buffer)));
141		result += "\"";
142		return result;
143	}
144
145	return context.FormatPointer(data) + " (" + strerror(error) + ")";
146}
147
148// const void*
149template<>
150string
151TypeHandlerImpl<const void*>::GetParameterValue(Context &context, Parameter *,
152						const void *address)
153{
154	return context.FormatPointer(*(void **)address);
155}
156
157template<>
158string
159TypeHandlerImpl<const void*>::GetReturnValue(Context &context, uint64 value)
160{
161	return context.FormatPointer((void *)value);
162}
163
164// const char*
165template<>
166string
167TypeHandlerImpl<const char*>::GetParameterValue(Context &context, Parameter *,
168						const void *address)
169{
170	return read_string(context, *(void **)address);
171}
172
173template<>
174string
175TypeHandlerImpl<const char*>::GetReturnValue(Context &context, uint64 value)
176{
177	return read_string(context, (void *)value);
178}
179
180EnumTypeHandler::EnumTypeHandler(const EnumMap &m) : fMap(m) {}
181
182string
183EnumTypeHandler::GetParameterValue(Context &context, Parameter *,
184				   const void *address)
185{
186	return RenderValue(context, get_value<unsigned int>(address));
187}
188
189string
190EnumTypeHandler::GetReturnValue(Context &context, uint64 value)
191{
192	return RenderValue(context, value);
193}
194
195string
196EnumTypeHandler::RenderValue(Context &context, unsigned int value) const
197{
198	if (context.GetContents(Context::ENUMERATIONS)) {
199		EnumMap::const_iterator i = fMap.find(value);
200		if (i != fMap.end() && i->second != NULL)
201			return i->second;
202	}
203
204	return context.FormatUnsigned(value);
205}
206
207FlagsTypeHandler::FlagsTypeHandler(const FlagsList &m) : fList(m) {}
208
209string
210FlagsTypeHandler::GetParameterValue(Context &context, Parameter *,
211	const void *address)
212{
213	return RenderValue(context, get_value<unsigned int>(address));
214}
215
216string
217FlagsTypeHandler::GetReturnValue(Context &context, uint64 value)
218{
219	return RenderValue(context, value);
220}
221
222string
223FlagsTypeHandler::RenderValue(Context &context, unsigned int value) const
224{
225	if (context.GetContents(Context::ENUMERATIONS)) {
226		// Enumerate the list in reverse. That way, any later values which use
227		// the same bits as earlier values will be processed correctly.
228		string rendered;
229		FlagsList::const_reverse_iterator i = fList.rbegin();
230		for (; i != fList.rend(); i++) {
231			if (value == 0)
232				break;
233			if ((value & i->value) != i->value)
234				continue;
235
236			if (!rendered.empty())
237				rendered.insert(0, "|");
238			rendered.insert(0, i->name);
239			value &= ~(i->value);
240		}
241		if (value != 0) {
242			if (!rendered.empty())
243				rendered += "|";
244
245			char hex[20];
246			snprintf(hex, sizeof(hex), "0x%x", value);
247			rendered += hex;
248		}
249		if (rendered.empty())
250			rendered = "0";
251		return rendered;
252	}
253
254	return context.FormatUnsigned(value);
255}
256
257TypeHandlerSelector::TypeHandlerSelector(const SelectMap &m, int sibling,
258					 TypeHandler *def)
259	: fMap(m), fSibling(sibling), fDefault(def) {}
260
261string
262TypeHandlerSelector::GetParameterValue(Context &context, Parameter *param,
263				       const void *address)
264{
265	TypeHandler *target = fDefault;
266
267	int index = get_value<int>(context.GetValue(context.GetSibling(fSibling)));
268
269	SelectMap::const_iterator i = fMap.find(index);
270	if (i != fMap.end())
271		target = i->second;
272
273	return target->GetParameterValue(context, param, address);
274}
275
276string
277TypeHandlerSelector::GetReturnValue(Context &context, uint64 value)
278{
279	return fDefault->GetReturnValue(context, value);
280}
281
282template<typename Type>
283static bool
284obtain_pointer_data(Context &context, Type *data, void *address, uint32 what)
285{
286	if (address == NULL || !context.GetContents(what))
287		return false;
288
289	int32 bytesRead;
290
291	status_t err = context.Reader().Read(address, data, sizeof(Type), bytesRead);
292	if (err != B_OK || bytesRead < (int32)sizeof(Type))
293		return false;
294
295	return true;
296}
297
298template<typename Type>
299static string
300format_signed_integer_pointer(Context &context, void *address, uint32 count)
301{
302	Type data;
303
304	if (obtain_pointer_data(context, &data, address, Context::POINTER_VALUES)) {
305		string formatted = "[" + context.FormatSigned(data);
306		for (uint32 i = 1; i < count; i++) {
307			address = (void*)((Type*)address + 1);
308			obtain_pointer_data(context, &data, address, Context::POINTER_VALUES);
309			formatted += ", " + context.FormatSigned(data);
310		}
311		formatted += "]";
312		return formatted;
313	}
314	return context.FormatPointer(address);
315}
316
317template<typename Type>
318static string
319format_unsigned_integer_pointer(Context &context, void *address, uint32 count)
320{
321	Type data;
322
323	if (obtain_pointer_data(context, &data, address, Context::POINTER_VALUES)) {
324		string formatted = "[" + context.FormatUnsigned(data);
325		for (uint32 i = 1; i < count; i++) {
326			address = (void*)((Type*)address + 1);
327			obtain_pointer_data(context, &data, address, Context::POINTER_VALUES);
328			formatted += ", " + context.FormatUnsigned(data);
329		}
330		formatted += "]";
331		return formatted;
332	}
333
334	return context.FormatPointer(address);
335}
336
337template<typename Type>
338class SignedIntegerTypeHandler : public TypeHandler {
339public:
340	string GetParameterValue(Context &context, Parameter *,
341				 const void *address)
342	{
343		return context.FormatSigned(get_value<Type>(address), sizeof(Type));
344	}
345
346	string GetReturnValue(Context &context, uint64 value)
347	{
348		return context.FormatSigned(value, sizeof(Type));
349	}
350};
351
352template<typename Type>
353class UnsignedIntegerTypeHandler : public TypeHandler {
354public:
355	string GetParameterValue(Context &context, Parameter *,
356				 const void *address)
357	{
358		return context.FormatUnsigned(get_value<Type>(address));
359	}
360
361	string GetReturnValue(Context &context, uint64 value)
362	{
363		return context.FormatUnsigned(value);
364	}
365};
366
367template<typename Type>
368class SignedIntegerPointerTypeHandler : public TypeHandler {
369	string GetParameterValue(Context &context, Parameter *parameter,
370				 const void *address)
371	{
372		return format_signed_integer_pointer<Type>(context, *(void **)address,
373			parameter->Count());
374	}
375
376	string GetReturnValue(Context &context, uint64 value)
377	{
378		return format_signed_integer_pointer<Type>(context, (void *)value, 1);
379	}
380};
381
382template<typename Type>
383class UnsignedIntegerPointerTypeHandler : public TypeHandler {
384	string GetParameterValue(Context &context, Parameter *parameter,
385				 const void *address)
386	{
387		return format_unsigned_integer_pointer<Type>(context, *(void **)address,
388			parameter->Count());
389	}
390
391	string GetReturnValue(Context &context, uint64 value)
392	{
393		return format_unsigned_integer_pointer<Type>(context, (void *)value, 1);
394	}
395};
396
397#define SIGNED_INTEGER_TYPE(type) \
398	template<> \
399	TypeHandler * \
400	TypeHandlerFactory<type>::Create() \
401	{ \
402		return new SignedIntegerTypeHandler<type>(); \
403	}
404
405#define UNSIGNED_INTEGER_TYPE(type) \
406	template<> \
407	TypeHandler * \
408	TypeHandlerFactory<type>::Create() \
409	{ \
410		return new UnsignedIntegerTypeHandler<type>(); \
411	}
412
413#define SIGNED_INTEGER_POINTER_TYPE(name, type) \
414	TypeHandler *create_##name##_type_handler() \
415	{ \
416		return new SignedIntegerPointerTypeHandler<type>(); \
417	}
418
419#define UNSIGNED_INTEGER_POINTER_TYPE(name, type) \
420	TypeHandler *create_##name##_type_handler() \
421	{ \
422		return new UnsignedIntegerPointerTypeHandler<type>(); \
423	}
424
425
426SIGNED_INTEGER_TYPE(char);
427SIGNED_INTEGER_TYPE(short);
428SIGNED_INTEGER_TYPE(int);
429SIGNED_INTEGER_TYPE(long);
430SIGNED_INTEGER_TYPE(long long);
431
432UNSIGNED_INTEGER_TYPE(unsigned char);
433UNSIGNED_INTEGER_TYPE(unsigned short);
434UNSIGNED_INTEGER_TYPE(unsigned int);
435UNSIGNED_INTEGER_TYPE(unsigned long);
436UNSIGNED_INTEGER_TYPE(unsigned long long);
437
438SIGNED_INTEGER_POINTER_TYPE(int_ptr, int);
439SIGNED_INTEGER_POINTER_TYPE(long_ptr, long);
440SIGNED_INTEGER_POINTER_TYPE(longlong_ptr, long long);
441
442UNSIGNED_INTEGER_POINTER_TYPE(uint_ptr, unsigned int);
443UNSIGNED_INTEGER_POINTER_TYPE(ulong_ptr, unsigned long);
444UNSIGNED_INTEGER_POINTER_TYPE(ulonglong_ptr, unsigned long long);
445
446