Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ qtest
*.dSYM
.vscode
.devcontainer
core*
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ Tools for evaluating your queue code
* Makefile : Builds the evaluation program `qtest`
* README.md : This file
* scripts/driver.py : The driver program, runs `qtest` on a standard set of traces
* scripts/debug.py : The helper program for GDB, executes qtest without SIGALRM and/or analyzes generated core dump file.

Helper files
* console.{c,h} : Implements command-line interpreter for qtest
Expand All @@ -97,6 +98,49 @@ Trace files
* XX is the trace number (1-15). CAT describes the general nature of the test.
* traces/trace-eg.cmd : A simple, documented trace file to demonstrate the operation of `qtest`

## Debugging Facilities

Before using GDB debug `qtest`, there are some routine instructions need to do. The script `scripts/debug.py` covers these instructions and provides basic debug function.
```
$ scripts/debug.py -h
usage: debug.py [-h] [-d | -a]

optional arguments:
-h, --help show this help message and exit
-d, --debug Enter gdb shell
-a, --analyze Analyze the core dump file
```
* Enter GDB without interruption by **SIGALRM**.
```
$ scripts/debug.py -d
Reading symbols from lab0-c/qtest...done.
Signal Stop Print Pass to program Description
SIGALRM No No No Alarm clock
Starting program: lab0-c/qtest
cmd>
```
* When `qtest` encountered **Segmentation fault** while it ran outside GDB, we could invoke GDB in the post-mortem debugging mode to figure out the bug.

The core dump file was created in the working directory of the `qtest`.
* Allow the core dumps by using shell built-in command **ulimit** to set core file size.
```
$ ulimit -c unlimited
$ ulimit -c
unlimited
```
* Enter GDB and analyze
```
$ scripts/debug.py -a
Reading symbols from lab0-c/qtest...done.
[New LWP 9424]
Core was generated by `lab0-c/qtest'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 ...
#1 ... (backtrace information)
#2 ...
(gdb)
```

## License

`lab0-c`is released under the BSD 2 clause license. Use of this source code is governed by
Expand Down
8 changes: 5 additions & 3 deletions qtest.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,9 +629,11 @@ static bool do_show(int argc, char *argv[])
/* Signal handlers */
static void sigsegvhandler(int sig)
{
trigger_exception(
"Segmentation fault occurred. You dereferenced a NULL or invalid "
"pointer");
report(1,
"Segmentation fault occurred. You dereferenced a NULL or invalid "
"pointer");
/* Raising a SIGABRT signal to produce a core dump for debugging. */
abort();
}

static void sigalrmhandler(int sig)
Expand Down
83 changes: 83 additions & 0 deletions scripts/debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env python3

import argparse
import shutil
import subprocess
import pathlib
import os

class Debugger:
def __init__(self, command, common_opts):
self.command = command
self.common_opts = common_opts

def __call__(self, argv, **kwargs):
g = subprocess.Popen([self.command] + self.common_opts + argv, **kwargs)

while g.returncode != 0:
try:
g.communicate()
except KeyboardInterrupt:
pass

return g

def debug(self, program):
return self([
"-ex", "handle SIGALRM ignore",
"-ex", "run",
program
])

def analyze(self, program, core_file):
return self([
program,
core_file,
"-ex", "backtrace"
])


def main(argv):
common = [
"-quiet",
f"-cd={ROOT}"
]

gdb = Debugger(GDB_PATH, common)

if argv.debug:
gdb.debug(QTEST)

elif argv.analyze:
if not os.path.exists(CORE_DUMP):
print("ERROR: core dump file is not exist")
exit(1)

gdb.analyze(QTEST, CORE_DUMP)

else:
parser.print_help()

if __name__ == "__main__":
ROOT = str(pathlib.Path(__file__).resolve().parents[1])
GDB_PATH = shutil.which("gdb")
QTEST = ROOT + "/qtest"
CORE_DUMP = ROOT + "/core"

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-d", "--debug", dest="debug", action="store_true",
help="Enter gdb shell")
group.add_argument("-a", "--analyze", dest="analyze", action="store_true",
help="Analyze the core dump file")
args = parser.parse_args()

if not GDB_PATH:
print("ERROR: gdb is not installed")
exit(1)

if not os.path.exists(QTEST):
print("ERROR: qtest is not exist")
exit(1)

main(args)