简短的回答是:不,不更改代码并重新编译内核是不可能的。这个问题的正常解决方案是指导你的学生将他们的可执行文件命名为<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 *tsk和regs->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;
}
即使完整路径在它之前可用,它也会删除除了路径名的最后一部分之外的所有内容,留下文件名。
因此,任何运行时配置选项都不允许在您看到的段错误消息中打印出文件的完整路径名。
注意:我已将内核源代码的所有链接更改为存档,而不是原始位置。这些链接将接近我写这篇文章时的代码,2104-09。毫不奇怪,代码确实会随着时间而发展,因此当您阅读本文时,当前的代码可能相似,也可能不同,或者按照此处描述的方式执行。