Warm tip: This article is reproduced from serverfault.com, please click

How to find the instruction causing crash using objdump

发布于 2020-12-02 16:24:44

Hi I'm doing homework about operating system using Pintos. I was asked to find the faulting instruction in one test. The testing framework expected Pintos to output “do-nothing: exit(162)”. This is the standard message that Pintos prints when a process exits. However, Pintos did not output this message; instead, the do-nothing program crashed in userspace due to a memory access violation (a segmentation fault).

#include "tests/lib.h"

int
main (int argc UNUSED, char *argv[] UNUSED)
{
  return 162;
}

I looked into the result of this test,

FAIL
Test output failed to match any acceptable form.

Acceptable output:
  do-nothing: exit(162)
Differences in `diff -u' format:
- do-nothing: exit(162)
+ Page fault at 0xc0000008: rights violation error reading page in user context.
+ do-nothing: dying due to interrupt 0x0e (#PF Page-Fault Exception).
+ Interrupt 0x0e (#PF Page-Fault Exception) at eip=0x8048757
+  cr2=c0000008 error=00000005
+  eax=00000000 ebx=00000000 ecx=00000000 edx=00000000
+  esi=00000000 edi=00000000 esp=bfffffe4 ebp=00000000
+  cs=001b ds=0023 es=0023 ss=0023

The questions :

  1. What virtual address did the program try to access from userspace that caused it to crash? A: From the result file, I think it's 0xc000008
  2. What is the virtual address of the instruction that resulted in the crash? A: eip = 0x8048757, it's the virtual address of the instruction.
  3. To investigate, disassemble the do-nothing binary using objdump. What is the name of the function the program was in when it crashed? Copy the disassembled code for that function onto Gradescope, and identify the instruction at which the program crashed.

I have no idea about how to find the answer of 3. question, the output with "objdump -S do-nothing.o" is really simple :

Disassembly of section .text:

00000000 <main>:

int
main (int argc UNUSED, char *argv[] UNUSED)
{
  return 162;
}
   0:   b8 a2 00 00 00          mov    $0xa2,%eax
   5:   c3                      ret    

A:

void
_start (int argc, char *argv[])
{
 8048754:   83 ec 1c                sub    $0x1c,%esp
  exit (main (argc, argv));
 8048757:   8b 44 24 24             mov    0x24(%esp),%eax
 804875b:   89 44 24 04             mov    %eax,0x4(%esp)
 804875f:   8b 44 24 20             mov    0x20(%esp),%eax
 8048763:   89 04 24                mov    %eax,(%esp)
 8048766:   e8 35 f9 ff ff          call   80480a0 <main>
 804876b:   89 04 24                mov    %eax,(%esp)
 804876e:   e8 49 1b 00 00          call   804a2bc <exit>
  1. Find the C code for the function you identified above. For each instruction in the disassembled function in #3, explain in a few words why it’s necessary and/or what it’s trying to do.
#include <syscall.h>

int main (int, char *[]);
void _start (int argc, char *argv[]);

void
_start (int argc, char *argv[])
{
  exit (main (argc, argv));
}
  1. Why did the instruction you identified in #3 try to access memory at the virtual address you identified in #1? Don’t explain this in terms of the values of registers; we’re looking for a higher level explanation. A: I found the faulting instruction but I'm even more confused,
8048757:    8b 44 24 24             mov    0x24(%esp),%eax

**why would this instruction lead to segmentation fault? **

sub    $0x1c,%esp
mov    0x24(%esp),%eax

Firstly it allocated some stack space (0x1c), then move the argument argv at 0x24(%esp) [which was 0x8 before stack pointer changed] to %eax, why would this simple instruction lead to segmentation fault?

Questioner
badtastetea
Viewed
0
238k 2020-12-18 16:20:20

I am not an expert in PintOS, but I can offer some insight. You are using OBJDUMP on an object file (.o). These are unlinked ELF object files without any VMA (Virtual Memory Address) starting point (aka Origin Point) and doesn't include any of the user mode runtime code in each PintOS program. Things like a C startup that sets up the user mode application and starts the code at main with the argc and argv parameters.

What you need to do is build the object file into a user mode program with the normal PintOS build processes. The userland executables have the same name as the .o file with the .o removed. do-nothing is the name of the executable and it appears these can be found in the directory pintos/src/userprog/build/tests/userprog/. Run OBJDUMP on this executable, search for address 0x8048757. You should be able to readily find the function name and all the code for it easily. With that information you should be able to answer the 3rd question. The answer you have for question 1 and 2 is correct.