1 /*
2 * Copyright 2009, Michael Lotz, mmlr@mlotz.ch
3 * Distributed under the terms of the MIT License.
4 */
5 #include <debug.h>
6 #include <signal.h>
7 #include <string.h>
8 #include <image.h>
9
10
11 static sem_id sRequestSem = -1;
12 static char sCommandBuffer[1024];
13 static uint32 sCommandOffset = 0;
14 static uint32 sCommandCount = 0;
15
16
17 static int32
run_on_exit_loop(void * data)18 run_on_exit_loop(void *data)
19 {
20 while (true) {
21 if (acquire_sem(sRequestSem) != B_OK)
22 break;
23
24 char *pointer = sCommandBuffer;
25 while (sCommandCount > 0) {
26 uint8 argCount = (uint8)pointer[0];
27 pointer++;
28
29 const char *args[argCount];
30 for (uint8 i = 0; i < argCount; i++) {
31 args[i] = pointer;
32 uint32 length = strlen(pointer);
33 pointer += length + 1;
34 }
35
36 thread_id thread = load_image(argCount, args, NULL);
37 if (thread >= B_OK)
38 resume_thread(thread);
39 sCommandCount--;
40 }
41
42 sCommandOffset = 0;
43 }
44
45 return 0;
46 }
47
48
49 static int
add_run_on_exit_command(int argc,char ** argv)50 add_run_on_exit_command(int argc, char **argv)
51 {
52 if (argc < 2 || strcmp(argv[1], "--help") == 0) {
53 print_debugger_command_usage(argv[0]);
54 return 0;
55 }
56
57 if (argc > 256) {
58 kprintf("too many arguments\n");
59 return 0;
60 }
61
62 size_t totalLength = 1;
63 for (int32 i = 1; i < argc; i++)
64 totalLength += strlen(argv[i]) + 1;
65
66 if (sCommandOffset + totalLength > sizeof(sCommandBuffer)) {
67 kprintf("no space left in command buffer\n");
68 return 0;
69 }
70
71 char *pointer = sCommandBuffer + sCommandOffset;
72 *pointer++ = (char)(argc - 1);
73
74 for (int32 i = 1; i < argc; i++) {
75 strcpy(pointer, argv[i]);
76 pointer += strlen(argv[i]) + 1;
77 }
78
79 sCommandOffset += totalLength;
80 sCommandCount++;
81 return 0;
82 }
83
84
85 static void
exit_debugger()86 exit_debugger()
87 {
88 if (sCommandCount > 0)
89 release_sem_etc(sRequestSem, 1, B_DO_NOT_RESCHEDULE);
90 }
91
92
93 static status_t
std_ops(int32 op,...)94 std_ops(int32 op, ...)
95 {
96 if (op == B_MODULE_INIT) {
97 sRequestSem = create_sem(0, "run_on_exit_request");
98 if (sRequestSem < B_OK)
99 return sRequestSem;
100
101 thread_id thread = spawn_kernel_thread(&run_on_exit_loop,
102 "run_on_exit_loop", B_NORMAL_PRIORITY, NULL);
103 if (thread < B_OK)
104 return thread;
105
106 resume_thread(thread);
107
108 add_debugger_command_etc("on_exit", &add_run_on_exit_command,
109 "Adds a command to be run when leaving the kernel debugger",
110 "<command> [<arguments>]\n"
111 "Adds a command to be run when leaving the kernel debugger.\n", 0);
112
113 return B_OK;
114 } else if (op == B_MODULE_UNINIT) {
115 remove_debugger_command("on_exit", &add_run_on_exit_command);
116 // deleting the sem will also cause the thread to exit
117 delete_sem(sRequestSem);
118 sRequestSem = -1;
119 return B_OK;
120 }
121
122 return B_BAD_VALUE;
123 }
124
125
126 static struct debugger_module_info sModuleInfo = {
127 {
128 "debugger/run_on_exit/v1",
129 B_KEEP_LOADED,
130 &std_ops
131 },
132
133 NULL,
134 exit_debugger,
135 NULL,
136 NULL
137 };
138
139 module_info *modules[] = {
140 (module_info *)&sModuleInfo,
141 NULL
142 };
143