xref: /haiku/src/system/libroot/os/debug.c (revision e688bf23d48bfd1216a0cacbdbda5e35a1bcd779)
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 
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 bool _rtDebugFlag = true;
58 
59 
60 void
61 debugger(const char *message)
62 {
63 	debug_printf("%" B_PRId32 ": DEBUGGER: %s\n", find_thread(NULL), message);
64 	_kern_debugger(message);
65 }
66 
67 
68 int
69 disable_debugger(int state)
70 {
71 	return _kern_disable_debugger(state);
72 }
73 
74 
75 status_t
76 install_default_debugger(port_id debuggerPort)
77 {
78 	return _kern_install_default_debugger(debuggerPort);
79 }
80 
81 
82 port_id
83 install_team_debugger(team_id team, port_id debuggerPort)
84 {
85 	return _kern_install_team_debugger(team, debuggerPort);
86 }
87 
88 
89 status_t
90 remove_team_debugger(team_id team)
91 {
92 	return _kern_remove_team_debugger(team);
93 }
94 
95 
96 status_t
97 debug_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 
112 void
113 wait_for_debugger(void)
114 {
115 	_kern_wait_for_debugger();
116 }
117 
118 
119 status_t
120 set_debugger_breakpoint(void *address)
121 {
122 	return _kern_set_debugger_breakpoint(address, 0, 0, false);
123 }
124 
125 
126 status_t
127 clear_debugger_breakpoint(void *address)
128 {
129 	return _kern_clear_debugger_breakpoint(address, false);
130 }
131 
132 
133 status_t
134 set_debugger_watchpoint(void *address, uint32 type, int32 length)
135 {
136 	return _kern_set_debugger_breakpoint(address, type, length, true);
137 }
138 
139 
140 status_t
141 clear_debugger_watchpoint(void *address)
142 {
143 	return _kern_clear_debugger_breakpoint(address, true);
144 }
145 
146 
147 static void
148 get_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 
167 void
168 get_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 
176 void
177 get_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 
188 bool
189 _debugFlag(void)
190 {
191 	return _rtDebugFlag;
192 }
193 
194 
195 bool
196 _setDebugFlag(bool flag)
197 {
198 	bool previous = _rtDebugFlag;
199 	_rtDebugFlag = flag;
200 	return previous;
201 }
202 
203 
204 int
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 
221 int
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 
242 int
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 
256 int
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 
274 void
275 debug_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 
285 void
286 debug_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 
295 void
296 ktrace_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 
307 void
308 ktrace_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