version 1.3, 2010/07/14 23:44:13
|
version 1.12, 2015/08/05 12:58:13
|
Line 1
|
Line 1
|
# Introduction |
# Introduction |
|
|
Virtual machines are a convenient way to test, debug or even audit different systems on one single host. This is particularly helpful when you need to set up a machine for which you do not necessarily have the hardware, or the access, in a very cheap way, without risking breaking your day-to-day system. |
This HOWTO explains how to set up a test environment for symbolic |
|
debugging of the NetBSD kernel using a pair of QEMU virtual machines. |
|
|
This tutorial show the different steps required to set up a raw disk image like the one used by QEMU. It deals with two different point of views: |
## Prerequisites |
|
|
* the host, which is the machine and OS hosting the different VMs. |
You need a computer running an OS capable of cross-building NetBSD |
* the guest(s), representing the different systems emulated/hosted on the host, through QEMU. |
(the "host system"). |
|
This can be NetBSD itself, Linux, or some other Unix-like OS. |
|
These instructions have been tested with NetBSD/amd64 6.1.4 and |
|
Debian 7 hosts. There should be at least 20 gigabytes of available |
|
disk space. |
|
|
# Setting up the environment |
If your host system is running NetBSD, install the following packages |
|
from pkgsrc: |
|
|
## Creating the raw disk image |
* emulators/qemu >= 2.0.0nb4 |
|
* misc/py-anita |
|
|
To start our VM, we need some disk space to provide an emulated hard drive. For QEMU, by default, this is done through raw disk images. Therefore, the first step will be the creation of a disk image file. Here, we create a 2GB file, filled with zeros: |
If your host system uses a package system other than pkgsrc, |
|
use that to install cvs, make, gcc, qemu, the Python pexpect |
|
library, and genisoimage or mkisofs. Also download and |
|
install the most recent anita package from |
|
<http://www.gson.org/netbsd/anita/download/>. |
|
|
[[!template id=programlisting text=""" |
## Building the target system |
$ dd if=/dev/null of=netbsd-guest.img bs=1m count=2000 |
|
"""]] |
|
|
|
/!\ if you want to mount the file image from within the host later through [[!template id=man name="vnconfig" section="8"]], it is recommended to use [[!template id=man name="dd" section="1"]] and not the *qemu-img* tool, as [[!template id=man name="vnd" section="4"]] does not support sparse disk image yet. |
|
|
|
Now that the disk image file is ready, we will need to install our system inside. |
Check out the NetBSD-current sources from CVS and build a full release |
|
of NetBSD-current/i386 with debug symbols using the build.sh script. |
## Preparing the MBR, labels, and first stage boot loader |
The i386 port is the preferred test platform because the two |
|
other ports supported by anita are affected by known bugs: amd64 by |
Mount the image file as a [[!template id=man name="vnd" section="4"]] device. This will allow manipulating the image file just like a regular hard disk drive: |
[[PR 50128|http://gnats.NetBSD.org/50128]], and sparc by |
|
[[qemu bug 1399943|https://bugs.launchpad.net/qemu/+bug/1399943]]. |
|
If you do the build in a directory other than /usr/src, |
|
use the -fdebug-prefix-map option to ensure that the source file names embedded |
|
in the debug symbols point to /usr/src, which is where the sources will be |
|
installed on the target system. For example: |
|
|
[[!template id=programlisting text=""" |
[[!template id=programlisting text=""" |
# vnconfig -c vnd0 netbsd-guest.img |
$ CVSROOT=anoncvs@anoncvs.NetBSD.org:/cvsroot cvs checkout -A -P src |
|
$ cd src |
|
$ ./build.sh -j 4 -V MKDEBUG=YES -V COPTS="-g -fdebug-prefix-map=$(pwd)=/usr/src" -O ../obj -m i386 -U release sourcesets |
"""]] |
"""]] |
|
|
### Creating MBR |
For best performance, change the number after "-j" to the number of CPU cores |
|
you have, or slightly more. |
|
|
Setup the MBR; it musts contain the NetBSD partition. This will be done interactively via [[!template id=man name="fdisk" section="8"]]: |
## Installing the target system |
|
|
[[!template id=programlisting text=""" |
Install the system in a virtual machine, including the debug symbols and source code: |
# fdisk -u -a -0 /dev/rvnd0 |
|
Disk: /dev/rvnd0d |
|
[...] |
|
Do you want to change our idea of what BIOS thinks? [n] *n* |
|
|
|
Partition 0: |
[[!template id=programlisting text=""" |
<UNUSED> |
$ cd .. |
The data for partition 0 is: |
$ anita --workdir work --disk-size 4G --memory-size 256M \ |
<UNUSED> |
--sets kern-GENERIC,modules,base,etc,comp,debug,games,man,misc,tests,text,syssrc,src,sharesrc,gnusrc \ |
sysid: [0..255 default: 169] *press enter* |
install $(pwd)/obj/releasedir/i386/ |
start: [0..255dcyl default: 63, 0dcyl, 0MB] *press enter* |
|
size: [0..255dcyl default: 4095937, 255dcyl, 2000MB] *press enter* |
|
bootmenu: [] *press enter* |
|
Do you want to change the active partition? [n] *y* |
|
Choosing 4 will make no partition active. |
|
active partition: [0..4 default: 0] *press enter* |
|
Are you happy with this choice? [n] *y* |
|
We haven't written the MBR back to disk yet. This is your last chance. |
|
Partition table: |
|
0: NetBSD (sysid 169) |
|
start 63, size 4095937 (2000 MB, Cyls 0-254/245/55), Active |
|
PBR is not bootable: All bytes are identical (0x00) |
|
1: <UNUSED> |
|
2: <UNUSED> |
|
3: <UNUSED> |
|
Bootselector disabled. |
|
First active partition: 0 |
|
Should we write new partition table? [n] *y* |
|
"""]] |
"""]] |
|
|
### Editing labels |
## Booting the VMs |
|
|
|
Next, start two qemu virtual machines, one to run the kernel being |
|
debugged (the "target VM") and another to run gdb (the "gdb VM"). |
|
|
Edit the labels, with [[!template id=man name="disklabel" section="8"]]. The example below will create: |
The two VMs could be run on separate physical machines, but in this |
|
example, they are run on the same physical machine and share the same |
|
hard disk image. This sharing is made possible by the "-snapshot" |
|
option to qemu, which ensures that the disk image is not written to by |
|
either VM. |
|
|
* label **a**, approximately 1.5GiB long -- will contain the future FFS / partition |
First start the target VM, enabling qemu's built-in GDB target stub |
* label **b**, 512MiB swap. |
on TCP port 1234: |
|
|
[[!template id=programlisting text=""" |
[[!template id=programlisting text=""" |
# disklabel -e -I /dev/rvnd0 |
$ qemu-system-i386 -nographic -snapshot -hda work/wd0.img -gdb tcp::1234 |
[...] |
|
4 partitions: |
|
# size offset fstype [fsize bsize cpg/sgs] |
|
a: 3047361 63 4.2BSD 0 0 0 # (Cyl. 0*- 1487) |
|
b: 1048576 3047424 swap # (Cyl. 1488 - 1999) |
|
d: 4096000 0 unused 0 0 # (Cyl. 0 - 1999) |
|
"""]] |
"""]] |
|
|
### Copying first stage boot loader |
If you don't want everyone on the Internet to be able to debug your |
|
target, make sure incoming connections on port 1234 are blocked in |
|
your firewall. |
|
|
Lastly, we have to install the first stage boot loader, the one that will be able to read the second stage boot loader, which will reside in partition **a**. Use [[!template id=man name="installboot" section="8"]]: |
In a second terminal window, start the gdb VM: |
|
|
[[!template id=programlisting text=""" |
[[!template id=programlisting text=""" |
# installboot /dev/rvnd0a /usr/mdec/bootxx_ffsv2 |
$ qemu-system-i386 -nographic -snapshot -hda work/wd0.img |
"""]] |
"""]] |
|
|
## Format and mount the filesystem |
Log in to the gdb VM as root and set up the network: |
|
|
With [[!template id=man name="newfs" section="8"]], format label **a** in FFSv2: |
|
|
|
[[!template id=programlisting text=""" |
[[!template id=programlisting text=""" |
# newfs -O2 /dev/rvnd0a |
login: root |
/dev/rvnd0a: 1488.0MB (3047360 sectors) block size 16384, fragment size 2048 |
# dhcpcd |
using 9 cylinder groups of 165.34MB, 10582 blks, 20544 inodes. |
|
super-block backups (for fsck_ffs -b #) at: |
|
160, 338784, 677408, 1016032, 1354656, 1693280, 2031904, 2370528, 2709152, |
|
"""]] |
"""]] |
|
|
then [[!template id=man name="mount" section="8"]] it: |
Start gdb on the gdb VM and connect to the target: |
|
|
[[!template id=programlisting text=""" |
[[!template id=programlisting text=""" |
# mkdir /tmp/netbsd-guest |
# gdb /netbsd |
# mount /dev/vnd0a /tmp/netbsd-guest |
(gdb) target remote my.host.name:1234 |
"""]] |
"""]] |
|
|
# Installing the system |
where my.host.name is the domain name or IP address of the |
|
host system. |
|
|
## Quick and easy way |
Now you should be able to get a stack trace and start debugging |
|
with full debug symbols and access to the source code: |
|
|
|
[[!template id=programlisting text=""" |
|
(gdb) where |
|
(gdb) list |
|
"""]] |
|
|
## Through build.sh |
If the stack trace prints very slowly (like 30 seconds per stack |
|
frame), it's likely because you are using a version of qemu where |
|
the user-mode networking code fails to disable the Nagle algorithm. |
|
This is fixed in the qemu in pkgsrc, but you may run into it if your |
|
qemu is not installed via pkgsrc. |
|
|
# Configuring the system |
## Qemu tips |
|
|
# Starting-up the VM |
Here is a couple of useful qemu commands to know: |
|
|
# Debugging |
* Ctrl-a b will send a break which will make the NetBSD VM enter the ddb kernel debugger. |
|
|
# Convenient scripts |
* Ctrl-a c will switch to the qemu monitor where you can enter commands like "quit" to exit qemu, |
|
or do things like saving/restoring the VM to/from a file. |