[haiku-development] [PATCH 1/4] Allow non-interactive execution of KDL commands

* Add kernel_debugger_exec() which allows to execute a single command
* The optional parameter "halt" specifies if all other CPU's should be halted
  while executing the KDL command
* Route the output of the non-interactive command to syslog too commands to the
  syslog
---
 headers/os/drivers/KernelExport.h             |    1 +
 src/system/kernel/debug/debug.cpp             |  128 +++++++++++++++++++------
 src/system/kernel/debug/debug_commands.cpp    |    2 +-
 src/system/kernel/debug/debug_output_filter.h |    7 +-
 4 files changed, 106 insertions(+), 32 deletions(-)

diff --git a/headers/os/drivers/KernelExport.h 
b/headers/os/drivers/KernelExport.h
index 3a88928..34b92e9 100644
--- a/headers/os/drivers/KernelExport.h
+++ b/headers/os/drivers/KernelExport.h
@@ -164,6 +164,7 @@ extern bool                 set_dprintf_enabled(bool 
new_state);
 extern void                    panic(const char *format, ...) _PRINTFLIKE(1, 
2);
 
 extern void                    kernel_debugger(const char *message);
+extern void                    kernel_debugger_exec(const char *command, bool 
halt);
 extern uint64          parse_expression(const char *string);
 
 extern int                     add_debugger_command(char *name, 
debugger_command_hook hook, char *help);
diff --git a/src/system/kernel/debug/debug.cpp 
b/src/system/kernel/debug/debug.cpp
index 08ee466..1ec2ff5 100644
--- a/src/system/kernel/debug/debug.cpp
+++ b/src/system/kernel/debug/debug.cpp
@@ -70,7 +70,10 @@ static const char* sCurrentKernelDebuggerMessage;
 static char sOutputBuffer[OUTPUT_BUFFER_SIZE];
 static char sLastOutputBuffer[OUTPUT_BUFFER_SIZE];
 static DebugOutputFilter* sDebugOutputFilter = NULL;
+DebugOutputFilter *gCurrentDebugOutputFilter = NULL;
 DefaultDebugOutputFilter gDefaultDebugOutputFilter;
+ExecDebugOutputFilter gExecDebugOutputFilter;
+static vint32 sInDebugger = 0;
 
 static void flush_pending_repeats(void);
 static void check_pending_repeats(void *data, int iter);
@@ -92,6 +95,7 @@ static int32 sCurrentLine = 0;
 
 #define distance(a, b) ((a) < (b) ? (b) - (a) : (a) - (b))
 
+static void syslog_write(const char *text, int32 length);
 
 // #pragma mark - DebugOutputFilter
 
@@ -142,6 +146,18 @@ DefaultDebugOutputFilter::Print(const char* format, 
va_list args)
 }
 
 
+void
+ExecDebugOutputFilter::PrintString(const char* string)
+{
+       if (sSerialDebugEnabled)
+               arch_debug_serial_puts(string);
+       if (sBlueScreenEnabled || sDebugScreenEnabled)
+               blue_screen_puts(string);
+       if (sSyslogOutputEnabled)
+               syslog_write(string, strlen(string));
+}
+
+
 // #pragma mark -
 
 
@@ -178,7 +194,8 @@ kputs(const char *s)
 void
 kputs_unfiltered(const char *s)
 {
-       gDefaultDebugOutputFilter.PrintString(s);
+       if (gCurrentDebugOutputFilter)
+               gCurrentDebugOutputFilter->PrintString(s);
 }
 
 
@@ -907,6 +924,47 @@ call_modules_hook(bool enter)
 }
 
 
+static cpu_status
+debugger_halt_cpus(bool halt)
+{
+       cpu_status state;
+
+       state = disable_interrupts();
+       while (atomic_add(&sInDebugger, 1) > 0) {
+               // The debugger is already running, find out where...
+               if (sDebuggerOnCPU != smp_get_current_cpu()) {
+                       // Some other CPU must have entered the debugger and 
tried to halt
+                       // us. Process ICIs to ensure we get the halt request. 
Then we are
+                       // blocking there until everyone leaves the debugger 
and we can
+                       // try to enter it again.
+                       atomic_add(&sInDebugger, -1);
+                       smp_intercpu_int_handler();
+               } else {
+                       // We are re-entering the debugger on the same CPU.
+                       break;
+               }
+       }
+
+       if (sDebuggerOnCPU != smp_get_current_cpu() && smp_get_num_cpus() > 1 
&& halt) {
+               // First entry on a MP system, send a halt request to all of 
the other
+               // CPUs. Should they try to enter the debugger they will be 
cought in
+               // the loop above.
+               smp_send_broadcast_ici(SMP_MSG_CPU_HALT, 0, 0, 0,
+                       (void *)&sInDebugger, SMP_MSG_FLAG_SYNC);
+       }
+
+       return state;
+}
+
+
+static void
+debugger_resume_cpus(cpu_status state)
+{
+       atomic_add(&sInDebugger, -1);
+       restore_interrupts(state);
+}
+
+
 //     #pragma mark - private kernel API
 
 
