diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-04-28 16:55:03 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-04-28 16:55:03 +0100 |
commit | a9392bc93c8615ad1983047e9f91ee3fa8aae75f (patch) | |
tree | 0ff3fbb6401aa0addbbda6900ce4b984b0c1d2a3 /scripts | |
parent | 84cbd63f87c1d246f51ec8eee5367a5588f367fd (diff) | |
parent | 61007b316cd71ee7333ff7a0a749a8949527575f (diff) |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block patches
# gpg: Signature made Tue Apr 28 15:35:05 2015 BST using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"
* remotes/kevin/tags/for-upstream: (76 commits)
block: move I/O request processing to block/io.c
block: extract bdrv_setup_io_funcs()
block: add bdrv_set_dirty()/bdrv_reset_dirty() to block_int.h
block: replace bdrv_states iteration with bdrv_next()
vmdk: Widen before shifting 32 bit header field
block/dmg: make it modular
block/mirror: Always call block_job_sleep_ns()
iotests: add incremental backup granularity tests
iotests: add incremental backup failure recovery test
iotests: add simple incremental backup case
iotests: add QMP event waiting queue
iotests: add invalid input incremental backup tests
hbitmap: truncate tests
block: Resize bitmaps on bdrv_truncate
block: Ensure consistent bitmap function prototypes
block: add BdrvDirtyBitmap documentation
qmp: Add dirty bitmap status field in query-block
qmp: add block-dirty-bitmap-clear
qmp: Add support of "dirty-bitmap" sync mode for drive-backup
block: Add bitmap successors
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/checkpatch.pl | 11 | ||||
-rw-r--r-- | scripts/qemu-gdb.py | 75 | ||||
-rw-r--r-- | scripts/qmp/qmp.py | 95 |
3 files changed, 151 insertions, 30 deletions
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 5df61f9aa9..7f0aae977d 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2911,6 +2911,17 @@ sub process { if ($rawline =~ /\b(?:Qemu|QEmu)\b/) { WARN("use QEMU instead of Qemu or QEmu\n" . $herecurr); } + +# check for non-portable ffs() calls that have portable alternatives in QEMU + if ($line =~ /\bffs\(/) { + ERROR("use ctz32() instead of ffs()\n" . $herecurr); + } + if ($line =~ /\bffsl\(/) { + ERROR("use ctz32() or ctz64() instead of ffsl()\n" . $herecurr); + } + if ($line =~ /\bffsll\(/) { + ERROR("use ctz64() instead of ffsll()\n" . $herecurr); + } } # If we have no input at all, then there is nothing to report on diff --git a/scripts/qemu-gdb.py b/scripts/qemu-gdb.py index 8a0f30534f..6c7f4fbe53 100644 --- a/scripts/qemu-gdb.py +++ b/scripts/qemu-gdb.py @@ -22,12 +22,86 @@ def isnull(ptr): def int128(p): return long(p['lo']) + (long(p['hi']) << 64) +def get_fs_base(): + '''Fetch %fs base value using arch_prctl(ARCH_GET_FS)''' + # %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) + fs_base = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)') + gdb.execute('set *(uint64_t*)($rsp - 120) = %s' % old, False, True) + return fs_base + +def get_glibc_pointer_guard(): + '''Fetch glibc pointer guard value''' + fs_base = get_fs_base() + 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''' + JB_RBX = 0 + JB_RBP = 1 + JB_R12 = 2 + JB_R13 = 3 + JB_R14 = 4 + JB_R15 = 5 + 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)) + + 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) + class QemuCommand(gdb.Command): '''Prefix for QEMU debug support commands''' def __init__(self): gdb.Command.__init__(self, 'qemu', gdb.COMMAND_DATA, gdb.COMPLETE_NONE, True) +class CoroutineCommand(gdb.Command): + '''Display coroutine backtrace''' + def __init__(self): + gdb.Command.__init__(self, 'qemu coroutine', gdb.COMMAND_DATA, + gdb.COMPLETE_NONE) + + def invoke(self, arg, from_tty): + argv = gdb.string_to_argv(arg) + if len(argv) != 1: + 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']) + class MtreeCommand(gdb.Command): '''Display the memory tree hierarchy''' def __init__(self): @@ -86,4 +160,5 @@ class MtreeCommand(gdb.Command): subregion = subregion['subregions_link']['tqe_next'] QemuCommand() +CoroutineCommand() MtreeCommand() diff --git a/scripts/qmp/qmp.py b/scripts/qmp/qmp.py index 20b6ec795e..1d38e3e9e7 100644 --- a/scripts/qmp/qmp.py +++ b/scripts/qmp/qmp.py @@ -21,6 +21,9 @@ class QMPConnectError(QMPError): class QMPCapabilitiesError(QMPError): pass +class QMPTimeoutError(QMPError): + pass + class QEMUMonitorProtocol: def __init__(self, address, server=False): """ @@ -72,6 +75,44 @@ class QEMUMonitorProtocol: error = socket.error + def __get_events(self, wait=False): + """ + Check for new events in the stream and cache them in __events. + + @param wait (bool): block until an event is available. + @param wait (float): If wait is a float, treat it as a timeout value. + + @raise QMPTimeoutError: If a timeout float is provided and the timeout + period elapses. + @raise QMPConnectError: If wait is True but no events could be retrieved + or if some other error occurred. + """ + + # Check for new events regardless and pull them into the cache: + self.__sock.setblocking(0) + try: + self.__json_read() + except socket.error, err: + if err[0] == errno.EAGAIN: + # No data available + pass + self.__sock.setblocking(1) + + # Wait for new events, if needed. + # if wait is 0.0, this means "no wait" and is also implicitly false. + if not self.__events and wait: + if isinstance(wait, float): + self.__sock.settimeout(wait) + try: + ret = self.__json_read(only_event=True) + except socket.timeout: + raise QMPTimeoutError("Timeout waiting for event") + except: + raise QMPConnectError("Error while reading from socket") + if ret is None: + raise QMPConnectError("Error while reading from socket") + self.__sock.settimeout(None) + def connect(self, negotiate=True): """ Connect to the QMP Monitor and perform capabilities negotiation. @@ -140,43 +181,37 @@ class QEMUMonitorProtocol: """ Get and delete the first available QMP event. - @param wait: block until an event is available (bool) + @param wait (bool): block until an event is available. + @param wait (float): If wait is a float, treat it as a timeout value. + + @raise QMPTimeoutError: If a timeout float is provided and the timeout + period elapses. + @raise QMPConnectError: If wait is True but no events could be retrieved + or if some other error occurred. + + @return The first available QMP event, or None. """ - self.__sock.setblocking(0) - try: - self.__json_read() - except socket.error, err: - if err[0] == errno.EAGAIN: - # No data available - pass - self.__sock.setblocking(1) - if not self.__events and wait: - self.__json_read(only_event=True) - event = self.__events[0] - del self.__events[0] - return event + self.__get_events(wait) + + if self.__events: + return self.__events.pop(0) + return None def get_events(self, wait=False): """ Get a list of available QMP events. - @param wait: block until an event is available (bool) - """ - self.__sock.setblocking(0) - try: - self.__json_read() - except socket.error, err: - if err[0] == errno.EAGAIN: - # No data available - pass - self.__sock.setblocking(1) - if not self.__events and wait: - ret = self.__json_read(only_event=True) - if ret == None: - # We are in blocking mode, if don't get anything, something - # went wrong - raise QMPConnectError("Error while reading from socket") + @param wait (bool): block until an event is available. + @param wait (float): If wait is a float, treat it as a timeout value. + @raise QMPTimeoutError: If a timeout float is provided and the timeout + period elapses. + @raise QMPConnectError: If wait is True but no events could be retrieved + or if some other error occurred. + + @return The list of available QMP events. + """ + self.__get_events(wait) return self.__events def clear_events(self): |