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 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 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 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 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 send_signal_etc(thread, SIGCONT, B_DO_NOT_RESCHEDULE); 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