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