xref: /haiku/src/add-ons/kernel/debugger/run_on_exit/run_on_exit.cpp (revision 24df65921befcd0ad0c5c7866118f922da61cb96)
13613bfc8SMichael Lotz /*
23613bfc8SMichael Lotz  * Copyright 2009, Michael Lotz, mmlr@mlotz.ch
33613bfc8SMichael Lotz  * Distributed under the terms of the MIT License.
43613bfc8SMichael Lotz  */
53613bfc8SMichael Lotz #include <debug.h>
63613bfc8SMichael Lotz #include <signal.h>
73613bfc8SMichael Lotz #include <string.h>
83613bfc8SMichael Lotz #include <image.h>
93613bfc8SMichael Lotz 
103613bfc8SMichael Lotz 
113613bfc8SMichael Lotz static sem_id sRequestSem = -1;
123613bfc8SMichael Lotz static char sCommandBuffer[1024];
133613bfc8SMichael Lotz static uint32 sCommandOffset = 0;
143613bfc8SMichael Lotz static uint32 sCommandCount = 0;
153613bfc8SMichael Lotz 
163613bfc8SMichael Lotz 
173613bfc8SMichael Lotz static int32
run_on_exit_loop(void * data)183613bfc8SMichael Lotz run_on_exit_loop(void *data)
193613bfc8SMichael Lotz {
203613bfc8SMichael Lotz 	while (true) {
213613bfc8SMichael Lotz 		if (acquire_sem(sRequestSem) != B_OK)
223613bfc8SMichael Lotz 			break;
233613bfc8SMichael Lotz 
243613bfc8SMichael Lotz 		char *pointer = sCommandBuffer;
253613bfc8SMichael Lotz 		while (sCommandCount > 0) {
263613bfc8SMichael Lotz 			uint8 argCount = (uint8)pointer[0];
273613bfc8SMichael Lotz 			pointer++;
283613bfc8SMichael Lotz 
293613bfc8SMichael Lotz 			const char *args[argCount];
303613bfc8SMichael Lotz 			for (uint8 i = 0; i < argCount; i++) {
313613bfc8SMichael Lotz 				args[i] = pointer;
323613bfc8SMichael Lotz 				uint32 length = strlen(pointer);
333613bfc8SMichael Lotz 				pointer += length + 1;
343613bfc8SMichael Lotz 			}
353613bfc8SMichael Lotz 
363613bfc8SMichael Lotz 			thread_id thread = load_image(argCount, args, NULL);
373613bfc8SMichael Lotz 			if (thread >= B_OK)
383613bfc8SMichael Lotz 				resume_thread(thread);
393613bfc8SMichael Lotz 			sCommandCount--;
403613bfc8SMichael Lotz 		}
413613bfc8SMichael Lotz 
423613bfc8SMichael Lotz 		sCommandOffset = 0;
433613bfc8SMichael Lotz 	}
443613bfc8SMichael Lotz 
453613bfc8SMichael Lotz 	return 0;
463613bfc8SMichael Lotz }
473613bfc8SMichael Lotz 
483613bfc8SMichael Lotz 
493613bfc8SMichael Lotz static int
add_run_on_exit_command(int argc,char ** argv)503613bfc8SMichael Lotz add_run_on_exit_command(int argc, char **argv)
513613bfc8SMichael Lotz {
523613bfc8SMichael Lotz 	if (argc < 2 || strcmp(argv[1], "--help") == 0) {
533613bfc8SMichael Lotz 		print_debugger_command_usage(argv[0]);
543613bfc8SMichael Lotz 		return 0;
553613bfc8SMichael Lotz 	}
563613bfc8SMichael Lotz 
573613bfc8SMichael Lotz 	if (argc > 256) {
583613bfc8SMichael Lotz 		kprintf("too many arguments\n");
593613bfc8SMichael Lotz 		return 0;
603613bfc8SMichael Lotz 	}
613613bfc8SMichael Lotz 
623613bfc8SMichael Lotz 	size_t totalLength = 1;
633613bfc8SMichael Lotz 	for (int32 i = 1; i < argc; i++)
643613bfc8SMichael Lotz 		totalLength += strlen(argv[i]) + 1;
653613bfc8SMichael Lotz 
663613bfc8SMichael Lotz 	if (sCommandOffset + totalLength > sizeof(sCommandBuffer)) {
673613bfc8SMichael Lotz 		kprintf("no space left in command buffer\n");
683613bfc8SMichael Lotz 		return 0;
693613bfc8SMichael Lotz 	}
703613bfc8SMichael Lotz 
713613bfc8SMichael Lotz 	char *pointer = sCommandBuffer + sCommandOffset;
723613bfc8SMichael Lotz 	*pointer++ = (char)(argc - 1);
733613bfc8SMichael Lotz 
743613bfc8SMichael Lotz 	for (int32 i = 1; i < argc; i++) {
753613bfc8SMichael Lotz 		strcpy(pointer, argv[i]);
763613bfc8SMichael Lotz 		pointer += strlen(argv[i]) + 1;
773613bfc8SMichael Lotz 	}
783613bfc8SMichael Lotz 
793613bfc8SMichael Lotz 	sCommandOffset += totalLength;
803613bfc8SMichael Lotz 	sCommandCount++;
813613bfc8SMichael Lotz 	return 0;
823613bfc8SMichael Lotz }
833613bfc8SMichael Lotz 
843613bfc8SMichael Lotz 
853613bfc8SMichael Lotz static void
exit_debugger()863613bfc8SMichael Lotz exit_debugger()
873613bfc8SMichael Lotz {
883613bfc8SMichael Lotz 	if (sCommandCount > 0)
893613bfc8SMichael Lotz 		release_sem_etc(sRequestSem, 1, B_DO_NOT_RESCHEDULE);
903613bfc8SMichael Lotz }
913613bfc8SMichael Lotz 
923613bfc8SMichael Lotz 
933613bfc8SMichael Lotz static status_t
std_ops(int32 op,...)943613bfc8SMichael Lotz std_ops(int32 op, ...)
953613bfc8SMichael Lotz {
963613bfc8SMichael Lotz 	if (op == B_MODULE_INIT) {
973613bfc8SMichael Lotz 		sRequestSem = create_sem(0, "run_on_exit_request");
983613bfc8SMichael Lotz 		if (sRequestSem < B_OK)
993613bfc8SMichael Lotz 			return sRequestSem;
1003613bfc8SMichael Lotz 
1013613bfc8SMichael Lotz 		thread_id thread = spawn_kernel_thread(&run_on_exit_loop,
1023613bfc8SMichael Lotz 			"run_on_exit_loop", B_NORMAL_PRIORITY, NULL);
1033613bfc8SMichael Lotz 		if (thread < B_OK)
1043613bfc8SMichael Lotz 			return thread;
1053613bfc8SMichael Lotz 
106*24df6592SIngo Weinhold 		resume_thread(thread);
1073613bfc8SMichael Lotz 
1083613bfc8SMichael Lotz 		add_debugger_command_etc("on_exit", &add_run_on_exit_command,
1093613bfc8SMichael Lotz 			"Adds a command to be run when leaving the kernel debugger",
1103613bfc8SMichael Lotz 			"<command> [<arguments>]\n"
1113613bfc8SMichael Lotz 			"Adds a command to be run when leaving the kernel debugger.\n", 0);
1123613bfc8SMichael Lotz 
1133613bfc8SMichael Lotz 		return B_OK;
1143613bfc8SMichael Lotz 	} else if (op == B_MODULE_UNINIT) {
1153613bfc8SMichael Lotz 		remove_debugger_command("on_exit", &add_run_on_exit_command);
1163613bfc8SMichael Lotz 		// deleting the sem will also cause the thread to exit
1173613bfc8SMichael Lotz 		delete_sem(sRequestSem);
1183613bfc8SMichael Lotz 		sRequestSem = -1;
1193613bfc8SMichael Lotz 		return B_OK;
1203613bfc8SMichael Lotz 	}
1213613bfc8SMichael Lotz 
1223613bfc8SMichael Lotz 	return B_BAD_VALUE;
1233613bfc8SMichael Lotz }
1243613bfc8SMichael Lotz 
1253613bfc8SMichael Lotz 
1263613bfc8SMichael Lotz static struct debugger_module_info sModuleInfo = {
1273613bfc8SMichael Lotz 	{
1283613bfc8SMichael Lotz 		"debugger/run_on_exit/v1",
1293613bfc8SMichael Lotz 		B_KEEP_LOADED,
1303613bfc8SMichael Lotz 		&std_ops
1313613bfc8SMichael Lotz 	},
1323613bfc8SMichael Lotz 
1333613bfc8SMichael Lotz 	NULL,
1343613bfc8SMichael Lotz 	exit_debugger,
1353613bfc8SMichael Lotz 	NULL,
1363613bfc8SMichael Lotz 	NULL
1373613bfc8SMichael Lotz };
1383613bfc8SMichael Lotz 
1393613bfc8SMichael Lotz module_info *modules[] = {
1403613bfc8SMichael Lotz 	(module_info *)&sModuleInfo,
1413613bfc8SMichael Lotz 	NULL
1423613bfc8SMichael Lotz };
143