1/*
2 * Copyright 2002-2008, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <debugger.h>
8#include <OS.h>
9#include <Debug.h>
10#include "syscalls.h"
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15
16
17typedef struct debug_string_entry {
18	const char	*string;
19	uint32		code;
20} debug_string_entry;
21
22static const debug_string_entry sDebugMessageStrings[] = {
23	{ "Thread not running",	B_DEBUGGER_MESSAGE_THREAD_DEBUGGED },
24	{ "Debugger call",		B_DEBUGGER_MESSAGE_DEBUGGER_CALL },
25	{ "Breakpoint hit",		B_DEBUGGER_MESSAGE_BREAKPOINT_HIT },
26	{ "Watchpoint hit",		B_DEBUGGER_MESSAGE_WATCHPOINT_HIT },
27	{ "Single step",		B_DEBUGGER_MESSAGE_SINGLE_STEP },
28	{ "Before syscall",		B_DEBUGGER_MESSAGE_PRE_SYSCALL },
29	{ "After syscall",		B_DEBUGGER_MESSAGE_POST_SYSCALL },
30	{ "Signal received",	B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED },
31	{ "Exception occurred",	B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED },
32	{ "Team created",		B_DEBUGGER_MESSAGE_TEAM_CREATED },
33	{ "Team deleted",		B_DEBUGGER_MESSAGE_TEAM_DELETED },
34	{ "Thread created",		B_DEBUGGER_MESSAGE_THREAD_CREATED },
35	{ "Thread created",		B_DEBUGGER_MESSAGE_THREAD_DELETED },
36	{ "Image created",		B_DEBUGGER_MESSAGE_IMAGE_CREATED },
37	{ "Image deleted",		B_DEBUGGER_MESSAGE_IMAGE_DELETED },
38	{ NULL, 0 }
39};
40
41static const debug_string_entry sDebugExceptionTypeStrings[] = {
42	{ "Non-maskable interrupt",		B_NON_MASKABLE_INTERRUPT },
43	{ "Machine check exception",	B_MACHINE_CHECK_EXCEPTION },
44	{ "Segment violation",			B_SEGMENT_VIOLATION },
45	{ "Alignment exception",		B_ALIGNMENT_EXCEPTION },
46	{ "Divide error",				B_DIVIDE_ERROR },
47	{ "Overflow exception",			B_OVERFLOW_EXCEPTION },
48	{ "Bounds check exception",		B_BOUNDS_CHECK_EXCEPTION },
49	{ "Invalid opcode exception",	B_INVALID_OPCODE_EXCEPTION },
50	{ "Segment not present",		B_SEGMENT_NOT_PRESENT },
51	{ "Stack fault",				B_STACK_FAULT },
52	{ "General protection fault",	B_GENERAL_PROTECTION_FAULT },
53	{ "Floating point exception",	B_FLOATING_POINT_EXCEPTION },
54	{ NULL, 0 }
55};
56
57bool _rtDebugFlag = true;
58
59
60void
61debugger(const char *message)
62{
63	debug_printf("%" B_PRId32 ": DEBUGGER: %s\n", find_thread(NULL), message);
64	_kern_debugger(message);
65}
66
67
68int
69disable_debugger(int state)
70{
71	return _kern_disable_debugger(state);
72}
73
74
75status_t
76install_default_debugger(port_id debuggerPort)
77{
78	return _kern_install_default_debugger(debuggerPort);
79}
80
81
82port_id
83install_team_debugger(team_id team, port_id debuggerPort)
84{
85	return _kern_install_team_debugger(team, debuggerPort);
86}
87
88
89status_t
90remove_team_debugger(team_id team)
91{
92	return _kern_remove_team_debugger(team);
93}
94
95
96status_t
97debug_thread(thread_id thread)
98{
99	return _kern_debug_thread(thread);
100}
101
102
103/**	\brief Suspends the thread until a debugger has been installed for this
104 *		   team.
105 *
106 *	As soon as this happens (immediately, if a debugger is already installed)
107 *	the thread stops for debugging. This is desirable for debuggers that spawn
108 *	their debugged teams via fork() and want the child to wait till they have
109 *	installed themselves as team debugger before continuing with exec*().
110 */
111
112void
113wait_for_debugger(void)
114{
115	_kern_wait_for_debugger();
116}
117
118
119status_t
120set_debugger_breakpoint(void *address)
121{
122	return _kern_set_debugger_breakpoint(address, 0, 0, false);
123}
124
125
126status_t
127clear_debugger_breakpoint(void *address)
128{
129	return _kern_clear_debugger_breakpoint(address, false);
130}
131
132
133status_t
134set_debugger_watchpoint(void *address, uint32 type, int32 length)
135{
136	return _kern_set_debugger_breakpoint(address, type, length, true);
137}
138
139
140status_t
141clear_debugger_watchpoint(void *address)
142{
143	return _kern_clear_debugger_breakpoint(address, true);
144}
145
146
147static void
148get_debug_string(const debug_string_entry *stringEntries,
149	const char *defaultString, uint32 code, char *buffer, int32 bufferSize)
150{
151	int i;
152
153	if (!buffer || bufferSize <= 0)
154		return;
155
156	for (i = 0; stringEntries[i].string; i++) {
157		if (stringEntries[i].code == code) {
158			strlcpy(buffer, stringEntries[i].string, bufferSize);
159			return;
160		}
161	}
162
163	snprintf(buffer, bufferSize, defaultString, code);
164}
165
166
167void
168get_debug_message_string(debug_debugger_message message, char *buffer,
169	int32 bufferSize)
170{
171	get_debug_string(sDebugMessageStrings, "Unknown message %lu",
172		(uint32)message, buffer, bufferSize);
173}
174
175
176void
177get_debug_exception_string(debug_exception_type exception, char *buffer,
178	int32 bufferSize)
179{
180	get_debug_string(sDebugExceptionTypeStrings, "Unknown exception %lu",
181		(uint32)exception, buffer, bufferSize);
182}
183
184
185//	#pragma mark - Debug.h functions
186
187
188bool
189_debugFlag(void)
190{
191	return _rtDebugFlag;
192}
193
194
195bool
196_setDebugFlag(bool flag)
197{
198	bool previous = _rtDebugFlag;
199	_rtDebugFlag = flag;
200	return previous;
201}
202
203
204int
205_debugPrintf(const char *fmt, ...)
206{
207	va_list ap;
208	int ret;
209
210	if (!_rtDebugFlag)
211		return 0;
212
213	va_start(ap, fmt);
214	ret = vfprintf(stdout, fmt, ap);
215	va_end(ap);
216
217	return ret;
218}
219
220
221int
222_sPrintf(const char *fmt, ...)
223{
224	char buffer[512];
225	va_list ap;
226	int ret;
227
228	if (!_rtDebugFlag)
229		return 0;
230
231	va_start(ap, fmt);
232	ret = vsnprintf(buffer, sizeof(buffer), fmt, ap);
233	va_end(ap);
234
235	if (ret >= 0)
236		_kern_debug_output(buffer);
237
238	return ret;
239}
240
241
242int
243_xdebugPrintf(const char *fmt, ...)
244{
245	va_list ap;
246	int ret;
247
248	va_start(ap, fmt);
249	ret = vfprintf(stdout, fmt, ap);
250	va_end(ap);
251
252	return ret;
253}
254
255
256int
257_debuggerAssert(const char *file, int line, const char *message)
258{
259	char buffer[1024];
260	snprintf(buffer, sizeof(buffer),
261		"Assert failed: File: %s, Line: %d, %s",
262		file, line, message);
263
264	debug_printf("%" B_PRId32 ": ASSERT: %s:%d %s\n", find_thread(NULL), file,
265		line, buffer);
266	_kern_debugger(buffer);
267
268	return 0;
269}
270
271// TODO: Remove. Temporary debug helper.
272// (accidently these are more or less the same as _sPrintf())
273
274void
275debug_printf(const char *format, ...)
276{
277	va_list list;
278	va_start(list, format);
279
280	debug_vprintf(format, list);
281
282	va_end(list);
283}
284
285void
286debug_vprintf(const char *format, va_list args)
287{
288	char buffer[1024];
289	vsnprintf(buffer, sizeof(buffer), format, args);
290
291	_kern_debug_output(buffer);
292}
293
294
295void
296ktrace_printf(const char *format, ...)
297{
298	va_list list;
299	va_start(list, format);
300
301	ktrace_vprintf(format, list);
302
303	va_end(list);
304}
305
306
307void
308ktrace_vprintf(const char *format, va_list args)
309{
310	char buffer[1024];
311	vsnprintf(buffer, sizeof(buffer), format, args);
312
313	_kern_ktrace_output(buffer);
314}
315