【问题标题】:How can i know that i have The Stack-Segment Fault somewhere?我怎么知道我在某处有堆栈段错误?
【发布时间】:2023-03-22 14:48:02
【问题描述】:

这是我第一次看到当我将一个值压入堆栈时,堆栈仍然是空的。

我认为可能是内核崩溃,所以我在调用函数之前添加了cli ; cld,但什么也没添加。

示例是当我想调用函数时,函数被称为 memset

eflags         0x6                 [ IOPL=0 PF ]  
│   0xf0100d6a <mem_init+172>       cli                                                                                                                                 │
│   0xf0100d6b <mem_init+173>       cld                                                                                                                                 │
│   0xf0100d6c <mem_init+174>       sub    esp,0x4                                                                                                                      │
│   0xf0100d6f <mem_init+177>       mov    eax,DWORD PTR [edi+0x1fb8]                                                                                                   │
│   0xf0100d75 <mem_init+183>       shl    eax,0x3                                                                                                                      │
│   0xf0100d78 <mem_init+186>       push   eax                                                                                                                          │
│   0xf0100d79 <mem_init+187>       push   0x0                                                                                                                          │
│   0xf0100d7b <mem_init+189>       push   DWORD PTR [edi+0x1fb0]                                                                                                       │
│  >0xf0100d81 <mem_init+195>       call   0xf010234b <memset>  

         

    (gdb) p $esp
$1 = (void *) 0xf00d1f8c
(gdb) stepi
=> 0xf0100d78 <mem_init+186>:   push   eax
=> 0xf0100d79 <mem_init+187>:   push   0x0
=> 0xf0100d7b <mem_init+189>:   push   DWORD PTR [edi+0x1fb0]
=> 0xf0100d81 <mem_init+195>:   call   0xf010234b <memset>
(gdb) p $esp
$2 = (void *) 0xf00d1f80
(gdb) x/4w $esp
0xf00d1f80:     0x00000000      0x00000000      0x00000000      0x00000000
(gdb) 

有 C 代码:

asm("cli ; cld") ;
    
memset((void*) pages , 0 , (size_t)(sizeof(*pages)*npages) );

你能告诉我哪里出错了吗? 是堆栈段错误吗??

【问题讨论】:

  • $eip 的值是多少?看来您在第一个push之前停止了。
  • 0xf0100d81eip 的值
  • info registers 和 x/x $edi + 0x1fb0。 $eax 和那个内存位置是 0 吗?
  • Eax 具有非零值
  • 我会使用选项 -no-shutdown -no-reboot -d int 运行 QEMU。 -d int 非常重要,因为它会为每个引发的中断/异常转储信息。 v= 条目是向量编号,它旁边的 e= 值很重要,它是可以指示问题所在的错误编号。

标签: x86 kernel osdev


【解决方案1】:

您正在执行一条特权指令。我不知道你是在内核模式还是用户模式,但是如果你在用户模式,这会立即产生一个陷阱。

编辑

从你说你在内核模式的cmets,所以mi下一条评论是关于cli指令不会抑制陷阱,而只会抑制硬件中断线,而不是由页面错误或指令错误引起的陷阱,分段违规,访问未分配的内存等。陷阱是由错误指令引起的错误(同步),因此 cpu 无法继续忽略它们,即使中断标志正在禁止中断,因此无论如何都会跳转陷阱。最可能的情况是您在 memset 内写入未分配的内存(在页表中标记为不可用),因此请仔细检查指针 pages 和覆盖 pages ... pages + npages * sizeof *pages 的段。

【讨论】:

  • 我在内核模式下先生
  • 你有关于内核恐慌的信息吗?
  • @EsaïeNjongssi:如果 memset 尝试写入页表未映射的内存,您是否希望 cli 阻止引发#PF 异常?正如 Luis 解释的那样,禁用中断只会阻止 外部 中断,而不是由运行指令触发的同步异常/故障。所以不要将错误的地址传递给 memset,和/或检查你的页表。 (BOCHS 的内置调试器可以解码页表,因此您可以检查它们是否按照您的预期设置。)
猜你喜欢
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
相关资源
最近更新 更多