Debug extension implementation for NLKD to access the kernel trace buffer. Signed-Off-By: Jan Beulich Index: 2.6.14-nlkd/kernel/printk.c =================================================================== --- 2.6.14-nlkd.orig/kernel/printk.c 2005-11-09 10:40:17.000000000 +0100 +++ 2.6.14-nlkd/kernel/printk.c 2005-11-04 16:19:34.000000000 +0100 @@ -1032,3 +1032,190 @@ int printk_ratelimit(void) printk_ratelimit_burst); } EXPORT_SYMBOL(printk_ratelimit); + +#if defined(CONFIG_PRINTK) && defined(CONFIG_NLKD) +# include +# include + +static int match(unsigned long start, unsigned long end, const char *pattern, size_t len) +{ + unsigned long stop; + + start &= LOG_BUF_MASK; + stop = end &= LOG_BUF_MASK; + if (stop < start) + stop = log_buf_len; + for (;;) { + const char *p; + + while (((end - start) & LOG_BUF_MASK) >= len + && (p = memchr(log_buf + start, *pattern, stop - start)) != NULL) { + unsigned long where = p - log_buf; + + if (len > stop - where + ? !memcmp(p, pattern, stop - where) + && !memcmp(p + (stop - where), + pattern + (stop - where), + len - (stop - where)) + : !memcmp(p, pattern, len)) + return 1; + start = where + 1; + } + if (end >= start) + return 0; + start = 0; + stop = end; + } +} + +static void do_mgrep(const char *pattern, long skip, long count) +{ + int backward = 1; + unsigned long line, cur; + size_t len = pattern ? strlen(pattern) : 0; + + if (count == 0) + count = 5; + else if (count < 0) { + count = -count; + backward = 0; + } + if (skip < 0) { + skip = -skip; + backward = 0; + } +#define LOG_IDX_MATCH(idx1, idx2) (!(((idx1) ^ (idx2)) & LOG_BUF_MASK)) + if (backward) { + /* Search from end. */ + int end; + + skip += count - 1; + line = log_end; + do { + for (cur = line - 1; !LOG_IDX_MATCH(cur, log_end) && LOG_BUF(cur) && LOG_BUF(cur) == '\n'; --cur) + ; + for (; !(end = LOG_IDX_MATCH(cur, log_end) || !LOG_BUF(cur)) && LOG_BUF(cur) != '\n'; --cur) + ; + if (len && !match(cur + 1, line, pattern, len)) + ++skip; + line = cur + 1; + } while (skip-- && !end); + if (++skip < count) + count -= skip; + else + count = 0; + } + else { + /* Search from start. */ + for (cur = LOG_BUF(log_end) ? log_end : 0; line = cur, skip; --skip) { + while (LOG_BUF(cur) != '\n') + if (!LOG_BUF(cur) || LOG_IDX_MATCH(++cur, log_end)) + return; + while (LOG_BUF(cur) == '\n') + if (!LOG_BUF(cur) || LOG_IDX_MATCH(++cur, log_end)) + return; + if (len && !match(line, cur, pattern, len)) + ++skip; + } + } + while (count) { + for (cur = line; LOG_BUF(cur) && LOG_BUF(cur) != '\n'; ++cur) + if (LOG_IDX_MATCH(cur + 1, 0)) { + for (cur = 0; LOG_BUF(cur) && LOG_BUF(cur) != '\n'; ++cur) + if (LOG_IDX_MATCH(cur + 1, line)) + break; + break; + } + if(!len || match(line, cur, pattern, len)) { + if (cur < line) { + nlkdExtPrintf("%.*s", log_buf_len - (int)(line & LOG_BUF_MASK), &LOG_BUF(line)); + nlkdExtPrintf("%.*s\n", (int)cur, log_buf); + } + else + nlkdExtPrintf("%.*s\n", (int)(cur - line), &LOG_BUF(line)); + --count; + } + if (LOG_BUF(cur) != '\n') + break; + for (line = cur + 1; LOG_BUF(line) == '\n'; ++line) + ; + } +#undef LOG_IDX_MATCH +} + +static char *skipComma(char *s) { + while (*s && isspace(*s)) + ++s; + if (*s == ';' || *s == ',') + ++s; + while (*s && isspace(*s)) + ++s; + return s; +} + +/* + * !dmesg [[<# to skip>;]<# of lines>] + */ +static void dbgxt_dmesg(void *pattern, const char *command) { + long skip = 0, count = 0; + + if (!command) + return; + if (!pattern && *command == '?') { + nlkdExtOutputString("dmesg [[<# to skip>] <# of entries>]"); + return; + } + if (*command) { + char *tail; + + skip = simple_strtol(command, &tail, 0); + if (*(tail = skipComma(tail))) + count = simple_strtol(tail, NULL, 0); + else { + count = skip; + skip = 0; + } + } + do_mgrep(pattern, skip, count); +} + +/* + * !mgrep [[<# to skip>];<# of lines>] + */ +static void dbgxt_mgrep(void *unused, const char *command) { + if (!command) + return; + if (!strcmp(command, "?")) { + nlkdExtOutputString("mgrep [[<# to skip>] <# of entries>]"); + return; + } + if (*command) { + char pattern[256], *dst; + char quote = strchr("\"\'", *command) != NULL ? *command++ : 0; + + for (dst = pattern; *command && (quote ? *command != quote : !isspace(*command)); ++command) + if(dst < pattern + ARRAY_SIZE(pattern) - 1) + *dst++ = *command; + *dst = 0; + if (*command) + ++command; + while (*command && isspace(*command)) + ++command; + dbgxt_dmesg((void *)pattern, command); + } +} + +static THIS_MODULE_ID(printkModuleId); +NLKD_EXTENSION(dmesg, + dbgxt_dmesg, + NULL, + printkModuleId, + "Display trace buffer records", + 0); +NLKD_EXTENSION(mgrep, + dbgxt_mgrep, + NULL, + printkModuleId, + "Grep trace buffer records", + 0); +#endif