Save previous session's debug syslog during boot

Add boot loader debug menu option "Save syslog from previous session
during boot". If enabled (defaults to true), the previous session's
debug syslog data is copy to a separate buffer and passed to the
kernel, which writes it back to the file /var/log/previous_syslog.
As long as Haiku still boots, this should now be the most convenient way
to retrieve the output from a kernel crash.
This commit is contained in:
Ingo Weinhold
2014-01-19 10:46:00 +01:00
parent be5e6fefdf
commit 8540ec2446
5 changed files with 102 additions and 12 deletions
+13
View File
@@ -82,8 +82,21 @@ typedef struct kernel_args {
FixedWidthPointer<void> edid_info;
FixedWidthPointer<void> debug_output;
// If keep_debug_output_buffer, points to a ring_buffer, else to a
// simple flat buffer. In either case it stores the debug output from
// the boot loader.
FixedWidthPointer<void> previous_debug_output;
// A flat pointer to a buffer containing the debug output from the
// previous session. May be NULL.
uint32 debug_size;
// If keep_debug_output_buffer, the size of the ring buffer, otherwise
// the size of the flat buffer debug_output points to.
uint32 previous_debug_size;
// The size of the buffer previous_debug_output points to. Used as a
// boolean indicator whether to save the previous session's debug output
// until initialized for the kernel.
bool keep_debug_output_buffer;
// If true, debug_output is a ring buffer, otherwise a flat buffer.
platform_kernel_args platform_args;
arch_kernel_args arch_args;
+2
View File
@@ -39,6 +39,8 @@ main(stage2_args *args)
// set debug syslog default
#if KDEBUG_ENABLE_DEBUG_SYSLOG
gKernelArgs.keep_debug_output_buffer = true;
gKernelArgs.previous_debug_size = true;
// used as a boolean indicator until initialized for the kernel
#endif
add_stage2_driver_settings(args);
+23 -3
View File
@@ -1026,6 +1026,14 @@ debug_menu_toggle_debug_syslog(Menu* menu, MenuItem* item)
}
static bool
debug_menu_toggle_previous_debug_syslog(Menu* menu, MenuItem* item)
{
gKernelArgs.previous_debug_size = item->IsMarked();
return true;
}
static bool
debug_menu_save_previous_syslog(Menu* menu, MenuItem* item)
{
@@ -1280,6 +1288,20 @@ add_debug_menu()
item->SetHelpText("Enables a special in-memory syslog buffer for this "
"session that the boot loader will be able to access after rebooting.");
ring_buffer* syslogBuffer
= (ring_buffer*)gKernelArgs.debug_output.Pointer();
bool hasPreviousSyslog
= syslogBuffer != NULL && ring_buffer_readable(syslogBuffer) > 0;
if (hasPreviousSyslog) {
menu->AddItem(item = new(nothrow) MenuItem(
"Save syslog from previous session during boot"));
item->SetType(MENU_ITEM_MARKABLE);
item->SetMarked(gKernelArgs.previous_debug_size);
item->SetTarget(&debug_menu_toggle_previous_debug_syslog);
item->SetHelpText("Saves the syslog from the previous Haiku session to "
"/var/log/previous_syslog when booting.");
}
bool currentLogItemVisible = platform_debug_get_log_buffer(NULL) != NULL;
if (currentLogItemVisible) {
menu->AddSeparatorItem();
@@ -1291,9 +1313,7 @@ add_debug_menu()
"Displays the debug info the boot loader has logged.");
}
ring_buffer* syslogBuffer
= (ring_buffer*)gKernelArgs.debug_output.Pointer();
if (syslogBuffer != NULL && ring_buffer_readable(syslogBuffer) > 0) {
if (hasPreviousSyslog) {
if (!currentLogItemVisible)
menu->AddSeparatorItem();
@@ -172,6 +172,23 @@ void
debug_cleanup(void)
{
if (sDebugSyslogBuffer != NULL) {
// If desired, store the debug syslog data from the previous session for
// the kernel.
size_t bytesReadable = 0;
if (gKernelArgs.previous_debug_size != 0) {
bytesReadable = ring_buffer_readable(sDebugSyslogBuffer);
gKernelArgs.previous_debug_size = bytesReadable;
}
if (bytesReadable != 0) {
if (uint8* buffer = (uint8*)kernel_args_malloc(bytesReadable)) {
ring_buffer_read(sDebugSyslogBuffer, buffer, bytesReadable);
gKernelArgs.previous_debug_output = buffer;
} else
gKernelArgs.previous_debug_size = 0;
}
// Prepare the debug syslog buffer for this session.
size_t signatureLength = strlen(kDebugSyslogSignature);
void* buffer
= (void*)ROUNDDOWN((addr_t)sDebugSyslogBuffer, B_PAGE_SIZE);
+47 -9
View File
@@ -13,8 +13,17 @@
#include "blue_screen.h"
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <algorithm>
#include <AutoDeleter.h>
#include <boot/kernel_args.h>
#include <cpu.h>
#include <debug.h>
@@ -39,13 +48,6 @@
#include <syslog_daemon.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "debug_builtin_commands.h"
#include "debug_commands.h"
#include "debug_output_filter.h"
@@ -106,6 +108,9 @@ static size_t sSyslogDebuggerOffset = 0;
// (relative) buffer offset of the kernel debugger messages of the current
// KDL session
static void* sPreviousSessionSyslogBuffer = NULL;
static size_t sPreviousSessionSyslogBufferSize = 0;
static const char* sCurrentKernelDebuggerMessagePrefix;
static const char* sCurrentKernelDebuggerMessage;
static va_list sCurrentKernelDebuggerMessageArgs;
@@ -1406,6 +1411,17 @@ syslog_init_post_vm(struct kernel_args* args)
args->debug_size, false);
}
// Allocate memory for the previous session's debug syslog output. In
// syslog_init_post_modules() we'll write it back to disk and free it.
if (args->previous_debug_output != NULL) {
sPreviousSessionSyslogBuffer = malloc(args->previous_debug_size);
if (sPreviousSessionSyslogBuffer != NULL) {
sPreviousSessionSyslogBufferSize = args->previous_debug_size;
memcpy(sPreviousSessionSyslogBuffer, args->previous_debug_output,
sPreviousSessionSyslogBufferSize);
}
}
char revisionBuffer[64];
length = snprintf(revisionBuffer, sizeof(revisionBuffer),
"Welcome to syslog debug output!\nHaiku revision: %s\n",
@@ -1429,6 +1445,28 @@ err1:
return status;
}
static void
syslog_init_post_modules()
{
if (sPreviousSessionSyslogBuffer == NULL)
return;
void* buffer = sPreviousSessionSyslogBuffer;
size_t bufferSize = sPreviousSessionSyslogBufferSize;
sPreviousSessionSyslogBuffer = NULL;
sPreviousSessionSyslogBufferSize = 0;
MemoryDeleter bufferDeleter(buffer);
int fd = open("/var/log/previous_syslog", O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd < 0) {
dprintf("Failed to open previous syslog file: %s\n", strerror(errno));
return;
}
write(fd, buffer, bufferSize);
close(fd);
}
static status_t
syslog_init(struct kernel_args* args)
@@ -1713,7 +1751,7 @@ debug_init_post_settings(struct kernel_args* args)
void
debug_init_post_modules(struct kernel_args* args)
{
void* cookie;
syslog_init_post_modules();
// check for dupped lines every 10/10 second
register_kernel_daemon(check_pending_repeats, NULL, 10);
@@ -1724,7 +1762,7 @@ debug_init_post_modules(struct kernel_args* args)
static const char* kDemanglePrefix = "debugger/demangle/";
cookie = open_module_list("debugger");
void* cookie = open_module_list("debugger");
uint32 count = 0;
while (count < kMaxDebuggerModules) {
char name[B_FILE_NAME_LENGTH];