-----BEGIN PGP SIGNATURE-----

Version: GnuPG v1
 
 iQEcBAABAgAGBQJWMmDMAAoJEJykq7OBq3PIHkIIAKyL9iY4EipKrtdMoWZu/Kfm
 I9g4NVVqPF4QmTfYpZVxWglvBy0g0+2p1h4DQ5KheUNr7DV2uchSSsN38MWnEgH/
 XTRpY858jcWx4sSAvYpz+kUVRBEtJJL8a/1aTBvYRxcbNE1X1lm72m7mm4KXGGud
 PZ0fdj/UODHeoTOnMHddbs8Rs0kdHhlckl2Mfkz2dUgYAuZMK7xR7OIE7kOqWBcR
 p5/I1Jq3wgmp267ZPVNS17u8Cff2PIElv0Z3Ouubixhhf+k5kvLBtgTbTJ81h7/4
 NfmIRwsmAPhtnDSDXqFJ8KgwUYpGYYtPrK8DIXIWYwPdSjkIIdl1gNtc2CGyV3w=
 =nA50
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging

# gpg: Signature made Thu 29 Oct 2015 18:09:16 GMT using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"

* remotes/stefanha/tags/block-pull-request:
  block: Consider all child nodes in bdrv_requests_pending()
  target-arm: xlnx-zynqmp: Add sdhci support.
  sdhci: Split sdhci.h for public and internal device usage
  sd.h: Move sd.h to include/hw/sd/
  virtio: sync the dataplane vring state to the virtqueue before virtio_save
  gdb command: qemu handlers
  virtio-blk: switch off scsi-passthrough by default
  ppc/spapr: add 2.4 compat props
  s390x: include HW_COMPAT_* props
  qemu-gdb: add $qemu_coroutine_sp and $qemu_coroutine_pc
  qemu-gdb: extract parts of "qemu coroutine" implementation
  qemu-gdb: allow using glibc_pointer_guard() on core dumps

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-10-30 19:47:47 +00:00
commit 3a958f559e
21 changed files with 293 additions and 116 deletions

View File

@ -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;
}

View File

@ -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[] = {

View File

@ -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),

View File

@ -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 = {

View File

@ -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",\

View File

@ -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);
}

View File

@ -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),

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 \
{\

94
include/hw/sd/sdhci.h Normal file
View File

@ -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 */

View File

@ -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.

58
scripts/qemugdb/aio.py Normal file
View File

@ -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)

View File

@ -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)