@@ -980,6 +1038,7 @@ status_t
 debug_init(kernel_args *args)
 {
        new(&gDefaultDebugOutputFilter) DefaultDebugOutputFilter;
+       new(&gExecDebugOutputFilter) ExecDebugOutputFilter;
 
        debug_paranoia_init();
        return arch_debug_console_init(args);
@@ -1095,43 +1154,21 @@ panic(const char *format, ...)
 void
 kernel_debugger(const char *message)
 {
-       static vint32 inDebugger = 0;
        cpu_status state;
        bool dprintfState;
 
-       state = disable_interrupts();
-       while (atomic_add(&inDebugger, 1) > 0) {
-               // The debugger is already running, find out where...
-               if (sDebuggerOnCPU != smp_get_current_cpu()) {
-                       // Some other CPU must have entered the debugger and 
tried to halt
-                       // us. Process ICIs to ensure we get the halt request. 
Then we are
-                       // blocking there until everyone leaves the debugger 
and we can
-                       // try to enter it again.
-                       atomic_add(&inDebugger, -1);
-                       smp_intercpu_int_handler();
-               } else {
-                       // We are re-entering the debugger on the same CPU.
-                       break;
-               }
-       }
+       state = debugger_halt_cpus(true);
 
        arch_debug_save_registers(&dbg_register_file[smp_get_current_cpu()][0]);
        dprintfState = set_dprintf_enabled(true);
 
-       if (sDebuggerOnCPU != smp_get_current_cpu() && smp_get_num_cpus() > 1) {
-               // First entry on a MP system, send a halt request to all of 
the other
-               // CPUs. Should they try to enter the debugger they will be 
cought in
-               // the loop above.
-               smp_send_broadcast_ici(SMP_MSG_CPU_HALT, 0, 0, 0,
-                       (void *)&inDebugger, SMP_MSG_FLAG_SYNC);
-       }
-
        if (sBlueScreenOutput) {
                if (blue_screen_enter(false) == B_OK)
                        sBlueScreenEnabled = true;
        }
 
        sDebugOutputFilter = &gDefaultDebugOutputFilter;
+       gCurrentDebugOutputFilter = sDebugOutputFilter;
 
        if (message)
                kprintf("PANIC: %s\n", message);
@@ -1149,15 +1186,43 @@ kernel_debugger(const char *message)
        set_dprintf_enabled(dprintfState);
 
        sDebugOutputFilter = NULL;
+       gCurrentDebugOutputFilter = NULL;
 
        sBlueScreenEnabled = false;
-       atomic_add(&inDebugger, -1);
-       restore_interrupts(state);
+
+       debugger_resume_cpus(state);
 
        // ToDo: in case we change dbg_register_file - don't we want to restore 
it?
 }
 
 
+void
+kernel_debugger_exec(const char *command, bool halt)
+{
+       cpu_status state;
+       bool dprintfState;
+
+       state = debugger_halt_cpus(halt);
+
+       dprintfState = set_dprintf_enabled(true);
+       arch_debug_save_registers(&dbg_register_file[smp_get_current_cpu()][0]);
+       sDebugOutputFilter = &gExecDebugOutputFilter;
+       gCurrentDebugOutputFilter = sDebugOutputFilter;
+       sCurrentKernelDebuggerMessage = NULL;
+
+       // sort the commands
+       sort_debugger_commands();
+
+       evaluate_debug_command(command);
+
+       set_dprintf_enabled(dprintfState);
+       sDebugOutputFilter = NULL;
+       gCurrentDebugOutputFilter = NULL;
+
+       debugger_resume_cpus(state);
+}
+
+
 bool
 set_dprintf_enabled(bool newState)
 {
@@ -1321,9 +1386,12 @@ void
 kprintf_unfiltered(const char *format, ...)
 {
        va_list args;
-       va_start(args, format);
-       gDefaultDebugOutputFilter.Print(format, args);
-       va_end(args);
+
+       if (gCurrentDebugOutputFilter) {
+               va_start(args, format);
+               gCurrentDebugOutputFilter->Print(format, args);
+               va_end(args);
+       }
 }
 
 
diff --git a/src/system/kernel/debug/debug_commands.cpp 
b/src/system/kernel/debug/debug_commands.cpp
index ea42af7..111a5a5 100644
--- a/src/system/kernel/debug/debug_commands.cpp
+++ b/src/system/kernel/debug/debug_commands.cpp
@@ -155,7 +155,7 @@ invoke_pipe_segment(debugger_command_pipe* pipe, int32 
index, char* argument)
        // set debug output
        DebugOutputFilter* oldFilter = set_debug_output_filter(
                index == pipe->segment_count - 1
-                       ? &gDefaultDebugOutputFilter
+                       ? gCurrentDebugOutputFilter
                        : (DebugOutputFilter*)&sPipeOutputFilters[index]);
 
        // set last command argument
diff --git a/src/system/kernel/debug/debug_output_filter.h 
b/src/system/kernel/debug/debug_output_filter.h
index 7a7ede2..e0dbc39 100644
--- a/src/system/kernel/debug/debug_output_filter.h
+++ b/src/system/kernel/debug/debug_output_filter.h
@@ -25,8 +25,13 @@ public:
        virtual void Print(const char* format, va_list args);
 };
 
+class ExecDebugOutputFilter : public DefaultDebugOutputFilter {
+public:
+       virtual void PrintString(const char* string);
+};
+
 
-extern DefaultDebugOutputFilter gDefaultDebugOutputFilter;
+extern DebugOutputFilter *gCurrentDebugOutputFilter;
 
 
 DebugOutputFilter* set_debug_output_filter(DebugOutputFilter* filter);
-- 
1.5.4.2


Other related posts: