qemu/scripts/replay-dump.py
<<
>>
Prefs
   1#!/usr/bin/env python
   2# -*- coding: utf-8 -*-
   3#
   4# Dump the contents of a recorded execution stream
   5#
   6#  Copyright (c) 2017 Alex Bennée <alex.bennee@linaro.org>
   7#
   8# This library is free software; you can redistribute it and/or
   9# modify it under the terms of the GNU Lesser General Public
  10# License as published by the Free Software Foundation; either
  11# version 2 of the License, or (at your option) any later version.
  12#
  13# This library is distributed in the hope that it will be useful,
  14# but WITHOUT ANY WARRANTY; without even the implied warranty of
  15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16# Lesser General Public License for more details.
  17#
  18# You should have received a copy of the GNU Lesser General Public
  19# License along with this library; if not, see <http://www.gnu.org/licenses/>.
  20
  21from __future__ import print_function
  22import argparse
  23import struct
  24from collections import namedtuple
  25
  26# This mirrors some of the global replay state which some of the
  27# stream loading refers to. Some decoders may read the next event so
  28# we need handle that case. Calling reuse_event will ensure the next
  29# event is read from the cache rather than advancing the file.
  30
  31class ReplayState(object):
  32    def __init__(self):
  33        self.event = -1
  34        self.event_count = 0
  35        self.already_read = False
  36        self.current_checkpoint = 0
  37        self.checkpoint = 0
  38
  39    def set_event(self, ev):
  40        self.event = ev
  41        self.event_count += 1
  42
  43    def get_event(self):
  44        self.already_read = False
  45        return self.event
  46
  47    def reuse_event(self, ev):
  48        self.event = ev
  49        self.already_read = True
  50
  51    def set_checkpoint(self):
  52        self.checkpoint = self.event - self.checkpoint_start
  53
  54    def get_checkpoint(self):
  55        return self.checkpoint
  56
  57replay_state = ReplayState()
  58
  59# Simple read functions that mirror replay-internal.c
  60# The file-stream is big-endian and manually written out a byte at a time.
  61
  62def read_byte(fin):
  63    "Read a single byte"
  64    return struct.unpack('>B', fin.read(1))[0]
  65
  66def read_event(fin):
  67    "Read a single byte event, but save some state"
  68    if replay_state.already_read:
  69        return replay_state.get_event()
  70    else:
  71        replay_state.set_event(read_byte(fin))
  72        return replay_state.event
  73
  74def read_word(fin):
  75    "Read a 16 bit word"
  76    return struct.unpack('>H', fin.read(2))[0]
  77
  78def read_dword(fin):
  79    "Read a 32 bit word"
  80    return struct.unpack('>I', fin.read(4))[0]
  81
  82def read_qword(fin):
  83    "Read a 64 bit word"
  84    return struct.unpack('>Q', fin.read(8))[0]
  85
  86# Generic decoder structure
  87Decoder = namedtuple("Decoder", "eid name fn")
  88
  89def call_decode(table, index, dumpfile):
  90    "Search decode table for next step"
  91    decoder = next((d for d in table if d.eid == index), None)
  92    if not decoder:
  93        print("Could not decode index: %d" % (index))
  94        print("Entry is: %s" % (decoder))
  95        print("Decode Table is:\n%s" % (table))
  96        return False
  97    else:
  98        return decoder.fn(decoder.eid, decoder.name, dumpfile)
  99
 100# Print event
 101def print_event(eid, name, string=None, event_count=None):
 102    "Print event with count"
 103    if not event_count:
 104        event_count = replay_state.event_count
 105
 106    if string:
 107        print("%d:%s(%d) %s" % (event_count, name, eid, string))
 108    else:
 109        print("%d:%s(%d)" % (event_count, name, eid))
 110
 111
 112# Decoders for each event type
 113
 114def decode_unimp(eid, name, _unused_dumpfile):
 115    "Unimplimented decoder, will trigger exit"
 116    print("%s not handled - will now stop" % (name))
 117    return False
 118
 119# Checkpoint decoder
 120def swallow_async_qword(eid, name, dumpfile):
 121    "Swallow a qword of data without looking at it"
 122    step_id = read_qword(dumpfile)
 123    print("  %s(%d) @ %d" % (name, eid, step_id))
 124    return True
 125
 126async_decode_table = [ Decoder(0, "REPLAY_ASYNC_EVENT_BH", swallow_async_qword),
 127                       Decoder(1, "REPLAY_ASYNC_INPUT", decode_unimp),
 128                       Decoder(2, "REPLAY_ASYNC_INPUT_SYNC", decode_unimp),
 129                       Decoder(3, "REPLAY_ASYNC_CHAR_READ", decode_unimp),
 130                       Decoder(4, "REPLAY_ASYNC_EVENT_BLOCK", decode_unimp),
 131                       Decoder(5, "REPLAY_ASYNC_EVENT_NET", decode_unimp),
 132]
 133# See replay_read_events/replay_read_event
 134def decode_async(eid, name, dumpfile):
 135    """Decode an ASYNC event"""
 136
 137    print_event(eid, name)
 138
 139    async_event_kind = read_byte(dumpfile)
 140    async_event_checkpoint = read_byte(dumpfile)
 141
 142    if async_event_checkpoint != replay_state.current_checkpoint:
 143        print("  mismatch between checkpoint %d and async data %d" % (
 144            replay_state.current_checkpoint, async_event_checkpoint))
 145        return True
 146
 147    return call_decode(async_decode_table, async_event_kind, dumpfile)
 148
 149
 150def decode_instruction(eid, name, dumpfile):
 151    ins_diff = read_dword(dumpfile)
 152    print_event(eid, name, "0x%x" % (ins_diff))
 153    return True
 154
 155def decode_audio_out(eid, name, dumpfile):
 156    audio_data = read_dword(dumpfile)
 157    print_event(eid, name, "%d" % (audio_data))
 158    return True
 159
 160def decode_checkpoint(eid, name, dumpfile):
 161    """Decode a checkpoint.
 162
 163    Checkpoints contain a series of async events with their own specific data.
 164    """
 165    replay_state.set_checkpoint()
 166    # save event count as we peek ahead
 167    event_number = replay_state.event_count
 168    next_event = read_event(dumpfile)
 169
 170    # if the next event is EVENT_ASYNC there are a bunch of
 171    # async events to read, otherwise we are done
 172    if next_event != 3:
 173        print_event(eid, name, "no additional data", event_number)
 174    else:
 175        print_event(eid, name, "more data follows", event_number)
 176
 177    replay_state.reuse_event(next_event)
 178    return True
 179
 180def decode_checkpoint_init(eid, name, dumpfile):
 181    print_event(eid, name)
 182    return True
 183
 184def decode_interrupt(eid, name, dumpfile):
 185    print_event(eid, name)
 186    return True
 187
 188def decode_clock(eid, name, dumpfile):
 189    clock_data = read_qword(dumpfile)
 190    print_event(eid, name, "0x%x" % (clock_data))
 191    return True
 192
 193
 194# pre-MTTCG merge
 195v5_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
 196                  Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
 197                  Decoder(2, "EVENT_EXCEPTION", decode_unimp),
 198                  Decoder(3, "EVENT_ASYNC", decode_async),
 199                  Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
 200                  Decoder(5, "EVENT_CHAR_WRITE", decode_unimp),
 201                  Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
 202                  Decoder(7, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
 203                  Decoder(8, "EVENT_CLOCK_HOST", decode_clock),
 204                  Decoder(9, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
 205                  Decoder(10, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint),
 206                  Decoder(11, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint),
 207                  Decoder(12, "EVENT_CP_RESET_REQUESTED", decode_checkpoint),
 208                  Decoder(13, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint),
 209                  Decoder(14, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint),
 210                  Decoder(15, "EVENT_CP_CLOCK_HOST", decode_checkpoint),
 211                  Decoder(16, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
 212                  Decoder(17, "EVENT_CP_INIT", decode_checkpoint_init),
 213                  Decoder(18, "EVENT_CP_RESET", decode_checkpoint),
 214]
 215
 216# post-MTTCG merge, AUDIO support added
 217v6_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
 218                  Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
 219                  Decoder(2, "EVENT_EXCEPTION", decode_unimp),
 220                  Decoder(3, "EVENT_ASYNC", decode_async),
 221                  Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
 222                  Decoder(5, "EVENT_CHAR_WRITE", decode_unimp),
 223                  Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
 224                  Decoder(7, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
 225                  Decoder(8, "EVENT_AUDIO_OUT", decode_audio_out),
 226                  Decoder(9, "EVENT_AUDIO_IN", decode_unimp),
 227                  Decoder(10, "EVENT_CLOCK_HOST", decode_clock),
 228                  Decoder(11, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
 229                  Decoder(12, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint),
 230                  Decoder(13, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint),
 231                  Decoder(14, "EVENT_CP_RESET_REQUESTED", decode_checkpoint),
 232                  Decoder(15, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint),
 233                  Decoder(16, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint),
 234                  Decoder(17, "EVENT_CP_CLOCK_HOST", decode_checkpoint),
 235                  Decoder(18, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
 236                  Decoder(19, "EVENT_CP_INIT", decode_checkpoint_init),
 237                  Decoder(20, "EVENT_CP_RESET", decode_checkpoint),
 238]
 239
 240# Shutdown cause added
 241v7_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
 242                  Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
 243                  Decoder(2, "EVENT_EXCEPTION", decode_unimp),
 244                  Decoder(3, "EVENT_ASYNC", decode_async),
 245                  Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
 246                  Decoder(5, "EVENT_SHUTDOWN_HOST_ERR", decode_unimp),
 247                  Decoder(6, "EVENT_SHUTDOWN_HOST_QMP", decode_unimp),
 248                  Decoder(7, "EVENT_SHUTDOWN_HOST_SIGNAL", decode_unimp),
 249                  Decoder(8, "EVENT_SHUTDOWN_HOST_UI", decode_unimp),
 250                  Decoder(9, "EVENT_SHUTDOWN_GUEST_SHUTDOWN", decode_unimp),
 251                  Decoder(10, "EVENT_SHUTDOWN_GUEST_RESET", decode_unimp),
 252                  Decoder(11, "EVENT_SHUTDOWN_GUEST_PANIC", decode_unimp),
 253                  Decoder(12, "EVENT_SHUTDOWN___MAX", decode_unimp),
 254                  Decoder(13, "EVENT_CHAR_WRITE", decode_unimp),
 255                  Decoder(14, "EVENT_CHAR_READ_ALL", decode_unimp),
 256                  Decoder(15, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
 257                  Decoder(16, "EVENT_AUDIO_OUT", decode_audio_out),
 258                  Decoder(17, "EVENT_AUDIO_IN", decode_unimp),
 259                  Decoder(18, "EVENT_CLOCK_HOST", decode_clock),
 260                  Decoder(19, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
 261                  Decoder(20, "EVENT_CP_CLOCK_WARP_START", decode_checkpoint),
 262                  Decoder(21, "EVENT_CP_CLOCK_WARP_ACCOUNT", decode_checkpoint),
 263                  Decoder(22, "EVENT_CP_RESET_REQUESTED", decode_checkpoint),
 264                  Decoder(23, "EVENT_CP_SUSPEND_REQUESTED", decode_checkpoint),
 265                  Decoder(24, "EVENT_CP_CLOCK_VIRTUAL", decode_checkpoint),
 266                  Decoder(25, "EVENT_CP_CLOCK_HOST", decode_checkpoint),
 267                  Decoder(26, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
 268                  Decoder(27, "EVENT_CP_INIT", decode_checkpoint_init),
 269                  Decoder(28, "EVENT_CP_RESET", decode_checkpoint),
 270]
 271
 272def parse_arguments():
 273    "Grab arguments for script"
 274    parser = argparse.ArgumentParser()
 275    parser.add_argument("-f", "--file", help='record/replay dump to read from',
 276                        required=True)
 277    return parser.parse_args()
 278
 279def decode_file(filename):
 280    "Decode a record/replay dump"
 281    dumpfile = open(filename, "rb")
 282
 283    # read and throwaway the header
 284    version = read_dword(dumpfile)
 285    junk = read_qword(dumpfile)
 286
 287    print("HEADER: version 0x%x" % (version))
 288
 289    if version == 0xe02007:
 290        event_decode_table = v7_event_table
 291        replay_state.checkpoint_start = 12
 292    elif version == 0xe02006:
 293        event_decode_table = v6_event_table
 294        replay_state.checkpoint_start = 12
 295    else:
 296        event_decode_table = v5_event_table
 297        replay_state.checkpoint_start = 10
 298
 299    try:
 300        decode_ok = True
 301        while decode_ok:
 302            event = read_event(dumpfile)
 303            decode_ok = call_decode(event_decode_table, event, dumpfile)
 304    finally:
 305        dumpfile.close()
 306
 307if __name__ == "__main__":
 308    args = parse_arguments()
 309    decode_file(args.file)
 310