Author: bonefish Date: 2010-03-18 01:47:43 +0100 (Thu, 18 Mar 2010) New Revision: 35896 Changeset: http://dev.haiku-os.org/changeset/35896/haiku Modified: haiku/trunk/src/system/kernel/debug/debug.cpp Log: * sCurrentKernelDebuggerMessageArgs is no longer used directly. Whenever it is passed to some v*printf(), we clone it first. This way we can use it repeatedly. It worked only on certain architectures correctly before. * Changed the panic() semantics a bit: When the format contains the (hopefully unusual enough) string "@!" only the part before it is considered to belong to the panic message. The part after it is interpreted as a command line to be executed directly after entering KDL. This way it is possible to provide helpful command invocations only developers somewhat familiar with the subsystem might come up with. E.g.: panic("dec_vnode_ref_count: called on busy vnode %p" "@! vnode -p %p; mount _mount", vnode, vnode); Modified: haiku/trunk/src/system/kernel/debug/debug.cpp =================================================================== --- haiku/trunk/src/system/kernel/debug/debug.cpp 2010-03-17 22:56:07 UTC (rev 35895) +++ haiku/trunk/src/system/kernel/debug/debug.cpp 2010-03-18 00:47:43 UTC (rev 35896) @@ -51,6 +51,11 @@ #include "debug_variables.h" +#if __GNUC__ == 2 +# define va_copy(to, from) __va_copy(to, from) +#endif + + struct debug_memcpy_parameters { void* to; const void* from; @@ -66,6 +71,8 @@ static const char* const kKDLPrompt = "kdebug> "; +static const char* const kKDLMessageCommandSeparator = "@!"; + // separates panic() message from command list to execute extern "C" int kgets(char* buffer, int length); @@ -696,14 +703,6 @@ } -static inline void -kprintf_args(const char* format, va_list args) -{ - if (sDebugOutputFilter != NULL) - sDebugOutputFilter->Print(format, args); -} - - static void print_kernel_debugger_message() { @@ -711,9 +710,36 @@ || sCurrentKernelDebuggerMessage != NULL) { if (sCurrentKernelDebuggerMessagePrefix != NULL) kprintf("%s", sCurrentKernelDebuggerMessagePrefix); - if (sCurrentKernelDebuggerMessage != NULL) { - kprintf_args(sCurrentKernelDebuggerMessage, - sCurrentKernelDebuggerMessageArgs); + if (sCurrentKernelDebuggerMessage != NULL + && sDebugOutputFilter != NULL) { + va_list args; + va_copy(args, sCurrentKernelDebuggerMessageArgs); + + if (const char* commandDelimiter = strstr( + sCurrentKernelDebuggerMessage, + kKDLMessageCommandSeparator)) { + // The message string contains a list of commands to be + // executed when entering the kernel debugger. We don't + // want to print those, so we copy the interesting part of + // the format string. + if (commandDelimiter != sCurrentKernelDebuggerMessage) { + size_t length = commandDelimiter + - sCurrentKernelDebuggerMessage; + if (char* format = (char*)debug_malloc(length + 1)) { + memcpy(format, sCurrentKernelDebuggerMessage, length); + format[length] = '\0'; + sDebugOutputFilter->Print(format, args); + debug_free(format); + } else { + // allocation failed -- just print everything + sDebugOutputFilter->Print(sCurrentKernelDebuggerMessage, + args); + } + } + } else + sDebugOutputFilter->Print(sCurrentKernelDebuggerMessage, args); + + va_end(args); } kprintf("\n"); @@ -732,11 +758,8 @@ sCurrentKernelDebuggerMessagePrefix = messagePrefix; sCurrentKernelDebuggerMessage = message; -#if __GNUC__ == 2 - __va_copy(sCurrentKernelDebuggerMessageArgs, args); -#else - va_copy(sCurrentKernelDebuggerMessageArgs, args); -#endif + if (sCurrentKernelDebuggerMessage != NULL) + va_copy(sCurrentKernelDebuggerMessageArgs, args); print_kernel_debugger_message(); @@ -779,8 +802,37 @@ } } - if (!has_debugger_command("help")) + if (has_debugger_command("help")) { + // commands are registered already + if (sCurrentKernelDebuggerMessage != NULL + && strstr(sCurrentKernelDebuggerMessage, + kKDLMessageCommandSeparator) != NULL) { + // The panic() message specifies commands to execute. + const size_t kCommandBufferSize = 512; + char* commandBuffer = (char*)debug_malloc(kCommandBufferSize); + if (commandBuffer != NULL) { + va_list tempArgs; + va_copy(tempArgs, sCurrentKernelDebuggerMessageArgs); + if (vsnprintf(commandBuffer, kCommandBufferSize, + sCurrentKernelDebuggerMessage, tempArgs) + < (int)kCommandBufferSize) { + const char* commands = strstr(commandBuffer, + kKDLMessageCommandSeparator); + if (commands != NULL) { + commands += strlen(kKDLMessageCommandSeparator); + kprintf("initial commands: %s\n", commands); + evaluate_debug_command(commands); + } + } + va_end(tempArgs); + + debug_free(commandBuffer); + } + } + } else { + // no commands yet -- always print a stack trace at least arch_debug_stack_trace(); + } int32 continuableLine = -1; // Index of the previous command line, if the command returned @@ -831,7 +883,8 @@ } } - va_end(sCurrentKernelDebuggerMessageArgs); + if (sCurrentKernelDebuggerMessage != NULL) + va_end(sCurrentKernelDebuggerMessageArgs); delete_debug_alloc_pool(allocPool); @@ -1851,7 +1904,7 @@ if (sDebugOutputFilter != NULL) { va_list args; va_start(args, format); - kprintf_args(format, args); + sDebugOutputFilter->Print(format, args); va_end(args); } }