配置kern.log以提供有关segfault的更多信息

时间:2014-09-07 20:32:56

标签: linux logging segmentation-fault kernel debian

目前我可以在kern.log条目中找到如下:

[6516247.445846] ex3.x[30901]: segfault at 0 ip 0000000000400564 sp 00007fff96ecb170 error 6 in ex3.x[400000+1000]
[6516254.095173] ex3.x[30907]: segfault at 0 ip 0000000000400564 sp 00007fff0001dcf0 error 6 in ex3.x[400000+1000]
[6516662.523395] ex3.x[31524]: segfault at 7fff80000000 ip 00007f2e11e4aa79 sp 00007fff807061a0 error 4 in libc-2.13.so[7f2e11dcf000+180000]

(你看,引起段错误的应用被命名为ex3.x,意味着练习3可执行)。

有没有办法让kern.log记录完整路径?类似的东西:

[6...] /home/user/cclass/ex3.x[3...]: segfault at 0 ip 0564 sp 07f70 error 6 in ex3.x[4...]

所以我可以很容易地从谁(用户/学生)这个ex3.x中找出来?

谢谢! 贝乔

2 个答案:

答案 0 :(得分:3)

该日志消息来自具有固定格式的内核,该格式仅包括可执行文件的前16个字母,不包括show_signal_msg的路径,请参阅非x86体系结构上的分段错误的其他相关行。

如Makyen所述,在没有对内核进行重大更改和重新编译的情况下,传递给syslog的klogd消息将不包含您请求的信息。

我不知道syslog或klogd中的任何日志转换或注入功能,它们允许您获取文件的名称并在文件系统上运行locate或file以查找完整路径。

获取所需信息的最佳方法是使用崩溃拦截软件,例如apportabrtcorekeeper。这些工具存储来自/ proc文件系统的进程元数据,包括进程的命令行,其中包括运行目录,假设二进制文件以完整路径运行,并且尚未在路径中。

另一种更通用的方法是启用核心转储,然后将/ proc / sys / kernel / core_pattern设置为包含%E,以便使核心文件名包含二进制文件的路径。

答案 1 :(得分:2)

简短的回答是:不,不进行代码更改并重新编译内核是不可能的。此问题的常规解决方案是指示学生将可执行文件命名为<student user name>_ex3.x,以便您可以轻松获取此信息。

但是,可以从其他方法获取您想要的信息Appleman1234在回答这个问题时提供了一些替代方案。

我们如何知道答案是“在不重新编译内核的情况下,kern.log段错误消息中的完整路径不可能”:

我们查看内核源代码,了解消息的生成方式以及是否有任何配置选项。

有问题的文件是内核源代码的一部分。您可以将整个内核源代码下载为rpm包(或其他类型的包),以用于从各种地方运行的任何版本的linux / debian。

具体来说,您看到的输出是根据您的架构中的以下任何文件生成的:

其中一个文件( linux / arch / x86 / mm / fault.c )的相关功能示例:

/*
 * Print out info about fatal segfaults, if the show_unhandled_signals
 * sysctl is set:
 */
static inline void
show_signal_msg(struct pt_regs *regs, unsigned long error_code,
        unsigned long address, struct task_struct *tsk)
{
    if (!unhandled_signal(tsk, SIGSEGV))
        return;

    if (!printk_ratelimit())
        return;

    printk("%s%s[%d]: segfault at %lx ip %p sp %p error %lx",
        task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
        tsk->comm, task_pid_nr(tsk), address,
        (void *)regs->ip, (void *)regs->sp, error_code);

    print_vma_addr(KERN_CONT " in ", regs->ip);

    printk(KERN_CONT "\n");
}

从那里我们看到传递给打印输出流程标识符的变量是tsk->comm其中struct task_struct *tskregs->ip其中struct pt_regs *regs

然后从linux/include/linux/sched.h

struct task_struct {
    ...
    char comm[TASK_COMM_LEN]; /* executable name excluding path
                                 - access with [gs]et_task_comm (which lock
                                   it with task_lock())
                                 - initialized normally by setup_new_exec */

注释清楚地表明可执行文件的路径未存储在结构中。

对于regs->ip struct pt_regs *regs,其中以下列哪个版本适用于您的架构:

从那里我们看到struct pt_regs正在为架构定义寄存器。 ip只是:unsigned long ip;

因此,我们必须看看print_vma_addr()的作用。它在mm/memory.c

中定义
/*
 * Print the name of a VMA.
 */
void print_vma_addr(char *prefix, unsigned long ip)
{
    struct mm_struct *mm = current->mm;
    struct vm_area_struct *vma;

    /*
     * Do not print if we are in atomic
     * contexts (in exception stacks, etc.):
     */
    if (preempt_count())
        return;

    down_read(&mm->mmap_sem);
    vma = find_vma(mm, ip);
    if (vma && vma->vm_file) {
        struct file *f = vma->vm_file;
        char *buf = (char *)__get_free_page(GFP_KERNEL);
        if (buf) {
            char *p;

            p = d_path(&f->f_path, buf, PAGE_SIZE);
            if (IS_ERR(p))
                p = "?";
            printk("%s%s[%lx+%lx]", prefix, kbasename(p),
                    vma->vm_start,
                    vma->vm_end - vma->vm_start);
            free_page((unsigned long)buf);
        }
    }
    up_read(&mm->mmap_sem);
}

向我们展示路径可用。我们需要检查它是路径,但是在代码中稍微进一步说明它可能并不重要。我们需要看看kbasename()对传递给它的路径做了什么。 kbasename()include/linux/string.h中定义为:

/**
 * kbasename - return the last part of a pathname.
 *
 * @path: path to extract the filename from.
 */
static inline const char *kbasename(const char *path)
{
    const char *tail = strrchr(path, '/');
    return tail ? tail + 1 : path;
}

即使在它之前有完整路径,除了路径名的最后一部分之外,还要删除所有内容。保留文件名。

因此,没有多少运行时配置选项允许在您看到的段错误消息中打印出文件的完整路径名。