[Crash-utility] invalid regs display in bt
Dave Anderson
anderson at redhat.com
Thu Sep 27 19:13:56 UTC 2007
Dave Anderson wrote:
> Richard J Moore wrote:
>
>>
>>
>> crash-utility-bounces at redhat.com wrote on 27/09/2007 17:13:45:
>>
>> > Richard J Moore wrote:
>> > >
>> > > crash-utility-bounces at redhat.com wrote on 27/09/2007 15:45:21:
>> > >
>> > > > Richard J Moore wrote:
>> > > >
>> > > > > On looking at the code in entry.S at page_fault and the other
>> > > exception
>> > > > > entry points I see no attempt to save regs to create a
>> pt_regs struct.
>> > > > > The fact that do_page_fault takes pt_regs as the first arg is a
>> > > hack to
>> > > > > get at CS:EIP and SS:ESP at the time of exception.
>> > > >
>> > > > KPROBE_ENTRY(page_fault)
>> > > > RING0_EC_FRAME
>> > > > pushl $do_page_fault
>> > > > CFI_ADJUST_CFA_OFFSET 4
>> > > > ALIGN
>> > > > error_code:
>> > > > /* the function address is in %fs's slot on the stack */
>> > > > pushl %es
>> > > > CFI_ADJUST_CFA_OFFSET 4
>> > > > /*CFI_REL_OFFSET es, 0*/
>> > > > pushl %ds
>> > > > CFI_ADJUST_CFA_OFFSET 4
>> > > > /*CFI_REL_OFFSET ds, 0*/
>> > > > pushl %eax
>> > > > CFI_ADJUST_CFA_OFFSET 4
>> > > > CFI_REL_OFFSET eax, 0
>> > > > pushl %ebp
>> > > > CFI_ADJUST_CFA_OFFSET 4
>> > > > CFI_REL_OFFSET ebp, 0
>> > > > pushl %edi
>> > > > CFI_ADJUST_CFA_OFFSET 4
>> > > > CFI_REL_OFFSET edi, 0
>> > > > pushl %esi
>> > > > CFI_ADJUST_CFA_OFFSET 4
>> > > > CFI_REL_OFFSET esi, 0
>> > > > pushl %edx
>> > > > CFI_ADJUST_CFA_OFFSET 4
>> > > > CFI_REL_OFFSET edx, 0
>> > > > pushl %ecx
>> > > > CFI_ADJUST_CFA_OFFSET 4
>> > > > CFI_REL_OFFSET ecx, 0
>> > > > pushl %ebx
>> > > > CFI_ADJUST_CFA_OFFSET 4
>> > > > CFI_REL_OFFSET ebx, 0
>> > > > cld
>> > > > pushl %fs
>> > > > CFI_ADJUST_CFA_OFFSET 4
>> > > > /*CFI_REL_OFFSET fs, 0*/
>> > > > movl $(__KERNEL_PERCPU), %ecx
>> > > > movl %ecx, %fs
>> > > > UNWIND_ESPFIX_STACK
>> > > > popl %ecx
>> > > > CFI_ADJUST_CFA_OFFSET -4
>> > > > /*CFI_REGISTER es, ecx*/
>> > > > movl PT_FS(%esp), %edi # get the function address
>> > > > movl PT_ORIG_EAX(%esp), %edx # get the error code
>> > > > movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart
>> > > > mov %ecx, PT_FS(%esp)
>> > > > /*CFI_REL_OFFSET fs, ES*/
>> > > > movl $(__USER_DS), %ecx
>> > > > movl %ecx, %ds
>> > > > movl %ecx, %es
>> > > > movl %esp,%eax # pt_regs pointer
>> > > > call *%edi
>> > > > jmp ret_from_exception
>> > > > CFI_ENDPROC
>> > > > KPROBE_END(page_fault)
>> > > >
>> > >
>> > > Dave, it looks like error_code: has been change relatively
>> recently. My
>> > > source starts:
>> > > error_code:
>> > > pushl %ds
>> > > pushl %eax
>> > > xorl %eax,%eax
>> > > pushl %ebp
>> > > > > and so on. Clearly not a valid pt_regs struct.
>> > > The source I'm working with is from FC5. On your version of the
>> kernel
>> > > only the ERR, SS and ESP would be invalid.
>> > > What tree is yours taken from?
>> > >
>> >
>> > My example was from upstream 2.6.22-5. RHEL5 (2.6.18-based)
>> > is slightly different, as the "error_code:" chunk is located
>> > in the "divide_error" entry point, but like 2.6.22-5, all of
>> > the other exceptions jmp to it.
>> >
>> > But even your code is creating the remainder of the pt_regs
>> > after the essential registers laid down by the hardware
>> > exception mechanism, by pushing the remaining registers,
>> > "upwards" towards the beginning of the structure:
>> >
>> > struct pt_regs {
>> > long ebx;
>> > long ecx;
>> > long edx;
>> > long esi;
>> > long edi;
>> > long ebp;
>> > long eax;
>> > int xds;
>> > int xes;
>> > long orig_eax;
>> > long eip;
>> > int xcs;
>> > long eflags;
>> > long esp;
>> > int xss;
>> > };
>> >
>> > Right?
>> >
>> > Dave
>> >
>>
>> I don't think so. Am I misreading this:
>>
>> we take a page fault at ring 0. The cpu pushes eflags, cs, eip,
>> error-code
>> we enter the kernel at:
>> ENTRY(page_fault)
>> pushl $do_page_fault
>> jmp error_code
>>
>> we have errror code in orig_eax
>>
>>
>> error_code:
>> pushl %ds
>> pushl %eax
>> xorl %eax, %eax
>> pushl %ebp
>> pushl %edi
>> pushl %esi
>> pushl %edx
>> decl %eax # eax = -1
>> pushl %ecx
>> pushl %ebx
>> cld
>> pushl %es
>> UNWIND_ESPFIX_STACK
>> popl %ecx
>> movl ES(%esp), %edi # get the function address
>> movl ORIG_EAX(%esp), %edx # get the error code
>> movl %eax, ORIG_EAX(%esp)
>> movl %ecx, ES(%esp)
>> movl $(__USER_DS), %ecx
>> movl %ecx, %ds
>> movl %ecx, %es
>> movl %esp,%eax # pt_regs pointer
>> call *%edi
>> jmp ret_from_exception
>>
>>
>> Aren't we sorting ds in the pt_regs.ES ? and therefore one register out?
>>
>> Maybe I'm missing something?
>
>
> This code piece does seem to change from version to version,
> but I think it gets the ES register into the proper pt_regs
> location by pushing it here:
>
> > pushl %es
>
> and then popping it into %ecx here:
>
> > popl %ecx
>
> and then later storing it in the pt_regs here:
>
> > movl %ecx, ES(%esp)
>
> I think...
>
Yeah -- that's exactly it, before jumping to error_code,
it pushes the address of the fault handler onto the stack,
essentially into the "pt_regs.xes" location:
>> ENTRY(page_fault)
>> pushl $do_page_fault
>> jmp error_code
Then it pushes the remaining pt_regs register values,
but with the pt_regs.xes still needing to be set up.
So then later after the popl of the ES value into %ecx,
it grabs the exception handler address from the pt_regs.xes
location, and puts it into %edi:
>> popl %ecx
>> movl ES(%esp), %edi # get the function address
and then puts the ES value from %ecx into the pt_regs location:
>> movl %ecx, ES(%esp)
and later calls the handler:
>> call *%edi
Dave
More information about the Crash-utility
mailing list