调试器开发 ﹣ 在qemu裹创造一个debug server的stub

QEMU支持GDB, 它内置了一个GDB server,就是说如果你懂GDB protocol的话,你可以直接向GDB发送指令,控制GDB。

但GDB不是完美, 所以你有理主去搞一个自己的debug server, 如果你是在开发调试器的话, 你更加需要一个自己的debug protocol.


这编文章我会示范怎样去创造一个debug server, 经TCP去接收指令. 我会以qemu-kvm来示范, qemu-kvm代码来讲和qemu不同, 但加debug server来说都是差不多.


我会用eclipse+CDT来调qemu,我不会用gdb了, 因为命令行对我来说是灾难.




Here we go:

所有我改过的variable和function, 我都会以peter为开头,我在代码里搜peter就可以知道我改过什么地方了。

Step 1) Qemu 的开始是在文件vl.c, 行2041, 我们需要加一个identifier去enum, 就叫它 "DEV_PETER"

struct device_config {
    enum {
        DEV_USB,       /* -usbdevice     */
        DEV_BT,        /* -bt            */
        DEV_SERIAL,    /* -serial        */
        DEV_PARALLEL,  /* -parallel      */
        DEV_VIRTCON,   /* -virtioconsole */
        DEV_DEBUGCON,  /* -debugcon */
        DEV_GDB,       /* -gdb, -s */
        DEV_PETER   /* peter */
    } type;
    const char *cmdline;
    Location loc;
    QTAILQ_ENTRY(device_config) next;
};

Step 2) 在行2793, 你可以见到一个"switch loop", 它是用来parse命令行的参数的, 因为我想指定我的debug server的tcp port, 所以我在执行qemu时会加一个参数"-peter 1234"


            case QEMU_OPTION_s:
                add_device_config(DEV_GDB, "tcp::" DEFAULT_GDBSTUB_PORT);
                break;
            case QEMU_OPTION_gdb:
                add_device_config(DEV_GDB, optarg);
                break;
            case QEMU_OPTION_peter:
                peter_cmdline=optarg;
                break;
            case QEMU_OPTION_L:
                data_dir = optarg;
                break;

請在vl.c的頭頂加入const char *peter_cmdline;

我们需要改文件qemu-options.hx, 它决定command-line-argument-parser 怎样 parse 我们的参数"-peter 1234". 所以要在行2390加入:



DEF("peter", HAS_ARG, QEMU_OPTION_peter, \
    "-peter dev        wait for peter connection on 'dev'\n", QEMU_ARCH_ALL)
STEXI
@findex -peter
Wait for peter 
@example
(peter) target remote | exec qemu-system-i386 -peter stdio ...
@end example
ETEXI

Step 3) 在main(), 行239

const char *peter_cmdline;

在main(), 行3788

    if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) {
        exit(1);
    }

    if (peter_start(peter_cmdline)>0){
    fprintf(stderr, "start peter error\n");
    exit(0);
    }

    qdev_machine_creation_done();

    if (rom_load_all() != 0) {
        fprintf(stderr, "rom loading failed\n");
        exit(1);
    }

Step 4) 这里是peterstub.h 和 peterstub.h, 请放它们到代码树的最顶层 (和文件gdbserver.c相同):

peterstub.c:

#include "config.h"
#include "qemu-common.h"
#ifdef CONFIG_USER_ONLY
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#include "qemu.h"
#else
#include "monitor.h"
#include "qemu-char.h"
#include "sysemu.h"
#include "gdbstub.h"
#endif

#include "peterstub.h"

static int peter_chr_can_receive(void *opaque) {
printf("peter_chr_can_receive\n");
return 4096;
}

static void peter_chr_receive(void *opaque, const uint8_t *buf, int size) {
printf("gdb_chr_receive, size=%d, buf=%s\n", size, buf);
}

static void peter_chr_event(void *opaque, int event) {
printf("gdb_chr_event, event=%d\n", event);
}

int peter_start(const char *device) {
char gdbstub_device_name[128];
printf("peter_start, cmdline=%s\n", device);
CharDriverState *chr = NULL;
if (strcmp(device, "none") != 0) {
if (strstart(device, "tcp:", NULL)) {
/* enforce required TCP attributes */
snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
"%s,nowait,nodelay,server", device);
device = gdbstub_device_name;
}
}

chr = qemu_chr_new("peter", device, NULL);
if (!chr)
return -1;
qemu_chr_add_handlers(chr, peter_chr_can_receive, peter_chr_receive,
peter_chr_event, NULL);
return 0;
}

peterstub.h:

#ifndef PETERSTUB_H_
#define PETERSTUB_H_

int peter_start(const char *device);

#endif /* PETERSTUB_H_ */

Step 5)  加你的.o到Makefile.target

#########################################################

# System emulator target

ifdef CONFIG_SOFTMMU

CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)

CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)

CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)

CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING)),n,y)

CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y)


obj-y += arch_init.o cpus.o monitor.o gdbstub.o gkd.o balloon.o ioport.o

obj-y += hw/

obj-$(CONFIG_KVM) += kvm-all.o

obj-$(CONFIG_NO_KVM) += kvm-stub.o

obj-y += memory.o savevm.o cputlb.o

obj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += memory_mapping.o

obj-$(CONFIG_HAVE_CORE_DUMP) += dump.o

obj-$(CONFIG_NO_GET_MEMORY_MAPPING) += memory_mapping-stub.o

obj-$(CONFIG_NO_CORE_DUMP) += dump-stub.o

LIBS+=-lz



Step 6) 最后一步, 执行qemu, 把"-peter 1234"加到参数去



QEMU成功执行之后, 可以在linux里用nv指令发送一些string去debug server以作测试














  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值