1/*
2 * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 *
5 * Userland debugger support.
6 */
7#ifndef _KERNEL_USER_DEBUGGER_H
8#define _KERNEL_USER_DEBUGGER_H
9
10
11#include <debugger.h>
12
13#include <arch/user_debugger.h>
14
15#include <timer.h>
16
17
18// limits
19#define B_DEBUG_MIN_PROFILE_INTERVAL			10			/* in us */
20#define B_DEBUG_STACK_TRACE_DEPTH				128
21#define	B_DEBUG_PROFILE_BUFFER_FLUSH_THRESHOLD	70			/* in % */
22
23
24struct BreakpointManager;
25struct ConditionVariable;
26struct function_profile_info;
27
28namespace BKernel {
29	struct Thread;
30}
31
32using BKernel::Thread;
33
34
35// Team related debugging data.
36//
37// Locking policy:
38// 1) When accessing the structure it must be made sure, that the structure,
39//    (i.e. the struct Team it lives in) isn't deleted. Thus one either needs to
40//    get a team reference, lock the team, or one accesses the structure from a
41//    thread of that team.
42// 2) Access to the `flags' field is atomic. Reading via atomic_get()
43//    requires no further locks (in addition to 1) that is). Writing requires
44//    `lock' to be held and must be done atomically, too
45//    (atomic_{set,and,or}()). Reading with `lock' being held doesn't need to
46//    be done atomically.
47// 3) Access to all other fields (read or write) requires `lock' to be held.
48// 4) Locking order is scheduler lock -> Team -> Thread -> team_debug_info::lock
49//    -> thread_debug_info::lock.
50//
51struct team_debug_info {
52	spinlock	lock;
53		// Guards the remaining fields. Should always be the innermost lock
54		// to be acquired/released, save for thread_debug_info::lock.
55
56	int32		flags;
57		// Set atomically. So reading atomically is OK, even when the lock is
58		// not held (at least if it is certain, that the team struct won't go).
59
60	team_id		debugger_team;
61	port_id		debugger_port;
62	thread_id	nub_thread;
63	port_id		nub_port;
64		// the port the nub thread is waiting on for commands from the debugger
65	sem_id		debugger_write_lock;
66		// synchronizes writes to the debugger port with the setting (but not
67		// clearing) of the B_TEAM_DEBUG_DEBUGGER_HANDOVER flag
68	thread_id	causing_thread;
69		// thread that caused the debugger to be attached; -1 for manual
70		// debugger attachment (or no debugger installed)
71	int32		image_event;
72		// counter incremented whenever an image is created/deleted
73
74	struct ConditionVariable* debugger_changed_condition;
75		// Set to a condition variable when going to change the debugger. Anyone
76		// who wants to change the debugger as well, needs to wait until the
77		// condition variable is unset again (waiting for the condition and
78		// rechecking again). The field and the condition variable is protected
79		// by 'lock'. After setting the a condition variable the team is
80		// guaranteed not to be deleted (until it is unset) it might be removed
81		// from the team hash table, though.
82
83	struct BreakpointManager* breakpoint_manager;
84		// manages hard- and software breakpoints
85
86	struct arch_team_debug_info	arch_info;
87};
88
89// Thread related debugging data.
90//
91// Locking policy:
92// 1) When accessing the structure it must be made sure, that the structure,
93//    (i.e. the struct Thread it lives in) isn't deleted. Thus one either needs
94//    to get a thread reference, lock the thread, or one accesses the structure
95//    of the current thread.
96// 2) Access to the `flags' field is atomic. Reading via atomic_get()
97//    requires no further locks (in addition to 1) that is). Writing requires
98//    `lock' to be held and must be done atomically, too
99//    (atomic_{set,and,or}()). Reading with `lock' being held doesn't need to
100//    be done atomically.
101// 3) Access to all other fields (read or write) requires `lock' to be held.
102// 4) Locking order is scheduler lock -> Team -> Thread -> team_debug_info::lock
103//    -> thread_debug_info::lock.
104//
105struct thread_debug_info {
106	spinlock	lock;
107		// Guards the remaining fields. Should always be the innermost lock
108		// to be acquired/released.
109
110	int32		flags;
111		// Set atomically. So reading atomically is OK, even when the lock is
112		// not held (at least if it is certain, that the thread struct won't
113		// go).
114	port_id		debug_port;
115		// the port the thread is waiting on for commands from the nub thread
116
117	sigset_t	ignore_signals;
118		// the signals the debugger is not interested in
119	sigset_t	ignore_signals_once;
120		// the signals the debugger wishes not to be notified of, when they
121		// occur the next time
122
123	// profiling related part; if samples != NULL, the thread is profiled
124	struct {
125		bigtime_t		interval;
126			// sampling interval
127		area_id			sample_area;
128			// cloned sample buffer area
129		addr_t*			samples;
130			// sample buffer
131		int32			max_samples;
132			// maximum number of samples the buffer can hold
133		int32			flush_threshold;
134			// number of sample when the buffer is flushed (if possible)
135		int32			sample_count;
136			// number of samples the buffer currently holds
137		int32			stack_depth;
138			// number of return addresses to record per timer interval
139		int32			dropped_ticks;
140			// number of ticks that had to be dropped when the sample buffer was
141			// full and couldn't be flushed
142		int32			image_event;
143			// number of the image event when the first sample was written into
144			// the buffer
145		int32			last_image_event;
146			// number of the image event when the last sample was written into
147			// the buffer
148		bool			variable_stack_depth;
149			// record a variable number of samples per hit
150		bool			buffer_full;
151			// indicates that the sample buffer is full
152		union {
153			bigtime_t	interval_left;
154				// when unscheduled: the time left of the current sampling
155				// interval
156			bigtime_t	timer_end;
157				// when running: the absolute time the timer is supposed to go
158				// off
159		};
160		timer*			installed_timer;
161			// when running and being profiled: the CPU's profiling timer
162	} profile;
163
164	struct arch_thread_debug_info	arch_info;
165};
166
167#define GRAB_TEAM_DEBUG_INFO_LOCK(info)		acquire_spinlock(&(info).lock)
168#define RELEASE_TEAM_DEBUG_INFO_LOCK(info)	release_spinlock(&(info).lock)
169
170// team debugging flags (user-specifiable flags are in <debugger.h>)
171enum {
172	B_TEAM_DEBUG_DEBUGGER_INSTALLED		= 0x0001,
173	B_TEAM_DEBUG_DEBUGGER_HANDOVER		= 0x0002,	// marked for hand-over
174	B_TEAM_DEBUG_DEBUGGER_HANDING_OVER	= 0x0004,	// handing over
175	B_TEAM_DEBUG_DEBUGGER_DISABLED		= 0x0008,
176
177	B_TEAM_DEBUG_KERNEL_FLAG_MASK		= 0xffff,
178
179	B_TEAM_DEBUG_DEFAULT_FLAGS			= 0,
180	B_TEAM_DEBUG_INHERITED_FLAGS		= B_TEAM_DEBUG_DEBUGGER_DISABLED
181};
182
183// thread debugging flags (user-specifiable flags are in <debugger.h>)
184enum {
185	B_THREAD_DEBUG_INITIALIZED			= 0x0001,
186	B_THREAD_DEBUG_DYING				= 0x0002,
187	B_THREAD_DEBUG_STOP					= 0x0004,
188	B_THREAD_DEBUG_STOPPED				= 0x0008,
189	B_THREAD_DEBUG_SINGLE_STEP			= 0x0010,
190	B_THREAD_DEBUG_NOTIFY_SINGLE_STEP	= 0x0020,
191
192	B_THREAD_DEBUG_NUB_THREAD			= 0x0040,	// marks the nub thread
193
194	B_THREAD_DEBUG_KERNEL_FLAG_MASK		= 0xffff,
195
196	B_THREAD_DEBUG_DEFAULT_FLAGS		= 0,
197};
198
199// messages sent from the debug nub thread to a debugged thread
200typedef enum {
201	B_DEBUGGED_THREAD_MESSAGE_CONTINUE	= 0,
202	B_DEBUGGED_THREAD_SET_CPU_STATE,
203	B_DEBUGGED_THREAD_GET_CPU_STATE,
204	B_DEBUGGED_THREAD_DEBUGGER_CHANGED,
205} debugged_thread_message;
206
207typedef struct {
208	uint32	handle_event;
209	bool	single_step;
210} debugged_thread_continue;
211
212typedef struct {
213	port_id	reply_port;
214} debugged_thread_get_cpu_state;
215
216typedef struct {
217	debug_cpu_state	cpu_state;
218} debugged_thread_set_cpu_state;
219
220typedef union {
221	debugged_thread_continue		continue_thread;
222	debugged_thread_set_cpu_state	set_cpu_state;
223	debugged_thread_get_cpu_state	get_cpu_state;
224} debugged_thread_message_data;
225
226
227// internal messages sent to the nub thread
228typedef enum {
229	B_DEBUG_MESSAGE_HANDED_OVER		= -1,
230} debug_nub_kernel_message;
231
232
233#ifdef __cplusplus
234extern "C" {
235#endif
236
237// service calls
238
239void clear_team_debug_info(struct team_debug_info *info, bool initLock);
240
241void init_thread_debug_info(struct thread_debug_info *info);
242void clear_thread_debug_info(struct thread_debug_info *info, bool dying);
243void destroy_thread_debug_info(struct thread_debug_info *info);
244
245void user_debug_prepare_for_exec();
246void user_debug_finish_after_exec();
247
248void init_user_debug();
249
250
251// debug event callbacks
252
253void user_debug_pre_syscall(uint32 syscall, void *args);
254void user_debug_post_syscall(uint32 syscall, void *args, uint64 returnValue,
255		bigtime_t startTime);
256bool user_debug_exception_occurred(debug_exception_type exception, int signal);
257bool user_debug_handle_signal(int signal, struct sigaction *handler,
258		siginfo_t *info, bool deadly);
259void user_debug_stop_thread();
260void user_debug_team_created(team_id teamID);
261void user_debug_team_deleted(team_id teamID, port_id debuggerPort);
262void user_debug_team_exec();
263void user_debug_update_new_thread_flags(Thread* thread);
264void user_debug_thread_created(thread_id threadID);
265void user_debug_thread_deleted(team_id teamID, thread_id threadID);
266void user_debug_thread_exiting(Thread* thread);
267void user_debug_image_created(const image_info *imageInfo);
268void user_debug_image_deleted(const image_info *imageInfo);
269void user_debug_breakpoint_hit(bool software);
270void user_debug_watchpoint_hit();
271void user_debug_single_stepped();
272
273void user_debug_thread_unscheduled(Thread* thread);
274void user_debug_thread_scheduled(Thread* thread);
275
276
277// syscalls
278
279void		_user_debugger(const char *message);
280int			_user_disable_debugger(int state);
281
282status_t	_user_install_default_debugger(port_id debuggerPort);
283port_id		_user_install_team_debugger(team_id team, port_id debuggerPort);
284status_t	_user_remove_team_debugger(team_id team);
285status_t	_user_debug_thread(thread_id thread);
286void		_user_wait_for_debugger(void);
287
288status_t	_user_set_debugger_breakpoint(void *address, uint32 type,
289				int32 length, bool watchpoint);
290status_t	_user_clear_debugger_breakpoint(void *address, bool watchpoint);
291
292ssize_t		_user_get_stack_trace(size_t addressCount, addr_t* returnAddresses);
293
294#ifdef __cplusplus
295}	// extern "C"
296#endif
297
298
299#endif	// _KERNEL_USER_DEBUGGER_H
300