[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH] Workaround to the real-mode/protected-mode conflict
From: |
Laurent Vivier |
Subject: |
[Qemu-devel] [PATCH] Workaround to the real-mode/protected-mode conflict in GDB. |
Date: |
Tue, 24 Jan 2012 13:40:23 +0100 |
When qemu is started with '-S' to freeze at startup and gdb is connected to
inner gdb server, gdb is using by default 16-bit real-mode. Then if we put
a breakpoint inside kernel linux, the CPU is switched to 32/64-bit protected
mode but GDB is always in 16 bit real-mode. The size of the registers dump
differs and GDB is not able to manage it.
See the following thread for more details:
"Failed to use gdb with qemu 15.1 (with and without kvm support)"
http://permalink.gmane.org/gmane.comp.emulators.qemu/133120
By adding a breakpoint at startup, we can connect GDB to qemu gdb server
when CPU is already in protected mode.
Example:
- find the address of the symbol to stop on.
$ nm ../linux/vmlinux | grep start_kernel
ffffffff81ad391f T start_kernel
ffffffff81ad334a T x86_64_start_kernel
ffffffff81ad6a9c T xen_start_kernel
- Then start qemu with the breakpoint option (-hb):
./x86_64-softmmu/qemu-system-x86_64 -kernel ../linux/arch/x86/boot/bzImage \
-append console=ttyS0 -nographic \
-hb 0xffffffff81ad391f
- and now start GDB:
$ gdb
(gdb) set arch i386:x86-64
The target architecture is assumed to be i386:x86-64
(gdb) sym vmlinux
Reading symbols from /home/laurent/linux/vmlinux...done.
(gdb) target remote :1234
Remote debugging using :1234
start_kernel () at init/main.c:468
468 {
(gdb) x/i $pc
=> 0xffffffff81ad391f <start_kernel>: push %rbp
(gdb) c
Signed-off-by: Laurent Vivier <address@hidden>
---
gdbstub.c | 5 ++++-
gdbstub.h | 2 +-
monitor.c | 2 +-
qemu-options.hx | 10 ++++++++++
vl.c | 11 ++++++++++-
5 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/gdbstub.c b/gdbstub.c
index 640cf4e..e27c262 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2860,7 +2860,7 @@ static void gdb_sigterm_handler(int signal)
}
#endif
-int gdbserver_start(const char *device)
+int gdbserver_start(const char *device, unsigned long long hbreak)
{
GDBState *s;
char gdbstub_device_name[128];
@@ -2916,6 +2916,9 @@ int gdbserver_start(const char *device)
s->state = chr ? RS_IDLE : RS_INACTIVE;
s->mon_chr = mon_chr;
+ if (hbreak != (unsigned long long)-1) {
+ gdb_breakpoint_insert(hbreak, 1, GDB_BREAKPOINT_HW);
+ }
return 0;
}
#endif
diff --git a/gdbstub.h b/gdbstub.h
index d82334f..25d34ed 100644
--- a/gdbstub.h
+++ b/gdbstub.h
@@ -35,7 +35,7 @@ void gdb_register_coprocessor(CPUState *env,
#ifdef CONFIG_USER_ONLY
int gdbserver_start(int);
#else
-int gdbserver_start(const char *port);
+int gdbserver_start(const char *port, unsigned long long hbreak);
#endif
/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
diff --git a/monitor.c b/monitor.c
index 1be222e..208624b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1137,7 +1137,7 @@ static void do_gdbserver(Monitor *mon, const QDict *qdict)
const char *device = qdict_get_try_str(qdict, "device");
if (!device)
device = "tcp::" DEFAULT_GDBSTUB_PORT;
- if (gdbserver_start(device) < 0) {
+ if (gdbserver_start(device, -1) < 0) {
monitor_printf(mon, "Could not open gdbserver on device '%s'\n",
device);
} else if (strcmp(device, "none") == 0) {
diff --git a/qemu-options.hx b/qemu-options.hx
index b3db10c..c0d2435 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2194,6 +2194,16 @@ Shorthand for -gdb tcp::1234, i.e. open a gdbserver on
TCP port 1234
(@pxref{gdb_usage}).
ETEXI
+DEF("hb", HAS_ARG, QEMU_OPTION_breakpoint, \
+ "-hb addr set an hardware breakpoint at address addr\n",
+ QEMU_ARCH_ALL)
+STEXI
address@hidden -hb @var{addr}
address@hidden -hb
+Set an hardware breakpoint at address @var{addr}, by default implies "-s".
+ETEXI
+
+
DEF("d", HAS_ARG, QEMU_OPTION_d, \
"-d item1,... output log to /tmp/qemu.log (use -d ? for a list of log
items)\n",
QEMU_ARCH_ALL)
diff --git a/vl.c b/vl.c
index 5372a96..9e5dc64 100644
--- a/vl.c
+++ b/vl.c
@@ -188,6 +188,7 @@ int mem_prealloc = 0; /* force preallocation of physical
target memory */
int nb_nics;
NICInfo nd_table[MAX_NICS];
int autostart;
+unsigned long long hbreak;
static int rtc_utc = 1;
static int rtc_date_offset = -1; /* -1 means no change */
QEMUClock *rtc_clock;
@@ -2222,6 +2223,7 @@ int main(int argc, char **argv, char **envp)
nb_nics = 0;
autostart= 1;
+ hbreak = -1;
/* first pass of option parsing */
optind = 1;
@@ -2582,6 +2584,13 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_S:
autostart = 0;
break;
+ case QEMU_OPTION_breakpoint:
+ hbreak = strtoull(optarg, NULL, 0);
+ /* hbreak needs a gdb server */
+ if (gdbstub_dev == NULL) {
+ gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT;
+ }
+ break;
case QEMU_OPTION_k:
keyboard_layout = optarg;
break;
@@ -3442,7 +3451,7 @@ int main(int argc, char **argv, char **envp)
}
text_consoles_set_display(ds);
- if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
+ if (gdbstub_dev && gdbserver_start(gdbstub_dev, hbreak) < 0) {
fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n",
gdbstub_dev);
exit(1);
--
1.7.5.4
- [Qemu-devel] [PATCH] Workaround to the real-mode/protected-mode conflict in GDB.,
Laurent Vivier <=