xref: /haiku/src/system/libroot/os/debug.c (revision a54c125e3744602e914808f2c95c360b2e8c9c54)
1 /*
2  * Copyright 2002-2006, 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 
17 typedef struct debug_string_entry {
18 	const char	*string;
19 	uint32		code;
20 } debug_string_entry;
21 
22 static 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 
41 static 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 
57 
58 void
59 debugger(const char *message)
60 {
61 	debug_printf("%ld: DEBUGGER: %s\n", find_thread(NULL), message);
62 	_kern_debugger(message);
63 }
64 
65 
66 int
67 disable_debugger(int state)
68 {
69 	return _kern_disable_debugger(state);
70 }
71 
72 
73 status_t
74 install_default_debugger(port_id debuggerPort)
75 {
76 	return _kern_install_default_debugger(debuggerPort);
77 }
78 
79 
80 port_id
81 install_team_debugger(team_id team, port_id debuggerPort)
82 {
83 	return _kern_install_team_debugger(team, debuggerPort);
84 }
85 
86 
87 status_t
88 remove_team_debugger(team_id team)
89 {
90 	return _kern_remove_team_debugger(team);
91 }
92 
93 
94 status_t
95 debug_thread(thread_id thread)
96 {
97 	return _kern_debug_thread(thread);
98 }
99 
100 
101 /**	\brief Suspends the thread until a debugger has been installed for this
102  *		   team.
103  *
104  *	As soon as this happens (immediately, if a debugger is already installed)
105  *	the thread stops for debugging. This is desirable for debuggers that spawn
106  *	their debugged teams via fork() and want the child to wait till they have
107  *	installed themselves as team debugger before continuing with exec*().
108  */
109 
110 void
111 wait_for_debugger(void)
112 {
113 	_kern_wait_for_debugger();
114 }
115 
116 
117 status_t
118 set_debugger_breakpoint(void *address)
119 {
120 	return _kern_set_debugger_breakpoint(address, 0, 0, false);
121 }
122 
123 
124 status_t
125 clear_debugger_breakpoint(void *address)
126 {
127 	return _kern_clear_debugger_breakpoint(address, false);
128 }
129 
130 
131 status_t
132 set_debugger_watchpoint(void *address, uint32 type, int32 length)
133 {
134 	return _kern_set_debugger_breakpoint(address, type, length, true);
135 }
136 
137 
138 status_t
139 clear_debugger_watchpoint(void *address)
140 {
141 	return _kern_clear_debugger_breakpoint(address, true);
142 }
143 
144 
145 static void
146 get_debug_string(const debug_string_entry *stringEntries,
147 	const char *defaultString, uint32 code, char *buffer, int32 bufferSize)
148 {
149 	int i;
150 
151 	if (!buffer || bufferSize <= 0)
152 		return;
153 
154 	for (i = 0; stringEntries[i].string; i++) {
155 		if (stringEntries[i].code == code) {
156 			strlcpy(buffer, stringEntries[i].string, bufferSize);
157 			return;
158 		}
159 	}
160 
161 	snprintf(buffer, bufferSize, defaultString, code);
162 }
163 
164 
165 void
166 get_debug_message_string(debug_debugger_message message, char *buffer,
167 	int32 bufferSize)
168 {
169 	get_debug_string(sDebugMessageStrings, "Unknown message %lu",
170 		(uint32)message, buffer, bufferSize);
171 }
172 
173 
174 void
175 get_debug_exception_string(debug_exception_type exception, char *buffer,
176 	int32 bufferSize)
177 {
178 	get_debug_string(sDebugExceptionTypeStrings, "Unknown exception %lu",
179 		(uint32)exception, buffer, bufferSize);
180 }
181 
182 
183 //	#pragma mark -
184 //	Debug.h functions
185 
186 // TODO: verify these functions
187 // TODO: add implementations for printfs?
188 
189 
190 bool _rtDebugFlag = false;
191 
192 bool
193 _debugFlag(void)
194 {
195 	return _rtDebugFlag;
196 }
197 
198 
199 bool
200 _setDebugFlag(bool flag)
201 {
202 	bool previous = _rtDebugFlag;
203 	_rtDebugFlag = flag;
204 	return previous;
205 }
206 
207 
208 int
209 _debugPrintf(const char *fmt, ...)
210 {
211 	va_list ap;
212 	int ret;
213 
214 	va_start(ap, fmt);
215 	ret = vfprintf(stdout, fmt, ap);
216 	va_end(ap);
217 
218 	return ret;
219 }
220 
221 
222 int
223 _sPrintf(const char *fmt, ...)
224 {
225 	char buffer[1024];
226 	va_list ap;
227 	int ret;
228 
229 	va_start(ap, fmt);
230 	ret = vsnprintf(buffer, sizeof(buffer), fmt, ap);
231 	va_end(ap);
232 
233 	if (ret >= 0)
234 		_kern_debug_output(buffer);
235 
236 	return ret;
237 }
238 
239 
240 int
241 _xdebugPrintf(const char * fmt, ...)
242 {
243 	va_list ap;
244 	int ret;
245 
246 	va_start(ap, fmt);
247 	ret = vfprintf(stdout, fmt, ap);
248 	va_end(ap);
249 
250 	return ret;
251 }
252 
253 
254 int
255 _debuggerAssert(const char * file, int line, char *message)
256 {
257 	char buffer[1024];
258 	snprintf(buffer, sizeof(buffer),
259 		"Assert failed: File: %s, Line: %d, %s",
260 		file, line, message);
261 
262 	debug_printf("%ld: ASSERT: %s\n", find_thread(NULL), buffer);
263 	_kern_debugger(buffer);
264 
265 	return 0;
266 }
267 
268 // TODO: Remove. Temporary debug helper.
269 // (accidently these are more or less the same as _sPrintf())
270 
271 void
272 debug_printf(const char *format, ...)
273 {
274 	va_list list;
275 	va_start(list, format);
276 
277 	debug_vprintf(format, list);
278 
279 	va_end(list);
280 }
281 
282 void
283 debug_vprintf(const char *format, va_list args)
284 {
285 	char buffer[1024];
286 	vsnprintf(buffer, sizeof(buffer), format, args);
287 
288 	_kern_debug_output(buffer);
289 }
290 
291 
292 void
293 ktrace_printf(const char *format, ...)
294 {
295 	va_list list;
296 	va_start(list, format);
297 
298 	ktrace_vprintf(format, list);
299 
300 	va_end(list);
301 }
302 
303 
304 void
305 ktrace_vprintf(const char *format, va_list args)
306 {
307 	char buffer[1024];
308 	vsnprintf(buffer, sizeof(buffer), format, args);
309 
310 	_kern_ktrace_output(buffer);
311 }
312