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