diff options
-rw-r--r-- | block/io.c | 13 | ||||
-rw-r--r-- | hw/arm/xlnx-zynqmp.c | 28 | ||||
-rw-r--r-- | hw/block/virtio-blk.c | 7 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 9 | ||||
-rw-r--r-- | hw/s390x/s390-virtio-ccw.c | 2 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi.c | 5 | ||||
-rw-r--r-- | hw/sd/milkymist-memcard.c | 2 | ||||
-rw-r--r-- | hw/sd/omap_mmc.c | 2 | ||||
-rw-r--r-- | hw/sd/pl181.c | 2 | ||||
-rw-r--r-- | hw/sd/pxa2xx_mmci.c | 2 | ||||
-rw-r--r-- | hw/sd/sd.c | 2 | ||||
-rw-r--r-- | hw/sd/sdhci-internal.h (renamed from hw/sd/sdhci.h) | 73 | ||||
-rw-r--r-- | hw/sd/sdhci.c | 3 | ||||
-rw-r--r-- | hw/sd/ssi-sd.c | 2 | ||||
-rw-r--r-- | include/hw/arm/xlnx-zynqmp.h | 3 | ||||
-rw-r--r-- | include/hw/compat.h | 6 | ||||
-rw-r--r-- | include/hw/sd/sd.h (renamed from include/hw/sd.h) | 0 | ||||
-rw-r--r-- | include/hw/sd/sdhci.h | 94 | ||||
-rw-r--r-- | scripts/qemu-gdb.py | 6 | ||||
-rw-r--r-- | scripts/qemugdb/aio.py | 58 | ||||
-rw-r--r-- | scripts/qemugdb/coroutine.py | 90 |
21 files changed, 293 insertions, 116 deletions
@@ -216,6 +216,8 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs) /* Check if any requests are in-flight (including throttled requests) */ bool bdrv_requests_pending(BlockDriverState *bs) { + BdrvChild *child; + if (!QLIST_EMPTY(&bs->tracked_requests)) { return true; } @@ -225,12 +227,13 @@ bool bdrv_requests_pending(BlockDriverState *bs) if (!qemu_co_queue_empty(&bs->throttled_reqs[1])) { return true; } - if (bs->file && bdrv_requests_pending(bs->file->bs)) { - return true; - } - if (bs->backing && bdrv_requests_pending(bs->backing->bs)) { - return true; + + QLIST_FOREACH(child, &bs->children, next) { + if (bdrv_requests_pending(child->bs)) { + return true; + } } + return false; } diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index b36ca3d..87553bb 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -48,6 +48,14 @@ static const int uart_intr[XLNX_ZYNQMP_NUM_UARTS] = { 21, 22, }; +static const uint64_t sdhci_addr[XLNX_ZYNQMP_NUM_SDHCI] = { + 0xFF160000, 0xFF170000, +}; + +static const int sdhci_intr[XLNX_ZYNQMP_NUM_SDHCI] = { + 48, 49, +}; + typedef struct XlnxZynqMPGICRegion { int region_index; uint32_t address; @@ -97,6 +105,13 @@ static void xlnx_zynqmp_init(Object *obj) object_initialize(&s->sata, sizeof(s->sata), TYPE_SYSBUS_AHCI); qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default()); + + for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { + object_initialize(&s->sdhci[i], sizeof(s->sdhci[i]), + TYPE_SYSBUS_SDHCI); + qdev_set_parent_bus(DEVICE(&s->sdhci[i]), + sysbus_get_default()); + } } static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) @@ -258,6 +273,19 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, SATA_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]); + + for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { + object_property_set_bool(OBJECT(&s->sdhci[i]), true, + "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci[i]), 0, + sdhci_addr[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0, + gic_spi[sdhci_intr[i]]); + } } static Property xlnx_zynqmp_props[] = { diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 3e230de..093e475 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -798,6 +798,11 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) static void virtio_blk_save(QEMUFile *f, void *opaque) { VirtIODevice *vdev = VIRTIO_DEVICE(opaque); + VirtIOBlock *s = VIRTIO_BLK(vdev); + + if (s->dataplane) { + virtio_blk_data_plane_stop(s->dataplane); + } virtio_save(vdev, f); } @@ -972,7 +977,7 @@ static Property virtio_blk_properties[] = { DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial), DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true), #ifdef __linux__ - DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, true), + DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, false), #endif DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0, true), diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 288b57e..0ed8527 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2285,7 +2285,11 @@ static const TypeInfo spapr_machine_info = { }, }; +#define SPAPR_COMPAT_2_4 \ + HW_COMPAT_2_4 + #define SPAPR_COMPAT_2_3 \ + SPAPR_COMPAT_2_4 \ HW_COMPAT_2_3 \ {\ .driver = "spapr-pci-host-bridge",\ @@ -2399,11 +2403,16 @@ static const TypeInfo spapr_machine_2_3_info = { static void spapr_machine_2_4_class_init(ObjectClass *oc, void *data) { + static GlobalProperty compat_props[] = { + SPAPR_COMPAT_2_4 + { /* end of list */ } + }; MachineClass *mc = MACHINE_CLASS(oc); mc->desc = "pSeries Logical Partition (PAPR compliant) v2.4"; mc->alias = "pseries"; mc->is_default = 0; + mc->compat_props = compat_props; } static const TypeInfo spapr_machine_2_4_info = { diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index faba773..84221f4 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -20,6 +20,7 @@ #include "qemu/config-file.h" #include "s390-pci-bus.h" #include "hw/s390x/storage-keys.h" +#include "hw/compat.h" #define TYPE_S390_CCW_MACHINE "s390-ccw-machine" @@ -236,6 +237,7 @@ static const TypeInfo ccw_machine_info = { }; #define CCW_COMPAT_2_4 \ + HW_COMPAT_2_4 \ {\ .driver = TYPE_S390_SKEYS,\ .property = "migration-enabled",\ diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 46553e1..7655401 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -653,6 +653,11 @@ static void virtio_scsi_reset(VirtIODevice *vdev) static void virtio_scsi_save(QEMUFile *f, void *opaque) { VirtIODevice *vdev = VIRTIO_DEVICE(opaque); + VirtIOSCSI *s = VIRTIO_SCSI(vdev); + + if (s->dataplane_started) { + virtio_scsi_dataplane_stop(s); + } virtio_save(vdev, f); } diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index 2209ef1..b430d56 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -28,7 +28,7 @@ #include "qemu/error-report.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" -#include "hw/sd.h" +#include "hw/sd/sd.h" enum { ENABLE_CMD_TX = (1<<0), diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c index 35d8033..5bc4719 100644 --- a/hw/sd/omap_mmc.c +++ b/hw/sd/omap_mmc.c @@ -18,7 +18,7 @@ */ #include "hw/hw.h" #include "hw/arm/omap.h" -#include "hw/sd.h" +#include "hw/sd/sd.h" struct omap_mmc_s { qemu_irq irq; diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c index 5242176..326c53a 100644 --- a/hw/sd/pl181.c +++ b/hw/sd/pl181.c @@ -10,7 +10,7 @@ #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "hw/sysbus.h" -#include "hw/sd.h" +#include "hw/sd/sd.h" //#define DEBUG_PL181 1 diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index d1fe6d5..b2170800 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -12,7 +12,7 @@ #include "hw/hw.h" #include "hw/arm/pxa.h" -#include "hw/sd.h" +#include "hw/sd/sd.h" #include "hw/qdev.h" struct PXA2xxMMCIState { @@ -31,7 +31,7 @@ #include "hw/hw.h" #include "sysemu/block-backend.h" -#include "hw/sd.h" +#include "hw/sd/sd.h" #include "qemu/bitmap.h" //#define DEBUG_SD 1 diff --git a/hw/sd/sdhci.h b/hw/sd/sdhci-internal.h index e2de92d..c712daf 100644 --- a/hw/sd/sdhci.h +++ b/hw/sd/sdhci-internal.h @@ -21,15 +21,10 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#ifndef SDHCI_INTERNAL_H +#define SDHCI_INTERNAL_H -#ifndef SDHCI_H -#define SDHCI_H - -#include "qemu-common.h" -#include "hw/block/block.h" -#include "hw/pci/pci.h" -#include "hw/sysbus.h" -#include "hw/sd.h" +#include "hw/sd/sdhci.h" /* R/W SDMA System Address register 0x0 */ #define SDHC_SYSAD 0x00 @@ -232,66 +227,6 @@ enum { sdhc_gap_write = 2 /* SDHC stopped at block gap during write operation */ }; -/* SD/MMC host controller state */ -typedef struct SDHCIState { - union { - PCIDevice pcidev; - SysBusDevice busdev; - }; - SDState *card; - MemoryRegion iomem; - BlockConf conf; - - QEMUTimer *insert_timer; /* timer for 'changing' sd card. */ - QEMUTimer *transfer_timer; - qemu_irq eject_cb; - qemu_irq ro_cb; - qemu_irq irq; - - uint32_t sdmasysad; /* SDMA System Address register */ - uint16_t blksize; /* Host DMA Buff Boundary and Transfer BlkSize Reg */ - uint16_t blkcnt; /* Blocks count for current transfer */ - uint32_t argument; /* Command Argument Register */ - uint16_t trnmod; /* Transfer Mode Setting Register */ - uint16_t cmdreg; /* Command Register */ - uint32_t rspreg[4]; /* Response Registers 0-3 */ - uint32_t prnsts; /* Present State Register */ - uint8_t hostctl; /* Host Control Register */ - uint8_t pwrcon; /* Power control Register */ - uint8_t blkgap; /* Block Gap Control Register */ - uint8_t wakcon; /* WakeUp Control Register */ - uint16_t clkcon; /* Clock control Register */ - uint8_t timeoutcon; /* Timeout Control Register */ - uint8_t admaerr; /* ADMA Error Status Register */ - uint16_t norintsts; /* Normal Interrupt Status Register */ - uint16_t errintsts; /* Error Interrupt Status Register */ - uint16_t norintstsen; /* Normal Interrupt Status Enable Register */ - uint16_t errintstsen; /* Error Interrupt Status Enable Register */ - uint16_t norintsigen; /* Normal Interrupt Signal Enable Register */ - uint16_t errintsigen; /* Error Interrupt Signal Enable Register */ - uint16_t acmd12errsts; /* Auto CMD12 error status register */ - uint64_t admasysaddr; /* ADMA System Address Register */ - - uint32_t capareg; /* Capabilities Register */ - uint32_t maxcurr; /* Maximum Current Capabilities Register */ - uint8_t *fifo_buffer; /* SD host i/o FIFO buffer */ - uint32_t buf_maxsz; - uint16_t data_count; /* current element in FIFO buffer */ - uint8_t stopped_state;/* Current SDHC state */ - /* Buffer Data Port Register - virtual access point to R and W buffers */ - /* Software Reset Register - always reads as 0 */ - /* Force Event Auto CMD12 Error Interrupt Reg - write only */ - /* Force Event Error Interrupt Register- write only */ - /* RO Host Controller Version Register always reads as 0x2401 */ -} SDHCIState; - extern const VMStateDescription sdhci_vmstate; -#define TYPE_PCI_SDHCI "sdhci-pci" -#define PCI_SDHCI(obj) OBJECT_CHECK(SDHCIState, (obj), TYPE_PCI_SDHCI) - -#define TYPE_SYSBUS_SDHCI "generic-sdhci" -#define SYSBUS_SDHCI(obj) \ - OBJECT_CHECK(SDHCIState, (obj), TYPE_SYSBUS_SDHCI) - -#endif /* SDHCI_H */ +#endif diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 7f73527..d70d1a6 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -29,8 +29,7 @@ #include "sysemu/dma.h" #include "qemu/timer.h" #include "qemu/bitops.h" - -#include "sdhci.h" +#include "sdhci-internal.h" /* host controller debug messages */ #ifndef SDHC_DEBUG diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index e4b2d4f..c49ff62f 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -13,7 +13,7 @@ #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "hw/ssi.h" -#include "hw/sd.h" +#include "hw/sd/sd.h" //#define DEBUG_SSI_SD 1 diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h index 4005a99..d116092 100644 --- a/include/hw/arm/xlnx-zynqmp.h +++ b/include/hw/arm/xlnx-zynqmp.h @@ -24,6 +24,7 @@ #include "hw/char/cadence_uart.h" #include "hw/ide/pci.h" #include "hw/ide/ahci.h" +#include "hw/sd/sdhci.h" #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp" #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \ @@ -33,6 +34,7 @@ #define XLNX_ZYNQMP_NUM_RPU_CPUS 2 #define XLNX_ZYNQMP_NUM_GEMS 4 #define XLNX_ZYNQMP_NUM_UARTS 2 +#define XLNX_ZYNQMP_NUM_SDHCI 2 #define XLNX_ZYNQMP_NUM_OCM_BANKS 4 #define XLNX_ZYNQMP_OCM_RAM_0_ADDRESS 0xFFFC0000 @@ -63,6 +65,7 @@ typedef struct XlnxZynqMPState { CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS]; CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS]; SysbusAHCIState sata; + SDHCIState sdhci[XLNX_ZYNQMP_NUM_SDHCI]; char *boot_cpu; ARMCPU *boot_cpu_ptr; diff --git a/include/hw/compat.h b/include/hw/compat.h index 095de5d..93e71af 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -2,7 +2,11 @@ #define HW_COMPAT_H #define HW_COMPAT_2_4 \ - /* empty */ + {\ + .driver = "virtio-blk-device",\ + .property = "scsi",\ + .value = "true",\ + }, #define HW_COMPAT_2_3 \ {\ diff --git a/include/hw/sd.h b/include/hw/sd/sd.h index 79adb5b..79adb5b 100644 --- a/include/hw/sd.h +++ b/include/hw/sd/sd.h diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h new file mode 100644 index 0000000..9b3031f --- /dev/null +++ b/include/hw/sd/sdhci.h @@ -0,0 +1,94 @@ +/* + * SD Association Host Standard Specification v2.0 controller emulation + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Mitsyanko Igor <i.mitsyanko@samsung.com> + * Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com> + * + * Based on MMC controller for Samsung S5PC1xx-based board emulation + * by Alexey Merkulov and Vladimir Monakhov. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU _General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SDHCI_H +#define SDHCI_H + +#include "qemu-common.h" +#include "hw/block/block.h" +#include "hw/pci/pci.h" +#include "hw/sysbus.h" +#include "hw/sd/sd.h" + +/* SD/MMC host controller state */ +typedef struct SDHCIState { + union { + PCIDevice pcidev; + SysBusDevice busdev; + }; + SDState *card; + MemoryRegion iomem; + BlockConf conf; + + QEMUTimer *insert_timer; /* timer for 'changing' sd card. */ + QEMUTimer *transfer_timer; + qemu_irq eject_cb; + qemu_irq ro_cb; + qemu_irq irq; + + uint32_t sdmasysad; /* SDMA System Address register */ + uint16_t blksize; /* Host DMA Buff Boundary and Transfer BlkSize Reg */ + uint16_t blkcnt; /* Blocks count for current transfer */ + uint32_t argument; /* Command Argument Register */ + uint16_t trnmod; /* Transfer Mode Setting Register */ + uint16_t cmdreg; /* Command Register */ + uint32_t rspreg[4]; /* Response Registers 0-3 */ + uint32_t prnsts; /* Present State Register */ + uint8_t hostctl; /* Host Control Register */ + uint8_t pwrcon; /* Power control Register */ + uint8_t blkgap; /* Block Gap Control Register */ + uint8_t wakcon; /* WakeUp Control Register */ + uint16_t clkcon; /* Clock control Register */ + uint8_t timeoutcon; /* Timeout Control Register */ + uint8_t admaerr; /* ADMA Error Status Register */ + uint16_t norintsts; /* Normal Interrupt Status Register */ + uint16_t errintsts; /* Error Interrupt Status Register */ + uint16_t norintstsen; /* Normal Interrupt Status Enable Register */ + uint16_t errintstsen; /* Error Interrupt Status Enable Register */ + uint16_t norintsigen; /* Normal Interrupt Signal Enable Register */ + uint16_t errintsigen; /* Error Interrupt Signal Enable Register */ + uint16_t acmd12errsts; /* Auto CMD12 error status register */ + uint64_t admasysaddr; /* ADMA System Address Register */ + + uint32_t capareg; /* Capabilities Register */ + uint32_t maxcurr; /* Maximum Current Capabilities Register */ + uint8_t *fifo_buffer; /* SD host i/o FIFO buffer */ + uint32_t buf_maxsz; + uint16_t data_count; /* current element in FIFO buffer */ + uint8_t stopped_state;/* Current SDHC state */ + /* Buffer Data Port Register - virtual access point to R and W buffers */ + /* Software Reset Register - always reads as 0 */ + /* Force Event Auto CMD12 Error Interrupt Reg - write only */ + /* Force Event Error Interrupt Register- write only */ + /* RO Host Controller Version Register always reads as 0x2401 */ +} SDHCIState; + +#define TYPE_PCI_SDHCI "sdhci-pci" +#define PCI_SDHCI(obj) OBJECT_CHECK(SDHCIState, (obj), TYPE_PCI_SDHCI) + +#define TYPE_SYSBUS_SDHCI "generic-sdhci" +#define SYSBUS_SDHCI(obj) \ + OBJECT_CHECK(SDHCIState, (obj), TYPE_SYSBUS_SDHCI) + +#endif /* SDHCI_H */ diff --git a/scripts/qemu-gdb.py b/scripts/qemu-gdb.py index d6f2e5a..b3f8e04 100644 --- a/scripts/qemu-gdb.py +++ b/scripts/qemu-gdb.py @@ -26,7 +26,7 @@ import os, sys sys.path.append(os.path.dirname(__file__)) -from qemugdb import mtree, coroutine +from qemugdb import aio, mtree, coroutine class QemuCommand(gdb.Command): '''Prefix for QEMU debug support commands''' @@ -37,6 +37,10 @@ class QemuCommand(gdb.Command): QemuCommand() coroutine.CoroutineCommand() mtree.MtreeCommand() +aio.HandlersCommand() + +coroutine.CoroutineSPFunction() +coroutine.CoroutinePCFunction() # Default to silently passing through SIGUSR1, because QEMU sends it # to itself a lot. diff --git a/scripts/qemugdb/aio.py b/scripts/qemugdb/aio.py new file mode 100644 index 0000000..2ba00c4 --- /dev/null +++ b/scripts/qemugdb/aio.py @@ -0,0 +1,58 @@ +#!/usr/bin/python + +# GDB debugging support: aio/iohandler debug +# +# Copyright (c) 2015 Red Hat, Inc. +# +# Author: Dr. David Alan Gilbert <dgilbert@redhat.com> +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. +# + +import gdb +from qemugdb import coroutine + +def isnull(ptr): + return ptr == gdb.Value(0).cast(ptr.type) + +def dump_aiocontext(context, verbose): + '''Display a dump and backtrace for an aiocontext''' + cur = context['aio_handlers']['lh_first'] + # Get pointers to functions we're going to process specially + sym_fd_coroutine_enter = gdb.parse_and_eval('fd_coroutine_enter') + + while not isnull(cur): + entry = cur.dereference() + gdb.write('----\n%s\n' % entry) + if verbose and cur['io_read'] == sym_fd_coroutine_enter: + coptr = (cur['opaque'].cast(gdb.lookup_type('FDYieldUntilData').pointer()))['co'] + coptr = coptr.cast(gdb.lookup_type('CoroutineUContext').pointer()) + coroutine.bt_jmpbuf(coptr['env']['__jmpbuf']) + cur = cur['node']['le_next']; + + gdb.write('----\n') + +class HandlersCommand(gdb.Command): + '''Display aio handlers''' + def __init__(self): + gdb.Command.__init__(self, 'qemu handlers', gdb.COMMAND_DATA, + gdb.COMPLETE_NONE) + + def invoke(self, arg, from_tty): + verbose = False + argv = gdb.string_to_argv(arg) + + if len(argv) > 0 and argv[0] == '--verbose': + verbose = True + argv.pop(0) + + if len(argv) > 1: + gdb.write('usage: qemu handlers [--verbose] [handler]\n') + return + + if len(argv) == 1: + handlers_name = argv[0] + else: + handlers_name = 'qemu_aio_context' + dump_aiocontext(gdb.parse_and_eval(handlers_name), verbose) diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py index 3c54918..ab69979 100644 --- a/scripts/qemugdb/coroutine.py +++ b/scripts/qemugdb/coroutine.py @@ -15,8 +15,11 @@ import gdb +VOID_PTR = gdb.lookup_type('void').pointer() + def get_fs_base(): - '''Fetch %fs base value using arch_prctl(ARCH_GET_FS)''' + '''Fetch %fs base value using arch_prctl(ARCH_GET_FS). This is + pthread_self().''' # %rsp - 120 is scratch space according to the SystemV ABI old = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)') gdb.execute('call arch_prctl(0x1003, $rsp - 120)', False, True) @@ -24,17 +27,29 @@ def get_fs_base(): gdb.execute('set *(uint64_t*)($rsp - 120) = %s' % old, False, True) return fs_base +def pthread_self(): + '''Fetch pthread_self() from the glibc start_thread function.''' + f = gdb.newest_frame() + while f.name() != 'start_thread': + f = f.older() + if f is None: + return get_fs_base() + + try: + return f.read_var("arg") + except ValueError: + return get_fs_base() + def get_glibc_pointer_guard(): '''Fetch glibc pointer guard value''' - fs_base = get_fs_base() + fs_base = pthread_self() return gdb.parse_and_eval('*(uint64_t*)((uint64_t)%s + 0x30)' % fs_base) def glibc_ptr_demangle(val, pointer_guard): '''Undo effect of glibc's PTR_MANGLE()''' return gdb.parse_and_eval('(((uint64_t)%s >> 0x11) | ((uint64_t)%s << (64 - 0x11))) ^ (uint64_t)%s' % (val, val, pointer_guard)) -def bt_jmpbuf(jmpbuf): - '''Backtrace a jmpbuf''' +def get_jmpbuf_regs(jmpbuf): JB_RBX = 0 JB_RBP = 1 JB_R12 = 2 @@ -44,35 +59,35 @@ def bt_jmpbuf(jmpbuf): JB_RSP = 6 JB_PC = 7 - old_rbx = gdb.parse_and_eval('(uint64_t)$rbx') - old_rbp = gdb.parse_and_eval('(uint64_t)$rbp') - old_rsp = gdb.parse_and_eval('(uint64_t)$rsp') - old_r12 = gdb.parse_and_eval('(uint64_t)$r12') - old_r13 = gdb.parse_and_eval('(uint64_t)$r13') - old_r14 = gdb.parse_and_eval('(uint64_t)$r14') - old_r15 = gdb.parse_and_eval('(uint64_t)$r15') - old_rip = gdb.parse_and_eval('(uint64_t)$rip') - pointer_guard = get_glibc_pointer_guard() - gdb.execute('set $rbx = %s' % jmpbuf[JB_RBX]) - gdb.execute('set $rbp = %s' % glibc_ptr_demangle(jmpbuf[JB_RBP], pointer_guard)) - gdb.execute('set $rsp = %s' % glibc_ptr_demangle(jmpbuf[JB_RSP], pointer_guard)) - gdb.execute('set $r12 = %s' % jmpbuf[JB_R12]) - gdb.execute('set $r13 = %s' % jmpbuf[JB_R13]) - gdb.execute('set $r14 = %s' % jmpbuf[JB_R14]) - gdb.execute('set $r15 = %s' % jmpbuf[JB_R15]) - gdb.execute('set $rip = %s' % glibc_ptr_demangle(jmpbuf[JB_PC], pointer_guard)) + return {'rbx': jmpbuf[JB_RBX], + 'rbp': glibc_ptr_demangle(jmpbuf[JB_RBP], pointer_guard), + 'rsp': glibc_ptr_demangle(jmpbuf[JB_RSP], pointer_guard), + 'r12': jmpbuf[JB_R12], + 'r13': jmpbuf[JB_R13], + 'r14': jmpbuf[JB_R14], + 'r15': jmpbuf[JB_R15], + 'rip': glibc_ptr_demangle(jmpbuf[JB_PC], pointer_guard) } + +def bt_jmpbuf(jmpbuf): + '''Backtrace a jmpbuf''' + regs = get_jmpbuf_regs(jmpbuf) + old = dict() + + for i in regs: + old[i] = gdb.parse_and_eval('(uint64_t)$%s' % i) + + for i in regs: + gdb.execute('set $%s = %s' % (i, regs[i])) gdb.execute('bt') - gdb.execute('set $rbx = %s' % old_rbx) - gdb.execute('set $rbp = %s' % old_rbp) - gdb.execute('set $rsp = %s' % old_rsp) - gdb.execute('set $r12 = %s' % old_r12) - gdb.execute('set $r13 = %s' % old_r13) - gdb.execute('set $r14 = %s' % old_r14) - gdb.execute('set $r15 = %s' % old_r15) - gdb.execute('set $rip = %s' % old_rip) + for i in regs: + gdb.execute('set $%s = %s' % (i, old[i])) + +def coroutine_to_jmpbuf(co): + coroutine_pointer = co.cast(gdb.lookup_type('CoroutineUContext').pointer()) + return coroutine_pointer['env']['__jmpbuf'] class CoroutineCommand(gdb.Command): @@ -87,5 +102,18 @@ class CoroutineCommand(gdb.Command): gdb.write('usage: qemu coroutine <coroutine-pointer>\n') return - coroutine_pointer = gdb.parse_and_eval(argv[0]).cast(gdb.lookup_type('CoroutineUContext').pointer()) - bt_jmpbuf(coroutine_pointer['env']['__jmpbuf']) + bt_jmpbuf(coroutine_to_jmpbuf(gdb.parse_and_eval(argv[0]))) + +class CoroutineSPFunction(gdb.Function): + def __init__(self): + gdb.Function.__init__(self, 'qemu_coroutine_sp') + + def invoke(self, addr): + return get_jmpbuf_regs(coroutine_to_jmpbuf(addr))['rsp'].cast(VOID_PTR) + +class CoroutinePCFunction(gdb.Function): + def __init__(self): + gdb.Function.__init__(self, 'qemu_coroutine_pc') + + def invoke(self, addr): + return get_jmpbuf_regs(coroutine_to_jmpbuf(addr))['rip'].cast(VOID_PTR) |