diff options
author | 2017-04-25 03:31:15 -0700 | |
---|---|---|
committer | 2017-05-22 06:48:08 +0000 | |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/scripts | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/scripts')
79 files changed, 0 insertions, 17460 deletions
diff --git a/qemu/scripts/analyse-9p-simpletrace.py b/qemu/scripts/analyse-9p-simpletrace.py deleted file mode 100755 index 3c3dee433..000000000 --- a/qemu/scripts/analyse-9p-simpletrace.py +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/env python -# Pretty print 9p simpletrace log -# Usage: ./analyse-9p-simpletrace <trace-events> <trace-pid> -# -# Author: Harsh Prateek Bora -import os -import simpletrace - -symbol_9p = { - 6 : 'TLERROR', - 7 : 'RLERROR', - 8 : 'TSTATFS', - 9 : 'RSTATFS', - 12 : 'TLOPEN', - 13 : 'RLOPEN', - 14 : 'TLCREATE', - 15 : 'RLCREATE', - 16 : 'TSYMLINK', - 17 : 'RSYMLINK', - 18 : 'TMKNOD', - 19 : 'RMKNOD', - 20 : 'TRENAME', - 21 : 'RRENAME', - 22 : 'TREADLINK', - 23 : 'RREADLINK', - 24 : 'TGETATTR', - 25 : 'RGETATTR', - 26 : 'TSETATTR', - 27 : 'RSETATTR', - 30 : 'TXATTRWALK', - 31 : 'RXATTRWALK', - 32 : 'TXATTRCREATE', - 33 : 'RXATTRCREATE', - 40 : 'TREADDIR', - 41 : 'RREADDIR', - 50 : 'TFSYNC', - 51 : 'RFSYNC', - 52 : 'TLOCK', - 53 : 'RLOCK', - 54 : 'TGETLOCK', - 55 : 'RGETLOCK', - 70 : 'TLINK', - 71 : 'RLINK', - 72 : 'TMKDIR', - 73 : 'RMKDIR', - 74 : 'TRENAMEAT', - 75 : 'RRENAMEAT', - 76 : 'TUNLINKAT', - 77 : 'RUNLINKAT', - 100 : 'TVERSION', - 101 : 'RVERSION', - 102 : 'TAUTH', - 103 : 'RAUTH', - 104 : 'TATTACH', - 105 : 'RATTACH', - 106 : 'TERROR', - 107 : 'RERROR', - 108 : 'TFLUSH', - 109 : 'RFLUSH', - 110 : 'TWALK', - 111 : 'RWALK', - 112 : 'TOPEN', - 113 : 'ROPEN', - 114 : 'TCREATE', - 115 : 'RCREATE', - 116 : 'TREAD', - 117 : 'RREAD', - 118 : 'TWRITE', - 119 : 'RWRITE', - 120 : 'TCLUNK', - 121 : 'RCLUNK', - 122 : 'TREMOVE', - 123 : 'RREMOVE', - 124 : 'TSTAT', - 125 : 'RSTAT', - 126 : 'TWSTAT', - 127 : 'RWSTAT' -} - -class VirtFSRequestTracker(simpletrace.Analyzer): - def begin(self): - print "Pretty printing 9p simpletrace log ..." - - def v9fs_rerror(self, tag, id, err): - print "RERROR (tag =", tag, ", id =", symbol_9p[id], ", err = \"", os.strerror(err), "\")" - - def v9fs_version(self, tag, id, msize, version): - print "TVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")" - - def v9fs_version_return(self, tag, id, msize, version): - print "RVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")" - - def v9fs_attach(self, tag, id, fid, afid, uname, aname): - print "TATTACH (tag =", tag, ", fid =", fid, ", afid =", afid, ", uname =", uname, ", aname =", aname, ")" - - def v9fs_attach_return(self, tag, id, type, version, path): - print "RATTACH (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})" - - def v9fs_stat(self, tag, id, fid): - print "TSTAT (tag =", tag, ", fid =", fid, ")" - - def v9fs_stat_return(self, tag, id, mode, atime, mtime, length): - print "RSTAT (tag =", tag, ", mode =", mode, ", atime =", atime, ", mtime =", mtime, ", length =", length, ")" - - def v9fs_getattr(self, tag, id, fid, request_mask): - print "TGETATTR (tag =", tag, ", fid =", fid, ", request_mask =", hex(request_mask), ")" - - def v9fs_getattr_return(self, tag, id, result_mask, mode, uid, gid): - print "RGETATTR (tag =", tag, ", result_mask =", hex(result_mask), ", mode =", oct(mode), ", uid =", uid, ", gid =", gid, ")" - - def v9fs_walk(self, tag, id, fid, newfid, nwnames): - print "TWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", nwnames =", nwnames, ")" - - def v9fs_walk_return(self, tag, id, nwnames, qids): - print "RWALK (tag =", tag, ", nwnames =", nwnames, ", qids =", hex(qids), ")" - - def v9fs_open(self, tag, id, fid, mode): - print "TOPEN (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ")" - - def v9fs_open_return(self, tag, id, type, version, path, iounit): - print "ROPEN (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")" - - def v9fs_lcreate(self, tag, id, dfid, flags, mode, gid): - print "TLCREATE (tag =", tag, ", dfid =", dfid, ", flags =", oct(flags), ", mode =", oct(mode), ", gid =", gid, ")" - - def v9fs_lcreate_return(self, tag, id, type, version, path, iounit): - print "RLCREATE (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")" - - def v9fs_fsync(self, tag, id, fid, datasync): - print "TFSYNC (tag =", tag, ", fid =", fid, ", datasync =", datasync, ")" - - def v9fs_clunk(self, tag, id, fid): - print "TCLUNK (tag =", tag, ", fid =", fid, ")" - - def v9fs_read(self, tag, id, fid, off, max_count): - print "TREAD (tag =", tag, ", fid =", fid, ", off =", off, ", max_count =", max_count, ")" - - def v9fs_read_return(self, tag, id, count, err): - print "RREAD (tag =", tag, ", count =", count, ", err =", err, ")" - - def v9fs_readdir(self, tag, id, fid, offset, max_count): - print "TREADDIR (tag =", tag, ", fid =", fid, ", offset =", offset, ", max_count =", max_count, ")" - - def v9fs_readdir_return(self, tag, id, count, retval): - print "RREADDIR (tag =", tag, ", count =", count, ", retval =", retval, ")" - - def v9fs_write(self, tag, id, fid, off, count, cnt): - print "TWRITE (tag =", tag, ", fid =", fid, ", off =", off, ", count =", count, ", cnt =", cnt, ")" - - def v9fs_write_return(self, tag, id, total, err): - print "RWRITE (tag =", tag, ", total =", total, ", err =", err, ")" - - def v9fs_create(self, tag, id, fid, name, perm, mode): - print "TCREATE (tag =", tag, ", fid =", fid, ", perm =", oct(perm), ", name =", name, ", mode =", oct(mode), ")" - - def v9fs_create_return(self, tag, id, type, version, path, iounit): - print "RCREATE (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, iounit =", iounit, ")" - - def v9fs_symlink(self, tag, id, fid, name, symname, gid): - print "TSYMLINK (tag =", tag, ", fid =", fid, ", name =", name, ", symname =", symname, ", gid =", gid, ")" - - def v9fs_symlink_return(self, tag, id, type, version, path): - print "RSYMLINK (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "})" - - def v9fs_flush(self, tag, id, flush_tag): - print "TFLUSH (tag =", tag, ", flush_tag =", flush_tag, ")" - - def v9fs_link(self, tag, id, dfid, oldfid, name): - print "TLINK (tag =", tag, ", dfid =", dfid, ", oldfid =", oldfid, ", name =", name, ")" - - def v9fs_remove(self, tag, id, fid): - print "TREMOVE (tag =", tag, ", fid =", fid, ")" - - def v9fs_wstat(self, tag, id, fid, mode, atime, mtime): - print "TWSTAT (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", atime =", atime, "mtime =", mtime, ")" - - def v9fs_mknod(self, tag, id, fid, mode, major, minor): - print "TMKNOD (tag =", tag, ", fid =", fid, ", mode =", oct(mode), ", major =", major, ", minor =", minor, ")" - - def v9fs_lock(self, tag, id, fid, type, start, length): - print "TLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")" - - def v9fs_lock_return(self, tag, id, status): - print "RLOCK (tag =", tag, ", status =", status, ")" - - def v9fs_getlock(self, tag, id, fid, type, start, length): - print "TGETLOCK (tag =", tag, ", fid =", fid, "type =", type, ", start =", start, ", length =", length, ")" - - def v9fs_getlock_return(self, tag, id, type, start, length, proc_id): - print "RGETLOCK (tag =", tag, "type =", type, ", start =", start, ", length =", length, ", proc_id =", proc_id, ")" - - def v9fs_mkdir(self, tag, id, fid, name, mode, gid): - print "TMKDIR (tag =", tag, ", fid =", fid, ", name =", name, ", mode =", mode, ", gid =", gid, ")" - - def v9fs_mkdir_return(self, tag, id, type, version, path, err): - print "RMKDIR (tag =", tag, ", qid={type =", type, ", version =", version, ", path =", path, "}, err =", err, ")" - - def v9fs_xattrwalk(self, tag, id, fid, newfid, name): - print "TXATTRWALK (tag =", tag, ", fid =", fid, ", newfid =", newfid, ", xattr name =", name, ")" - - def v9fs_xattrwalk_return(self, tag, id, size): - print "RXATTRWALK (tag =", tag, ", xattrsize =", size, ")" - - def v9fs_xattrcreate(self, tag, id, fid, name, size, flags): - print "TXATTRCREATE (tag =", tag, ", fid =", fid, ", name =", name, ", xattrsize =", size, ", flags =", flags, ")" - - def v9fs_readlink(self, tag, id, fid): - print "TREADLINK (tag =", tag, ", fid =", fid, ")" - - def v9fs_readlink_return(self, tag, id, target): - print "RREADLINK (tag =", tag, ", target =", target, ")" - -simpletrace.run(VirtFSRequestTracker()) diff --git a/qemu/scripts/analyze-migration.py b/qemu/scripts/analyze-migration.py deleted file mode 100755 index 14553876a..000000000 --- a/qemu/scripts/analyze-migration.py +++ /dev/null @@ -1,610 +0,0 @@ -#!/usr/bin/env python -# -# Migration Stream Analyzer -# -# Copyright (c) 2015 Alexander Graf <agraf@suse.de> -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, see <http://www.gnu.org/licenses/>. - -import numpy as np -import json -import os -import argparse -import collections -import pprint - -def mkdir_p(path): - try: - os.makedirs(path) - except OSError: - pass - -class MigrationFile(object): - def __init__(self, filename): - self.filename = filename - self.file = open(self.filename, "rb") - - def read64(self): - return np.asscalar(np.fromfile(self.file, count=1, dtype='>i8')[0]) - - def read32(self): - return np.asscalar(np.fromfile(self.file, count=1, dtype='>i4')[0]) - - def read16(self): - return np.asscalar(np.fromfile(self.file, count=1, dtype='>i2')[0]) - - def read8(self): - return np.asscalar(np.fromfile(self.file, count=1, dtype='>i1')[0]) - - def readstr(self, len = None): - if len is None: - len = self.read8() - if len == 0: - return "" - return np.fromfile(self.file, count=1, dtype=('S%d' % len))[0] - - def readvar(self, size = None): - if size is None: - size = self.read8() - if size == 0: - return "" - value = self.file.read(size) - if len(value) != size: - raise Exception("Unexpected end of %s at 0x%x" % (self.filename, self.file.tell())) - return value - - def tell(self): - return self.file.tell() - - # The VMSD description is at the end of the file, after EOF. Look for - # the last NULL byte, then for the beginning brace of JSON. - def read_migration_debug_json(self): - QEMU_VM_VMDESCRIPTION = 0x06 - - # Remember the offset in the file when we started - entrypos = self.file.tell() - - # Read the last 10MB - self.file.seek(0, os.SEEK_END) - endpos = self.file.tell() - self.file.seek(max(-endpos, -10 * 1024 * 1024), os.SEEK_END) - datapos = self.file.tell() - data = self.file.read() - # The full file read closed the file as well, reopen it - self.file = open(self.filename, "rb") - - # Find the last NULL byte, then the first brace after that. This should - # be the beginning of our JSON data. - nulpos = data.rfind("\0") - jsonpos = data.find("{", nulpos) - - # Check backwards from there and see whether we guessed right - self.file.seek(datapos + jsonpos - 5, 0) - if self.read8() != QEMU_VM_VMDESCRIPTION: - raise Exception("No Debug Migration device found") - - jsonlen = self.read32() - - # Seek back to where we were at the beginning - self.file.seek(entrypos, 0) - - return data[jsonpos:jsonpos + jsonlen] - - def close(self): - self.file.close() - -class RamSection(object): - RAM_SAVE_FLAG_COMPRESS = 0x02 - RAM_SAVE_FLAG_MEM_SIZE = 0x04 - RAM_SAVE_FLAG_PAGE = 0x08 - RAM_SAVE_FLAG_EOS = 0x10 - RAM_SAVE_FLAG_CONTINUE = 0x20 - RAM_SAVE_FLAG_XBZRLE = 0x40 - RAM_SAVE_FLAG_HOOK = 0x80 - - def __init__(self, file, version_id, ramargs, section_key): - if version_id != 4: - raise Exception("Unknown RAM version %d" % version_id) - - self.file = file - self.section_key = section_key - self.TARGET_PAGE_SIZE = ramargs['page_size'] - self.dump_memory = ramargs['dump_memory'] - self.write_memory = ramargs['write_memory'] - self.sizeinfo = collections.OrderedDict() - self.data = collections.OrderedDict() - self.data['section sizes'] = self.sizeinfo - self.name = '' - if self.write_memory: - self.files = { } - if self.dump_memory: - self.memory = collections.OrderedDict() - self.data['memory'] = self.memory - - def __repr__(self): - return self.data.__repr__() - - def __str__(self): - return self.data.__str__() - - def getDict(self): - return self.data - - def read(self): - # Read all RAM sections - while True: - addr = self.file.read64() - flags = addr & (self.TARGET_PAGE_SIZE - 1) - addr &= ~(self.TARGET_PAGE_SIZE - 1) - - if flags & self.RAM_SAVE_FLAG_MEM_SIZE: - while True: - namelen = self.file.read8() - # We assume that no RAM chunk is big enough to ever - # hit the first byte of the address, so when we see - # a zero here we know it has to be an address, not the - # length of the next block. - if namelen == 0: - self.file.file.seek(-1, 1) - break - self.name = self.file.readstr(len = namelen) - len = self.file.read64() - self.sizeinfo[self.name] = '0x%016x' % len - if self.write_memory: - print self.name - mkdir_p('./' + os.path.dirname(self.name)) - f = open('./' + self.name, "wb") - f.truncate(0) - f.truncate(len) - self.files[self.name] = f - flags &= ~self.RAM_SAVE_FLAG_MEM_SIZE - - if flags & self.RAM_SAVE_FLAG_COMPRESS: - if flags & self.RAM_SAVE_FLAG_CONTINUE: - flags &= ~self.RAM_SAVE_FLAG_CONTINUE - else: - self.name = self.file.readstr() - fill_char = self.file.read8() - # The page in question is filled with fill_char now - if self.write_memory and fill_char != 0: - self.files[self.name].seek(addr, os.SEEK_SET) - self.files[self.name].write(chr(fill_char) * self.TARGET_PAGE_SIZE) - if self.dump_memory: - self.memory['%s (0x%016x)' % (self.name, addr)] = 'Filled with 0x%02x' % fill_char - flags &= ~self.RAM_SAVE_FLAG_COMPRESS - elif flags & self.RAM_SAVE_FLAG_PAGE: - if flags & self.RAM_SAVE_FLAG_CONTINUE: - flags &= ~self.RAM_SAVE_FLAG_CONTINUE - else: - self.name = self.file.readstr() - - if self.write_memory or self.dump_memory: - data = self.file.readvar(size = self.TARGET_PAGE_SIZE) - else: # Just skip RAM data - self.file.file.seek(self.TARGET_PAGE_SIZE, 1) - - if self.write_memory: - self.files[self.name].seek(addr, os.SEEK_SET) - self.files[self.name].write(data) - if self.dump_memory: - hexdata = " ".join("{0:02x}".format(ord(c)) for c in data) - self.memory['%s (0x%016x)' % (self.name, addr)] = hexdata - - flags &= ~self.RAM_SAVE_FLAG_PAGE - elif flags & self.RAM_SAVE_FLAG_XBZRLE: - raise Exception("XBZRLE RAM compression is not supported yet") - elif flags & self.RAM_SAVE_FLAG_HOOK: - raise Exception("RAM hooks don't make sense with files") - - # End of RAM section - if flags & self.RAM_SAVE_FLAG_EOS: - break - - if flags != 0: - raise Exception("Unknown RAM flags: %x" % flags) - - def __del__(self): - if self.write_memory: - for key in self.files: - self.files[key].close() - - -class HTABSection(object): - HASH_PTE_SIZE_64 = 16 - - def __init__(self, file, version_id, device, section_key): - if version_id != 1: - raise Exception("Unknown HTAB version %d" % version_id) - - self.file = file - self.section_key = section_key - - def read(self): - - header = self.file.read32() - - if (header > 0): - # First section, just the hash shift - return - - # Read until end marker - while True: - index = self.file.read32() - n_valid = self.file.read16() - n_invalid = self.file.read16() - - if index == 0 and n_valid == 0 and n_invalid == 0: - break - - self.file.readvar(n_valid * self.HASH_PTE_SIZE_64) - - def getDict(self): - return "" - - -class ConfigurationSection(object): - def __init__(self, file): - self.file = file - - def read(self): - name_len = self.file.read32() - name = self.file.readstr(len = name_len) - -class VMSDFieldGeneric(object): - def __init__(self, desc, file): - self.file = file - self.desc = desc - self.data = "" - - def __repr__(self): - return str(self.__str__()) - - def __str__(self): - return " ".join("{0:02x}".format(ord(c)) for c in self.data) - - def getDict(self): - return self.__str__() - - def read(self): - size = int(self.desc['size']) - self.data = self.file.readvar(size) - return self.data - -class VMSDFieldInt(VMSDFieldGeneric): - def __init__(self, desc, file): - super(VMSDFieldInt, self).__init__(desc, file) - self.size = int(desc['size']) - self.format = '0x%%0%dx' % (self.size * 2) - self.sdtype = '>i%d' % self.size - self.udtype = '>u%d' % self.size - - def __repr__(self): - if self.data < 0: - return ('%s (%d)' % ((self.format % self.udata), self.data)) - else: - return self.format % self.data - - def __str__(self): - return self.__repr__() - - def getDict(self): - return self.__str__() - - def read(self): - super(VMSDFieldInt, self).read() - self.sdata = np.fromstring(self.data, count=1, dtype=(self.sdtype))[0] - self.udata = np.fromstring(self.data, count=1, dtype=(self.udtype))[0] - self.data = self.sdata - return self.data - -class VMSDFieldUInt(VMSDFieldInt): - def __init__(self, desc, file): - super(VMSDFieldUInt, self).__init__(desc, file) - - def read(self): - super(VMSDFieldUInt, self).read() - self.data = self.udata - return self.data - -class VMSDFieldIntLE(VMSDFieldInt): - def __init__(self, desc, file): - super(VMSDFieldIntLE, self).__init__(desc, file) - self.dtype = '<i%d' % self.size - -class VMSDFieldBool(VMSDFieldGeneric): - def __init__(self, desc, file): - super(VMSDFieldBool, self).__init__(desc, file) - - def __repr__(self): - return self.data.__repr__() - - def __str__(self): - return self.data.__str__() - - def getDict(self): - return self.data - - def read(self): - super(VMSDFieldBool, self).read() - if self.data[0] == 0: - self.data = False - else: - self.data = True - return self.data - -class VMSDFieldStruct(VMSDFieldGeneric): - QEMU_VM_SUBSECTION = 0x05 - - def __init__(self, desc, file): - super(VMSDFieldStruct, self).__init__(desc, file) - self.data = collections.OrderedDict() - - # When we see compressed array elements, unfold them here - new_fields = [] - for field in self.desc['struct']['fields']: - if not 'array_len' in field: - new_fields.append(field) - continue - array_len = field.pop('array_len') - field['index'] = 0 - new_fields.append(field) - for i in xrange(1, array_len): - c = field.copy() - c['index'] = i - new_fields.append(c) - - self.desc['struct']['fields'] = new_fields - - def __repr__(self): - return self.data.__repr__() - - def __str__(self): - return self.data.__str__() - - def read(self): - for field in self.desc['struct']['fields']: - try: - reader = vmsd_field_readers[field['type']] - except: - reader = VMSDFieldGeneric - - field['data'] = reader(field, self.file) - field['data'].read() - - if 'index' in field: - if field['name'] not in self.data: - self.data[field['name']] = [] - a = self.data[field['name']] - if len(a) != int(field['index']): - raise Exception("internal index of data field unmatched (%d/%d)" % (len(a), int(field['index']))) - a.append(field['data']) - else: - self.data[field['name']] = field['data'] - - if 'subsections' in self.desc['struct']: - for subsection in self.desc['struct']['subsections']: - if self.file.read8() != self.QEMU_VM_SUBSECTION: - raise Exception("Subsection %s not found at offset %x" % ( subsection['vmsd_name'], self.file.tell())) - name = self.file.readstr() - version_id = self.file.read32() - self.data[name] = VMSDSection(self.file, version_id, subsection, (name, 0)) - self.data[name].read() - - def getDictItem(self, value): - # Strings would fall into the array category, treat - # them specially - if value.__class__ is ''.__class__: - return value - - try: - return self.getDictOrderedDict(value) - except: - try: - return self.getDictArray(value) - except: - try: - return value.getDict() - except: - return value - - def getDictArray(self, array): - r = [] - for value in array: - r.append(self.getDictItem(value)) - return r - - def getDictOrderedDict(self, dict): - r = collections.OrderedDict() - for (key, value) in dict.items(): - r[key] = self.getDictItem(value) - return r - - def getDict(self): - return self.getDictOrderedDict(self.data) - -vmsd_field_readers = { - "bool" : VMSDFieldBool, - "int8" : VMSDFieldInt, - "int16" : VMSDFieldInt, - "int32" : VMSDFieldInt, - "int32 equal" : VMSDFieldInt, - "int32 le" : VMSDFieldIntLE, - "int64" : VMSDFieldInt, - "uint8" : VMSDFieldUInt, - "uint16" : VMSDFieldUInt, - "uint32" : VMSDFieldUInt, - "uint32 equal" : VMSDFieldUInt, - "uint64" : VMSDFieldUInt, - "int64 equal" : VMSDFieldInt, - "uint8 equal" : VMSDFieldInt, - "uint16 equal" : VMSDFieldInt, - "float64" : VMSDFieldGeneric, - "timer" : VMSDFieldGeneric, - "buffer" : VMSDFieldGeneric, - "unused_buffer" : VMSDFieldGeneric, - "bitmap" : VMSDFieldGeneric, - "struct" : VMSDFieldStruct, - "unknown" : VMSDFieldGeneric, -} - -class VMSDSection(VMSDFieldStruct): - def __init__(self, file, version_id, device, section_key): - self.file = file - self.data = "" - self.vmsd_name = "" - self.section_key = section_key - desc = device - if 'vmsd_name' in device: - self.vmsd_name = device['vmsd_name'] - - # A section really is nothing but a FieldStruct :) - super(VMSDSection, self).__init__({ 'struct' : desc }, file) - -############################################################################### - -class MigrationDump(object): - QEMU_VM_FILE_MAGIC = 0x5145564d - QEMU_VM_FILE_VERSION = 0x00000003 - QEMU_VM_EOF = 0x00 - QEMU_VM_SECTION_START = 0x01 - QEMU_VM_SECTION_PART = 0x02 - QEMU_VM_SECTION_END = 0x03 - QEMU_VM_SECTION_FULL = 0x04 - QEMU_VM_SUBSECTION = 0x05 - QEMU_VM_VMDESCRIPTION = 0x06 - QEMU_VM_CONFIGURATION = 0x07 - QEMU_VM_SECTION_FOOTER= 0x7e - - def __init__(self, filename): - self.section_classes = { ( 'ram', 0 ) : [ RamSection, None ], - ( 'spapr/htab', 0) : ( HTABSection, None ) } - self.filename = filename - self.vmsd_desc = None - - def read(self, desc_only = False, dump_memory = False, write_memory = False): - # Read in the whole file - file = MigrationFile(self.filename) - - # File magic - data = file.read32() - if data != self.QEMU_VM_FILE_MAGIC: - raise Exception("Invalid file magic %x" % data) - - # Version (has to be v3) - data = file.read32() - if data != self.QEMU_VM_FILE_VERSION: - raise Exception("Invalid version number %d" % data) - - self.load_vmsd_json(file) - - # Read sections - self.sections = collections.OrderedDict() - - if desc_only: - return - - ramargs = {} - ramargs['page_size'] = self.vmsd_desc['page_size'] - ramargs['dump_memory'] = dump_memory - ramargs['write_memory'] = write_memory - self.section_classes[('ram',0)][1] = ramargs - - while True: - section_type = file.read8() - if section_type == self.QEMU_VM_EOF: - break - elif section_type == self.QEMU_VM_CONFIGURATION: - section = ConfigurationSection(file) - section.read() - elif section_type == self.QEMU_VM_SECTION_START or section_type == self.QEMU_VM_SECTION_FULL: - section_id = file.read32() - name = file.readstr() - instance_id = file.read32() - version_id = file.read32() - section_key = (name, instance_id) - classdesc = self.section_classes[section_key] - section = classdesc[0](file, version_id, classdesc[1], section_key) - self.sections[section_id] = section - section.read() - elif section_type == self.QEMU_VM_SECTION_PART or section_type == self.QEMU_VM_SECTION_END: - section_id = file.read32() - self.sections[section_id].read() - elif section_type == self.QEMU_VM_SECTION_FOOTER: - read_section_id = file.read32() - if read_section_id != section_id: - raise Exception("Mismatched section footer: %x vs %x" % (read_section_id, section_id)) - else: - raise Exception("Unknown section type: %d" % section_type) - file.close() - - def load_vmsd_json(self, file): - vmsd_json = file.read_migration_debug_json() - self.vmsd_desc = json.loads(vmsd_json, object_pairs_hook=collections.OrderedDict) - for device in self.vmsd_desc['devices']: - key = (device['name'], device['instance_id']) - value = ( VMSDSection, device ) - self.section_classes[key] = value - - def getDict(self): - r = collections.OrderedDict() - for (key, value) in self.sections.items(): - key = "%s (%d)" % ( value.section_key[0], key ) - r[key] = value.getDict() - return r - -############################################################################### - -class JSONEncoder(json.JSONEncoder): - def default(self, o): - if isinstance(o, VMSDFieldGeneric): - return str(o) - return json.JSONEncoder.default(self, o) - -parser = argparse.ArgumentParser() -parser.add_argument("-f", "--file", help='migration dump to read from', required=True) -parser.add_argument("-m", "--memory", help='dump RAM contents as well', action='store_true') -parser.add_argument("-d", "--dump", help='what to dump ("state" or "desc")', default='state') -parser.add_argument("-x", "--extract", help='extract contents into individual files', action='store_true') -args = parser.parse_args() - -jsonenc = JSONEncoder(indent=4, separators=(',', ': ')) - -if args.extract: - dump = MigrationDump(args.file) - - dump.read(desc_only = True) - print "desc.json" - f = open("desc.json", "wb") - f.truncate() - f.write(jsonenc.encode(dump.vmsd_desc)) - f.close() - - dump.read(write_memory = True) - dict = dump.getDict() - print "state.json" - f = open("state.json", "wb") - f.truncate() - f.write(jsonenc.encode(dict)) - f.close() -elif args.dump == "state": - dump = MigrationDump(args.file) - dump.read(dump_memory = args.memory) - dict = dump.getDict() - print jsonenc.encode(dict) -elif args.dump == "desc": - dump = MigrationDump(args.file) - dump.read(desc_only = True) - print jsonenc.encode(dump.vmsd_desc) -else: - raise Exception("Please specify either -x, -d state or -d dump") diff --git a/qemu/scripts/check-qerror.sh b/qemu/scripts/check-qerror.sh deleted file mode 100755 index af7fbd524..000000000 --- a/qemu/scripts/check-qerror.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -# This script verifies that qerror definitions and table entries are -# alphabetically ordered. - -check_order() { - errmsg=$1 - shift - - # sort -C verifies order but does not print a message. sort -c does print a - # message. These options are both in POSIX. - if ! "$@" | sort -C; then - echo "$errmsg" - "$@" | sort -c - exit 1 - fi - return 0 -} - -check_order 'Definitions in qerror.h must be in alphabetical order:' \ - grep '^#define QERR_' qerror.h -check_order 'Entries in qerror.c:qerror_table must be in alphabetical order:' \ - sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c diff --git a/qemu/scripts/checkpatch.pl b/qemu/scripts/checkpatch.pl deleted file mode 100755 index c9554ba64..000000000 --- a/qemu/scripts/checkpatch.pl +++ /dev/null @@ -1,2607 +0,0 @@ -#!/usr/bin/perl -w -# (c) 2001, Dave Jones. (the file handling bit) -# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit) -# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite) -# (c) 2008-2010 Andy Whitcroft <apw@canonical.com> -# Licensed under the terms of the GNU GPL License version 2 - -use strict; - -my $P = $0; -$P =~ s@.*/@@g; - -my $V = '0.31'; - -use Getopt::Long qw(:config no_auto_abbrev); - -my $quiet = 0; -my $tree = 1; -my $chk_signoff = 1; -my $chk_patch = 1; -my $tst_only; -my $emacs = 0; -my $terse = 0; -my $file = 0; -my $check = 0; -my $summary = 1; -my $mailback = 0; -my $summary_file = 0; -my $root; -my %debug; -my $help = 0; - -sub help { - my ($exitcode) = @_; - - print << "EOM"; -Usage: $P [OPTION]... [FILE]... -Version: $V - -Options: - -q, --quiet quiet - --no-tree run without a kernel tree - --no-signoff do not check for 'Signed-off-by' line - --patch treat FILE as patchfile (default) - --emacs emacs compile window format - --terse one line per report - -f, --file treat FILE as regular source file - --subjective, --strict enable more subjective tests - --root=PATH PATH to the kernel tree root - --no-summary suppress the per-file summary - --mailback only produce a report in case of warnings/errors - --summary-file include the filename in summary - --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of - 'values', 'possible', 'type', and 'attr' (default - is all off) - --test-only=WORD report only warnings/errors containing WORD - literally - -h, --help, --version display this help and exit - -When FILE is - read standard input. -EOM - - exit($exitcode); -} - -GetOptions( - 'q|quiet+' => \$quiet, - 'tree!' => \$tree, - 'signoff!' => \$chk_signoff, - 'patch!' => \$chk_patch, - 'emacs!' => \$emacs, - 'terse!' => \$terse, - 'f|file!' => \$file, - 'subjective!' => \$check, - 'strict!' => \$check, - 'root=s' => \$root, - 'summary!' => \$summary, - 'mailback!' => \$mailback, - 'summary-file!' => \$summary_file, - - 'debug=s' => \%debug, - 'test-only=s' => \$tst_only, - 'h|help' => \$help, - 'version' => \$help -) or help(1); - -help(0) if ($help); - -my $exit = 0; - -if ($#ARGV < 0) { - print "$P: no input files\n"; - exit(1); -} - -my $dbg_values = 0; -my $dbg_possible = 0; -my $dbg_type = 0; -my $dbg_attr = 0; -my $dbg_adv_dcs = 0; -my $dbg_adv_checking = 0; -my $dbg_adv_apw = 0; -for my $key (keys %debug) { - ## no critic - eval "\${dbg_$key} = '$debug{$key}';"; - die "$@" if ($@); -} - -my $rpt_cleaners = 0; - -if ($terse) { - $emacs = 1; - $quiet++; -} - -if ($tree) { - if (defined $root) { - if (!top_of_kernel_tree($root)) { - die "$P: $root: --root does not point at a valid tree\n"; - } - } else { - if (top_of_kernel_tree('.')) { - $root = '.'; - } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ && - top_of_kernel_tree($1)) { - $root = $1; - } - } - - if (!defined $root) { - print "Must be run from the top-level dir. of a kernel tree\n"; - exit(2); - } -} - -my $emitted_corrupt = 0; - -our $Ident = qr{ - [A-Za-z_][A-Za-z\d_]* - (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)* - }x; -our $Storage = qr{extern|static|asmlinkage}; -our $Sparse = qr{ - __force - }x; - -# Notes to $Attribute: -our $Attribute = qr{ - const| - volatile| - QEMU_NORETURN| - QEMU_WARN_UNUSED_RESULT| - QEMU_SENTINEL| - QEMU_ARTIFICIAL| - QEMU_PACKED| - GCC_FMT_ATTR - }x; -our $Modifier; -our $Inline = qr{inline}; -our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; -our $Lval = qr{$Ident(?:$Member)*}; - -our $Constant = qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*}; -our $Assignment = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)}; -our $Compare = qr{<=|>=|==|!=|<|>}; -our $Operators = qr{ - <=|>=|==|!=| - =>|->|<<|>>|<|>|!|~| - &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|% - }x; - -our $NonptrType; -our $Type; -our $Declare; - -our $UTF8 = qr { - [\x09\x0A\x0D\x20-\x7E] # ASCII - | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte - | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs - | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte - | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates - | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 - | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 - | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 -}x; - -# There are still some false positives, but this catches most -# common cases. -our $typeTypedefs = qr{(?x: - [A-Z][A-Z\d_]*[a-z][A-Za-z\d_]* # camelcase - | [A-Z][A-Z\d_]*AIOCB # all uppercase - | [A-Z][A-Z\d_]*CPU # all uppercase - | QEMUBH # all uppercase -)}; - -our @typeList = ( - qr{void}, - qr{(?:unsigned\s+)?char}, - qr{(?:unsigned\s+)?short}, - qr{(?:unsigned\s+)?int}, - qr{(?:unsigned\s+)?long}, - qr{(?:unsigned\s+)?long\s+int}, - qr{(?:unsigned\s+)?long\s+long}, - qr{(?:unsigned\s+)?long\s+long\s+int}, - qr{unsigned}, - qr{float}, - qr{double}, - qr{bool}, - qr{struct\s+$Ident}, - qr{union\s+$Ident}, - qr{enum\s+$Ident}, - qr{${Ident}_t}, - qr{${Ident}_handler}, - qr{${Ident}_handler_fn}, - qr{target_(?:u)?long}, -); - -# This can be modified by sub possible. Since it can be empty, be careful -# about regexes that always match, because they can cause infinite loops. -our @modifierList = ( -); - -sub build_types { - my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)"; - if (@modifierList > 0) { - my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)"; - $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; - } else { - $Modifier = qr{(?:$Attribute|$Sparse)}; - } - $NonptrType = qr{ - (?:$Modifier\s+|const\s+)* - (?: - (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)| - (?:$typeTypedefs\b)| - (?:${all}\b) - ) - (?:\s+$Modifier|\s+const)* - }x; - $Type = qr{ - $NonptrType - (?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)? - (?:\s+$Inline|\s+$Modifier)* - }x; - $Declare = qr{(?:$Storage\s+)?$Type}; -} -build_types(); - -$chk_signoff = 0 if ($file); - -my @rawlines = (); -my @lines = (); -my $vname; -for my $filename (@ARGV) { - my $FILE; - if ($file) { - open($FILE, '-|', "diff -u /dev/null $filename") || - die "$P: $filename: diff failed - $!\n"; - } elsif ($filename eq '-') { - open($FILE, '<&STDIN'); - } else { - open($FILE, '<', "$filename") || - die "$P: $filename: open failed - $!\n"; - } - if ($filename eq '-') { - $vname = 'Your patch'; - } else { - $vname = $filename; - } - while (<$FILE>) { - chomp; - push(@rawlines, $_); - } - close($FILE); - if (!process($filename)) { - $exit = 1; - } - @rawlines = (); - @lines = (); -} - -exit($exit); - -sub top_of_kernel_tree { - my ($root) = @_; - - my @tree_check = ( - "COPYING", "MAINTAINERS", "Makefile", - "README", "docs", "VERSION", - "vl.c" - ); - - foreach my $check (@tree_check) { - if (! -e $root . '/' . $check) { - return 0; - } - } - return 1; -} - -sub expand_tabs { - my ($str) = @_; - - my $res = ''; - my $n = 0; - for my $c (split(//, $str)) { - if ($c eq "\t") { - $res .= ' '; - $n++; - for (; ($n % 8) != 0; $n++) { - $res .= ' '; - } - next; - } - $res .= $c; - $n++; - } - - return $res; -} -sub copy_spacing { - (my $res = shift) =~ tr/\t/ /c; - return $res; -} - -sub line_stats { - my ($line) = @_; - - # Drop the diff line leader and expand tabs - $line =~ s/^.//; - $line = expand_tabs($line); - - # Pick the indent from the front of the line. - my ($white) = ($line =~ /^(\s*)/); - - return (length($line), length($white)); -} - -my $sanitise_quote = ''; - -sub sanitise_line_reset { - my ($in_comment) = @_; - - if ($in_comment) { - $sanitise_quote = '*/'; - } else { - $sanitise_quote = ''; - } -} -sub sanitise_line { - my ($line) = @_; - - my $res = ''; - my $l = ''; - - my $qlen = 0; - my $off = 0; - my $c; - - # Always copy over the diff marker. - $res = substr($line, 0, 1); - - for ($off = 1; $off < length($line); $off++) { - $c = substr($line, $off, 1); - - # Comments we are wacking completly including the begin - # and end, all to $;. - if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { - $sanitise_quote = '*/'; - - substr($res, $off, 2, "$;$;"); - $off++; - next; - } - if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') { - $sanitise_quote = ''; - substr($res, $off, 2, "$;$;"); - $off++; - next; - } - if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') { - $sanitise_quote = '//'; - - substr($res, $off, 2, $sanitise_quote); - $off++; - next; - } - - # A \ in a string means ignore the next character. - if (($sanitise_quote eq "'" || $sanitise_quote eq '"') && - $c eq "\\") { - substr($res, $off, 2, 'XX'); - $off++; - next; - } - # Regular quotes. - if ($c eq "'" || $c eq '"') { - if ($sanitise_quote eq '') { - $sanitise_quote = $c; - - substr($res, $off, 1, $c); - next; - } elsif ($sanitise_quote eq $c) { - $sanitise_quote = ''; - } - } - - #print "c<$c> SQ<$sanitise_quote>\n"; - if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") { - substr($res, $off, 1, $;); - } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") { - substr($res, $off, 1, $;); - } elsif ($off != 0 && $sanitise_quote && $c ne "\t") { - substr($res, $off, 1, 'X'); - } else { - substr($res, $off, 1, $c); - } - } - - if ($sanitise_quote eq '//') { - $sanitise_quote = ''; - } - - # The pathname on a #include may be surrounded by '<' and '>'. - if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) { - my $clean = 'X' x length($1); - $res =~ s@\<.*\>@<$clean>@; - - # The whole of a #error is a string. - } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) { - my $clean = 'X' x length($1); - $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@; - } - - return $res; -} - -sub ctx_statement_block { - my ($linenr, $remain, $off) = @_; - my $line = $linenr - 1; - my $blk = ''; - my $soff = $off; - my $coff = $off - 1; - my $coff_set = 0; - - my $loff = 0; - - my $type = ''; - my $level = 0; - my @stack = (); - my $p; - my $c; - my $len = 0; - - my $remainder; - while (1) { - @stack = (['', 0]) if ($#stack == -1); - - #warn "CSB: blk<$blk> remain<$remain>\n"; - # If we are about to drop off the end, pull in more - # context. - if ($off >= $len) { - for (; $remain > 0; $line++) { - last if (!defined $lines[$line]); - next if ($lines[$line] =~ /^-/); - $remain--; - $loff = $len; - $blk .= $lines[$line] . "\n"; - $len = length($blk); - $line++; - last; - } - # Bail if there is no further context. - #warn "CSB: blk<$blk> off<$off> len<$len>\n"; - if ($off >= $len) { - last; - } - } - $p = $c; - $c = substr($blk, $off, 1); - $remainder = substr($blk, $off); - - #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n"; - - # Handle nested #if/#else. - if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) { - push(@stack, [ $type, $level ]); - } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) { - ($type, $level) = @{$stack[$#stack - 1]}; - } elsif ($remainder =~ /^#\s*endif\b/) { - ($type, $level) = @{pop(@stack)}; - } - - # Statement ends at the ';' or a close '}' at the - # outermost level. - if ($level == 0 && $c eq ';') { - last; - } - - # An else is really a conditional as long as its not else if - if ($level == 0 && $coff_set == 0 && - (!defined($p) || $p =~ /(?:\s|\}|\+)/) && - $remainder =~ /^(else)(?:\s|{)/ && - $remainder !~ /^else\s+if\b/) { - $coff = $off + length($1) - 1; - $coff_set = 1; - #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n"; - #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n"; - } - - if (($type eq '' || $type eq '(') && $c eq '(') { - $level++; - $type = '('; - } - if ($type eq '(' && $c eq ')') { - $level--; - $type = ($level != 0)? '(' : ''; - - if ($level == 0 && $coff < $soff) { - $coff = $off; - $coff_set = 1; - #warn "CSB: mark coff<$coff>\n"; - } - } - if (($type eq '' || $type eq '{') && $c eq '{') { - $level++; - $type = '{'; - } - if ($type eq '{' && $c eq '}') { - $level--; - $type = ($level != 0)? '{' : ''; - - if ($level == 0) { - if (substr($blk, $off + 1, 1) eq ';') { - $off++; - } - last; - } - } - $off++; - } - # We are truly at the end, so shuffle to the next line. - if ($off == $len) { - $loff = $len + 1; - $line++; - $remain--; - } - - my $statement = substr($blk, $soff, $off - $soff + 1); - my $condition = substr($blk, $soff, $coff - $soff + 1); - - #warn "STATEMENT<$statement>\n"; - #warn "CONDITION<$condition>\n"; - - #print "coff<$coff> soff<$off> loff<$loff>\n"; - - return ($statement, $condition, - $line, $remain + 1, $off - $loff + 1, $level); -} - -sub statement_lines { - my ($stmt) = @_; - - # Strip the diff line prefixes and rip blank lines at start and end. - $stmt =~ s/(^|\n)./$1/g; - $stmt =~ s/^\s*//; - $stmt =~ s/\s*$//; - - my @stmt_lines = ($stmt =~ /\n/g); - - return $#stmt_lines + 2; -} - -sub statement_rawlines { - my ($stmt) = @_; - - my @stmt_lines = ($stmt =~ /\n/g); - - return $#stmt_lines + 2; -} - -sub statement_block_size { - my ($stmt) = @_; - - $stmt =~ s/(^|\n)./$1/g; - $stmt =~ s/^\s*\{//; - $stmt =~ s/}\s*$//; - $stmt =~ s/^\s*//; - $stmt =~ s/\s*$//; - - my @stmt_lines = ($stmt =~ /\n/g); - my @stmt_statements = ($stmt =~ /;/g); - - my $stmt_lines = $#stmt_lines + 2; - my $stmt_statements = $#stmt_statements + 1; - - if ($stmt_lines > $stmt_statements) { - return $stmt_lines; - } else { - return $stmt_statements; - } -} - -sub ctx_statement_full { - my ($linenr, $remain, $off) = @_; - my ($statement, $condition, $level); - - my (@chunks); - - # Grab the first conditional/block pair. - ($statement, $condition, $linenr, $remain, $off, $level) = - ctx_statement_block($linenr, $remain, $off); - #print "F: c<$condition> s<$statement> remain<$remain>\n"; - push(@chunks, [ $condition, $statement ]); - if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) { - return ($level, $linenr, @chunks); - } - - # Pull in the following conditional/block pairs and see if they - # could continue the statement. - for (;;) { - ($statement, $condition, $linenr, $remain, $off, $level) = - ctx_statement_block($linenr, $remain, $off); - #print "C: c<$condition> s<$statement> remain<$remain>\n"; - last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s)); - #print "C: push\n"; - push(@chunks, [ $condition, $statement ]); - } - - return ($level, $linenr, @chunks); -} - -sub ctx_block_get { - my ($linenr, $remain, $outer, $open, $close, $off) = @_; - my $line; - my $start = $linenr - 1; - my $blk = ''; - my @o; - my @c; - my @res = (); - - my $level = 0; - my @stack = ($level); - for ($line = $start; $remain > 0; $line++) { - next if ($rawlines[$line] =~ /^-/); - $remain--; - - $blk .= $rawlines[$line]; - - # Handle nested #if/#else. - if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) { - push(@stack, $level); - } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) { - $level = $stack[$#stack - 1]; - } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) { - $level = pop(@stack); - } - - foreach my $c (split(//, $lines[$line])) { - ##print "C<$c>L<$level><$open$close>O<$off>\n"; - if ($off > 0) { - $off--; - next; - } - - if ($c eq $close && $level > 0) { - $level--; - last if ($level == 0); - } elsif ($c eq $open) { - $level++; - } - } - - if (!$outer || $level <= 1) { - push(@res, $rawlines[$line]); - } - - last if ($level == 0); - } - - return ($level, @res); -} -sub ctx_block_outer { - my ($linenr, $remain) = @_; - - my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0); - return @r; -} -sub ctx_block { - my ($linenr, $remain) = @_; - - my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0); - return @r; -} -sub ctx_statement { - my ($linenr, $remain, $off) = @_; - - my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off); - return @r; -} -sub ctx_block_level { - my ($linenr, $remain) = @_; - - return ctx_block_get($linenr, $remain, 0, '{', '}', 0); -} -sub ctx_statement_level { - my ($linenr, $remain, $off) = @_; - - return ctx_block_get($linenr, $remain, 0, '(', ')', $off); -} - -sub ctx_locate_comment { - my ($first_line, $end_line) = @_; - - # Catch a comment on the end of the line itself. - my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); - return $current_comment if (defined $current_comment); - - # Look through the context and try and figure out if there is a - # comment. - my $in_comment = 0; - $current_comment = ''; - for (my $linenr = $first_line; $linenr < $end_line; $linenr++) { - my $line = $rawlines[$linenr - 1]; - #warn " $line\n"; - if ($linenr == $first_line and $line =~ m@^.\s*\*@) { - $in_comment = 1; - } - if ($line =~ m@/\*@) { - $in_comment = 1; - } - if (!$in_comment && $current_comment ne '') { - $current_comment = ''; - } - $current_comment .= $line . "\n" if ($in_comment); - if ($line =~ m@\*/@) { - $in_comment = 0; - } - } - - chomp($current_comment); - return($current_comment); -} -sub ctx_has_comment { - my ($first_line, $end_line) = @_; - my $cmt = ctx_locate_comment($first_line, $end_line); - - ##print "LINE: $rawlines[$end_line - 1 ]\n"; - ##print "CMMT: $cmt\n"; - - return ($cmt ne ''); -} - -sub raw_line { - my ($linenr, $cnt) = @_; - - my $offset = $linenr - 1; - $cnt++; - - my $line; - while ($cnt) { - $line = $rawlines[$offset++]; - next if (defined($line) && $line =~ /^-/); - $cnt--; - } - - return $line; -} - -sub cat_vet { - my ($vet) = @_; - my ($res, $coded); - - $res = ''; - while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) { - $res .= $1; - if ($2 ne '') { - $coded = sprintf("^%c", unpack('C', $2) + 64); - $res .= $coded; - } - } - $res =~ s/$/\$/; - - return $res; -} - -my $av_preprocessor = 0; -my $av_pending; -my @av_paren_type; -my $av_pend_colon; - -sub annotate_reset { - $av_preprocessor = 0; - $av_pending = '_'; - @av_paren_type = ('E'); - $av_pend_colon = 'O'; -} - -sub annotate_values { - my ($stream, $type) = @_; - - my $res; - my $var = '_' x length($stream); - my $cur = $stream; - - print "$stream\n" if ($dbg_values > 1); - - while (length($cur)) { - @av_paren_type = ('E') if ($#av_paren_type < 0); - print " <" . join('', @av_paren_type) . - "> <$type> <$av_pending>" if ($dbg_values > 1); - if ($cur =~ /^(\s+)/o) { - print "WS($1)\n" if ($dbg_values > 1); - if ($1 =~ /\n/ && $av_preprocessor) { - $type = pop(@av_paren_type); - $av_preprocessor = 0; - } - - } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') { - print "CAST($1)\n" if ($dbg_values > 1); - push(@av_paren_type, $type); - $type = 'C'; - - } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) { - print "DECLARE($1)\n" if ($dbg_values > 1); - $type = 'T'; - - } elsif ($cur =~ /^($Modifier)\s*/) { - print "MODIFIER($1)\n" if ($dbg_values > 1); - $type = 'T'; - - } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) { - print "DEFINE($1,$2)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - push(@av_paren_type, $type); - if ($2 ne '') { - $av_pending = 'N'; - } - $type = 'E'; - - } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) { - print "UNDEF($1)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - push(@av_paren_type, $type); - - } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) { - print "PRE_START($1)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - - push(@av_paren_type, $type); - push(@av_paren_type, $type); - $type = 'E'; - - } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) { - print "PRE_RESTART($1)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - - push(@av_paren_type, $av_paren_type[$#av_paren_type]); - - $type = 'E'; - - } elsif ($cur =~ /^(\#\s*(?:endif))/o) { - print "PRE_END($1)\n" if ($dbg_values > 1); - - $av_preprocessor = 1; - - # Assume all arms of the conditional end as this - # one does, and continue as if the #endif was not here. - pop(@av_paren_type); - push(@av_paren_type, $type); - $type = 'E'; - - } elsif ($cur =~ /^(\\\n)/o) { - print "PRECONT($1)\n" if ($dbg_values > 1); - - } elsif ($cur =~ /^(__attribute__)\s*\(?/o) { - print "ATTR($1)\n" if ($dbg_values > 1); - $av_pending = $type; - $type = 'N'; - - } elsif ($cur =~ /^(sizeof)\s*(\()?/o) { - print "SIZEOF($1)\n" if ($dbg_values > 1); - if (defined $2) { - $av_pending = 'V'; - } - $type = 'N'; - - } elsif ($cur =~ /^(if|while|for)\b/o) { - print "COND($1)\n" if ($dbg_values > 1); - $av_pending = 'E'; - $type = 'N'; - - } elsif ($cur =~/^(case)/o) { - print "CASE($1)\n" if ($dbg_values > 1); - $av_pend_colon = 'C'; - $type = 'N'; - - } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) { - print "KEYWORD($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~ /^(\()/o) { - print "PAREN('$1')\n" if ($dbg_values > 1); - push(@av_paren_type, $av_pending); - $av_pending = '_'; - $type = 'N'; - - } elsif ($cur =~ /^(\))/o) { - my $new_type = pop(@av_paren_type); - if ($new_type ne '_') { - $type = $new_type; - print "PAREN('$1') -> $type\n" - if ($dbg_values > 1); - } else { - print "PAREN('$1')\n" if ($dbg_values > 1); - } - - } elsif ($cur =~ /^($Ident)\s*\(/o) { - print "FUNC($1)\n" if ($dbg_values > 1); - $type = 'V'; - $av_pending = 'V'; - - } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) { - if (defined $2 && $type eq 'C' || $type eq 'T') { - $av_pend_colon = 'B'; - } elsif ($type eq 'E') { - $av_pend_colon = 'L'; - } - print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1); - $type = 'V'; - - } elsif ($cur =~ /^($Ident|$Constant)/o) { - print "IDENT($1)\n" if ($dbg_values > 1); - $type = 'V'; - - } elsif ($cur =~ /^($Assignment)/o) { - print "ASSIGN($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~/^(;|{|})/) { - print "END($1)\n" if ($dbg_values > 1); - $type = 'E'; - $av_pend_colon = 'O'; - - } elsif ($cur =~/^(,)/) { - print "COMMA($1)\n" if ($dbg_values > 1); - $type = 'C'; - - } elsif ($cur =~ /^(\?)/o) { - print "QUESTION($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~ /^(:)/o) { - print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1); - - substr($var, length($res), 1, $av_pend_colon); - if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') { - $type = 'E'; - } else { - $type = 'N'; - } - $av_pend_colon = 'O'; - - } elsif ($cur =~ /^(\[)/o) { - print "CLOSE($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) { - my $variant; - - print "OPV($1)\n" if ($dbg_values > 1); - if ($type eq 'V') { - $variant = 'B'; - } else { - $variant = 'U'; - } - - substr($var, length($res), 1, $variant); - $type = 'N'; - - } elsif ($cur =~ /^($Operators)/o) { - print "OP($1)\n" if ($dbg_values > 1); - if ($1 ne '++' && $1 ne '--') { - $type = 'N'; - } - - } elsif ($cur =~ /(^.)/o) { - print "C($1)\n" if ($dbg_values > 1); - } - if (defined $1) { - $cur = substr($cur, length($1)); - $res .= $type x length($1); - } - } - - return ($res, $var); -} - -sub possible { - my ($possible, $line) = @_; - my $notPermitted = qr{(?: - ^(?: - $Modifier| - $Storage| - $Type| - DEFINE_\S+ - )$| - ^(?: - goto| - return| - case| - else| - asm|__asm__| - do| - \#| - \#\# - )(?:\s|$)| - ^(?:typedef|struct|enum)\b - )}x; - warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2); - if ($possible !~ $notPermitted) { - # Check for modifiers. - $possible =~ s/\s*$Storage\s*//g; - $possible =~ s/\s*$Sparse\s*//g; - if ($possible =~ /^\s*$/) { - - } elsif ($possible =~ /\s/) { - $possible =~ s/\s*$Type\s*//g; - for my $modifier (split(' ', $possible)) { - if ($modifier !~ $notPermitted) { - warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible); - push(@modifierList, $modifier); - } - } - - } else { - warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible); - push(@typeList, $possible); - } - build_types(); - } else { - warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1); - } -} - -my $prefix = ''; - -sub report { - if (defined $tst_only && $_[0] !~ /\Q$tst_only\E/) { - return 0; - } - my $line = $prefix . $_[0]; - - $line = (split('\n', $line))[0] . "\n" if ($terse); - - push(our @report, $line); - - return 1; -} -sub report_dump { - our @report; -} -sub ERROR { - if (report("ERROR: $_[0]\n")) { - our $clean = 0; - our $cnt_error++; - } -} -sub WARN { - if (report("WARNING: $_[0]\n")) { - our $clean = 0; - our $cnt_warn++; - } -} -sub CHK { - if ($check && report("CHECK: $_[0]\n")) { - our $clean = 0; - our $cnt_chk++; - } -} - -sub process { - my $filename = shift; - - my $linenr=0; - my $prevline=""; - my $prevrawline=""; - my $stashline=""; - my $stashrawline=""; - - my $length; - my $indent; - my $previndent=0; - my $stashindent=0; - - our $clean = 1; - my $signoff = 0; - my $is_patch = 0; - - our @report = (); - our $cnt_lines = 0; - our $cnt_error = 0; - our $cnt_warn = 0; - our $cnt_chk = 0; - - # Trace the real file/line as we go. - my $realfile = ''; - my $realline = 0; - my $realcnt = 0; - my $here = ''; - my $in_comment = 0; - my $comment_edge = 0; - my $first_line = 0; - my $p1_prefix = ''; - - my $prev_values = 'E'; - - # suppression flags - my %suppress_ifbraces; - my %suppress_whiletrailers; - my %suppress_export; - - # Pre-scan the patch sanitizing the lines. - - sanitise_line_reset(); - my $line; - foreach my $rawline (@rawlines) { - $linenr++; - $line = $rawline; - - if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { - $realline=$1-1; - if (defined $2) { - $realcnt=$3+1; - } else { - $realcnt=1+1; - } - $in_comment = 0; - - # Guestimate if this is a continuing comment. Run - # the context looking for a comment "edge". If this - # edge is a close comment then we must be in a comment - # at context start. - my $edge; - my $cnt = $realcnt; - for (my $ln = $linenr + 1; $cnt > 0; $ln++) { - next if (defined $rawlines[$ln - 1] && - $rawlines[$ln - 1] =~ /^-/); - $cnt--; - #print "RAW<$rawlines[$ln - 1]>\n"; - last if (!defined $rawlines[$ln - 1]); - if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ && - $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) { - ($edge) = $1; - last; - } - } - if (defined $edge && $edge eq '*/') { - $in_comment = 1; - } - - # Guestimate if this is a continuing comment. If this - # is the start of a diff block and this line starts - # ' *' then it is very likely a comment. - if (!defined $edge && - $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@) - { - $in_comment = 1; - } - - ##print "COMMENT:$in_comment edge<$edge> $rawline\n"; - sanitise_line_reset($in_comment); - - } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) { - # Standardise the strings and chars within the input to - # simplify matching -- only bother with positive lines. - $line = sanitise_line($rawline); - } - push(@lines, $line); - - if ($realcnt > 1) { - $realcnt-- if ($line =~ /^(?:\+| |$)/); - } else { - $realcnt = 0; - } - - #print "==>$rawline\n"; - #print "-->$line\n"; - } - - $prefix = ''; - - $realcnt = 0; - $linenr = 0; - foreach my $line (@lines) { - $linenr++; - - my $rawline = $rawlines[$linenr - 1]; - -#extract the line range in the file after the patch is applied - if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { - $is_patch = 1; - $first_line = $linenr + 1; - $realline=$1-1; - if (defined $2) { - $realcnt=$3+1; - } else { - $realcnt=1+1; - } - annotate_reset(); - $prev_values = 'E'; - - %suppress_ifbraces = (); - %suppress_whiletrailers = (); - %suppress_export = (); - next; - -# track the line number as we move through the hunk, note that -# new versions of GNU diff omit the leading space on completely -# blank context lines so we need to count that too. - } elsif ($line =~ /^( |\+|$)/) { - $realline++; - $realcnt-- if ($realcnt != 0); - - # Measure the line length and indent. - ($length, $indent) = line_stats($rawline); - - # Track the previous line. - ($prevline, $stashline) = ($stashline, $line); - ($previndent, $stashindent) = ($stashindent, $indent); - ($prevrawline, $stashrawline) = ($stashrawline, $rawline); - - #warn "line<$line>\n"; - - } elsif ($realcnt == 1) { - $realcnt--; - } - - my $hunk_line = ($realcnt != 0); - -#make up the handle for any error we report on this line - $prefix = "$filename:$realline: " if ($emacs && $file); - $prefix = "$filename:$linenr: " if ($emacs && !$file); - - $here = "#$linenr: " if (!$file); - $here = "#$realline: " if ($file); - - # extract the filename as it passes - if ($line =~ /^diff --git.*?(\S+)$/) { - $realfile = $1; - $realfile =~ s@^([^/]*)/@@; - - } elsif ($line =~ /^\+\+\+\s+(\S+)/) { - $realfile = $1; - $realfile =~ s@^([^/]*)/@@; - - $p1_prefix = $1; - if (!$file && $tree && $p1_prefix ne '' && - -e "$root/$p1_prefix") { - WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); - } - - next; - } - - $here .= "FILE: $realfile:$realline:" if ($realcnt != 0); - - my $hereline = "$here\n$rawline\n"; - my $herecurr = "$here\n$rawline\n"; - my $hereprev = "$here\n$prevrawline\n$rawline\n"; - - $cnt_lines++ if ($realcnt != 0); - -# Check for incorrect file permissions - if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { - my $permhere = $here . "FILE: $realfile\n"; - if ($realfile =~ /(\bMakefile(?:\.objs)?|\.c|\.cc|\.cpp|\.h|\.mak|\.[sS])$/) { - ERROR("do not set execute permissions for source files\n" . $permhere); - } - } - -#check the patch for a signoff: - if ($line =~ /^\s*signed-off-by:/i) { - # This is a signoff, if ugly, so do not double report. - $signoff++; - if (!($line =~ /^\s*Signed-off-by:/)) { - WARN("Signed-off-by: is the preferred form\n" . - $herecurr); - } - if ($line =~ /^\s*signed-off-by:\S/i) { - WARN("space required after Signed-off-by:\n" . - $herecurr); - } - } - -# Check for wrappage within a valid hunk of the file - if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { - ERROR("patch seems to be corrupt (line wrapped?)\n" . - $herecurr) if (!$emitted_corrupt++); - } - -# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php - if (($realfile =~ /^$/ || $line =~ /^\+/) && - $rawline !~ m/^$UTF8*$/) { - my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/); - - my $blank = copy_spacing($rawline); - my $ptr = substr($blank, 0, length($utf8_prefix)) . "^"; - my $hereptr = "$hereline$ptr\n"; - - ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr); - } - -# ignore non-hunk lines and lines being removed - next if (!$hunk_line || $line =~ /^-/); - -#trailing whitespace - if ($line =~ /^\+.*\015/) { - my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("DOS line endings\n" . $herevet); - - } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { - my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("trailing whitespace\n" . $herevet); - $rpt_cleaners = 1; - } - -# check we are in a valid source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c|cpp|s|S|pl|sh)$/); - -#80 column limit - if ($line =~ /^\+/ && - !($line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) && - $length > 80) - { - WARN("line over 80 characters\n" . $herecurr); - } - -# check for spaces before a quoted newline - if ($rawline =~ /^.*\".*\s\\n/) { - WARN("unnecessary whitespace before a quoted newline\n" . $herecurr); - } - -# check for adding lines without a newline. - if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) { - WARN("adding a line without newline at end of file\n" . $herecurr); - } - -# check we are in a valid source file C or perl if not then ignore this hunk - next if ($realfile !~ /\.(h|c|cpp|pl)$/); - -# in QEMU, no tabs are allowed - if ($rawline =~ /^\+.*\t/) { - my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("code indent should never use tabs\n" . $herevet); - $rpt_cleaners = 1; - } - -# check we are in a valid C source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c|cpp)$/); - -# check for RCS/CVS revision markers - if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) { - WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr); - } - -# Check for potential 'bare' types - my ($stat, $cond, $line_nr_next, $remain_next, $off_next, - $realline_next); - if ($realcnt && $line =~ /.\s*\S/) { - ($stat, $cond, $line_nr_next, $remain_next, $off_next) = - ctx_statement_block($linenr, $realcnt, 0); - $stat =~ s/\n./\n /g; - $cond =~ s/\n./\n /g; - - # Find the real next line. - $realline_next = $line_nr_next; - if (defined $realline_next && - (!defined $lines[$realline_next - 1] || - substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) { - $realline_next++; - } - - my $s = $stat; - $s =~ s/{.*$//s; - - # Ignore goto labels. - if ($s =~ /$Ident:\*$/s) { - - # Ignore functions being called - } elsif ($s =~ /^.\s*$Ident\s*\(/s) { - - } elsif ($s =~ /^.\s*else\b/s) { - - # declarations always start with types - } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) { - my $type = $1; - $type =~ s/\s+/ /g; - possible($type, "A:" . $s); - - # definitions in global scope can only start with types - } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) { - possible($1, "B:" . $s); - } - - # any (foo ... *) is a pointer cast, and foo is a type - while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) { - possible($1, "C:" . $s); - } - - # Check for any sort of function declaration. - # int foo(something bar, other baz); - # void (*store_gdt)(x86_descr_ptr *); - if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) { - my ($name_len) = length($1); - - my $ctx = $s; - substr($ctx, 0, $name_len + 1, ''); - $ctx =~ s/\)[^\)]*$//; - - for my $arg (split(/\s*,\s*/, $ctx)) { - if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) { - - possible($1, "D:" . $s); - } - } - } - - } - -# -# Checks which may be anchored in the context. -# - -# Check for switch () and associated case and default -# statements should be at the same indent. - if ($line=~/\bswitch\s*\(.*\)/) { - my $err = ''; - my $sep = ''; - my @ctx = ctx_block_outer($linenr, $realcnt); - shift(@ctx); - for my $ctx (@ctx) { - my ($clen, $cindent) = line_stats($ctx); - if ($ctx =~ /^\+\s*(case\s+|default:)/ && - $indent != $cindent) { - $err .= "$sep$ctx\n"; - $sep = ''; - } else { - $sep = "[...]\n"; - } - } - if ($err ne '') { - ERROR("switch and case should be at the same indent\n$hereline$err"); - } - } - -# if/while/etc brace do not go on next line, unless defining a do while loop, -# or if that brace on the next line is for something else - if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { - my $pre_ctx = "$1$2"; - - my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); - my $ctx_cnt = $realcnt - $#ctx - 1; - my $ctx = join("\n", @ctx); - - my $ctx_ln = $linenr; - my $ctx_skip = $realcnt; - - while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt && - defined $lines[$ctx_ln - 1] && - $lines[$ctx_ln - 1] =~ /^-/)) { - ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n"; - $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/); - $ctx_ln++; - } - - #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n"; - #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n"; - - # The length of the "previous line" is checked against 80 because it - # includes the + at the beginning of the line (if the actual line has - # 79 or 80 characters, it is no longer possible to add a space and an - # opening brace there) - if ($#ctx == 0 && $ctx !~ /{\s*/ && - defined($lines[$ctx_ln - 1]) && $lines[$ctx_ln - 1] =~ /^\+\s*\{/ && - defined($lines[$ctx_ln - 2]) && length($lines[$ctx_ln - 2]) < 80) { - ERROR("that open brace { should be on the previous line\n" . - "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); - } - if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ && - $ctx =~ /\)\s*\;\s*$/ && - defined $lines[$ctx_ln - 1]) - { - my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]); - if ($nindent > $indent) { - WARN("trailing semicolon indicates no statements, indent implies otherwise\n" . - "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); - } - } - } - -# Check relative indent for conditionals and blocks. - if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { - my ($s, $c) = ($stat, $cond); - - substr($s, 0, length($c), ''); - - # Make sure we remove the line prefixes as we have - # none on the first line, and are going to readd them - # where necessary. - $s =~ s/\n./\n/gs; - - # Find out how long the conditional actually is. - my @newlines = ($c =~ /\n/gs); - my $cond_lines = 1 + $#newlines; - - # We want to check the first line inside the block - # starting at the end of the conditional, so remove: - # 1) any blank line termination - # 2) any opening brace { on end of the line - # 3) any do (...) { - my $continuation = 0; - my $check = 0; - $s =~ s/^.*\bdo\b//; - $s =~ s/^\s*\{//; - if ($s =~ s/^\s*\\//) { - $continuation = 1; - } - if ($s =~ s/^\s*?\n//) { - $check = 1; - $cond_lines++; - } - - # Also ignore a loop construct at the end of a - # preprocessor statement. - if (($prevline =~ /^.\s*#\s*define\s/ || - $prevline =~ /\\\s*$/) && $continuation == 0) { - $check = 0; - } - - my $cond_ptr = -1; - $continuation = 0; - while ($cond_ptr != $cond_lines) { - $cond_ptr = $cond_lines; - - # If we see an #else/#elif then the code - # is not linear. - if ($s =~ /^\s*\#\s*(?:else|elif)/) { - $check = 0; - } - - # Ignore: - # 1) blank lines, they should be at 0, - # 2) preprocessor lines, and - # 3) labels. - if ($continuation || - $s =~ /^\s*?\n/ || - $s =~ /^\s*#\s*?/ || - $s =~ /^\s*$Ident\s*:/) { - $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0; - if ($s =~ s/^.*?\n//) { - $cond_lines++; - } - } - } - - my (undef, $sindent) = line_stats("+" . $s); - my $stat_real = raw_line($linenr, $cond_lines); - - # Check if either of these lines are modified, else - # this is not this patch's fault. - if (!defined($stat_real) || - $stat !~ /^\+/ && $stat_real !~ /^\+/) { - $check = 0; - } - if (defined($stat_real) && $cond_lines > 1) { - $stat_real = "[...]\n$stat_real"; - } - - #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; - - if ($check && (($sindent % 4) != 0 || - ($sindent <= $indent && $s ne ''))) { - WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); - } - } - - # Track the 'values' across context and added lines. - my $opline = $line; $opline =~ s/^./ /; - my ($curr_values, $curr_vars) = - annotate_values($opline . "\n", $prev_values); - $curr_values = $prev_values . $curr_values; - if ($dbg_values) { - my $outline = $opline; $outline =~ s/\t/ /g; - print "$linenr > .$outline\n"; - print "$linenr > $curr_values\n"; - print "$linenr > $curr_vars\n"; - } - $prev_values = substr($curr_values, -1); - -#ignore lines not being added - if ($line=~/^[^\+]/) {next;} - -# TEST: allow direct testing of the type matcher. - if ($dbg_type) { - if ($line =~ /^.\s*$Declare\s*$/) { - ERROR("TEST: is type\n" . $herecurr); - } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) { - ERROR("TEST: is not type ($1 is)\n". $herecurr); - } - next; - } -# TEST: allow direct testing of the attribute matcher. - if ($dbg_attr) { - if ($line =~ /^.\s*$Modifier\s*$/) { - ERROR("TEST: is attr\n" . $herecurr); - } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) { - ERROR("TEST: is not attr ($1 is)\n". $herecurr); - } - next; - } - -# check for initialisation to aggregates open brace on the next line - if ($line =~ /^.\s*\{/ && - $prevline =~ /(?:^|[^=])=\s*$/) { - ERROR("that open brace { should be on the previous line\n" . $hereprev); - } - -# -# Checks which are anchored on the added line. -# - -# check for malformed paths in #include statements (uses RAW line) - if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) { - my $path = $1; - if ($path =~ m{//}) { - ERROR("malformed #include filename\n" . - $herecurr); - } - } - -# no C99 // comments - if ($line =~ m{//}) { - ERROR("do not use C99 // comments\n" . $herecurr); - } - # Remove C99 comments. - $line =~ s@//.*@@; - $opline =~ s@//.*@@; - -# check for global initialisers. - if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) { - ERROR("do not initialise globals to 0 or NULL\n" . - $herecurr); - } -# check for static initialisers. - if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) { - ERROR("do not initialise statics to 0 or NULL\n" . - $herecurr); - } - -# * goes on variable not on type - # (char*[ const]) - if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) { - my ($from, $to) = ($1, $1); - - # Should start with a space. - $to =~ s/^(\S)/ $1/; - # Should not end with a space. - $to =~ s/\s+$//; - # '*'s should not have spaces between. - while ($to =~ s/\*\s+\*/\*\*/) { - } - - #print "from<$from> to<$to>\n"; - if ($from ne $to) { - ERROR("\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr); - } - } elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) { - my ($from, $to, $ident) = ($1, $1, $2); - - # Should start with a space. - $to =~ s/^(\S)/ $1/; - # Should not end with a space. - $to =~ s/\s+$//; - # '*'s should not have spaces between. - while ($to =~ s/\*\s+\*/\*\*/) { - } - # Modifiers should have spaces. - $to =~ s/(\b$Modifier$)/$1 /; - - #print "from<$from> to<$to> ident<$ident>\n"; - if ($from ne $to && $ident !~ /^$Modifier$/) { - ERROR("\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr); - } - } - -# function brace can't be on same line, except for #defines of do while, -# or if closed on same line - if (($line=~/$Type\s*$Ident\(.*\).*\s\{/) and - !($line=~/\#\s*define.*do\s\{/) and !($line=~/}/)) { - ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr); - } - -# open braces for enum, union and struct go on the same line. - if ($line =~ /^.\s*\{/ && - $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { - ERROR("open brace '{' following $1 go on the same line\n" . $hereprev); - } - -# missing space after union, struct or enum definition - if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) { - ERROR("missing space after $1 definition\n" . $herecurr); - } - -# check for spacing round square brackets; allowed: -# 1. with a type on the left -- int [] a; -# 2. at the beginning of a line for slice initialisers -- [0...10] = 5, -# 3. inside a curly brace -- = { [0...10] = 5 } -# 4. after a comma -- [1] = 5, [2] = 6 -# 5. in a macro definition -- #define abc(x) [x] = y - while ($line =~ /(.*?\s)\[/g) { - my ($where, $prefix) = ($-[1], $1); - if ($prefix !~ /$Type\s+$/ && - ($where != 0 || $prefix !~ /^.\s+$/) && - $prefix !~ /{\s+$/ && - $prefix !~ /\#\s*define[^(]*\([^)]*\)\s+$/ && - $prefix !~ /,\s+$/) { - ERROR("space prohibited before open square bracket '['\n" . $herecurr); - } - } - -# check for spaces between functions and their parentheses. - while ($line =~ /($Ident)\s+\(/g) { - my $name = $1; - my $ctx_before = substr($line, 0, $-[1]); - my $ctx = "$ctx_before$name"; - - # Ignore those directives where spaces _are_ permitted. - if ($name =~ /^(?: - if|for|while|switch|return|case| - volatile|__volatile__| - __attribute__|format|__extension__| - asm|__asm__)$/x) - { - - # Ignore 'catch (...)' in C++ - } elsif ($name =~ /^catch$/ && $realfile =~ /(\.cpp|\.h)$/) { - - # cpp #define statements have non-optional spaces, ie - # if there is a space between the name and the open - # parenthesis it is simply not a parameter group. - } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) { - - # cpp #elif statement condition may start with a ( - } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) { - - # If this whole things ends with a type its most - # likely a typedef for a function. - } elsif ($ctx =~ /$Type$/) { - - } else { - WARN("space prohibited between function name and open parenthesis '('\n" . $herecurr); - } - } -# Check operator spacing. - if (!($line=~/\#\s*include/)) { - my $ops = qr{ - <<=|>>=|<=|>=|==|!=| - \+=|-=|\*=|\/=|%=|\^=|\|=|&=| - =>|->|<<|>>|<|>|=|!|~| - &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| - \?|::|: - }x; - my @elements = split(/($ops|;)/, $opline); - my $off = 0; - - my $blank = copy_spacing($opline); - - for (my $n = 0; $n < $#elements; $n += 2) { - $off += length($elements[$n]); - - # Pick up the preceding and succeeding characters. - my $ca = substr($opline, 0, $off); - my $cc = ''; - if (length($opline) >= ($off + length($elements[$n + 1]))) { - $cc = substr($opline, $off + length($elements[$n + 1])); - } - my $cb = "$ca$;$cc"; - - my $a = ''; - $a = 'V' if ($elements[$n] ne ''); - $a = 'W' if ($elements[$n] =~ /\s$/); - $a = 'C' if ($elements[$n] =~ /$;$/); - $a = 'B' if ($elements[$n] =~ /(\[|\()$/); - $a = 'O' if ($elements[$n] eq ''); - $a = 'E' if ($ca =~ /^\s*$/); - - my $op = $elements[$n + 1]; - - my $c = ''; - if (defined $elements[$n + 2]) { - $c = 'V' if ($elements[$n + 2] ne ''); - $c = 'W' if ($elements[$n + 2] =~ /^\s/); - $c = 'C' if ($elements[$n + 2] =~ /^$;/); - $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/); - $c = 'O' if ($elements[$n + 2] eq ''); - $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/); - } else { - $c = 'E'; - } - - my $ctx = "${a}x${c}"; - - my $at = "(ctx:$ctx)"; - - my $ptr = substr($blank, 0, $off) . "^"; - my $hereptr = "$hereline$ptr\n"; - - # Pull out the value of this operator. - my $op_type = substr($curr_values, $off + 1, 1); - - # Get the full operator variant. - my $opv = $op . substr($curr_vars, $off, 1); - - # Ignore operators passed as parameters. - if ($op_type ne 'V' && - $ca =~ /\s$/ && $cc =~ /^\s*,/) { - -# # Ignore comments -# } elsif ($op =~ /^$;+$/) { - - # ; should have either the end of line or a space or \ after it - } elsif ($op eq ';') { - if ($ctx !~ /.x[WEBC]/ && - $cc !~ /^\\/ && $cc !~ /^;/) { - ERROR("space required after that '$op' $at\n" . $hereptr); - } - - # // is a comment - } elsif ($op eq '//') { - - # Ignore : used in class declaration in C++ - } elsif ($opv eq ':B' && $ctx =~ /Wx[WE]/ && - $line =~ /class/ && $realfile =~ /(\.cpp|\.h)$/) { - - # No spaces for: - # -> - # : when part of a bitfield - } elsif ($op eq '->' || $opv eq ':B') { - if ($ctx =~ /Wx.|.xW/) { - ERROR("spaces prohibited around that '$op' $at\n" . $hereptr); - } - - # , must have a space on the right. - # not required when having a single },{ on one line - } elsif ($op eq ',') { - if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/ && - ($elements[$n] . $elements[$n + 2]) !~ " *}\\{") { - ERROR("space required after that '$op' $at\n" . $hereptr); - } - - # '*' as part of a type definition -- reported already. - } elsif ($opv eq '*_') { - #warn "'*' is part of type\n"; - - # unary operators should have a space before and - # none after. May be left adjacent to another - # unary operator, or a cast - } elsif ($op eq '!' || $op eq '~' || - $opv eq '*U' || $opv eq '-U' || - $opv eq '&U' || $opv eq '&&U') { - if ($op eq '~' && $ca =~ /::$/ && $realfile =~ /(\.cpp|\.h)$/) { - # '~' used as a name of Destructor - - } elsif ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { - ERROR("space required before that '$op' $at\n" . $hereptr); - } - if ($op eq '*' && $cc =~/\s*$Modifier\b/) { - # A unary '*' may be const - - } elsif ($ctx =~ /.xW/) { - ERROR("space prohibited after that '$op' $at\n" . $hereptr); - } - - # unary ++ and unary -- are allowed no space on one side. - } elsif ($op eq '++' or $op eq '--') { - if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) { - ERROR("space required one side of that '$op' $at\n" . $hereptr); - } - if ($ctx =~ /Wx[BE]/ || - ($ctx =~ /Wx./ && $cc =~ /^;/)) { - ERROR("space prohibited before that '$op' $at\n" . $hereptr); - } - if ($ctx =~ /ExW/) { - ERROR("space prohibited after that '$op' $at\n" . $hereptr); - } - - # A colon needs no spaces before when it is - # terminating a case value or a label. - } elsif ($opv eq ':C' || $opv eq ':L') { - if ($ctx =~ /Wx./) { - ERROR("space prohibited before that '$op' $at\n" . $hereptr); - } - - # All the others need spaces both sides. - } elsif ($ctx !~ /[EWC]x[CWE]/) { - my $ok = 0; - - if ($realfile =~ /\.cpp|\.h$/) { - # Ignore template arguments <...> in C++ - if (($op eq '<' || $op eq '>') && $line =~ /<.*>/) { - $ok = 1; - } - - # Ignore :: in C++ - if ($op eq '::') { - $ok = 1; - } - } - - # Ignore email addresses <foo@bar> - if (($op eq '<' && - $cc =~ /^\S+\@\S+>/) || - ($op eq '>' && - $ca =~ /<\S+\@\S+$/)) - { - $ok = 1; - } - - # Ignore ?: - if (($opv eq ':O' && $ca =~ /\?$/) || - ($op eq '?' && $cc =~ /^:/)) { - $ok = 1; - } - - if ($ok == 0) { - ERROR("spaces required around that '$op' $at\n" . $hereptr); - } - } - $off += length($elements[$n + 1]); - } - } - -#need space before brace following if, while, etc - if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) || - $line =~ /do\{/) { - ERROR("space required before the open brace '{'\n" . $herecurr); - } - -# closing brace should have a space following it when it has anything -# on the line - if ($line =~ /}(?!(?:,|;|\)))\S/) { - ERROR("space required after that close brace '}'\n" . $herecurr); - } - -# check spacing on square brackets - if ($line =~ /\[\s/ && $line !~ /\[\s*$/) { - ERROR("space prohibited after that open square bracket '['\n" . $herecurr); - } - if ($line =~ /\s\]/) { - ERROR("space prohibited before that close square bracket ']'\n" . $herecurr); - } - -# check spacing on parentheses - if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ && - $line !~ /for\s*\(\s+;/) { - ERROR("space prohibited after that open parenthesis '('\n" . $herecurr); - } - if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ && - $line !~ /for\s*\(.*;\s+\)/ && - $line !~ /:\s+\)/) { - ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr); - } - -# Return is not a function. - if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) { - my $spacing = $1; - my $value = $2; - - # Flatten any parentheses - $value =~ s/\(/ \(/g; - $value =~ s/\)/\) /g; - while ($value =~ s/\[[^\{\}]*\]/1/ || - $value !~ /(?:$Ident|-?$Constant)\s* - $Compare\s* - (?:$Ident|-?$Constant)/x && - $value =~ s/\([^\(\)]*\)/1/) { - } -#print "value<$value>\n"; - if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) { - ERROR("return is not a function, parentheses are not required\n" . $herecurr); - - } elsif ($spacing !~ /\s+/) { - ERROR("space required before the open parenthesis '('\n" . $herecurr); - } - } -# Return of what appears to be an errno should normally be -'ve - if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) { - my $name = $1; - if ($name ne 'EOF' && $name ne 'ERROR') { - WARN("return of an errno should typically be -ve (return -$1)\n" . $herecurr); - } - } - -# Need a space before open parenthesis after if, while etc - if ($line=~/\b(if|while|for|switch)\(/) { - ERROR("space required before the open parenthesis '('\n" . $herecurr); - } - -# Check for illegal assignment in if conditional -- and check for trailing -# statements after the conditional. - if ($line =~ /do\s*(?!{)/) { - my ($stat_next) = ctx_statement_block($line_nr_next, - $remain_next, $off_next); - $stat_next =~ s/\n./\n /g; - ##print "stat<$stat> stat_next<$stat_next>\n"; - - if ($stat_next =~ /^\s*while\b/) { - # If the statement carries leading newlines, - # then count those as offsets. - my ($whitespace) = - ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s); - my $offset = - statement_rawlines($whitespace) - 1; - - $suppress_whiletrailers{$line_nr_next + - $offset} = 1; - } - } - if (!defined $suppress_whiletrailers{$linenr} && - $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { - my ($s, $c) = ($stat, $cond); - - if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) { - ERROR("do not use assignment in if condition\n" . $herecurr); - } - - # Find out what is on the end of the line after the - # conditional. - substr($s, 0, length($c), ''); - $s =~ s/\n.*//g; - $s =~ s/$;//g; # Remove any comments - if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && - $c !~ /}\s*while\s*/) - { - # Find out how long the conditional actually is. - my @newlines = ($c =~ /\n/gs); - my $cond_lines = 1 + $#newlines; - my $stat_real = ''; - - $stat_real = raw_line($linenr, $cond_lines) - . "\n" if ($cond_lines); - if (defined($stat_real) && $cond_lines > 1) { - $stat_real = "[...]\n$stat_real"; - } - - ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real); - } - } - -# Check for bitwise tests written as boolean - if ($line =~ / - (?: - (?:\[|\(|\&\&|\|\|) - \s*0[xX][0-9]+\s* - (?:\&\&|\|\|) - | - (?:\&\&|\|\|) - \s*0[xX][0-9]+\s* - (?:\&\&|\|\||\)|\]) - )/x) - { - WARN("boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr); - } - -# if and else should not have general statements after it - if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { - my $s = $1; - $s =~ s/$;//g; # Remove any comments - if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { - ERROR("trailing statements should be on next line\n" . $herecurr); - } - } -# if should not continue a brace - if ($line =~ /}\s*if\b/) { - ERROR("trailing statements should be on next line\n" . - $herecurr); - } -# case and default should not have general statements after them - if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g && - $line !~ /\G(?: - (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$| - \s*return\s+ - )/xg) - { - ERROR("trailing statements should be on next line\n" . $herecurr); - } - - # Check for }<nl>else {, these must be at the same - # indent level to be relevant to each other. - if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and - $previndent == $indent) { - ERROR("else should follow close brace '}'\n" . $hereprev); - } - - if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and - $previndent == $indent) { - my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0); - - # Find out what is on the end of the line after the - # conditional. - substr($s, 0, length($c), ''); - $s =~ s/\n.*//g; - - if ($s =~ /^\s*;/) { - ERROR("while should follow close brace '}'\n" . $hereprev); - } - } - -#studly caps, commented out until figure out how to distinguish between use of existing and adding new -# if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) { -# print "No studly caps, use _\n"; -# print "$herecurr"; -# $clean = 0; -# } - -#no spaces allowed after \ in define - if ($line=~/\#\s*define.*\\\s$/) { - WARN("Whitepspace after \\ makes next lines useless\n" . $herecurr); - } - -# multi-statement macros should be enclosed in a do while loop, grab the -# first statement and ensure its the whole macro if its not enclosed -# in a known good container - if ($realfile !~ m@/vmlinux.lds.h$@ && - $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) { - my $ln = $linenr; - my $cnt = $realcnt; - my ($off, $dstat, $dcond, $rest); - my $ctx = ''; - - my $args = defined($1); - - # Find the end of the macro and limit our statement - # search to that. - while ($cnt > 0 && defined $lines[$ln - 1] && - $lines[$ln - 1] =~ /^(?:-|..*\\$)/) - { - $ctx .= $rawlines[$ln - 1] . "\n"; - $cnt-- if ($lines[$ln - 1] !~ /^-/); - $ln++; - } - $ctx .= $rawlines[$ln - 1]; - - ($dstat, $dcond, $ln, $cnt, $off) = - ctx_statement_block($linenr, $ln - $linenr + 1, 0); - #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n"; - #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n"; - - # Extract the remainder of the define (if any) and - # rip off surrounding spaces, and trailing \'s. - $rest = ''; - while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) { - #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n"; - if ($off != 0 || $lines[$ln - 1] !~ /^-/) { - $rest .= substr($lines[$ln - 1], $off) . "\n"; - $cnt--; - } - $ln++; - $off = 0; - } - $rest =~ s/\\\n.//g; - $rest =~ s/^\s*//s; - $rest =~ s/\s*$//s; - - # Clean up the original statement. - if ($args) { - substr($dstat, 0, length($dcond), ''); - } else { - $dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//; - } - $dstat =~ s/$;//g; - $dstat =~ s/\\\n.//g; - $dstat =~ s/^\s*//s; - $dstat =~ s/\s*$//s; - - # Flatten any parentheses and braces - while ($dstat =~ s/\([^\(\)]*\)/1/ || - $dstat =~ s/\{[^\{\}]*\}/1/ || - $dstat =~ s/\[[^\{\}]*\]/1/) - { - } - - my $exceptions = qr{ - $Declare| - module_param_named| - MODULE_PARAM_DESC| - DECLARE_PER_CPU| - DEFINE_PER_CPU| - __typeof__\(| - union| - struct| - \.$Ident\s*=\s*| - ^\"|\"$ - }x; - #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; - if ($rest ne '' && $rest ne ',') { - if ($rest !~ /while\s*\(/ && - $dstat !~ /$exceptions/) - { - ERROR("Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n"); - } - - } elsif ($ctx !~ /;/) { - if ($dstat ne '' && - $dstat !~ /^(?:$Ident|-?$Constant)$/ && - $dstat !~ /$exceptions/ && - $dstat !~ /^\.$Ident\s*=/ && - $dstat =~ /$Operators/) - { - ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n"); - } - } - } - -# check for missing bracing round if etc - if ($line =~ /(^.*)\bif\b/ && $line !~ /\#\s*if/) { - my ($level, $endln, @chunks) = - ctx_statement_full($linenr, $realcnt, 1); - if ($dbg_adv_apw) { - print "APW: chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; - print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n" - if $#chunks >= 1; - } - if ($#chunks >= 0 && $level == 0) { - my $allowed = 0; - my $seen = 0; - my $herectx = $here . "\n"; - my $ln = $linenr - 1; - for my $chunk (@chunks) { - my ($cond, $block) = @{$chunk}; - - # If the condition carries leading newlines, then count those as offsets. - my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s); - my $offset = statement_rawlines($whitespace) - 1; - - #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n"; - - # We have looked at and allowed this specific line. - $suppress_ifbraces{$ln + $offset} = 1; - - $herectx .= "$rawlines[$ln + $offset]\n[...]\n"; - $ln += statement_rawlines($block) - 1; - - substr($block, 0, length($cond), ''); - - my $spaced_block = $block; - $spaced_block =~ s/\n\+/ /g; - - $seen++ if ($spaced_block =~ /^\s*\{/); - - print "APW: cond<$cond> block<$block> allowed<$allowed>\n" - if $dbg_adv_apw; - if (statement_lines($cond) > 1) { - print "APW: ALLOWED: cond<$cond>\n" - if $dbg_adv_apw; - $allowed = 1; - } - if ($block =~/\b(?:if|for|while)\b/) { - print "APW: ALLOWED: block<$block>\n" - if $dbg_adv_apw; - $allowed = 1; - } - if (statement_block_size($block) > 1) { - print "APW: ALLOWED: lines block<$block>\n" - if $dbg_adv_apw; - $allowed = 1; - } - } - if ($seen != ($#chunks + 1)) { - WARN("braces {} are necessary for all arms of this statement\n" . $herectx); - } - } - } - if (!defined $suppress_ifbraces{$linenr - 1} && - $line =~ /\b(if|while|for|else)\b/ && - $line !~ /\#\s*if/ && - $line !~ /\#\s*else/) { - my $allowed = 0; - - # Check the pre-context. - if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { - my $pre = $1; - - if ($line !~ /else/) { - print "APW: ALLOWED: pre<$pre> line<$line>\n" - if $dbg_adv_apw; - $allowed = 1; - } - } - - my ($level, $endln, @chunks) = - ctx_statement_full($linenr, $realcnt, $-[0]); - - # Check the condition. - my ($cond, $block) = @{$chunks[0]}; - print "CHECKING<$linenr> cond<$cond> block<$block>\n" - if $dbg_adv_checking; - if (defined $cond) { - substr($block, 0, length($cond), ''); - } - if (statement_lines($cond) > 1) { - print "APW: ALLOWED: cond<$cond>\n" - if $dbg_adv_apw; - $allowed = 1; - } - if ($block =~/\b(?:if|for|while)\b/) { - print "APW: ALLOWED: block<$block>\n" - if $dbg_adv_apw; - $allowed = 1; - } - if (statement_block_size($block) > 1) { - print "APW: ALLOWED: lines block<$block>\n" - if $dbg_adv_apw; - $allowed = 1; - } - # Check the post-context. - if (defined $chunks[1]) { - my ($cond, $block) = @{$chunks[1]}; - if (defined $cond) { - substr($block, 0, length($cond), ''); - } - if ($block =~ /^\s*\{/) { - print "APW: ALLOWED: chunk-1 block<$block>\n" - if $dbg_adv_apw; - $allowed = 1; - } - } - print "DCS: level=$level block<$block> allowed=$allowed\n" - if $dbg_adv_dcs; - if ($level == 0 && $block !~ /^\s*\{/ && !$allowed) { - my $herectx = $here . "\n";; - my $cnt = statement_rawlines($block); - - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n";; - } - - WARN("braces {} are necessary even for single statement blocks\n" . $herectx); - } - } - -# no volatiles please - my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b}; - if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) { - WARN("Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr); - } - -# warn about #if 0 - if ($line =~ /^.\s*\#\s*if\s+0\b/) { - WARN("if this code is redundant consider removing it\n" . - $herecurr); - } - -# check for needless g_free() checks - if ($prevline =~ /\bif\s*\(([^\)]*)\)/) { - my $expr = $1; - if ($line =~ /\bg_free\(\Q$expr\E\);/) { - WARN("g_free(NULL) is safe this check is probably not required\n" . $hereprev); - } - } - -# warn about #ifdefs in C files -# if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) { -# print "#ifdef in C files should be avoided\n"; -# print "$herecurr"; -# $clean = 0; -# } - -# warn about spacing in #ifdefs - if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) { - ERROR("exactly one space required after that #$1\n" . $herecurr); - } -# check for memory barriers without a comment. - if ($line =~ /\b(smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) { - if (!ctx_has_comment($first_line, $linenr)) { - WARN("memory barrier without comment\n" . $herecurr); - } - } -# check of hardware specific defines -# we have e.g. CONFIG_LINUX and CONFIG_WIN32 for common cases -# where they might be necessary. - if ($line =~ m@^.\s*\#\s*if.*\b__@) { - WARN("architecture specific defines should be avoided\n" . $herecurr); - } - -# Check that the storage class is at the beginning of a declaration - if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) { - WARN("storage class should be at the beginning of the declaration\n" . $herecurr) - } - -# check the location of the inline attribute, that it is between -# storage class and type. - if ($line =~ /\b$Type\s+$Inline\b/ || - $line =~ /\b$Inline\s+$Storage\b/) { - ERROR("inline keyword should sit between storage class and type\n" . $herecurr); - } - -# check for sizeof(&) - if ($line =~ /\bsizeof\s*\(\s*\&/) { - WARN("sizeof(& should be avoided\n" . $herecurr); - } - -# check for new externs in .c files. - if ($realfile =~ /\.c$/ && defined $stat && - $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) - { - my $function_name = $1; - my $paren_space = $2; - - my $s = $stat; - if (defined $cond) { - substr($s, 0, length($cond), ''); - } - if ($s =~ /^\s*;/ && - $function_name ne 'uninitialized_var') - { - WARN("externs should be avoided in .c files\n" . $herecurr); - } - - if ($paren_space =~ /\n/) { - WARN("arguments for function declarations should follow identifier\n" . $herecurr); - } - - } elsif ($realfile =~ /\.c$/ && defined $stat && - $stat =~ /^.\s*extern\s+/) - { - WARN("externs should be avoided in .c files\n" . $herecurr); - } - -# check for pointless casting of g_malloc return - if ($line =~ /\*\s*\)\s*g_(try)?(m|re)alloc(0?)(_n)?\b/) { - if ($2 == 'm') { - WARN("unnecessary cast may hide bugs, use g_$1new$3 instead\n" . $herecurr); - } else { - WARN("unnecessary cast may hide bugs, use g_$1renew$3 instead\n" . $herecurr); - } - } - -# check for gcc specific __FUNCTION__ - if ($line =~ /__FUNCTION__/) { - WARN("__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr); - } - -# recommend qemu_strto* over strto* for numeric conversions - if ($line =~ /\b(strto[^k].*?)\s*\(/) { - WARN("consider using qemu_$1 in preference to $1\n" . $herecurr); - } -# check for module_init(), use category-specific init macros explicitly please - if ($line =~ /^module_init\s*\(/) { - WARN("please use block_init(), type_init() etc. instead of module_init()\n" . $herecurr); - } -# check for various ops structs, ensure they are const. - my $struct_ops = qr{AIOCBInfo| - BdrvActionOps| - BlockDevOps| - BlockJobDriver| - DisplayChangeListenerOps| - GraphicHwOps| - IDEDMAOps| - KVMCapabilityInfo| - MemoryRegionIOMMUOps| - MemoryRegionOps| - MemoryRegionPortio| - QEMUFileOps| - SCSIBusInfo| - SCSIReqOps| - Spice[A-Z][a-zA-Z0-9]*Interface| - TPMDriverOps| - USBDesc[A-Z][a-zA-Z0-9]*| - VhostOps| - VMStateDescription| - VMStateInfo}x; - if ($line !~ /\bconst\b/ && - $line =~ /\b($struct_ops)\b/) { - WARN("struct $1 should normally be const\n" . - $herecurr); - } - -# check for %L{u,d,i} in strings - my $string; - while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { - $string = substr($rawline, $-[1], $+[1] - $-[1]); - $string =~ s/%%/__/g; - if ($string =~ /(?<!%)%L[udi]/) { - WARN("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr); - last; - } - } - -# QEMU specific tests - if ($rawline =~ /\b(?:Qemu|QEmu)\b/) { - WARN("use QEMU instead of Qemu or QEmu\n" . $herecurr); - } - -# Qemu error function tests - - # Find newlines in error messages - my $qemu_error_funcs = qr{error_setg| - error_setg_errno| - error_setg_win32| - error_set| - error_vreport| - error_report}x; - - if ($rawline =~ /\b(?:$qemu_error_funcs)\s*\(\s*\".*\\n/) { - WARN("Error messages should not contain newlines\n" . $herecurr); - } - - # Continue checking for error messages that contains newlines. This - # check handles cases where string literals are spread over multiple lines. - # Example: - # error_report("Error msg line #1" - # "Error msg line #2\n"); - my $quoted_newline_regex = qr{\+\s*\".*\\n.*\"}; - my $continued_str_literal = qr{\+\s*\".*\"}; - - if ($rawline =~ /$quoted_newline_regex/) { - # Backtrack to first line that does not contain only a quoted literal - # and assume that it is the start of the statement. - my $i = $linenr - 2; - - while (($i >= 0) & $rawlines[$i] =~ /$continued_str_literal/) { - $i--; - } - - if ($rawlines[$i] =~ /\b(?:$qemu_error_funcs)\s*\(/) { - WARN("Error messages should not contain newlines\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 - # so just keep quiet. - if ($#rawlines == -1) { - exit(0); - } - - # In mailback mode only produce a report in the negative, for - # things that appear to be patches. - if ($mailback && ($clean == 1 || !$is_patch)) { - exit(0); - } - - # This is not a patch, and we are are in 'no-patch' mode so - # just keep quiet. - if (!$chk_patch && !$is_patch) { - exit(0); - } - - if (!$is_patch) { - ERROR("Does not appear to be a unified-diff format patch\n"); - } - if ($is_patch && $chk_signoff && $signoff == 0) { - ERROR("Missing Signed-off-by: line(s)\n"); - } - - print report_dump(); - if ($summary && !($clean == 1 && $quiet == 1)) { - print "$filename " if ($summary_file); - print "total: $cnt_error errors, $cnt_warn warnings, " . - (($check)? "$cnt_chk checks, " : "") . - "$cnt_lines lines checked\n"; - print "\n" if ($quiet == 0); - } - - if ($quiet == 0) { - # If there were whitespace errors which cleanpatch can fix - # then suggest that. -# if ($rpt_cleaners) { -# print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n"; -# print " scripts/cleanfile\n\n"; -# } - } - - if ($clean == 1 && $quiet == 0) { - print "$vname has no obvious style problems and is ready for submission.\n" - } - if ($clean == 0 && $quiet == 0) { - print "$vname has style problems, please review. If any of these errors\n"; - print "are false positives report them to the maintainer, see\n"; - print "CHECKPATCH in MAINTAINERS.\n"; - } - - return $clean; -} diff --git a/qemu/scripts/clean-includes b/qemu/scripts/clean-includes deleted file mode 100755 index 72b47f17f..000000000 --- a/qemu/scripts/clean-includes +++ /dev/null @@ -1,165 +0,0 @@ -#!/bin/sh -e -# -# Clean up QEMU #include lines by ensuring that qemu/osdep.h -# is the first include listed in .c files, and no headers provided -# by osdep.h itself are redundantly included in either .c or .h files. -# -# Copyright (c) 2015 Linaro Limited -# -# Authors: -# Peter Maydell <peter.maydell@linaro.org> -# -# This work is licensed under the terms of the GNU GPL, version 2 -# or (at your option) any later version. See the COPYING file in -# the top-level directory. - -# Usage: -# clean-includes [--git subjectprefix] file ... -# or -# clean-includes [--git subjectprefix] --all -# -# If the --git subjectprefix option is given, then after making -# the changes to the files this script will create a git commit -# with the subject line "subjectprefix: Clean up includes" -# and a boilerplate commit message. -# -# Using --all will cause clean-includes to run on the whole source -# tree (excluding certain directories which are known not to need -# handling). - -# This script requires Coccinelle to be installed. - -# .c files will have the osdep.h included added, and redundant -# includes removed. -# .h files will have redundant includes (including includes of osdep.h) -# removed. -# Other files (including C++ and ObjectiveC) can't be handled by this script. - -# The following one-liner may be handy for finding files to run this on. -# However some caution is required regarding files that might be part -# of the guest agent or standalone tests. - -# for i in `git ls-tree --name-only HEAD` ; do test -f $i && \ -# grep -E '^# *include' $i | head -1 | grep 'osdep.h' ; test $? != 0 && \ -# echo $i ; done - - -GIT=no - -# Extended regular expression defining files to ignore when using --all -XDIRREGEX='^(tests/tcg|tests/multiboot|pc-bios|disas/libvixl)' - -if [ $# -ne 0 ] && [ "$1" = "--git" ]; then - if [ $# -eq 1 ]; then - echo "--git option requires an argument" - exit 1 - fi - GITSUBJ="$2" - GIT=yes - shift - shift -fi - -if [ $# -eq 0 ]; then - echo "Usage: clean-includes [--git subjectprefix] [--all | foo.c ...]" - echo "(modifies the files in place)" - exit 1 -fi - -if [ "$1" = "--all" ]; then - # We assume there are no files in the tree with spaces in their name - set -- $(git ls-files '*.[ch]' | grep -E -v "$XDIRREGEX") -fi - -# Annoyingly coccinelle won't read a scriptfile unless its -# name ends '.cocci', so write it out to a tempfile with the -# right kind of name. -COCCIFILE="$(mktemp --suffix=.cocci)" - -trap 'rm -f -- "$COCCIFILE"' INT TERM HUP EXIT - -cat >"$COCCIFILE" <<EOT -@@ -@@ - -( -+ #include "qemu/osdep.h" - #include "..." -| -+ #include "qemu/osdep.h" - #include <...> -) -EOT - - -for f in "$@"; do - case "$f" in - *.inc.c) - # These aren't standalone C source files - echo "SKIPPING $f (not a standalone source file)" - continue - ;; - *.c) - MODE=c - ;; - *include/qemu/osdep.h | \ - *include/qemu/compiler.h | \ - *include/standard-headers/ ) - # Removing include lines from osdep.h itself would be counterproductive. - echo "SKIPPING $f (special case header)" - continue - ;; - *include/standard-headers/*) - echo "SKIPPING $f (autogenerated header)" - continue - ;; - *.h) - MODE=h - ;; - *) - echo "WARNING: ignoring $f (cannot handle non-C files)" - continue - ;; - esac - - if [ "$MODE" = "c" ]; then - # First, use Coccinelle to add qemu/osdep.h before the first existing include - # (this will add two lines if the file uses both "..." and <...> #includes, - # but we will remove the extras in the next step) - spatch --in-place --no-show-diff --cocci-file "$COCCIFILE" "$f" - - # Now remove any duplicate osdep.h includes - perl -n -i -e 'print if !/#include "qemu\/osdep.h"/ || !$n++;' "$f" - else - # Remove includes of osdep.h itself - perl -n -i -e 'print if !/\s*#\s*include\s*(["<][^>"]*[">])/ || - ! (grep { $_ eq $1 } qw ("qemu/osdep.h"))' "$f" - fi - - # Remove includes that osdep.h already provides - perl -n -i -e 'print if !/\s*#\s*include\s*(["<][^>"]*[">])/ || - ! (grep { $_ eq $1 } qw ( - "config-host.h" "config-target.h" "qemu/compiler.h" - <setjmp.h> <stdarg.h> <stddef.h> <stdbool.h> <stdint.h> <sys/types.h> - <stdlib.h> <stdio.h> <string.h> <strings.h> <inttypes.h> - <limits.h> <unistd.h> <time.h> <ctype.h> <errno.h> <fcntl.h> - <sys/stat.h> <sys/time.h> <assert.h> <signal.h> - "sysemu/os-posix.h, sysemu/os-win32.h "glib-compat.h" - "qemu/typedefs.h" - ))' "$f" - -done - -if [ "$GIT" = "yes" ]; then - git add -- "$@" - git commit --signoff -F - <<EOF -$GITSUBJ: Clean up includes - -Clean up includes so that osdep.h is included first and headers -which it implies are not included manually. - -This commit was created with scripts/clean-includes. - -EOF - -fi diff --git a/qemu/scripts/cleanup-trace-events.pl b/qemu/scripts/cleanup-trace-events.pl deleted file mode 100755 index 7e808efb6..000000000 --- a/qemu/scripts/cleanup-trace-events.pl +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/perl -# Copyright (C) 2013 Red Hat, Inc. -# -# Authors: -# Markus Armbruster <armbru@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. - -# Usage: cleanup-trace-events.pl trace-events -# -# Print cleaned up trace-events to standard output. - -use warnings; -use strict; - -my $buf = ''; -my %seen = (); - -sub out { - print $buf; - $buf = ''; - %seen = (); -} - -while (<>) { - if (/^(disable )?([a-z_0-9]+)\(/) { - open GREP, '-|', 'git', 'grep', '-lw', "trace_$2" - or die "run git grep: $!"; - my $fname; - while ($fname = <GREP>) { - chomp $fname; - next if $seen{$fname} || $fname eq 'trace-events'; - $seen{$fname} = 1; - $buf = "# $fname\n" . $buf; - } - unless (close GREP) { - die "close git grep: $!" - if $!; - next; - } - } elsif (/^# ([^ ]*\.[ch])$/) { - out; - next; - } elsif (!/^#|^$/) { - warn "unintelligible line"; - } - $buf .= $_; -} - -out; diff --git a/qemu/scripts/cocci-macro-file.h b/qemu/scripts/cocci-macro-file.h deleted file mode 100644 index eceb4be73..000000000 --- a/qemu/scripts/cocci-macro-file.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Macro file for Coccinelle - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Authors: - * Paolo Bonzini <pbonzini@redhat.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or, at your - * option, any later version. See the COPYING file in the top-level directory. - */ - -/* Coccinelle only does limited parsing of headers, and chokes on some idioms - * defined in compiler.h and queue.h. Macros that Coccinelle must know about - * in order to parse .c files must be in a separate macro file---which is - * exactly what you're staring at now. - * - * To use this file, add the "--macro-file scripts/cocci-macro-file.h" to the - * Coccinelle command line. - */ - -/* From qemu/compiler.h */ -#define QEMU_GNUC_PREREQ(maj, min) 1 -#define QEMU_NORETURN __attribute__ ((__noreturn__)) -#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -#define QEMU_SENTINEL __attribute__((sentinel)) -#define QEMU_ARTIFICIAL __attribute__((always_inline, artificial)) -#define QEMU_PACKED __attribute__((gcc_struct, packed)) - -#define cat(x,y) x ## y -#define cat2(x,y) cat(x,y) -#define QEMU_BUILD_BUG_ON(x) \ - typedef char cat2(qemu_build_bug_on__,__LINE__)[(x)?-1:1] __attribute__((unused)); - -#define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m))) - -#define xglue(x, y) x ## y -#define glue(x, y) xglue(x, y) -#define stringify(s) tostring(s) -#define tostring(s) #s - -#define typeof_field(type, field) typeof(((type *)0)->field) -#define type_check(t1,t2) ((t1*)0 - (t2*)0) - -/* From qemu/queue.h */ - -#define QLIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define QLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define QLIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * Singly-linked List definitions. - */ -#define QSLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define QSLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define QSLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Simple queue definitions. - */ -#define QSIMPLEQ_HEAD(name, type) \ -struct name { \ - struct type *sqh_first; /* first element */ \ - struct type **sqh_last; /* addr of last next element */ \ -} - -#define QSIMPLEQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).sqh_first } - -#define QSIMPLEQ_ENTRY(type) \ -struct { \ - struct type *sqe_next; /* next element */ \ -} - -/* - * Tail queue definitions. - */ -#define Q_TAILQ_HEAD(name, type, qual) \ -struct name { \ - qual type *tqh_first; /* first element */ \ - qual type *qual *tqh_last; /* addr of last next element */ \ -} -#define QTAILQ_HEAD(name, type) \ -struct name { \ - type *tqh_first; /* first element */ \ - type **tqh_last; /* addr of last next element */ \ -} - -#define QTAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define Q_TAILQ_ENTRY(type, qual) \ -struct { \ - qual type *tqe_next; /* next element */ \ - qual type *qual *tqe_prev; /* address of previous next element */\ -} -#define QTAILQ_ENTRY(type) \ -struct { \ - type *tqe_next; /* next element */ \ - type **tqe_prev; /* address of previous next element */ \ -} diff --git a/qemu/scripts/coverity-model.c b/qemu/scripts/coverity-model.c deleted file mode 100644 index ee5bf9d07..000000000 --- a/qemu/scripts/coverity-model.c +++ /dev/null @@ -1,369 +0,0 @@ -/* Coverity Scan model - * - * Copyright (C) 2014 Red Hat, Inc. - * - * Authors: - * Markus Armbruster <armbru@redhat.com> - * Paolo Bonzini <pbonzini@redhat.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or, at your - * option, any later version. See the COPYING file in the top-level directory. - */ - - -/* - * This is the source code for our Coverity user model file. The - * purpose of user models is to increase scanning accuracy by explaining - * code Coverity can't see (out of tree libraries) or doesn't - * sufficiently understand. Better accuracy means both fewer false - * positives and more true defects. Memory leaks in particular. - * - * - A model file can't import any header files. Some built-in primitives are - * available but not wchar_t, NULL etc. - * - Modeling doesn't need full structs and typedefs. Rudimentary structs - * and similar types are sufficient. - * - An uninitialized local variable signifies that the variable could be - * any value. - * - * The model file must be uploaded by an admin in the analysis settings of - * http://scan.coverity.com/projects/378 - */ - -#define NULL ((void *)0) - -typedef unsigned char uint8_t; -typedef char int8_t; -typedef unsigned int uint32_t; -typedef int int32_t; -typedef long ssize_t; -typedef unsigned long long uint64_t; -typedef long long int64_t; -typedef _Bool bool; - -typedef struct va_list_str *va_list; - -/* exec.c */ - -typedef struct AddressSpace AddressSpace; -typedef uint64_t hwaddr; -typedef uint32_t MemTxResult; -typedef uint64_t MemTxAttrs; - -static void __bufwrite(uint8_t *buf, ssize_t len) -{ - int first, last; - __coverity_negative_sink__(len); - if (len == 0) return; - buf[0] = first; - buf[len-1] = last; - __coverity_writeall__(buf); -} - -static void __bufread(uint8_t *buf, ssize_t len) -{ - __coverity_negative_sink__(len); - if (len == 0) return; - int first = buf[0]; - int last = buf[len-1]; -} - -MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, - uint8_t *buf, int len, bool is_write) -{ - MemTxResult result; - - // TODO: investigate impact of treating reads as producing - // tainted data, with __coverity_tainted_data_argument__(buf). - if (is_write) __bufread(buf, len); else __bufwrite(buf, len); - - return result; -} - -/* Tainting */ - -typedef struct {} name2keysym_t; -static int get_keysym(const name2keysym_t *table, - const char *name) -{ - int result; - if (result > 0) { - __coverity_tainted_string_sanitize_content__(name); - return result; - } else { - return 0; - } -} - -/* - * GLib memory allocation functions. - * - * Note that we ignore the fact that g_malloc of 0 bytes returns NULL, - * and g_realloc of 0 bytes frees the pointer. - * - * Modeling this would result in Coverity flagging a lot of memory - * allocations as potentially returning NULL, and asking us to check - * whether the result of the allocation is NULL or not. However, the - * resulting pointer should never be dereferenced anyway, and in fact - * it is not in the vast majority of cases. - * - * If a dereference did happen, this would suppress a defect report - * for an actual null pointer dereference. But it's too unlikely to - * be worth wading through the false positives, and with some luck - * we'll get a buffer overflow reported anyway. - */ - -/* - * Allocation primitives, cannot return NULL - * See also Coverity's library/generic/libc/all/all.c - */ - -void *g_malloc_n(size_t nmemb, size_t size) -{ - size_t sz; - void *ptr; - - __coverity_negative_sink__(nmemb); - __coverity_negative_sink__(size); - sz = nmemb * size; - ptr = __coverity_alloc__(sz); - __coverity_mark_as_uninitialized_buffer__(ptr); - __coverity_mark_as_afm_allocated__(ptr, "g_free"); - return ptr; -} - -void *g_malloc0_n(size_t nmemb, size_t size) -{ - size_t sz; - void *ptr; - - __coverity_negative_sink__(nmemb); - __coverity_negative_sink__(size); - sz = nmemb * size; - ptr = __coverity_alloc__(sz); - __coverity_writeall0__(ptr); - __coverity_mark_as_afm_allocated__(ptr, "g_free"); - return ptr; -} - -void *g_realloc_n(void *ptr, size_t nmemb, size_t size) -{ - size_t sz; - - __coverity_negative_sink__(nmemb); - __coverity_negative_sink__(size); - sz = nmemb * size; - __coverity_escape__(ptr); - ptr = __coverity_alloc__(sz); - /* - * Memory beyond the old size isn't actually initialized. Can't - * model that. See Coverity's realloc() model - */ - __coverity_writeall__(ptr); - __coverity_mark_as_afm_allocated__(ptr, "g_free"); - return ptr; -} - -void g_free(void *ptr) -{ - __coverity_free__(ptr); - __coverity_mark_as_afm_freed__(ptr, "g_free"); -} - -/* - * Derive the g_try_FOO_n() from the g_FOO_n() by adding indeterminate - * out of memory conditions - */ - -void *g_try_malloc_n(size_t nmemb, size_t size) -{ - int nomem; - - if (nomem) { - return NULL; - } - return g_malloc_n(nmemb, size); -} - -void *g_try_malloc0_n(size_t nmemb, size_t size) -{ - int nomem; - - if (nomem) { - return NULL; - } - return g_malloc0_n(nmemb, size); -} - -void *g_try_realloc_n(void *ptr, size_t nmemb, size_t size) -{ - int nomem; - - if (nomem) { - return NULL; - } - return g_realloc_n(ptr, nmemb, size); -} - -/* Trivially derive the g_FOO() from the g_FOO_n() */ - -void *g_malloc(size_t size) -{ - return g_malloc_n(1, size); -} - -void *g_malloc0(size_t size) -{ - return g_malloc0_n(1, size); -} - -void *g_realloc(void *ptr, size_t size) -{ - return g_realloc_n(ptr, 1, size); -} - -void *g_try_malloc(size_t size) -{ - return g_try_malloc_n(1, size); -} - -void *g_try_malloc0(size_t size) -{ - return g_try_malloc0_n(1, size); -} - -void *g_try_realloc(void *ptr, size_t size) -{ - return g_try_realloc_n(ptr, 1, size); -} - -/* Other memory allocation functions */ - -void *g_memdup(const void *ptr, unsigned size) -{ - unsigned char *dup; - unsigned i; - - if (!ptr) { - return NULL; - } - - dup = g_malloc(size); - for (i = 0; i < size; i++) - dup[i] = ((unsigned char *)ptr)[i]; - return dup; -} - -/* - * GLib string allocation functions - */ - -char *g_strdup(const char *s) -{ - char *dup; - size_t i; - - if (!s) { - return NULL; - } - - __coverity_string_null_sink__(s); - __coverity_string_size_sink__(s); - dup = __coverity_alloc_nosize__(); - __coverity_mark_as_afm_allocated__(dup, "g_free"); - for (i = 0; (dup[i] = s[i]); i++) ; - return dup; -} - -char *g_strndup(const char *s, size_t n) -{ - char *dup; - size_t i; - - __coverity_negative_sink__(n); - - if (!s) { - return NULL; - } - - dup = g_malloc(n + 1); - for (i = 0; i < n && (dup[i] = s[i]); i++) ; - dup[i] = 0; - return dup; -} - -char *g_strdup_printf(const char *format, ...) -{ - char ch, *s; - size_t len; - - __coverity_string_null_sink__(format); - __coverity_string_size_sink__(format); - - ch = *format; - - s = __coverity_alloc_nosize__(); - __coverity_writeall__(s); - __coverity_mark_as_afm_allocated__(s, "g_free"); - return s; -} - -char *g_strdup_vprintf(const char *format, va_list ap) -{ - char ch, *s; - size_t len; - - __coverity_string_null_sink__(format); - __coverity_string_size_sink__(format); - - ch = *format; - ch = *(char *)ap; - - s = __coverity_alloc_nosize__(); - __coverity_writeall__(s); - __coverity_mark_as_afm_allocated__(s, "g_free"); - - return len; -} - -char *g_strconcat(const char *s, ...) -{ - char *s; - - /* - * Can't model: last argument must be null, the others - * null-terminated strings - */ - - s = __coverity_alloc_nosize__(); - __coverity_writeall__(s); - __coverity_mark_as_afm_allocated__(s, "g_free"); - return s; -} - -/* Other glib functions */ - -typedef struct pollfd GPollFD; - -int poll(); - -int g_poll (GPollFD *fds, unsigned nfds, int timeout) -{ - return poll(fds, nfds, timeout); -} - -typedef struct _GIOChannel GIOChannel; -GIOChannel *g_io_channel_unix_new(int fd) -{ - GIOChannel *c = g_malloc0(sizeof(GIOChannel)); - __coverity_escape__(fd); - return c; -} - -void g_assertion_message_expr(const char *domain, - const char *file, - int line, - const char *func, - const char *expr) -{ - __coverity_panic__(); -} diff --git a/qemu/scripts/create_config b/qemu/scripts/create_config deleted file mode 100755 index 9cb176f1b..000000000 --- a/qemu/scripts/create_config +++ /dev/null @@ -1,125 +0,0 @@ -#!/bin/sh - -echo "/* Automatically generated by create_config - do not modify */" - -while read line; do - -case $line in - VERSION=*) # configuration - version=${line#*=} - echo "#define QEMU_VERSION \"$version\"" - ;; - PKGVERSION=*) # configuration - pkgversion=${line#*=} - echo "#define QEMU_PKGVERSION \"$pkgversion\"" - ;; - qemu_*dir=*) # qemu-specific directory configuration - name=${line%=*} - value=${line#*=} - define_name=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'` - eval "define_value=\"$value\"" - echo "#define CONFIG_$define_name \"$define_value\"" - # save for the next definitions - eval "$name=\$define_value" - ;; - prefix=*) - # save for the next definitions - prefix=${line#*=} - ;; - IASL=*) # iasl executable - value=${line#*=} - echo "#define CONFIG_IASL $value" - ;; - CONFIG_AUDIO_DRIVERS=*) - drivers=${line#*=} - echo "#define CONFIG_AUDIO_DRIVERS \\" - for drv in $drivers; do - echo " &${drv}_audio_driver,\\" - done - echo "" - ;; - CONFIG_BDRV_RW_WHITELIST=*) - echo "#define CONFIG_BDRV_RW_WHITELIST\\" - for drv in ${line#*=}; do - echo " \"${drv}\",\\" - done - echo " NULL" - ;; - CONFIG_BDRV_RO_WHITELIST=*) - echo "#define CONFIG_BDRV_RO_WHITELIST\\" - for drv in ${line#*=}; do - echo " \"${drv}\",\\" - done - echo " NULL" - ;; - CONFIG_*=y) # configuration - name=${line%=*} - echo "#define $name 1" - ;; - CONFIG_*=*) # configuration - name=${line%=*} - value=${line#*=} - echo "#define $name $value" - ;; - HAVE_*=y) # configuration - name=${line%=*} - echo "#define $name 1" - ;; - HAVE_*=*) # configuration - name=${line%=*} - value=${line#*=} - echo "#define $name $value" - ;; - ARCH=*) # configuration - arch=${line#*=} - arch_name=`echo $arch | LC_ALL=C tr '[a-z]' '[A-Z]'` - echo "#define HOST_$arch_name 1" - ;; - HOST_USB=*) - # do nothing - ;; - HOST_CC=*) - # do nothing - ;; - HOST_*=y) # configuration - name=${line%=*} - echo "#define $name 1" - ;; - HOST_*=*) # configuration - name=${line%=*} - value=${line#*=} - echo "#define $name $value" - ;; - TARGET_BASE_ARCH=*) # configuration - target_base_arch=${line#*=} - base_arch_name=`echo $target_base_arch | LC_ALL=C tr '[a-z]' '[A-Z]'` - echo "#define TARGET_$base_arch_name 1" - ;; - TARGET_XML_FILES=*) - # do nothing - ;; - TARGET_ABI_DIR=*) - # do nothing - ;; - TARGET_NAME=*) - target_name=${line#*=} - echo "#define TARGET_NAME \"$target_name\"" - ;; - TARGET_DIRS=*) - # do nothing - ;; - TARGET_*=y) # configuration - name=${line%=*} - echo "#define $name 1" - ;; - TARGET_*=*) # configuration - name=${line%=*} - value=${line#*=} - echo "#define $name $value" - ;; - DSOSUF=*) - echo "#define HOST_DSOSUF \"${line#*=}\"" - ;; -esac - -done # read diff --git a/qemu/scripts/disas-objdump.pl b/qemu/scripts/disas-objdump.pl deleted file mode 100755 index 8f7e8182a..000000000 --- a/qemu/scripts/disas-objdump.pl +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/perl -w - -use File::Temp qw/ tempfile /; -use Getopt::Long; - -# Default to the system objdump if a cross-compiler edition not given. -my $aobjdump = "objdump"; -my $hobjdump = ""; -my $tobjdump = ""; -my $hmachine = ""; -my $tmachine = ""; - -GetOptions ('O|objdump=s' => \$aobjdump, - 'host-objdump=s' => \$hobjdump, - 'target-objdump=s' => \$tobjdump, - 'h|host-machine=s' => \$hmachine, - 't|target-machine=s' => \$tmachine); - -# But we can't default the machines. Sanity check that we've at least one. -die "No host or target machine type" if !$hmachine && !$tmachine; - -# Reuse one temp file for all of the hunks. -my ($outh, $outname) = tempfile(); -binmode($outh); -END { unlink $outname; } - -# Pre-construct the command-lines for executing the dump. -sub mkobjcommand ($$) { - my ($cmd, $mach) = @_; - return 0 if !$mach; - $cmd = $aobjdump if !$cmd; - return "$cmd -m $mach --disassemble-all -b binary"; -} - -$objdump[1] = mkobjcommand($hobjdump, $hmachine); -$objdump[2] = mkobjcommand($tobjdump, $tmachine); - -# Zero-initialize current dumping state. -my $mem = ""; -my $inobjd = 0; -my $vma = 0; - -sub objcommand { - my $ret = $objdump[$inobjd]; - if (!$ret) { - die "Host machine type not specified" if $inobjd == 1; - die "Target machine type not specified" if $inobjd == 2; - die "Internal error"; - } - return $ret; -} - -while (<>) { - # Collect the data from the relevant OBJD-* lines ... - if (/^OBJD-H: /) { - die "Internal error" if $inobjd == 2; - $mem = $mem . pack("H*", substr($_, 8, -1)); - $inobjd = 1; - } elsif (/^OBJD-T: /) { - die "Internal error" if $inobjd == 1; - $mem = $mem . pack("H*", substr($_, 8, -1)); - $inobjd = 2; - } - # ... which will always be followed by a blank line, - # at which point we should produce our dump. - elsif ($inobjd) { - # Rewrite the temp file in one go; it will usually be small. - sysseek $outh, 0, 0; - truncate $outh, 0; - syswrite $outh, $mem; - - my $cmd = objcommand(); - $cmd = $cmd . " --adjust-vma=" . $vma if $vma; - $cmd = $cmd . " " . $outname; - - # Pipe from objdump... - open IN, "-|", $cmd; - - # ... copying all but the first 7 lines of boilerplate to our stdout. - my $i = 0; - while (<IN>) { - print if (++$i > 7); - } - close IN; - print "\n"; - - $mem = ""; - $inobjd = 0; - $vma = 0; - } - # The line before "OBJD-*" will be of the form "0x<hex>+: +\n". - # Extract the value for passing to --adjust-vma. - elsif (/^(0x[0-9a-fA-F]+):\s*$/) { - $vma = $1; - print; - } else { - print; - } -} diff --git a/qemu/scripts/dump-guest-memory.py b/qemu/scripts/dump-guest-memory.py deleted file mode 100644 index c0a2e99f4..000000000 --- a/qemu/scripts/dump-guest-memory.py +++ /dev/null @@ -1,529 +0,0 @@ -""" -This python script adds a new gdb command, "dump-guest-memory". It -should be loaded with "source dump-guest-memory.py" at the (gdb) -prompt. - -Copyright (C) 2013, Red Hat, Inc. - -Authors: - Laszlo Ersek <lersek@redhat.com> - Janosch Frank <frankja@linux.vnet.ibm.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 ctypes - -UINTPTR_T = gdb.lookup_type("uintptr_t") - -TARGET_PAGE_SIZE = 0x1000 -TARGET_PAGE_MASK = 0xFFFFFFFFFFFFF000 - -# Special value for e_phnum. This indicates that the real number of -# program headers is too large to fit into e_phnum. Instead the real -# value is in the field sh_info of section 0. -PN_XNUM = 0xFFFF - -EV_CURRENT = 1 - -ELFCLASS32 = 1 -ELFCLASS64 = 2 - -ELFDATA2LSB = 1 -ELFDATA2MSB = 2 - -ET_CORE = 4 - -PT_LOAD = 1 -PT_NOTE = 4 - -EM_386 = 3 -EM_PPC = 20 -EM_PPC64 = 21 -EM_S390 = 22 -EM_AARCH = 183 -EM_X86_64 = 62 - -class ELF(object): - """Representation of a ELF file.""" - - def __init__(self, arch): - self.ehdr = None - self.notes = [] - self.segments = [] - self.notes_size = 0 - self.endianess = None - self.elfclass = ELFCLASS64 - - if arch == 'aarch64-le': - self.endianess = ELFDATA2LSB - self.elfclass = ELFCLASS64 - self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) - self.ehdr.e_machine = EM_AARCH - - elif arch == 'aarch64-be': - self.endianess = ELFDATA2MSB - self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) - self.ehdr.e_machine = EM_AARCH - - elif arch == 'X86_64': - self.endianess = ELFDATA2LSB - self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) - self.ehdr.e_machine = EM_X86_64 - - elif arch == '386': - self.endianess = ELFDATA2LSB - self.elfclass = ELFCLASS32 - self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) - self.ehdr.e_machine = EM_386 - - elif arch == 's390': - self.endianess = ELFDATA2MSB - self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) - self.ehdr.e_machine = EM_S390 - - elif arch == 'ppc64-le': - self.endianess = ELFDATA2LSB - self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) - self.ehdr.e_machine = EM_PPC64 - - elif arch == 'ppc64-be': - self.endianess = ELFDATA2MSB - self.ehdr = get_arch_ehdr(self.endianess, self.elfclass) - self.ehdr.e_machine = EM_PPC64 - - else: - raise gdb.GdbError("No valid arch type specified.\n" - "Currently supported types:\n" - "aarch64-be, aarch64-le, X86_64, 386, s390, " - "ppc64-be, ppc64-le") - - self.add_segment(PT_NOTE, 0, 0) - - def add_note(self, n_name, n_desc, n_type): - """Adds a note to the ELF.""" - - note = get_arch_note(self.endianess, len(n_name), len(n_desc)) - note.n_namesz = len(n_name) + 1 - note.n_descsz = len(n_desc) - note.n_name = n_name.encode() - note.n_type = n_type - - # Desc needs to be 4 byte aligned (although the 64bit spec - # specifies 8 byte). When defining n_desc as uint32 it will be - # automatically aligned but we need the memmove to copy the - # string into it. - ctypes.memmove(note.n_desc, n_desc.encode(), len(n_desc)) - - self.notes.append(note) - self.segments[0].p_filesz += ctypes.sizeof(note) - self.segments[0].p_memsz += ctypes.sizeof(note) - - def add_segment(self, p_type, p_paddr, p_size): - """Adds a segment to the elf.""" - - phdr = get_arch_phdr(self.endianess, self.elfclass) - phdr.p_type = p_type - phdr.p_paddr = p_paddr - phdr.p_filesz = p_size - phdr.p_memsz = p_size - self.segments.append(phdr) - self.ehdr.e_phnum += 1 - - def to_file(self, elf_file): - """Writes all ELF structures to the the passed file. - - Structure: - Ehdr - Segment 0:PT_NOTE - Segment 1:PT_LOAD - Segment N:PT_LOAD - Note 0..N - Dump contents - """ - elf_file.write(self.ehdr) - off = ctypes.sizeof(self.ehdr) + \ - len(self.segments) * ctypes.sizeof(self.segments[0]) - - for phdr in self.segments: - phdr.p_offset = off - elf_file.write(phdr) - off += phdr.p_filesz - - for note in self.notes: - elf_file.write(note) - - -def get_arch_note(endianess, len_name, len_desc): - """Returns a Note class with the specified endianess.""" - - if endianess == ELFDATA2LSB: - superclass = ctypes.LittleEndianStructure - else: - superclass = ctypes.BigEndianStructure - - len_name = len_name + 1 - - class Note(superclass): - """Represents an ELF note, includes the content.""" - - _fields_ = [("n_namesz", ctypes.c_uint32), - ("n_descsz", ctypes.c_uint32), - ("n_type", ctypes.c_uint32), - ("n_name", ctypes.c_char * len_name), - ("n_desc", ctypes.c_uint32 * ((len_desc + 3) // 4))] - return Note() - - -class Ident(ctypes.Structure): - """Represents the ELF ident array in the ehdr structure.""" - - _fields_ = [('ei_mag0', ctypes.c_ubyte), - ('ei_mag1', ctypes.c_ubyte), - ('ei_mag2', ctypes.c_ubyte), - ('ei_mag3', ctypes.c_ubyte), - ('ei_class', ctypes.c_ubyte), - ('ei_data', ctypes.c_ubyte), - ('ei_version', ctypes.c_ubyte), - ('ei_osabi', ctypes.c_ubyte), - ('ei_abiversion', ctypes.c_ubyte), - ('ei_pad', ctypes.c_ubyte * 7)] - - def __init__(self, endianess, elfclass): - self.ei_mag0 = 0x7F - self.ei_mag1 = ord('E') - self.ei_mag2 = ord('L') - self.ei_mag3 = ord('F') - self.ei_class = elfclass - self.ei_data = endianess - self.ei_version = EV_CURRENT - - -def get_arch_ehdr(endianess, elfclass): - """Returns a EHDR64 class with the specified endianess.""" - - if endianess == ELFDATA2LSB: - superclass = ctypes.LittleEndianStructure - else: - superclass = ctypes.BigEndianStructure - - class EHDR64(superclass): - """Represents the 64 bit ELF header struct.""" - - _fields_ = [('e_ident', Ident), - ('e_type', ctypes.c_uint16), - ('e_machine', ctypes.c_uint16), - ('e_version', ctypes.c_uint32), - ('e_entry', ctypes.c_uint64), - ('e_phoff', ctypes.c_uint64), - ('e_shoff', ctypes.c_uint64), - ('e_flags', ctypes.c_uint32), - ('e_ehsize', ctypes.c_uint16), - ('e_phentsize', ctypes.c_uint16), - ('e_phnum', ctypes.c_uint16), - ('e_shentsize', ctypes.c_uint16), - ('e_shnum', ctypes.c_uint16), - ('e_shstrndx', ctypes.c_uint16)] - - def __init__(self): - super(superclass, self).__init__() - self.e_ident = Ident(endianess, elfclass) - self.e_type = ET_CORE - self.e_version = EV_CURRENT - self.e_ehsize = ctypes.sizeof(self) - self.e_phoff = ctypes.sizeof(self) - self.e_phentsize = ctypes.sizeof(get_arch_phdr(endianess, elfclass)) - self.e_phnum = 0 - - - class EHDR32(superclass): - """Represents the 32 bit ELF header struct.""" - - _fields_ = [('e_ident', Ident), - ('e_type', ctypes.c_uint16), - ('e_machine', ctypes.c_uint16), - ('e_version', ctypes.c_uint32), - ('e_entry', ctypes.c_uint32), - ('e_phoff', ctypes.c_uint32), - ('e_shoff', ctypes.c_uint32), - ('e_flags', ctypes.c_uint32), - ('e_ehsize', ctypes.c_uint16), - ('e_phentsize', ctypes.c_uint16), - ('e_phnum', ctypes.c_uint16), - ('e_shentsize', ctypes.c_uint16), - ('e_shnum', ctypes.c_uint16), - ('e_shstrndx', ctypes.c_uint16)] - - def __init__(self): - super(superclass, self).__init__() - self.e_ident = Ident(endianess, elfclass) - self.e_type = ET_CORE - self.e_version = EV_CURRENT - self.e_ehsize = ctypes.sizeof(self) - self.e_phoff = ctypes.sizeof(self) - self.e_phentsize = ctypes.sizeof(get_arch_phdr(endianess, elfclass)) - self.e_phnum = 0 - - # End get_arch_ehdr - if elfclass == ELFCLASS64: - return EHDR64() - else: - return EHDR32() - - -def get_arch_phdr(endianess, elfclass): - """Returns a 32 or 64 bit PHDR class with the specified endianess.""" - - if endianess == ELFDATA2LSB: - superclass = ctypes.LittleEndianStructure - else: - superclass = ctypes.BigEndianStructure - - class PHDR64(superclass): - """Represents the 64 bit ELF program header struct.""" - - _fields_ = [('p_type', ctypes.c_uint32), - ('p_flags', ctypes.c_uint32), - ('p_offset', ctypes.c_uint64), - ('p_vaddr', ctypes.c_uint64), - ('p_paddr', ctypes.c_uint64), - ('p_filesz', ctypes.c_uint64), - ('p_memsz', ctypes.c_uint64), - ('p_align', ctypes.c_uint64)] - - class PHDR32(superclass): - """Represents the 32 bit ELF program header struct.""" - - _fields_ = [('p_type', ctypes.c_uint32), - ('p_offset', ctypes.c_uint32), - ('p_vaddr', ctypes.c_uint32), - ('p_paddr', ctypes.c_uint32), - ('p_filesz', ctypes.c_uint32), - ('p_memsz', ctypes.c_uint32), - ('p_flags', ctypes.c_uint32), - ('p_align', ctypes.c_uint32)] - - # End get_arch_phdr - if elfclass == ELFCLASS64: - return PHDR64() - else: - return PHDR32() - - -def int128_get64(val): - """Returns low 64bit part of Int128 struct.""" - - assert val["hi"] == 0 - return val["lo"] - - -def qlist_foreach(head, field_str): - """Generator for qlists.""" - - var_p = head["lh_first"] - while var_p != 0: - var = var_p.dereference() - var_p = var[field_str]["le_next"] - yield var - - -def qemu_get_ram_block(ram_addr): - """Returns the RAMBlock struct to which the given address belongs.""" - - ram_blocks = gdb.parse_and_eval("ram_list.blocks") - - for block in qlist_foreach(ram_blocks, "next"): - if (ram_addr - block["offset"]) < block["used_length"]: - return block - - raise gdb.GdbError("Bad ram offset %x" % ram_addr) - - -def qemu_get_ram_ptr(ram_addr): - """Returns qemu vaddr for given guest physical address.""" - - block = qemu_get_ram_block(ram_addr) - return block["host"] + (ram_addr - block["offset"]) - - -def memory_region_get_ram_ptr(memory_region): - if memory_region["alias"] != 0: - return (memory_region_get_ram_ptr(memory_region["alias"].dereference()) - + memory_region["alias_offset"]) - - return qemu_get_ram_ptr(memory_region["ram_block"]["offset"]) - - -def get_guest_phys_blocks(): - """Returns a list of ram blocks. - - Each block entry contains: - 'target_start': guest block phys start address - 'target_end': guest block phys end address - 'host_addr': qemu vaddr of the block's start - """ - - guest_phys_blocks = [] - - print("guest RAM blocks:") - print("target_start target_end host_addr message " - "count") - print("---------------- ---------------- ---------------- ------- " - "-----") - - current_map_p = gdb.parse_and_eval("address_space_memory.current_map") - current_map = current_map_p.dereference() - - # Conversion to int is needed for python 3 - # compatibility. Otherwise range doesn't cast the value itself and - # breaks. - for cur in range(int(current_map["nr"])): - flat_range = (current_map["ranges"] + cur).dereference() - memory_region = flat_range["mr"].dereference() - - # we only care about RAM - if not memory_region["ram"]: - continue - - section_size = int128_get64(flat_range["addr"]["size"]) - target_start = int128_get64(flat_range["addr"]["start"]) - target_end = target_start + section_size - host_addr = (memory_region_get_ram_ptr(memory_region) - + flat_range["offset_in_region"]) - predecessor = None - - # find continuity in guest physical address space - if len(guest_phys_blocks) > 0: - predecessor = guest_phys_blocks[-1] - predecessor_size = (predecessor["target_end"] - - predecessor["target_start"]) - - # the memory API guarantees monotonically increasing - # traversal - assert predecessor["target_end"] <= target_start - - # we want continuity in both guest-physical and - # host-virtual memory - if (predecessor["target_end"] < target_start or - predecessor["host_addr"] + predecessor_size != host_addr): - predecessor = None - - if predecessor is None: - # isolated mapping, add it to the list - guest_phys_blocks.append({"target_start": target_start, - "target_end": target_end, - "host_addr": host_addr}) - message = "added" - else: - # expand predecessor until @target_end; predecessor's - # start doesn't change - predecessor["target_end"] = target_end - message = "joined" - - print("%016x %016x %016x %-7s %5u" % - (target_start, target_end, host_addr.cast(UINTPTR_T), - message, len(guest_phys_blocks))) - - return guest_phys_blocks - - -# The leading docstring doesn't have idiomatic Python formatting. It is -# printed by gdb's "help" command (the first line is printed in the -# "help data" summary), and it should match how other help texts look in -# gdb. -class DumpGuestMemory(gdb.Command): - """Extract guest vmcore from qemu process coredump. - -The two required arguments are FILE and ARCH: -FILE identifies the target file to write the guest vmcore to. -ARCH specifies the architecture for which the core will be generated. - -This GDB command reimplements the dump-guest-memory QMP command in -python, using the representation of guest memory as captured in the qemu -coredump. The qemu process that has been dumped must have had the -command line option "-machine dump-guest-core=on" which is the default. - -For simplicity, the "paging", "begin" and "end" parameters of the QMP -command are not supported -- no attempt is made to get the guest's -internal paging structures (ie. paging=false is hard-wired), and guest -memory is always fully dumped. - -Currently aarch64-be, aarch64-le, X86_64, 386, s390, ppc64-be, -ppc64-le guests are supported. - -The CORE/NT_PRSTATUS and QEMU notes (that is, the VCPUs' statuses) are -not written to the vmcore. Preparing these would require context that is -only present in the KVM host kernel module when the guest is alive. A -fake ELF note is written instead, only to keep the ELF parser of "crash" -happy. - -Dependent on how busted the qemu process was at the time of the -coredump, this command might produce unpredictable results. If qemu -deliberately called abort(), or it was dumped in response to a signal at -a halfway fortunate point, then its coredump should be in reasonable -shape and this command should mostly work.""" - - def __init__(self): - super(DumpGuestMemory, self).__init__("dump-guest-memory", - gdb.COMMAND_DATA, - gdb.COMPLETE_FILENAME) - self.elf = None - self.guest_phys_blocks = None - - def dump_init(self, vmcore): - """Prepares and writes ELF structures to core file.""" - - # Needed to make crash happy, data for more useful notes is - # not available in a qemu core. - self.elf.add_note("NONE", "EMPTY", 0) - - # We should never reach PN_XNUM for paging=false dumps, - # there's just a handful of discontiguous ranges after - # merging. - # The constant is needed to account for the PT_NOTE segment. - phdr_num = len(self.guest_phys_blocks) + 1 - assert phdr_num < PN_XNUM - - for block in self.guest_phys_blocks: - block_size = block["target_end"] - block["target_start"] - self.elf.add_segment(PT_LOAD, block["target_start"], block_size) - - self.elf.to_file(vmcore) - - def dump_iterate(self, vmcore): - """Writes guest core to file.""" - - qemu_core = gdb.inferiors()[0] - for block in self.guest_phys_blocks: - cur = block["host_addr"] - left = block["target_end"] - block["target_start"] - print("dumping range at %016x for length %016x" % - (cur.cast(UINTPTR_T), left)) - - while left > 0: - chunk_size = min(TARGET_PAGE_SIZE, left) - chunk = qemu_core.read_memory(cur, chunk_size) - vmcore.write(chunk) - cur += chunk_size - left -= chunk_size - - def invoke(self, args, from_tty): - """Handles command invocation from gdb.""" - - # Unwittingly pressing the Enter key after the command should - # not dump the same multi-gig coredump to the same file. - self.dont_repeat() - - argv = gdb.string_to_argv(args) - if len(argv) != 2: - raise gdb.GdbError("usage: dump-guest-memory FILE ARCH") - - self.elf = ELF(argv[1]) - self.guest_phys_blocks = get_guest_phys_blocks() - - with open(argv[0], "wb") as vmcore: - self.dump_init(vmcore) - self.dump_iterate(vmcore) - -DumpGuestMemory() diff --git a/qemu/scripts/extract-vsssdk-headers b/qemu/scripts/extract-vsssdk-headers deleted file mode 100755 index 9e38510f0..000000000 --- a/qemu/scripts/extract-vsssdk-headers +++ /dev/null @@ -1,35 +0,0 @@ -#! /bin/bash - -# extract-vsssdk-headers -# Author: Paolo Bonzini <pbonzini@redhat.com> - -set -e -if test $# != 1 || ! test -f "$1"; then - echo 'Usage: extract-vsssdk-headers /path/to/setup.exe' >&2 - exit 1 -fi - -if ! command -v msiextract > /dev/null; then - echo 'msiextract not found. Please install msitools.' >&2 - exit 1 -fi - -if test -e inc; then - echo '"inc" already exists.' >&2 - exit 1 -fi - -# Extract .MSI file in the .exe, looking for the OLE compound -# document signature. Extra data at the end does not matter. -export LC_ALL=C -MAGIC=$'\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1' -offset=$(grep -abom1 "$MAGIC" "$1" | sed -n 's/:/\n/; P') -tmpdir=$(mktemp -d) -trap 'rm -fr -- "$tmpdir" vsssdk.msi' EXIT HUP INT QUIT ALRM TERM -tail -c +$(($offset+1)) -- "$1" > vsssdk.msi - -# Now extract the files. -msiextract -C $tmpdir vsssdk.msi -mv "$tmpdir/Program Files/Microsoft/VSSSDK72/inc" inc -echo 'Extracted SDK headers into "inc" directory.' -exit 0 diff --git a/qemu/scripts/feature_to_c.sh b/qemu/scripts/feature_to_c.sh deleted file mode 100644 index fb1f3363f..000000000 --- a/qemu/scripts/feature_to_c.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/sh - -# Convert text files to compilable C arrays. -# -# Copyright (C) 2007 Free Software Foundation, Inc. -# -# This file is part of GDB. -# -# 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/>. - -output=$1 -shift - -if test -z "$output" || test -z "$1"; then - echo "Usage: $0 OUTPUTFILE INPUTFILE..." - exit 1 -fi - -if test -e "$output"; then - echo "Output file \"$output\" already exists; refusing to overwrite." - exit 1 -fi - -for input; do - arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'` - - ${AWK:-awk} 'BEGIN { n = 0 - printf "#include \"qemu/osdep.h\"\n" - printf "#include \"qemu-common.h\"\n" - printf "#include \"exec/gdbstub.h\"\n" - print "static const char '$arrayname'[] = {" - for (i = 0; i < 255; i++) - _ord_[sprintf("%c", i)] = i - } { - split($0, line, ""); - printf " " - for (i = 1; i <= length($0); i++) { - c = line[i] - if (c == "'\''") { - printf "'\''\\'\'''\'', " - } else if (c == "\\") { - printf "'\''\\\\'\'', " - } else if (_ord_[c] >= 32 && _ord_[c] < 127) { - printf "'\''%s'\'', ", c - } else { - printf "'\''\\%03o'\'', ", _ord_[c] - } - if (i % 10 == 0) - printf "\n " - } - printf "'\''\\n'\'', \n" - } END { - print " 0 };" - }' < $input >> $output -done - -echo >> $output -echo "const char *const xml_builtin[][2] = {" >> $output - -for input; do - basename=`echo $input | sed 's,.*/,,'` - arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'` - echo " { \"$basename\", $arrayname }," >> $output -done - -echo " { (char *)0, (char *)0 }" >> $output -echo "};" >> $output diff --git a/qemu/scripts/get_maintainer.pl b/qemu/scripts/get_maintainer.pl deleted file mode 100755 index 8261bcb1a..000000000 --- a/qemu/scripts/get_maintainer.pl +++ /dev/null @@ -1,2121 +0,0 @@ -#!/usr/bin/perl -w -# (c) 2007, Joe Perches <joe@perches.com> -# created from checkpatch.pl -# -# Print selected MAINTAINERS information for -# the files modified in a patch or for a file -# -# usage: perl scripts/get_maintainer.pl [OPTIONS] <patch> -# perl scripts/get_maintainer.pl [OPTIONS] -f <file> -# -# Licensed under the terms of the GNU GPL License version 2 - -use strict; - -my $P = $0; -my $V = '0.26'; - -use Getopt::Long qw(:config no_auto_abbrev); - -my $lk_path = "./"; -my $email = 1; -my $email_usename = 1; -my $email_maintainer = 1; -my $email_list = 1; -my $email_subscriber_list = 0; -my $email_git = 0; -my $email_git_all_signature_types = 0; -my $email_git_blame = 0; -my $email_git_blame_signatures = 1; -my $email_git_fallback = 1; -my $email_git_min_signatures = 1; -my $email_git_max_maintainers = 5; -my $email_git_min_percent = 5; -my $email_git_since = "1-year-ago"; -my $email_hg_since = "-365"; -my $interactive = 0; -my $email_remove_duplicates = 1; -my $email_use_mailmap = 1; -my $output_multiline = 1; -my $output_separator = ", "; -my $output_roles = 0; -my $output_rolestats = 1; -my $scm = 0; -my $web = 0; -my $subsystem = 0; -my $status = 0; -my $keywords = 1; -my $sections = 0; -my $file_emails = 0; -my $from_filename = 0; -my $pattern_depth = 0; -my $version = 0; -my $help = 0; - -my $vcs_used = 0; - -my $exit = 0; - -my %commit_author_hash; -my %commit_signer_hash; - -# Signature types of people who are either -# a) responsible for the code in question, or -# b) familiar enough with it to give relevant feedback -my @signature_tags = (); -push(@signature_tags, "Signed-off-by:"); -push(@signature_tags, "Reviewed-by:"); -push(@signature_tags, "Acked-by:"); - -my $signature_pattern = "\(" . join("|", @signature_tags) . "\)"; - -# rfc822 email address - preloaded methods go here. -my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])"; -my $rfc822_char = '[\\000-\\377]'; - -# VCS command support: class-like functions and strings - -my %VCS_cmds; - -my %VCS_cmds_git = ( - "execute_cmd" => \&git_execute_cmd, - "available" => '(which("git") ne "") && (-d ".git")', - "find_signers_cmd" => - "git log --no-color --follow --since=\$email_git_since " . - '--format="GitCommit: %H%n' . - 'GitAuthor: %an <%ae>%n' . - 'GitDate: %aD%n' . - 'GitSubject: %s%n' . - '%b%n"' . - " -- \$file", - "find_commit_signers_cmd" => - "git log --no-color " . - '--format="GitCommit: %H%n' . - 'GitAuthor: %an <%ae>%n' . - 'GitDate: %aD%n' . - 'GitSubject: %s%n' . - '%b%n"' . - " -1 \$commit", - "find_commit_author_cmd" => - "git log --no-color " . - '--format="GitCommit: %H%n' . - 'GitAuthor: %an <%ae>%n' . - 'GitDate: %aD%n' . - 'GitSubject: %s%n"' . - " -1 \$commit", - "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file", - "blame_file_cmd" => "git blame -l \$file", - "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})", - "blame_commit_pattern" => "^([0-9a-f]+) ", - "author_pattern" => "^GitAuthor: (.*)", - "subject_pattern" => "^GitSubject: (.*)", -); - -my %VCS_cmds_hg = ( - "execute_cmd" => \&hg_execute_cmd, - "available" => '(which("hg") ne "") && (-d ".hg")', - "find_signers_cmd" => - "hg log --date=\$email_hg_since " . - "--template='HgCommit: {node}\\n" . - "HgAuthor: {author}\\n" . - "HgSubject: {desc}\\n'" . - " -- \$file", - "find_commit_signers_cmd" => - "hg log " . - "--template='HgSubject: {desc}\\n'" . - " -r \$commit", - "find_commit_author_cmd" => - "hg log " . - "--template='HgCommit: {node}\\n" . - "HgAuthor: {author}\\n" . - "HgSubject: {desc|firstline}\\n'" . - " -r \$commit", - "blame_range_cmd" => "", # not supported - "blame_file_cmd" => "hg blame -n \$file", - "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})", - "blame_commit_pattern" => "^([ 0-9a-f]+):", - "author_pattern" => "^HgAuthor: (.*)", - "subject_pattern" => "^HgSubject: (.*)", -); - -my $conf = which_conf(".get_maintainer.conf"); -if (-f $conf) { - my @conf_args; - open(my $conffile, '<', "$conf") - or warn "$P: Can't find a readable .get_maintainer.conf file $!\n"; - - while (<$conffile>) { - my $line = $_; - - $line =~ s/\s*\n?$//g; - $line =~ s/^\s*//g; - $line =~ s/\s+/ /g; - - next if ($line =~ m/^\s*#/); - next if ($line =~ m/^\s*$/); - - my @words = split(" ", $line); - foreach my $word (@words) { - last if ($word =~ m/^#/); - push (@conf_args, $word); - } - } - close($conffile); - unshift(@ARGV, @conf_args) if @conf_args; -} - -if (!GetOptions( - 'email!' => \$email, - 'git!' => \$email_git, - 'git-all-signature-types!' => \$email_git_all_signature_types, - 'git-blame!' => \$email_git_blame, - 'git-blame-signatures!' => \$email_git_blame_signatures, - 'git-fallback!' => \$email_git_fallback, - 'git-min-signatures=i' => \$email_git_min_signatures, - 'git-max-maintainers=i' => \$email_git_max_maintainers, - 'git-min-percent=i' => \$email_git_min_percent, - 'git-since=s' => \$email_git_since, - 'hg-since=s' => \$email_hg_since, - 'i|interactive!' => \$interactive, - 'remove-duplicates!' => \$email_remove_duplicates, - 'mailmap!' => \$email_use_mailmap, - 'm!' => \$email_maintainer, - 'n!' => \$email_usename, - 'l!' => \$email_list, - 's!' => \$email_subscriber_list, - 'multiline!' => \$output_multiline, - 'roles!' => \$output_roles, - 'rolestats!' => \$output_rolestats, - 'separator=s' => \$output_separator, - 'subsystem!' => \$subsystem, - 'status!' => \$status, - 'scm!' => \$scm, - 'web!' => \$web, - 'pattern-depth=i' => \$pattern_depth, - 'k|keywords!' => \$keywords, - 'sections!' => \$sections, - 'fe|file-emails!' => \$file_emails, - 'f|file' => \$from_filename, - 'v|version' => \$version, - 'h|help|usage' => \$help, - )) { - die "$P: invalid argument - use --help if necessary\n"; -} - -if ($help != 0) { - usage(); - exit 0; -} - -if ($version != 0) { - print("${P} ${V}\n"); - exit 0; -} - -if (-t STDIN && !@ARGV) { - # We're talking to a terminal, but have no command line arguments. - die "$P: missing patchfile or -f file - use --help if necessary\n"; -} - -$output_multiline = 0 if ($output_separator ne ", "); -$output_rolestats = 1 if ($interactive); -$output_roles = 1 if ($output_rolestats); - -if ($sections) { - $email = 0; - $email_list = 0; - $scm = 0; - $status = 0; - $subsystem = 0; - $web = 0; - $keywords = 0; - $interactive = 0; -} else { - my $selections = $email + $scm + $status + $subsystem + $web; - if ($selections == 0) { - die "$P: Missing required option: email, scm, status, subsystem or web\n"; - } -} - -if ($email && - ($email_maintainer + $email_list + $email_subscriber_list + - $email_git + $email_git_blame) == 0) { - die "$P: Please select at least 1 email option\n"; -} - -if (!top_of_tree($lk_path)) { - die "$P: The current directory does not appear to be " - . "a QEMU source tree.\n"; -} - -## Read MAINTAINERS for type/value pairs - -my @typevalue = (); -my %keyword_hash; - -open (my $maint, '<', "${lk_path}MAINTAINERS") - or die "$P: Can't open MAINTAINERS: $!\n"; -while (<$maint>) { - my $line = $_; - - if ($line =~ m/^(.):\s*(.*)/) { - my $type = $1; - my $value = $2; - - ##Filename pattern matching - if ($type eq "F" || $type eq "X") { - $value =~ s@\.@\\\.@g; ##Convert . to \. - $value =~ s/\*/\.\*/g; ##Convert * to .* - $value =~ s/\?/\./g; ##Convert ? to . - ##if pattern is a directory and it lacks a trailing slash, add one - if ((-d $value)) { - $value =~ s@([^/])$@$1/@; - } - } elsif ($type eq "K") { - $keyword_hash{@typevalue} = $value; - } - push(@typevalue, "$type:$value"); - } elsif (!/^(\s)*$/) { - $line =~ s/\n$//g; - push(@typevalue, $line); - } -} -close($maint); - - -# -# Read mail address map -# - -my $mailmap; - -read_mailmap(); - -sub read_mailmap { - $mailmap = { - names => {}, - addresses => {} - }; - - return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap")); - - open(my $mailmap_file, '<', "${lk_path}.mailmap") - or warn "$P: Can't open .mailmap: $!\n"; - - while (<$mailmap_file>) { - s/#.*$//; #strip comments - s/^\s+|\s+$//g; #trim - - next if (/^\s*$/); #skip empty lines - #entries have one of the following formats: - # name1 <mail1> - # <mail1> <mail2> - # name1 <mail1> <mail2> - # name1 <mail1> name2 <mail2> - # (see man git-shortlog) - - if (/^([^<]+)<([^>]+)>$/) { - my $real_name = $1; - my $address = $2; - - $real_name =~ s/\s+$//; - ($real_name, $address) = parse_email("$real_name <$address>"); - $mailmap->{names}->{$address} = $real_name; - - } elsif (/^<([^>]+)>\s*<([^>]+)>$/) { - my $real_address = $1; - my $wrong_address = $2; - - $mailmap->{addresses}->{$wrong_address} = $real_address; - - } elsif (/^(.+)<([^>]+)>\s*<([^>]+)>$/) { - my $real_name = $1; - my $real_address = $2; - my $wrong_address = $3; - - $real_name =~ s/\s+$//; - ($real_name, $real_address) = - parse_email("$real_name <$real_address>"); - $mailmap->{names}->{$wrong_address} = $real_name; - $mailmap->{addresses}->{$wrong_address} = $real_address; - - } elsif (/^(.+)<([^>]+)>\s*(.+)\s*<([^>]+)>$/) { - my $real_name = $1; - my $real_address = $2; - my $wrong_name = $3; - my $wrong_address = $4; - - $real_name =~ s/\s+$//; - ($real_name, $real_address) = - parse_email("$real_name <$real_address>"); - - $wrong_name =~ s/\s+$//; - ($wrong_name, $wrong_address) = - parse_email("$wrong_name <$wrong_address>"); - - my $wrong_email = format_email($wrong_name, $wrong_address, 1); - $mailmap->{names}->{$wrong_email} = $real_name; - $mailmap->{addresses}->{$wrong_email} = $real_address; - } - } - close($mailmap_file); -} - -## use the filenames on the command line or find the filenames in the patchfiles - -my @files = (); -my @range = (); -my @keyword_tvi = (); -my @file_emails = (); - -if (!@ARGV) { - push(@ARGV, "&STDIN"); -} - -foreach my $file (@ARGV) { - if ($file ne "&STDIN") { - ##if $file is a directory and it lacks a trailing slash, add one - if ((-d $file)) { - $file =~ s@([^/])$@$1/@; - } elsif (!(-f $file)) { - die "$P: file '${file}' not found\n"; - } - } - if ($from_filename) { - push(@files, $file); - if ($file ne "MAINTAINERS" && -f $file && ($keywords || $file_emails)) { - open(my $f, '<', $file) - or die "$P: Can't open $file: $!\n"; - my $text = do { local($/) ; <$f> }; - close($f); - if ($keywords) { - foreach my $line (keys %keyword_hash) { - if ($text =~ m/$keyword_hash{$line}/x) { - push(@keyword_tvi, $line); - } - } - } - if ($file_emails) { - my @poss_addr = $text =~ m$[A-Za-zÀ-ÿ\"\' \,\.\+-]*\s*[\,]*\s*[\(\<\{]{0,1}[A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+\.[A-Za-z0-9]+[\)\>\}]{0,1}$g; - push(@file_emails, clean_file_emails(@poss_addr)); - } - } - } else { - my $file_cnt = @files; - my $lastfile; - - open(my $patch, "< $file") - or die "$P: Can't open $file: $!\n"; - - # We can check arbitrary information before the patch - # like the commit message, mail headers, etc... - # This allows us to match arbitrary keywords against any part - # of a git format-patch generated file (subject tags, etc...) - - my $patch_prefix = ""; #Parsing the intro - - while (<$patch>) { - my $patch_line = $_; - if (m/^\+\+\+\s+(\S+)/) { - my $filename = $1; - $filename =~ s@^[^/]*/@@; - $filename =~ s@\n@@; - $lastfile = $filename; - push(@files, $filename); - $patch_prefix = "^[+-].*"; #Now parsing the actual patch - } elsif (m/^\@\@ -(\d+),(\d+)/) { - if ($email_git_blame) { - push(@range, "$lastfile:$1:$2"); - } - } elsif ($keywords) { - foreach my $line (keys %keyword_hash) { - if ($patch_line =~ m/${patch_prefix}$keyword_hash{$line}/x) { - push(@keyword_tvi, $line); - } - } - } - } - close($patch); - - if ($file_cnt == @files) { - warn "$P: file '${file}' doesn't appear to be a patch. " - . "Add -f to options?\n"; - } - @files = sort_and_uniq(@files); - } -} - -@file_emails = uniq(@file_emails); - -my %email_hash_name; -my %email_hash_address; -my @email_to = (); -my %hash_list_to; -my @list_to = (); -my @scm = (); -my @web = (); -my @subsystem = (); -my @status = (); -my %deduplicate_name_hash = (); -my %deduplicate_address_hash = (); - -my @maintainers = get_maintainers(); - -if (@maintainers) { - @maintainers = merge_email(@maintainers); - output(@maintainers); -} - -if ($scm) { - @scm = uniq(@scm); - output(@scm); -} - -if ($status) { - @status = uniq(@status); - output(@status); -} - -if ($subsystem) { - @subsystem = uniq(@subsystem); - output(@subsystem); -} - -if ($web) { - @web = uniq(@web); - output(@web); -} - -exit($exit); - -sub range_is_maintained { - my ($start, $end) = @_; - - for (my $i = $start; $i < $end; $i++) { - my $line = $typevalue[$i]; - if ($line =~ m/^(.):\s*(.*)/) { - my $type = $1; - my $value = $2; - if ($type eq 'S') { - if ($value =~ /(maintain|support)/i) { - return 1; - } - } - } - } - return 0; -} - -sub range_has_maintainer { - my ($start, $end) = @_; - - for (my $i = $start; $i < $end; $i++) { - my $line = $typevalue[$i]; - if ($line =~ m/^(.):\s*(.*)/) { - my $type = $1; - my $value = $2; - if ($type eq 'M') { - return 1; - } - } - } - return 0; -} - -sub get_maintainers { - %email_hash_name = (); - %email_hash_address = (); - %commit_author_hash = (); - %commit_signer_hash = (); - @email_to = (); - %hash_list_to = (); - @list_to = (); - @scm = (); - @web = (); - @subsystem = (); - @status = (); - %deduplicate_name_hash = (); - %deduplicate_address_hash = (); - if ($email_git_all_signature_types) { - $signature_pattern = "(.+?)[Bb][Yy]:"; - } else { - $signature_pattern = "\(" . join("|", @signature_tags) . "\)"; - } - - # Find responsible parties - - my %exact_pattern_match_hash = (); - - foreach my $file (@files) { - - my %hash; - my $tvi = find_first_section(); - while ($tvi < @typevalue) { - my $start = find_starting_index($tvi); - my $end = find_ending_index($tvi); - my $exclude = 0; - my $i; - - #Do not match excluded file patterns - - for ($i = $start; $i < $end; $i++) { - my $line = $typevalue[$i]; - if ($line =~ m/^(.):\s*(.*)/) { - my $type = $1; - my $value = $2; - if ($type eq 'X') { - if (file_match_pattern($file, $value)) { - $exclude = 1; - last; - } - } - } - } - - if (!$exclude) { - for ($i = $start; $i < $end; $i++) { - my $line = $typevalue[$i]; - if ($line =~ m/^(.):\s*(.*)/) { - my $type = $1; - my $value = $2; - if ($type eq 'F') { - if (file_match_pattern($file, $value)) { - my $value_pd = ($value =~ tr@/@@); - my $file_pd = ($file =~ tr@/@@); - $value_pd++ if (substr($value,-1,1) ne "/"); - $value_pd = -1 if ($value =~ /^\.\*/); - if ($value_pd >= $file_pd && - range_is_maintained($start, $end) && - range_has_maintainer($start, $end)) { - $exact_pattern_match_hash{$file} = 1; - } - if ($pattern_depth == 0 || - (($file_pd - $value_pd) < $pattern_depth)) { - $hash{$tvi} = $value_pd; - } - } - } - } - } - } - $tvi = $end + 1; - } - - foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) { - add_categories($line); - if ($sections) { - my $i; - my $start = find_starting_index($line); - my $end = find_ending_index($line); - for ($i = $start; $i < $end; $i++) { - my $line = $typevalue[$i]; - if ($line =~ /^[FX]:/) { ##Restore file patterns - $line =~ s/([^\\])\.([^\*])/$1\?$2/g; - $line =~ s/([^\\])\.$/$1\?/g; ##Convert . back to ? - $line =~ s/\\\./\./g; ##Convert \. to . - $line =~ s/\.\*/\*/g; ##Convert .* to * - } - $line =~ s/^([A-Z]):/$1:\t/g; - print("$line\n"); - } - print("\n"); - } - } - } - - if ($keywords) { - @keyword_tvi = sort_and_uniq(@keyword_tvi); - foreach my $line (@keyword_tvi) { - add_categories($line); - } - } - - foreach my $email (@email_to, @list_to) { - $email->[0] = deduplicate_email($email->[0]); - } - - if ($email) { - if (! $interactive) { - $email_git_fallback = 0 if @email_to > 0 || $email_git || $email_git_blame; - if ($email_git_fallback) { - print STDERR "get_maintainer.pl: No maintainers found, printing recent contributors.\n"; - print STDERR "get_maintainer.pl: Do not blindly cc: them on patches! Use common sense.\n"; - print STDERR "\n"; - } - } - - foreach my $file (@files) { - if ($email_git || ($email_git_fallback && - !$exact_pattern_match_hash{$file})) { - vcs_file_signoffs($file); - } - if ($email_git_blame) { - vcs_file_blame($file); - } - } - - foreach my $email (@file_emails) { - my ($name, $address) = parse_email($email); - - my $tmp_email = format_email($name, $address, $email_usename); - push_email_address($tmp_email, ''); - add_role($tmp_email, 'in file'); - } - } - - my @to = (); - if ($email || $email_list) { - if ($email) { - @to = (@to, @email_to); - } - if ($email_list) { - @to = (@to, @list_to); - } - } - - if ($interactive) { - @to = interactive_get_maintainers(\@to); - } - - return @to; -} - -sub file_match_pattern { - my ($file, $pattern) = @_; - if (substr($pattern, -1) eq "/") { - if ($file =~ m@^$pattern@) { - return 1; - } - } else { - if ($file =~ m@^$pattern@) { - my $s1 = ($file =~ tr@/@@); - my $s2 = ($pattern =~ tr@/@@); - if ($s1 == $s2) { - return 1; - } - } - } - return 0; -} - -sub usage { - print <<EOT; -usage: $P [options] patchfile - $P [options] -f file|directory -version: $V - -MAINTAINER field selection options: - --email => print email address(es) if any - --git => include recent git \*-by: signers - --git-all-signature-types => include signers regardless of signature type - or use only ${signature_pattern} signers (default: $email_git_all_signature_types) - --git-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback) - --git-min-signatures => number of signatures required (default: $email_git_min_signatures) - --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers) - --git-min-percent => minimum percentage of commits required (default: $email_git_min_percent) - --git-blame => use git blame to find modified commits for patch or file - --git-since => git history to use (default: $email_git_since) - --hg-since => hg history to use (default: $email_hg_since) - --interactive => display a menu (mostly useful if used with the --git option) - --m => include maintainer(s) if any - --n => include name 'Full Name <addr\@domain.tld>' - --l => include list(s) if any - --s => include subscriber only list(s) if any - --remove-duplicates => minimize duplicate email names/addresses - --roles => show roles (status:subsystem, git-signer, list, etc...) - --rolestats => show roles and statistics (commits/total_commits, %) - --file-emails => add email addresses found in -f file (default: 0 (off)) - --scm => print SCM tree(s) if any - --status => print status if any - --subsystem => print subsystem name if any - --web => print website(s) if any - -Output type options: - --separator [, ] => separator for multiple entries on 1 line - using --separator also sets --nomultiline if --separator is not [, ] - --multiline => print 1 entry per line - -Other options: - --pattern-depth => Number of pattern directory traversals (default: 0 (all)) - --keywords => scan patch for keywords (default: $keywords) - --sections => print all of the subsystem sections with pattern matches - --mailmap => use .mailmap file (default: $email_use_mailmap) - --version => show version - --help => show this help information - -Default options: - [--email --nogit --git-fallback --m --n --l --multiline -pattern-depth=0 - --remove-duplicates --rolestats] - -Notes: - Using "-f directory" may give unexpected results: - Used with "--git", git signators for _all_ files in and below - directory are examined as git recurses directories. - Any specified X: (exclude) pattern matches are _not_ ignored. - Used with "--nogit", directory is used as a pattern match, - no individual file within the directory or subdirectory - is matched. - Used with "--git-blame", does not iterate all files in directory - Using "--git-blame" is slow and may add old committers and authors - that are no longer active maintainers to the output. - Using "--roles" or "--rolestats" with git send-email --cc-cmd or any - other automated tools that expect only ["name"] <email address> - may not work because of additional output after <email address>. - Using "--rolestats" and "--git-blame" shows the #/total=% commits, - not the percentage of the entire file authored. # of commits is - not a good measure of amount of code authored. 1 major commit may - contain a thousand lines, 5 trivial commits may modify a single line. - If git is not installed, but mercurial (hg) is installed and an .hg - repository exists, the following options apply to mercurial: - --git, - --git-min-signatures, --git-max-maintainers, --git-min-percent, and - --git-blame - Use --hg-since not --git-since to control date selection - File ".get_maintainer.conf", if it exists in the QEMU source root - directory, can change whatever get_maintainer defaults are desired. - Entries in this file can be any command line argument. - This file is prepended to any additional command line arguments. - Multiple lines and # comments are allowed. -EOT -} - -sub top_of_tree { - my ($lk_path) = @_; - - if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") { - $lk_path .= "/"; - } - if ( (-f "${lk_path}COPYING") - && (-f "${lk_path}MAINTAINERS") - && (-f "${lk_path}Makefile") - && (-d "${lk_path}docs") - && (-f "${lk_path}VERSION") - && (-f "${lk_path}vl.c")) { - return 1; - } - return 0; -} - -sub parse_email { - my ($formatted_email) = @_; - - my $name = ""; - my $address = ""; - - if ($formatted_email =~ /^([^<]+)<(.+\@.*)>.*$/) { - $name = $1; - $address = $2; - } elsif ($formatted_email =~ /^\s*<(.+\@\S*)>.*$/) { - $address = $1; - } elsif ($formatted_email =~ /^(.+\@\S*).*$/) { - $address = $1; - } - - $name =~ s/^\s+|\s+$//g; - $name =~ s/^\"|\"$//g; - $address =~ s/^\s+|\s+$//g; - - if ($name =~ /[^\w \-]/i) { ##has "must quote" chars - $name =~ s/(?<!\\)"/\\"/g; ##escape quotes - $name = "\"$name\""; - } - - return ($name, $address); -} - -sub format_email { - my ($name, $address, $usename) = @_; - - my $formatted_email; - - $name =~ s/^\s+|\s+$//g; - $name =~ s/^\"|\"$//g; - $address =~ s/^\s+|\s+$//g; - - if ($name =~ /[^\w \-]/i) { ##has "must quote" chars - $name =~ s/(?<!\\)"/\\"/g; ##escape quotes - $name = "\"$name\""; - } - - if ($usename) { - if ("$name" eq "") { - $formatted_email = "$address"; - } else { - $formatted_email = "$name <$address>"; - } - } else { - $formatted_email = $address; - } - - return $formatted_email; -} - -sub find_first_section { - my $index = 0; - - while ($index < @typevalue) { - my $tv = $typevalue[$index]; - if (($tv =~ m/^(.):\s*(.*)/)) { - last; - } - $index++; - } - - return $index; -} - -sub find_starting_index { - my ($index) = @_; - - while ($index > 0) { - my $tv = $typevalue[$index]; - if (!($tv =~ m/^(.):\s*(.*)/)) { - last; - } - $index--; - } - - return $index; -} - -sub find_ending_index { - my ($index) = @_; - - while ($index < @typevalue) { - my $tv = $typevalue[$index]; - if (!($tv =~ m/^(.):\s*(.*)/)) { - last; - } - $index++; - } - - return $index; -} - -sub get_maintainer_role { - my ($index) = @_; - - my $i; - my $start = find_starting_index($index); - my $end = find_ending_index($index); - - my $role = "unknown"; - my $subsystem = $typevalue[$start]; - if (length($subsystem) > 20) { - $subsystem = substr($subsystem, 0, 17); - $subsystem =~ s/\s*$//; - $subsystem = $subsystem . "..."; - } - - for ($i = $start + 1; $i < $end; $i++) { - my $tv = $typevalue[$i]; - if ($tv =~ m/^(.):\s*(.*)/) { - my $ptype = $1; - my $pvalue = $2; - if ($ptype eq "S") { - $role = $pvalue; - } - } - } - - $role = lc($role); - if ($role eq "supported") { - $role = "supporter"; - } elsif ($role eq "maintained") { - $role = "maintainer"; - } elsif ($role eq "odd fixes") { - $role = "odd fixer"; - } elsif ($role eq "orphan") { - $role = "orphan minder"; - } elsif ($role eq "obsolete") { - $role = "obsolete minder"; - } elsif ($role eq "buried alive in reporters") { - $role = "chief penguin"; - } - - return $role . ":" . $subsystem; -} - -sub get_list_role { - my ($index) = @_; - - my $i; - my $start = find_starting_index($index); - my $end = find_ending_index($index); - - my $subsystem = $typevalue[$start]; - if (length($subsystem) > 20) { - $subsystem = substr($subsystem, 0, 17); - $subsystem =~ s/\s*$//; - $subsystem = $subsystem . "..."; - } - - if ($subsystem eq "THE REST") { - $subsystem = ""; - } - - return $subsystem; -} - -sub add_categories { - my ($index) = @_; - - my $i; - my $start = find_starting_index($index); - my $end = find_ending_index($index); - - push(@subsystem, $typevalue[$start]); - - for ($i = $start + 1; $i < $end; $i++) { - my $tv = $typevalue[$i]; - if ($tv =~ m/^(.):\s*(.*)/) { - my $ptype = $1; - my $pvalue = $2; - if ($ptype eq "L") { - my $list_address = $pvalue; - my $list_additional = ""; - my $list_role = get_list_role($i); - - if ($list_role ne "") { - $list_role = ":" . $list_role; - } - if ($list_address =~ m/([^\s]+)\s+(.*)$/) { - $list_address = $1; - $list_additional = $2; - } - if ($list_additional =~ m/subscribers-only/) { - if ($email_subscriber_list) { - if (!$hash_list_to{lc($list_address)}) { - $hash_list_to{lc($list_address)} = 1; - push(@list_to, [$list_address, - "subscriber list${list_role}"]); - } - } - } else { - if ($email_list) { - if (!$hash_list_to{lc($list_address)}) { - $hash_list_to{lc($list_address)} = 1; - if ($list_additional =~ m/moderated/) { - push(@list_to, [$list_address, - "moderated list${list_role}"]); - } else { - push(@list_to, [$list_address, - "open list${list_role}"]); - } - } - } - } - } elsif ($ptype eq "M") { - my ($name, $address) = parse_email($pvalue); - if ($name eq "") { - if ($i > 0) { - my $tv = $typevalue[$i - 1]; - if ($tv =~ m/^(.):\s*(.*)/) { - if ($1 eq "P") { - $name = $2; - $pvalue = format_email($name, $address, $email_usename); - } - } - } - } - if ($email_maintainer) { - my $role = get_maintainer_role($i); - push_email_addresses($pvalue, $role); - } - } elsif ($ptype eq "T") { - push(@scm, $pvalue); - } elsif ($ptype eq "W") { - push(@web, $pvalue); - } elsif ($ptype eq "S") { - push(@status, $pvalue); - } - } - } -} - -sub email_inuse { - my ($name, $address) = @_; - - return 1 if (($name eq "") && ($address eq "")); - return 1 if (($name ne "") && exists($email_hash_name{lc($name)})); - return 1 if (($address ne "") && exists($email_hash_address{lc($address)})); - - return 0; -} - -sub push_email_address { - my ($line, $role) = @_; - - my ($name, $address) = parse_email($line); - - if ($address eq "") { - return 0; - } - - if (!$email_remove_duplicates) { - push(@email_to, [format_email($name, $address, $email_usename), $role]); - } elsif (!email_inuse($name, $address)) { - push(@email_to, [format_email($name, $address, $email_usename), $role]); - $email_hash_name{lc($name)}++ if ($name ne ""); - $email_hash_address{lc($address)}++; - } - - return 1; -} - -sub push_email_addresses { - my ($address, $role) = @_; - - my @address_list = (); - - if (rfc822_valid($address)) { - push_email_address($address, $role); - } elsif (@address_list = rfc822_validlist($address)) { - my $array_count = shift(@address_list); - while (my $entry = shift(@address_list)) { - push_email_address($entry, $role); - } - } else { - if (!push_email_address($address, $role)) { - warn("Invalid MAINTAINERS address: '" . $address . "'\n"); - } - } -} - -sub add_role { - my ($line, $role) = @_; - - my ($name, $address) = parse_email($line); - my $email = format_email($name, $address, $email_usename); - - foreach my $entry (@email_to) { - if ($email_remove_duplicates) { - my ($entry_name, $entry_address) = parse_email($entry->[0]); - if (($name eq $entry_name || $address eq $entry_address) - && ($role eq "" || !($entry->[1] =~ m/$role/)) - ) { - if ($entry->[1] eq "") { - $entry->[1] = "$role"; - } else { - $entry->[1] = "$entry->[1],$role"; - } - } - } else { - if ($email eq $entry->[0] - && ($role eq "" || !($entry->[1] =~ m/$role/)) - ) { - if ($entry->[1] eq "") { - $entry->[1] = "$role"; - } else { - $entry->[1] = "$entry->[1],$role"; - } - } - } - } -} - -sub which { - my ($bin) = @_; - - foreach my $path (split(/:/, $ENV{PATH})) { - if (-e "$path/$bin") { - return "$path/$bin"; - } - } - - return ""; -} - -sub which_conf { - my ($conf) = @_; - - foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) { - if (-e "$path/$conf") { - return "$path/$conf"; - } - } - - return ""; -} - -sub mailmap_email { - my ($line) = @_; - - my ($name, $address) = parse_email($line); - my $email = format_email($name, $address, 1); - my $real_name = $name; - my $real_address = $address; - - if (exists $mailmap->{names}->{$email} || - exists $mailmap->{addresses}->{$email}) { - if (exists $mailmap->{names}->{$email}) { - $real_name = $mailmap->{names}->{$email}; - } - if (exists $mailmap->{addresses}->{$email}) { - $real_address = $mailmap->{addresses}->{$email}; - } - } else { - if (exists $mailmap->{names}->{$address}) { - $real_name = $mailmap->{names}->{$address}; - } - if (exists $mailmap->{addresses}->{$address}) { - $real_address = $mailmap->{addresses}->{$address}; - } - } - return format_email($real_name, $real_address, 1); -} - -sub mailmap { - my (@addresses) = @_; - - my @mapped_emails = (); - foreach my $line (@addresses) { - push(@mapped_emails, mailmap_email($line)); - } - merge_by_realname(@mapped_emails) if ($email_use_mailmap); - return @mapped_emails; -} - -sub merge_by_realname { - my %address_map; - my (@emails) = @_; - - foreach my $email (@emails) { - my ($name, $address) = parse_email($email); - if (exists $address_map{$name}) { - $address = $address_map{$name}; - $email = format_email($name, $address, 1); - } else { - $address_map{$name} = $address; - } - } -} - -sub git_execute_cmd { - my ($cmd) = @_; - my @lines = (); - - my $output = `$cmd`; - $output =~ s/^\s*//gm; - @lines = split("\n", $output); - - return @lines; -} - -sub hg_execute_cmd { - my ($cmd) = @_; - my @lines = (); - - my $output = `$cmd`; - @lines = split("\n", $output); - - return @lines; -} - -sub extract_formatted_signatures { - my (@signature_lines) = @_; - - my @type = @signature_lines; - - s/\s*(.*):.*/$1/ for (@type); - - # cut -f2- -d":" - s/\s*.*:\s*(.+)\s*/$1/ for (@signature_lines); - -## Reformat email addresses (with names) to avoid badly written signatures - - foreach my $signer (@signature_lines) { - $signer = deduplicate_email($signer); - } - - return (\@type, \@signature_lines); -} - -sub vcs_find_signers { - my ($cmd) = @_; - my $commits; - my @lines = (); - my @signatures = (); - - @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); - - my $pattern = $VCS_cmds{"commit_pattern"}; - - $commits = grep(/$pattern/, @lines); # of commits - - @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines); - - return (0, @signatures) if !@signatures; - - save_commits_by_author(@lines) if ($interactive); - save_commits_by_signer(@lines) if ($interactive); - - my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures); - - return ($commits, @$signers_ref); -} - -sub vcs_find_author { - my ($cmd) = @_; - my @lines = (); - - @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); - - return @lines if !@lines; - - my @authors = (); - foreach my $line (@lines) { - if ($line =~ m/$VCS_cmds{"author_pattern"}/) { - my $author = $1; - my ($name, $address) = parse_email($author); - $author = format_email($name, $address, 1); - push(@authors, $author); - } - } - - save_commits_by_author(@lines) if ($interactive); - save_commits_by_signer(@lines) if ($interactive); - - return @authors; -} - -sub vcs_save_commits { - my ($cmd) = @_; - my @lines = (); - my @commits = (); - - @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); - - foreach my $line (@lines) { - if ($line =~ m/$VCS_cmds{"blame_commit_pattern"}/) { - push(@commits, $1); - } - } - - return @commits; -} - -sub vcs_blame { - my ($file) = @_; - my $cmd; - my @commits = (); - - return @commits if (!(-f $file)); - - if (@range && $VCS_cmds{"blame_range_cmd"} eq "") { - my @all_commits = (); - - $cmd = $VCS_cmds{"blame_file_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd - @all_commits = vcs_save_commits($cmd); - - foreach my $file_range_diff (@range) { - next if (!($file_range_diff =~ m/(.+):(.+):(.+)/)); - my $diff_file = $1; - my $diff_start = $2; - my $diff_length = $3; - next if ("$file" ne "$diff_file"); - for (my $i = $diff_start; $i < $diff_start + $diff_length; $i++) { - push(@commits, $all_commits[$i]); - } - } - } elsif (@range) { - foreach my $file_range_diff (@range) { - next if (!($file_range_diff =~ m/(.+):(.+):(.+)/)); - my $diff_file = $1; - my $diff_start = $2; - my $diff_length = $3; - next if ("$file" ne "$diff_file"); - $cmd = $VCS_cmds{"blame_range_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd - push(@commits, vcs_save_commits($cmd)); - } - } else { - $cmd = $VCS_cmds{"blame_file_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd - @commits = vcs_save_commits($cmd); - } - - foreach my $commit (@commits) { - $commit =~ s/^\^//g; - } - - return @commits; -} - -my $printed_novcs = 0; -sub vcs_exists { - %VCS_cmds = %VCS_cmds_git; - return 1 if eval $VCS_cmds{"available"}; - %VCS_cmds = %VCS_cmds_hg; - return 2 if eval $VCS_cmds{"available"}; - %VCS_cmds = (); - if (!$printed_novcs) { - warn("$P: No supported VCS found. Add --nogit to options?\n"); - warn("Using a git repository produces better results.\n"); - warn("Try latest git repository using:\n"); - warn("git clone git://git.qemu-project.org/qemu.git\n"); - $printed_novcs = 1; - } - return 0; -} - -sub vcs_is_git { - vcs_exists(); - return $vcs_used == 1; -} - -sub vcs_is_hg { - return $vcs_used == 2; -} - -sub interactive_get_maintainers { - my ($list_ref) = @_; - my @list = @$list_ref; - - vcs_exists(); - - my %selected; - my %authored; - my %signed; - my $count = 0; - my $maintained = 0; - foreach my $entry (@list) { - $maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i); - $selected{$count} = 1; - $authored{$count} = 0; - $signed{$count} = 0; - $count++; - } - - #menu loop - my $done = 0; - my $print_options = 0; - my $redraw = 1; - while (!$done) { - $count = 0; - if ($redraw) { - printf STDERR "\n%1s %2s %-65s", - "*", "#", "email/list and role:stats"; - if ($email_git || - ($email_git_fallback && !$maintained) || - $email_git_blame) { - print STDERR "auth sign"; - } - print STDERR "\n"; - foreach my $entry (@list) { - my $email = $entry->[0]; - my $role = $entry->[1]; - my $sel = ""; - $sel = "*" if ($selected{$count}); - my $commit_author = $commit_author_hash{$email}; - my $commit_signer = $commit_signer_hash{$email}; - my $authored = 0; - my $signed = 0; - $authored++ for (@{$commit_author}); - $signed++ for (@{$commit_signer}); - printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email; - printf STDERR "%4d %4d", $authored, $signed - if ($authored > 0 || $signed > 0); - printf STDERR "\n %s\n", $role; - if ($authored{$count}) { - my $commit_author = $commit_author_hash{$email}; - foreach my $ref (@{$commit_author}) { - print STDERR " Author: @{$ref}[1]\n"; - } - } - if ($signed{$count}) { - my $commit_signer = $commit_signer_hash{$email}; - foreach my $ref (@{$commit_signer}) { - print STDERR " @{$ref}[2]: @{$ref}[1]\n"; - } - } - - $count++; - } - } - my $date_ref = \$email_git_since; - $date_ref = \$email_hg_since if (vcs_is_hg()); - if ($print_options) { - $print_options = 0; - if (vcs_exists()) { - print STDERR <<EOT - -Version Control options: -g use git history [$email_git] -gf use git-fallback [$email_git_fallback] -b use git blame [$email_git_blame] -bs use blame signatures [$email_git_blame_signatures] -c# minimum commits [$email_git_min_signatures] -%# min percent [$email_git_min_percent] -d# history to use [$$date_ref] -x# max maintainers [$email_git_max_maintainers] -t all signature types [$email_git_all_signature_types] -m use .mailmap [$email_use_mailmap] -EOT - } - print STDERR <<EOT - -Additional options: -0 toggle all -tm toggle maintainers -tg toggle git entries -tl toggle open list entries -ts toggle subscriber list entries -f emails in file [$file_emails] -k keywords in file [$keywords] -r remove duplicates [$email_remove_duplicates] -p# pattern match depth [$pattern_depth] -EOT - } - print STDERR -"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): "; - - my $input = <STDIN>; - chomp($input); - - $redraw = 1; - my $rerun = 0; - my @wish = split(/[, ]+/, $input); - foreach my $nr (@wish) { - $nr = lc($nr); - my $sel = substr($nr, 0, 1); - my $str = substr($nr, 1); - my $val = 0; - $val = $1 if $str =~ /^(\d+)$/; - - if ($sel eq "y") { - $interactive = 0; - $done = 1; - $output_rolestats = 0; - $output_roles = 0; - last; - } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) { - $selected{$nr - 1} = !$selected{$nr - 1}; - } elsif ($sel eq "*" || $sel eq '^') { - my $toggle = 0; - $toggle = 1 if ($sel eq '*'); - for (my $i = 0; $i < $count; $i++) { - $selected{$i} = $toggle; - } - } elsif ($sel eq "0") { - for (my $i = 0; $i < $count; $i++) { - $selected{$i} = !$selected{$i}; - } - } elsif ($sel eq "t") { - if (lc($str) eq "m") { - for (my $i = 0; $i < $count; $i++) { - $selected{$i} = !$selected{$i} - if ($list[$i]->[1] =~ /^(maintainer|supporter)/i); - } - } elsif (lc($str) eq "g") { - for (my $i = 0; $i < $count; $i++) { - $selected{$i} = !$selected{$i} - if ($list[$i]->[1] =~ /^(author|commit|signer)/i); - } - } elsif (lc($str) eq "l") { - for (my $i = 0; $i < $count; $i++) { - $selected{$i} = !$selected{$i} - if ($list[$i]->[1] =~ /^(open list)/i); - } - } elsif (lc($str) eq "s") { - for (my $i = 0; $i < $count; $i++) { - $selected{$i} = !$selected{$i} - if ($list[$i]->[1] =~ /^(subscriber list)/i); - } - } - } elsif ($sel eq "a") { - if ($val > 0 && $val <= $count) { - $authored{$val - 1} = !$authored{$val - 1}; - } elsif ($str eq '*' || $str eq '^') { - my $toggle = 0; - $toggle = 1 if ($str eq '*'); - for (my $i = 0; $i < $count; $i++) { - $authored{$i} = $toggle; - } - } - } elsif ($sel eq "s") { - if ($val > 0 && $val <= $count) { - $signed{$val - 1} = !$signed{$val - 1}; - } elsif ($str eq '*' || $str eq '^') { - my $toggle = 0; - $toggle = 1 if ($str eq '*'); - for (my $i = 0; $i < $count; $i++) { - $signed{$i} = $toggle; - } - } - } elsif ($sel eq "o") { - $print_options = 1; - $redraw = 1; - } elsif ($sel eq "g") { - if ($str eq "f") { - bool_invert(\$email_git_fallback); - } else { - bool_invert(\$email_git); - } - $rerun = 1; - } elsif ($sel eq "b") { - if ($str eq "s") { - bool_invert(\$email_git_blame_signatures); - } else { - bool_invert(\$email_git_blame); - } - $rerun = 1; - } elsif ($sel eq "c") { - if ($val > 0) { - $email_git_min_signatures = $val; - $rerun = 1; - } - } elsif ($sel eq "x") { - if ($val > 0) { - $email_git_max_maintainers = $val; - $rerun = 1; - } - } elsif ($sel eq "%") { - if ($str ne "" && $val >= 0) { - $email_git_min_percent = $val; - $rerun = 1; - } - } elsif ($sel eq "d") { - if (vcs_is_git()) { - $email_git_since = $str; - } elsif (vcs_is_hg()) { - $email_hg_since = $str; - } - $rerun = 1; - } elsif ($sel eq "t") { - bool_invert(\$email_git_all_signature_types); - $rerun = 1; - } elsif ($sel eq "f") { - bool_invert(\$file_emails); - $rerun = 1; - } elsif ($sel eq "r") { - bool_invert(\$email_remove_duplicates); - $rerun = 1; - } elsif ($sel eq "m") { - bool_invert(\$email_use_mailmap); - read_mailmap(); - $rerun = 1; - } elsif ($sel eq "k") { - bool_invert(\$keywords); - $rerun = 1; - } elsif ($sel eq "p") { - if ($str ne "" && $val >= 0) { - $pattern_depth = $val; - $rerun = 1; - } - } elsif ($sel eq "h" || $sel eq "?") { - print STDERR <<EOT - -Interactive mode allows you to select the various maintainers, submitters, -commit signers and mailing lists that could be CC'd on a patch. - -Any *'d entry is selected. - -If you have git or hg installed, you can choose to summarize the commit -history of files in the patch. Also, each line of the current file can -be matched to its commit author and that commits signers with blame. - -Various knobs exist to control the length of time for active commit -tracking, the maximum number of commit authors and signers to add, -and such. - -Enter selections at the prompt until you are satisfied that the selected -maintainers are appropriate. You may enter multiple selections separated -by either commas or spaces. - -EOT - } else { - print STDERR "invalid option: '$nr'\n"; - $redraw = 0; - } - } - if ($rerun) { - print STDERR "git-blame can be very slow, please have patience..." - if ($email_git_blame); - goto &get_maintainers; - } - } - - #drop not selected entries - $count = 0; - my @new_emailto = (); - foreach my $entry (@list) { - if ($selected{$count}) { - push(@new_emailto, $list[$count]); - } - $count++; - } - return @new_emailto; -} - -sub bool_invert { - my ($bool_ref) = @_; - - if ($$bool_ref) { - $$bool_ref = 0; - } else { - $$bool_ref = 1; - } -} - -sub deduplicate_email { - my ($email) = @_; - - my $matched = 0; - my ($name, $address) = parse_email($email); - $email = format_email($name, $address, 1); - $email = mailmap_email($email); - - return $email if (!$email_remove_duplicates); - - ($name, $address) = parse_email($email); - - if ($name ne "" && $deduplicate_name_hash{lc($name)}) { - $name = $deduplicate_name_hash{lc($name)}->[0]; - $address = $deduplicate_name_hash{lc($name)}->[1]; - $matched = 1; - } elsif ($deduplicate_address_hash{lc($address)}) { - $name = $deduplicate_address_hash{lc($address)}->[0]; - $address = $deduplicate_address_hash{lc($address)}->[1]; - $matched = 1; - } - if (!$matched) { - $deduplicate_name_hash{lc($name)} = [ $name, $address ]; - $deduplicate_address_hash{lc($address)} = [ $name, $address ]; - } - $email = format_email($name, $address, 1); - $email = mailmap_email($email); - return $email; -} - -sub save_commits_by_author { - my (@lines) = @_; - - my @authors = (); - my @commits = (); - my @subjects = (); - - foreach my $line (@lines) { - if ($line =~ m/$VCS_cmds{"author_pattern"}/) { - my $author = $1; - $author = deduplicate_email($author); - push(@authors, $author); - } - push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/); - push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/); - } - - for (my $i = 0; $i < @authors; $i++) { - my $exists = 0; - foreach my $ref(@{$commit_author_hash{$authors[$i]}}) { - if (@{$ref}[0] eq $commits[$i] && - @{$ref}[1] eq $subjects[$i]) { - $exists = 1; - last; - } - } - if (!$exists) { - push(@{$commit_author_hash{$authors[$i]}}, - [ ($commits[$i], $subjects[$i]) ]); - } - } -} - -sub save_commits_by_signer { - my (@lines) = @_; - - my $commit = ""; - my $subject = ""; - - foreach my $line (@lines) { - $commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/); - $subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/); - if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) { - my @signatures = ($line); - my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures); - my @types = @$types_ref; - my @signers = @$signers_ref; - - my $type = $types[0]; - my $signer = $signers[0]; - - $signer = deduplicate_email($signer); - - my $exists = 0; - foreach my $ref(@{$commit_signer_hash{$signer}}) { - if (@{$ref}[0] eq $commit && - @{$ref}[1] eq $subject && - @{$ref}[2] eq $type) { - $exists = 1; - last; - } - } - if (!$exists) { - push(@{$commit_signer_hash{$signer}}, - [ ($commit, $subject, $type) ]); - } - } - } -} - -sub vcs_assign { - my ($role, $divisor, @lines) = @_; - - my %hash; - my $count = 0; - - return if (@lines <= 0); - - if ($divisor <= 0) { - warn("Bad divisor in " . (caller(0))[3] . ": $divisor\n"); - $divisor = 1; - } - - @lines = mailmap(@lines); - - return if (@lines <= 0); - - @lines = sort(@lines); - - # uniq -c - $hash{$_}++ for @lines; - - # sort -rn - foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) { - my $sign_offs = $hash{$line}; - my $percent = $sign_offs * 100 / $divisor; - - $percent = 100 if ($percent > 100); - $count++; - last if ($sign_offs < $email_git_min_signatures || - $count > $email_git_max_maintainers || - $percent < $email_git_min_percent); - push_email_address($line, ''); - if ($output_rolestats) { - my $fmt_percent = sprintf("%.0f", $percent); - add_role($line, "$role:$sign_offs/$divisor=$fmt_percent%"); - } else { - add_role($line, $role); - } - } -} - -sub vcs_file_signoffs { - my ($file) = @_; - - my @signers = (); - my $commits; - - $vcs_used = vcs_exists(); - return if (!$vcs_used); - - my $cmd = $VCS_cmds{"find_signers_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd - - ($commits, @signers) = vcs_find_signers($cmd); - - foreach my $signer (@signers) { - $signer = deduplicate_email($signer); - } - - vcs_assign("commit_signer", $commits, @signers); -} - -sub vcs_file_blame { - my ($file) = @_; - - my @signers = (); - my @all_commits = (); - my @commits = (); - my $total_commits; - my $total_lines; - - $vcs_used = vcs_exists(); - return if (!$vcs_used); - - @all_commits = vcs_blame($file); - @commits = uniq(@all_commits); - $total_commits = @commits; - $total_lines = @all_commits; - - if ($email_git_blame_signatures) { - if (vcs_is_hg()) { - my $commit_count; - my @commit_signers = (); - my $commit = join(" -r ", @commits); - my $cmd; - - $cmd = $VCS_cmds{"find_commit_signers_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd - - ($commit_count, @commit_signers) = vcs_find_signers($cmd); - - push(@signers, @commit_signers); - } else { - foreach my $commit (@commits) { - my $commit_count; - my @commit_signers = (); - my $cmd; - - $cmd = $VCS_cmds{"find_commit_signers_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd - - ($commit_count, @commit_signers) = vcs_find_signers($cmd); - - push(@signers, @commit_signers); - } - } - } - - if ($from_filename) { - if ($output_rolestats) { - my @blame_signers; - if (vcs_is_hg()) {{ # Double brace for last exit - my $commit_count; - my @commit_signers = (); - @commits = uniq(@commits); - @commits = sort(@commits); - my $commit = join(" -r ", @commits); - my $cmd; - - $cmd = $VCS_cmds{"find_commit_author_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd - - my @lines = (); - - @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); - - last if !@lines; - - my @authors = (); - foreach my $line (@lines) { - if ($line =~ m/$VCS_cmds{"author_pattern"}/) { - my $author = $1; - $author = deduplicate_email($author); - push(@authors, $author); - } - } - - save_commits_by_author(@lines) if ($interactive); - save_commits_by_signer(@lines) if ($interactive); - - push(@signers, @authors); - }} - else { - foreach my $commit (@commits) { - my $i; - my $cmd = $VCS_cmds{"find_commit_author_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd - my @author = vcs_find_author($cmd); - next if !@author; - - my $formatted_author = deduplicate_email($author[0]); - - my $count = grep(/$commit/, @all_commits); - for ($i = 0; $i < $count ; $i++) { - push(@blame_signers, $formatted_author); - } - } - } - if (@blame_signers) { - vcs_assign("authored lines", $total_lines, @blame_signers); - } - } - foreach my $signer (@signers) { - $signer = deduplicate_email($signer); - } - vcs_assign("commits", $total_commits, @signers); - } else { - foreach my $signer (@signers) { - $signer = deduplicate_email($signer); - } - vcs_assign("modified commits", $total_commits, @signers); - } -} - -sub uniq { - my (@parms) = @_; - - my %saw; - @parms = grep(!$saw{$_}++, @parms); - return @parms; -} - -sub sort_and_uniq { - my (@parms) = @_; - - my %saw; - @parms = sort @parms; - @parms = grep(!$saw{$_}++, @parms); - return @parms; -} - -sub clean_file_emails { - my (@file_emails) = @_; - my @fmt_emails = (); - - foreach my $email (@file_emails) { - $email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+)[\)\>\}]{0,1}/\<$1\>/g; - my ($name, $address) = parse_email($email); - if ($name eq '"[,\.]"') { - $name = ""; - } - - my @nw = split(/[^A-Za-zÀ-ÿ\'\,\.\+-]/, $name); - if (@nw > 2) { - my $first = $nw[@nw - 3]; - my $middle = $nw[@nw - 2]; - my $last = $nw[@nw - 1]; - - if (((length($first) == 1 && $first =~ m/[A-Za-z]/) || - (length($first) == 2 && substr($first, -1) eq ".")) || - (length($middle) == 1 || - (length($middle) == 2 && substr($middle, -1) eq "."))) { - $name = "$first $middle $last"; - } else { - $name = "$middle $last"; - } - } - - if (substr($name, -1) =~ /[,\.]/) { - $name = substr($name, 0, length($name) - 1); - } elsif (substr($name, -2) =~ /[,\.]"/) { - $name = substr($name, 0, length($name) - 2) . '"'; - } - - if (substr($name, 0, 1) =~ /[,\.]/) { - $name = substr($name, 1, length($name) - 1); - } elsif (substr($name, 0, 2) =~ /"[,\.]/) { - $name = '"' . substr($name, 2, length($name) - 2); - } - - my $fmt_email = format_email($name, $address, $email_usename); - push(@fmt_emails, $fmt_email); - } - return @fmt_emails; -} - -sub merge_email { - my @lines; - my %saw; - - for (@_) { - my ($address, $role) = @$_; - if (!$saw{$address}) { - if ($output_roles) { - push(@lines, "$address ($role)"); - } else { - push(@lines, $address); - } - $saw{$address} = 1; - } - } - - return @lines; -} - -sub output { - my (@parms) = @_; - - if ($output_multiline) { - foreach my $line (@parms) { - print("${line}\n"); - } - } else { - print(join($output_separator, @parms)); - print("\n"); - } -} - -my $rfc822re; - -sub make_rfc822re { -# Basic lexical tokens are specials, domain_literal, quoted_string, atom, and -# comment. We must allow for rfc822_lwsp (or comments) after each of these. -# This regexp will only work on addresses which have had comments stripped -# and replaced with rfc822_lwsp. - - my $specials = '()<>@,;:\\\\".\\[\\]'; - my $controls = '\\000-\\037\\177'; - - my $dtext = "[^\\[\\]\\r\\\\]"; - my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$rfc822_lwsp*"; - - my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$rfc822_lwsp)*\"$rfc822_lwsp*"; - -# Use zero-width assertion to spot the limit of an atom. A simple -# $rfc822_lwsp* causes the regexp engine to hang occasionally. - my $atom = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))"; - my $word = "(?:$atom|$quoted_string)"; - my $localpart = "$word(?:\\.$rfc822_lwsp*$word)*"; - - my $sub_domain = "(?:$atom|$domain_literal)"; - my $domain = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*"; - - my $addr_spec = "$localpart\@$rfc822_lwsp*$domain"; - - my $phrase = "$word*"; - my $route = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)"; - my $route_addr = "\\<$rfc822_lwsp*$route?$addr_spec\\>$rfc822_lwsp*"; - my $mailbox = "(?:$addr_spec|$phrase$route_addr)"; - - my $group = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*"; - my $address = "(?:$mailbox|$group)"; - - return "$rfc822_lwsp*$address"; -} - -sub rfc822_strip_comments { - my $s = shift; -# Recursively remove comments, and replace with a single space. The simpler -# regexps in the Email Addressing FAQ are imperfect - they will miss escaped -# chars in atoms, for example. - - while ($s =~ s/^((?:[^"\\]|\\.)* - (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*) - \((?:[^()\\]|\\.)*\)/$1 /osx) {} - return $s; -} - -# valid: returns true if the parameter is an RFC822 valid address -# -sub rfc822_valid { - my $s = rfc822_strip_comments(shift); - - if (!$rfc822re) { - $rfc822re = make_rfc822re(); - } - - return $s =~ m/^$rfc822re$/so && $s =~ m/^$rfc822_char*$/; -} - -# validlist: In scalar context, returns true if the parameter is an RFC822 -# valid list of addresses. -# -# In list context, returns an empty list on failure (an invalid -# address was found); otherwise a list whose first element is the -# number of addresses found and whose remaining elements are the -# addresses. This is needed to disambiguate failure (invalid) -# from success with no addresses found, because an empty string is -# a valid list. - -sub rfc822_validlist { - my $s = rfc822_strip_comments(shift); - - if (!$rfc822re) { - $rfc822re = make_rfc822re(); - } - # * null list items are valid according to the RFC - # * the '1' business is to aid in distinguishing failure from no results - - my @r; - if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so && - $s =~ m/^$rfc822_char*$/) { - while ($s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos) { - push(@r, $1); - } - return wantarray ? (scalar(@r), @r) : 1; - } - return wantarray ? () : 0; -} diff --git a/qemu/scripts/gtester-cat b/qemu/scripts/gtester-cat deleted file mode 100755 index 061a952ca..000000000 --- a/qemu/scripts/gtester-cat +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -# -# Copyright IBM, Corp. 2012 -# -# Authors: -# Anthony Liguori <aliguori@us.ibm.com> -# -# This work is licensed under the terms of the GNU GPLv2 or later. -# See the COPYING file in the top-level directory. - -cat <<EOF -<?xml version="1.0"?> -<gtester> - <info> - <package>qemu</package> - <version>0.0</version> - <revision>rev</revision> - </info> -EOF - -sed \ - -e '/<?xml/d' \ - -e '/^<gtester>$/d' \ - -e '/<info>/,/<\/info>/d' \ - -e '$b' \ - -e '/^<\/gtester>$/d' "$@" diff --git a/qemu/scripts/hxtool b/qemu/scripts/hxtool deleted file mode 100644 index 995bb7f08..000000000 --- a/qemu/scripts/hxtool +++ /dev/null @@ -1,105 +0,0 @@ -#!/bin/sh - -hxtoh() -{ - flag=1 - while read -r str; do - case $str in - HXCOMM*) - ;; - STEXI*|ETEXI*|SQMP*|EQMP*) flag=$(($flag^1)) - ;; - *) - test $flag -eq 1 && printf "%s\n" "$str" - ;; - esac - done -} - -hxtotexi() -{ - flag=0 - line=1 - while read -r str; do - case "$str" in - HXCOMM*) - ;; - STEXI*) - if test $flag -eq 1 ; then - echo "line $line: syntax error: expected ETEXI, found $str" >&2 - exit 1 - fi - flag=1 - ;; - ETEXI*) - if test $flag -ne 1 ; then - echo "line $line: syntax error: expected STEXI, found $str" >&2 - exit 1 - fi - flag=0 - ;; - SQMP*|EQMP*) - if test $flag -eq 1 ; then - echo "line $line: syntax error: expected ETEXI, found $str" >&2 - exit 1 - fi - ;; - DEFHEADING*) - echo "$(expr "$str" : "DEFHEADING(\(.*\))")" - ;; - ARCHHEADING*) - echo "$(expr "$str" : "ARCHHEADING(\(.*\),.*)")" - ;; - *) - test $flag -eq 1 && echo "$str" - ;; - esac - line=$((line+1)) - done -} - -hxtoqmp() -{ - IFS= - flag=0 - line=1 - while read -r str; do - case "$str" in - HXCOMM*) - ;; - SQMP*) - if test $flag -eq 1 ; then - echo "line $line: syntax error: expected EQMP, found $str" >&2 - exit 1 - fi - flag=1 - ;; - EQMP*) - if test $flag -ne 1 ; then - echo "line $line: syntax error: expected SQMP, found $str" >&2 - exit 1 - fi - flag=0 - ;; - STEXI*|ETEXI*) - if test $flag -eq 1 ; then - echo "line $line: syntax error: expected EQMP, found $str" >&2 - exit 1 - fi - ;; - *) - test $flag -eq 1 && echo "$str" - ;; - esac - line=$((line+1)) - done -} - -case "$1" in -"-h") hxtoh ;; -"-t") hxtotexi ;; -"-q") hxtoqmp ;; -*) exit 1 ;; -esac - -exit 0 diff --git a/qemu/scripts/kvm/kvm_flightrecorder b/qemu/scripts/kvm/kvm_flightrecorder deleted file mode 100755 index 7fb1c2d1a..000000000 --- a/qemu/scripts/kvm/kvm_flightrecorder +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python -# -# KVM Flight Recorder - ring buffer tracing script -# -# Copyright (C) 2012 IBM Corp -# -# Author: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> -# -# This script provides a command-line interface to kvm ftrace and is designed -# to be used as a flight recorder that is always running. To start in-memory -# recording: -# -# sudo kvm_flightrecorder start 8192 # 8 MB per-cpu ring buffers -# -# The per-cpu ring buffer size can be given in KB as an optional argument to -# the 'start' subcommand. -# -# To stop the flight recorder: -# -# sudo kvm_flightrecorder stop -# -# To dump the contents of the flight recorder (this can be done when the -# recorder is stopped or while it is running): -# -# sudo kvm_flightrecorder dump >/path/to/dump.txt -# -# To observe the trace while it is running, use the 'tail' subcommand: -# -# sudo kvm_flightrecorder tail -# -# Note that the flight recorder may impact overall system performance by -# consuming CPU cycles. No disk I/O is performed since the ring buffer holds a -# fixed-size in-memory trace. - -import sys -import os - -tracing_dir = '/sys/kernel/debug/tracing' - -def trace_path(*args): - return os.path.join(tracing_dir, *args) - -def write_file(path, data): - open(path, 'wb').write(data) - -def enable_event(subsystem, event, enable): - write_file(trace_path('events', subsystem, event, 'enable'), '1' if enable else '0') - -def enable_subsystem(subsystem, enable): - write_file(trace_path('events', subsystem, 'enable'), '1' if enable else '0') - -def start_tracing(): - enable_subsystem('kvm', True) - write_file(trace_path('tracing_on'), '1') - -def stop_tracing(): - write_file(trace_path('tracing_on'), '0') - enable_subsystem('kvm', False) - write_file(trace_path('events', 'enable'), '0') - write_file(trace_path('current_tracer'), 'nop') - -def dump_trace(): - tracefile = open(trace_path('trace'), 'r') - try: - lines = True - while lines: - lines = tracefile.readlines(64 * 1024) - sys.stdout.writelines(lines) - except KeyboardInterrupt: - pass - -def tail_trace(): - try: - for line in open(trace_path('trace_pipe'), 'r'): - sys.stdout.write(line) - except KeyboardInterrupt: - pass - -def usage(): - print 'Usage: %s start [buffer_size_kb] | stop | dump | tail' % sys.argv[0] - print 'Control the KVM flight recorder tracing.' - sys.exit(0) - -def main(): - if len(sys.argv) < 2: - usage() - - cmd = sys.argv[1] - if cmd == '--version': - print 'kvm_flightrecorder version 1.0' - sys.exit(0) - - if not os.path.isdir(tracing_dir): - print 'Unable to tracing debugfs directory, try:' - print 'mount -t debugfs none /sys/kernel/debug' - sys.exit(1) - if not os.access(tracing_dir, os.W_OK): - print 'Unable to write to tracing debugfs directory, please run as root' - sys.exit(1) - - if cmd == 'start': - stop_tracing() # clean up first - - if len(sys.argv) == 3: - try: - buffer_size_kb = int(sys.argv[2]) - except ValueError: - print 'Invalid per-cpu trace buffer size in KB' - sys.exit(1) - write_file(trace_path('buffer_size_kb'), str(buffer_size_kb)) - print 'Per-CPU ring buffer size set to %d KB' % buffer_size_kb - - start_tracing() - print 'KVM flight recorder enabled' - elif cmd == 'stop': - stop_tracing() - print 'KVM flight recorder disabled' - elif cmd == 'dump': - dump_trace() - elif cmd == 'tail': - tail_trace() - else: - usage() - -if __name__ == '__main__': - sys.exit(main()) diff --git a/qemu/scripts/kvm/kvm_stat b/qemu/scripts/kvm/kvm_stat deleted file mode 100755 index 769d884b6..000000000 --- a/qemu/scripts/kvm/kvm_stat +++ /dev/null @@ -1,825 +0,0 @@ -#!/usr/bin/python -# -# top-like utility for displaying kvm statistics -# -# Copyright 2006-2008 Qumranet Technologies -# Copyright 2008-2011 Red Hat, Inc. -# -# Authors: -# Avi Kivity <avi@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. - -import curses -import sys -import os -import time -import optparse -import ctypes -import fcntl -import resource -import struct -import re -from collections import defaultdict -from time import sleep - -VMX_EXIT_REASONS = { - 'EXCEPTION_NMI': 0, - 'EXTERNAL_INTERRUPT': 1, - 'TRIPLE_FAULT': 2, - 'PENDING_INTERRUPT': 7, - 'NMI_WINDOW': 8, - 'TASK_SWITCH': 9, - 'CPUID': 10, - 'HLT': 12, - 'INVLPG': 14, - 'RDPMC': 15, - 'RDTSC': 16, - 'VMCALL': 18, - 'VMCLEAR': 19, - 'VMLAUNCH': 20, - 'VMPTRLD': 21, - 'VMPTRST': 22, - 'VMREAD': 23, - 'VMRESUME': 24, - 'VMWRITE': 25, - 'VMOFF': 26, - 'VMON': 27, - 'CR_ACCESS': 28, - 'DR_ACCESS': 29, - 'IO_INSTRUCTION': 30, - 'MSR_READ': 31, - 'MSR_WRITE': 32, - 'INVALID_STATE': 33, - 'MWAIT_INSTRUCTION': 36, - 'MONITOR_INSTRUCTION': 39, - 'PAUSE_INSTRUCTION': 40, - 'MCE_DURING_VMENTRY': 41, - 'TPR_BELOW_THRESHOLD': 43, - 'APIC_ACCESS': 44, - 'EPT_VIOLATION': 48, - 'EPT_MISCONFIG': 49, - 'WBINVD': 54, - 'XSETBV': 55, - 'APIC_WRITE': 56, - 'INVPCID': 58, -} - -SVM_EXIT_REASONS = { - 'READ_CR0': 0x000, - 'READ_CR3': 0x003, - 'READ_CR4': 0x004, - 'READ_CR8': 0x008, - 'WRITE_CR0': 0x010, - 'WRITE_CR3': 0x013, - 'WRITE_CR4': 0x014, - 'WRITE_CR8': 0x018, - 'READ_DR0': 0x020, - 'READ_DR1': 0x021, - 'READ_DR2': 0x022, - 'READ_DR3': 0x023, - 'READ_DR4': 0x024, - 'READ_DR5': 0x025, - 'READ_DR6': 0x026, - 'READ_DR7': 0x027, - 'WRITE_DR0': 0x030, - 'WRITE_DR1': 0x031, - 'WRITE_DR2': 0x032, - 'WRITE_DR3': 0x033, - 'WRITE_DR4': 0x034, - 'WRITE_DR5': 0x035, - 'WRITE_DR6': 0x036, - 'WRITE_DR7': 0x037, - 'EXCP_BASE': 0x040, - 'INTR': 0x060, - 'NMI': 0x061, - 'SMI': 0x062, - 'INIT': 0x063, - 'VINTR': 0x064, - 'CR0_SEL_WRITE': 0x065, - 'IDTR_READ': 0x066, - 'GDTR_READ': 0x067, - 'LDTR_READ': 0x068, - 'TR_READ': 0x069, - 'IDTR_WRITE': 0x06a, - 'GDTR_WRITE': 0x06b, - 'LDTR_WRITE': 0x06c, - 'TR_WRITE': 0x06d, - 'RDTSC': 0x06e, - 'RDPMC': 0x06f, - 'PUSHF': 0x070, - 'POPF': 0x071, - 'CPUID': 0x072, - 'RSM': 0x073, - 'IRET': 0x074, - 'SWINT': 0x075, - 'INVD': 0x076, - 'PAUSE': 0x077, - 'HLT': 0x078, - 'INVLPG': 0x079, - 'INVLPGA': 0x07a, - 'IOIO': 0x07b, - 'MSR': 0x07c, - 'TASK_SWITCH': 0x07d, - 'FERR_FREEZE': 0x07e, - 'SHUTDOWN': 0x07f, - 'VMRUN': 0x080, - 'VMMCALL': 0x081, - 'VMLOAD': 0x082, - 'VMSAVE': 0x083, - 'STGI': 0x084, - 'CLGI': 0x085, - 'SKINIT': 0x086, - 'RDTSCP': 0x087, - 'ICEBP': 0x088, - 'WBINVD': 0x089, - 'MONITOR': 0x08a, - 'MWAIT': 0x08b, - 'MWAIT_COND': 0x08c, - 'XSETBV': 0x08d, - 'NPF': 0x400, -} - -# EC definition of HSR (from arch/arm64/include/asm/kvm_arm.h) -AARCH64_EXIT_REASONS = { - 'UNKNOWN': 0x00, - 'WFI': 0x01, - 'CP15_32': 0x03, - 'CP15_64': 0x04, - 'CP14_MR': 0x05, - 'CP14_LS': 0x06, - 'FP_ASIMD': 0x07, - 'CP10_ID': 0x08, - 'CP14_64': 0x0C, - 'ILL_ISS': 0x0E, - 'SVC32': 0x11, - 'HVC32': 0x12, - 'SMC32': 0x13, - 'SVC64': 0x15, - 'HVC64': 0x16, - 'SMC64': 0x17, - 'SYS64': 0x18, - 'IABT': 0x20, - 'IABT_HYP': 0x21, - 'PC_ALIGN': 0x22, - 'DABT': 0x24, - 'DABT_HYP': 0x25, - 'SP_ALIGN': 0x26, - 'FP_EXC32': 0x28, - 'FP_EXC64': 0x2C, - 'SERROR': 0x2F, - 'BREAKPT': 0x30, - 'BREAKPT_HYP': 0x31, - 'SOFTSTP': 0x32, - 'SOFTSTP_HYP': 0x33, - 'WATCHPT': 0x34, - 'WATCHPT_HYP': 0x35, - 'BKPT32': 0x38, - 'VECTOR32': 0x3A, - 'BRK64': 0x3C, -} - -# From include/uapi/linux/kvm.h, KVM_EXIT_xxx -USERSPACE_EXIT_REASONS = { - 'UNKNOWN': 0, - 'EXCEPTION': 1, - 'IO': 2, - 'HYPERCALL': 3, - 'DEBUG': 4, - 'HLT': 5, - 'MMIO': 6, - 'IRQ_WINDOW_OPEN': 7, - 'SHUTDOWN': 8, - 'FAIL_ENTRY': 9, - 'INTR': 10, - 'SET_TPR': 11, - 'TPR_ACCESS': 12, - 'S390_SIEIC': 13, - 'S390_RESET': 14, - 'DCR': 15, - 'NMI': 16, - 'INTERNAL_ERROR': 17, - 'OSI': 18, - 'PAPR_HCALL': 19, - 'S390_UCONTROL': 20, - 'WATCHDOG': 21, - 'S390_TSCH': 22, - 'EPR': 23, - 'SYSTEM_EVENT': 24, -} - -IOCTL_NUMBERS = { - 'SET_FILTER': 0x40082406, - 'ENABLE': 0x00002400, - 'DISABLE': 0x00002401, - 'RESET': 0x00002403, -} - -class Arch(object): - """Class that encapsulates global architecture specific data like - syscall and ioctl numbers. - - """ - @staticmethod - def get_arch(): - machine = os.uname()[4] - - if machine.startswith('ppc'): - return ArchPPC() - elif machine.startswith('aarch64'): - return ArchA64() - elif machine.startswith('s390'): - return ArchS390() - else: - # X86_64 - for line in open('/proc/cpuinfo'): - if not line.startswith('flags'): - continue - - flags = line.split() - if 'vmx' in flags: - return ArchX86(VMX_EXIT_REASONS) - if 'svm' in flags: - return ArchX86(SVM_EXIT_REASONS) - return - -class ArchX86(Arch): - def __init__(self, exit_reasons): - self.sc_perf_evt_open = 298 - self.ioctl_numbers = IOCTL_NUMBERS - self.exit_reasons = exit_reasons - -class ArchPPC(Arch): - def __init__(self): - self.sc_perf_evt_open = 319 - self.ioctl_numbers = IOCTL_NUMBERS - self.ioctl_numbers['ENABLE'] = 0x20002400 - self.ioctl_numbers['DISABLE'] = 0x20002401 - - # PPC comes in 32 and 64 bit and some generated ioctl - # numbers depend on the wordsize. - char_ptr_size = ctypes.sizeof(ctypes.c_char_p) - self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16 - -class ArchA64(Arch): - def __init__(self): - self.sc_perf_evt_open = 241 - self.ioctl_numbers = IOCTL_NUMBERS - self.exit_reasons = AARCH64_EXIT_REASONS - -class ArchS390(Arch): - def __init__(self): - self.sc_perf_evt_open = 331 - self.ioctl_numbers = IOCTL_NUMBERS - self.exit_reasons = None - -ARCH = Arch.get_arch() - - -def walkdir(path): - """Returns os.walk() data for specified directory. - - As it is only a wrapper it returns the same 3-tuple of (dirpath, - dirnames, filenames). - """ - return next(os.walk(path)) - - -def parse_int_list(list_string): - """Returns an int list from a string of comma separated integers and - integer ranges.""" - integers = [] - members = list_string.split(',') - - for member in members: - if '-' not in member: - integers.append(int(member)) - else: - int_range = member.split('-') - integers.extend(range(int(int_range[0]), - int(int_range[1]) + 1)) - - return integers - - -def get_online_cpus(): - with open('/sys/devices/system/cpu/online') as cpu_list: - cpu_string = cpu_list.readline() - return parse_int_list(cpu_string) - - -def get_filters(): - filters = {} - filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS) - if ARCH.exit_reasons: - filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) - return filters - -libc = ctypes.CDLL('libc.so.6', use_errno=True) -syscall = libc.syscall - -class perf_event_attr(ctypes.Structure): - _fields_ = [('type', ctypes.c_uint32), - ('size', ctypes.c_uint32), - ('config', ctypes.c_uint64), - ('sample_freq', ctypes.c_uint64), - ('sample_type', ctypes.c_uint64), - ('read_format', ctypes.c_uint64), - ('flags', ctypes.c_uint64), - ('wakeup_events', ctypes.c_uint32), - ('bp_type', ctypes.c_uint32), - ('bp_addr', ctypes.c_uint64), - ('bp_len', ctypes.c_uint64), - ] - - def __init__(self): - super(self.__class__, self).__init__() - self.type = PERF_TYPE_TRACEPOINT - self.size = ctypes.sizeof(self) - self.read_format = PERF_FORMAT_GROUP - -def perf_event_open(attr, pid, cpu, group_fd, flags): - return syscall(ARCH.sc_perf_evt_open, ctypes.pointer(attr), - ctypes.c_int(pid), ctypes.c_int(cpu), - ctypes.c_int(group_fd), ctypes.c_long(flags)) - -PERF_TYPE_TRACEPOINT = 2 -PERF_FORMAT_GROUP = 1 << 3 - -PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing' -PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm' - -class Group(object): - def __init__(self): - self.events = [] - - def add_event(self, event): - self.events.append(event) - - def read(self): - length = 8 * (1 + len(self.events)) - read_format = 'xxxxxxxx' + 'Q' * len(self.events) - return dict(zip([event.name for event in self.events], - struct.unpack(read_format, - os.read(self.events[0].fd, length)))) - -class Event(object): - def __init__(self, name, group, trace_cpu, trace_point, trace_filter, - trace_set='kvm'): - self.name = name - self.fd = None - self.setup_event(group, trace_cpu, trace_point, trace_filter, - trace_set) - - def setup_event_attribute(self, trace_set, trace_point): - id_path = os.path.join(PATH_DEBUGFS_TRACING, 'events', trace_set, - trace_point, 'id') - - event_attr = perf_event_attr() - event_attr.config = int(open(id_path).read()) - return event_attr - - def setup_event(self, group, trace_cpu, trace_point, trace_filter, - trace_set): - event_attr = self.setup_event_attribute(trace_set, trace_point) - - group_leader = -1 - if group.events: - group_leader = group.events[0].fd - - fd = perf_event_open(event_attr, -1, trace_cpu, - group_leader, 0) - if fd == -1: - err = ctypes.get_errno() - raise OSError(err, os.strerror(err), - 'while calling sys_perf_event_open().') - - if trace_filter: - fcntl.ioctl(fd, ARCH.ioctl_numbers['SET_FILTER'], - trace_filter) - - self.fd = fd - - def enable(self): - fcntl.ioctl(self.fd, ARCH.ioctl_numbers['ENABLE'], 0) - - def disable(self): - fcntl.ioctl(self.fd, ARCH.ioctl_numbers['DISABLE'], 0) - - def reset(self): - fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0) - -class TracepointProvider(object): - def __init__(self): - self.group_leaders = [] - self.filters = get_filters() - self._fields = self.get_available_fields() - self.setup_traces() - self.fields = self._fields - - def get_available_fields(self): - path = os.path.join(PATH_DEBUGFS_TRACING, 'events', 'kvm') - fields = walkdir(path)[1] - extra = [] - for field in fields: - if field in self.filters: - filter_name_, filter_dicts = self.filters[field] - for name in filter_dicts: - extra.append(field + '(' + name + ')') - fields += extra - return fields - - def setup_traces(self): - cpus = get_online_cpus() - - # The constant is needed as a buffer for python libs, std - # streams and other files that the script opens. - newlim = len(cpus) * len(self._fields) + 50 - try: - softlim_, hardlim = resource.getrlimit(resource.RLIMIT_NOFILE) - - if hardlim < newlim: - # Now we need CAP_SYS_RESOURCE, to increase the hard limit. - resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, newlim)) - else: - # Raising the soft limit is sufficient. - resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, hardlim)) - - except ValueError: - sys.exit("NOFILE rlimit could not be raised to {0}".format(newlim)) - - for cpu in cpus: - group = Group() - for name in self._fields: - tracepoint = name - tracefilter = None - match = re.match(r'(.*)\((.*)\)', name) - if match: - tracepoint, sub = match.groups() - tracefilter = ('%s==%d\0' % - (self.filters[tracepoint][0], - self.filters[tracepoint][1][sub])) - - group.add_event(Event(name=name, - group=group, - trace_cpu=cpu, - trace_point=tracepoint, - trace_filter=tracefilter)) - self.group_leaders.append(group) - - def available_fields(self): - return self.get_available_fields() - - @property - def fields(self): - return self._fields - - @fields.setter - def fields(self, fields): - self._fields = fields - for group in self.group_leaders: - for index, event in enumerate(group.events): - if event.name in fields: - event.reset() - event.enable() - else: - # Do not disable the group leader. - # It would disable all of its events. - if index != 0: - event.disable() - - def read(self): - ret = defaultdict(int) - for group in self.group_leaders: - for name, val in group.read().iteritems(): - if name in self._fields: - ret[name] += val - return ret - -class DebugfsProvider(object): - def __init__(self): - self._fields = self.get_available_fields() - - def get_available_fields(self): - return walkdir(PATH_DEBUGFS_KVM)[2] - - @property - def fields(self): - return self._fields - - @fields.setter - def fields(self, fields): - self._fields = fields - - def read(self): - def val(key): - return int(file(PATH_DEBUGFS_KVM + '/' + key).read()) - return dict([(key, val(key)) for key in self._fields]) - -class Stats(object): - def __init__(self, providers, fields=None): - self.providers = providers - self._fields_filter = fields - self.values = {} - self.update_provider_filters() - - def update_provider_filters(self): - def wanted(key): - if not self._fields_filter: - return True - return re.match(self._fields_filter, key) is not None - - # As we reset the counters when updating the fields we can - # also clear the cache of old values. - self.values = {} - for provider in self.providers: - provider_fields = [key for key in provider.get_available_fields() - if wanted(key)] - provider.fields = provider_fields - - @property - def fields_filter(self): - return self._fields_filter - - @fields_filter.setter - def fields_filter(self, fields_filter): - self._fields_filter = fields_filter - self.update_provider_filters() - - def get(self): - for provider in self.providers: - new = provider.read() - for key in provider.fields: - oldval = self.values.get(key, (0, 0)) - newval = new.get(key, 0) - newdelta = None - if oldval is not None: - newdelta = newval - oldval[0] - self.values[key] = (newval, newdelta) - return self.values - -LABEL_WIDTH = 40 -NUMBER_WIDTH = 10 - -class Tui(object): - def __init__(self, stats): - self.stats = stats - self.screen = None - self.drilldown = False - self.update_drilldown() - - def __enter__(self): - """Initialises curses for later use. Based on curses.wrapper - implementation from the Python standard library.""" - self.screen = curses.initscr() - curses.noecho() - curses.cbreak() - - # The try/catch works around a minor bit of - # over-conscientiousness in the curses module, the error - # return from C start_color() is ignorable. - try: - curses.start_color() - except: - pass - - curses.use_default_colors() - return self - - def __exit__(self, *exception): - """Resets the terminal to its normal state. Based on curses.wrappre - implementation from the Python standard library.""" - if self.screen: - self.screen.keypad(0) - curses.echo() - curses.nocbreak() - curses.endwin() - - def update_drilldown(self): - if not self.stats.fields_filter: - self.stats.fields_filter = r'^[^\(]*$' - - elif self.stats.fields_filter == r'^[^\(]*$': - self.stats.fields_filter = None - - def refresh(self, sleeptime): - self.screen.erase() - self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) - self.screen.addstr(2, 1, 'Event') - self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH - - len('Total'), 'Total') - self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 8 - - len('Current'), 'Current') - row = 3 - stats = self.stats.get() - def sortkey(x): - if stats[x][1]: - return (-stats[x][1], -stats[x][0]) - else: - return (0, -stats[x][0]) - for key in sorted(stats.keys(), key=sortkey): - - if row >= self.screen.getmaxyx()[0]: - break - values = stats[key] - if not values[0] and not values[1]: - break - col = 1 - self.screen.addstr(row, col, key) - col += LABEL_WIDTH - self.screen.addstr(row, col, '%10d' % (values[0],)) - col += NUMBER_WIDTH - if values[1] is not None: - self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,)) - row += 1 - self.screen.refresh() - - def show_filter_selection(self): - while True: - self.screen.erase() - self.screen.addstr(0, 0, - "Show statistics for events matching a regex.", - curses.A_BOLD) - self.screen.addstr(2, 0, - "Current regex: {0}" - .format(self.stats.fields_filter)) - self.screen.addstr(3, 0, "New regex: ") - curses.echo() - regex = self.screen.getstr() - curses.noecho() - if len(regex) == 0: - return - try: - re.compile(regex) - self.stats.fields_filter = regex - return - except re.error: - continue - - def show_stats(self): - sleeptime = 0.25 - while True: - self.refresh(sleeptime) - curses.halfdelay(int(sleeptime * 10)) - sleeptime = 3 - try: - char = self.screen.getkey() - if char == 'x': - self.drilldown = not self.drilldown - self.update_drilldown() - if char == 'q': - break - if char == 'f': - self.show_filter_selection() - except KeyboardInterrupt: - break - except curses.error: - continue - -def batch(stats): - s = stats.get() - time.sleep(1) - s = stats.get() - for key in sorted(s.keys()): - values = s[key] - print '%-42s%10d%10d' % (key, values[0], values[1]) - -def log(stats): - keys = sorted(stats.get().iterkeys()) - def banner(): - for k in keys: - print '%s' % k, - print - def statline(): - s = stats.get() - for k in keys: - print ' %9d' % s[k][1], - print - line = 0 - banner_repeat = 20 - while True: - time.sleep(1) - if line % banner_repeat == 0: - banner() - statline() - line += 1 - -def get_options(): - description_text = """ -This script displays various statistics about VMs running under KVM. -The statistics are gathered from the KVM debugfs entries and / or the -currently available perf traces. - -The monitoring takes additional cpu cycles and might affect the VM's -performance. - -Requirements: -- Access to: - /sys/kernel/debug/kvm - /sys/kernel/debug/trace/events/* - /proc/pid/task -- /proc/sys/kernel/perf_event_paranoid < 1 if user has no - CAP_SYS_ADMIN and perf events are used. -- CAP_SYS_RESOURCE if the hard limit is not high enough to allow - the large number of files that are possibly opened. -""" - - class PlainHelpFormatter(optparse.IndentedHelpFormatter): - def format_description(self, description): - if description: - return description + "\n" - else: - return "" - - optparser = optparse.OptionParser(description=description_text, - formatter=PlainHelpFormatter()) - optparser.add_option('-1', '--once', '--batch', - action='store_true', - default=False, - dest='once', - help='run in batch mode for one second', - ) - optparser.add_option('-l', '--log', - action='store_true', - default=False, - dest='log', - help='run in logging mode (like vmstat)', - ) - optparser.add_option('-t', '--tracepoints', - action='store_true', - default=False, - dest='tracepoints', - help='retrieve statistics from tracepoints', - ) - optparser.add_option('-d', '--debugfs', - action='store_true', - default=False, - dest='debugfs', - help='retrieve statistics from debugfs', - ) - optparser.add_option('-f', '--fields', - action='store', - default=None, - dest='fields', - help='fields to display (regex)', - ) - (options, _) = optparser.parse_args(sys.argv) - return options - -def get_providers(options): - providers = [] - - if options.tracepoints: - providers.append(TracepointProvider()) - if options.debugfs: - providers.append(DebugfsProvider()) - if len(providers) == 0: - providers.append(TracepointProvider()) - - return providers - -def check_access(options): - if not os.path.exists('/sys/kernel/debug'): - sys.stderr.write('Please enable CONFIG_DEBUG_FS in your kernel.') - sys.exit(1) - - if not os.path.exists(PATH_DEBUGFS_KVM): - sys.stderr.write("Please make sure, that debugfs is mounted and " - "readable by the current user:\n" - "('mount -t debugfs debugfs /sys/kernel/debug')\n" - "Also ensure, that the kvm modules are loaded.\n") - sys.exit(1) - - if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints - or not options.debugfs): - sys.stderr.write("Please enable CONFIG_TRACING in your kernel " - "when using the option -t (default).\n" - "If it is enabled, make {0} readable by the " - "current user.\n" - .format(PATH_DEBUGFS_TRACING)) - if options.tracepoints: - sys.exit(1) - - sys.stderr.write("Falling back to debugfs statistics!\n") - options.debugfs = True - sleep(5) - - return options - -def main(): - options = get_options() - options = check_access(options) - providers = get_providers(options) - stats = Stats(providers, fields=options.fields) - - if options.log: - log(stats) - elif not options.once: - with Tui(stats) as tui: - tui.show_stats() - else: - batch(stats) - -if __name__ == "__main__": - main() diff --git a/qemu/scripts/kvm/kvm_stat.texi b/qemu/scripts/kvm/kvm_stat.texi deleted file mode 100644 index 6ce00d80e..000000000 --- a/qemu/scripts/kvm/kvm_stat.texi +++ /dev/null @@ -1,55 +0,0 @@ -@example -@c man begin SYNOPSIS -usage: kvm_stat [OPTION]... -@c man end -@end example - -@c man begin DESCRIPTION - -kvm_stat prints counts of KVM kernel module trace events. These events signify -state transitions such as guest mode entry and exit. - -This tool is useful for observing guest behavior from the host perspective. -Often conclusions about performance or buggy behavior can be drawn from the -output. - -The set of KVM kernel module trace events may be specific to the kernel version -or architecture. It is best to check the KVM kernel module source code for the -meaning of events. - -Note that trace events are counted globally across all running guests. - -@c man end - -@c man begin OPTIONS -@table @option -@item -1, --once, --batch - run in batch mode for one second -@item -l, --log - run in logging mode (like vmstat) -@item -t, --tracepoints - retrieve statistics from tracepoints -@item -d, --debugfs - retrieve statistics from debugfs -@item -f, --fields=@var{fields} - fields to display (regex) -@item -h, --help - show help message -@end table - -@c man end - -@ignore - -@setfilename kvm_stat -@settitle Report KVM kernel module event counters. - -@c man begin AUTHOR -Stefan Hajnoczi <stefanha@redhat.com> -@c man end - -@c man begin SEEALSO -perf(1), trace-cmd(1) -@c man end - -@end ignore diff --git a/qemu/scripts/kvm/vmxcap b/qemu/scripts/kvm/vmxcap deleted file mode 100755 index 8f0371f49..000000000 --- a/qemu/scripts/kvm/vmxcap +++ /dev/null @@ -1,260 +0,0 @@ -#!/usr/bin/python -# -# tool for querying VMX capabilities -# -# Copyright 2009-2010 Red Hat, Inc. -# -# Authors: -# Avi Kivity <avi@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. - -MSR_IA32_VMX_BASIC = 0x480 -MSR_IA32_VMX_PINBASED_CTLS = 0x481 -MSR_IA32_VMX_PROCBASED_CTLS = 0x482 -MSR_IA32_VMX_EXIT_CTLS = 0x483 -MSR_IA32_VMX_ENTRY_CTLS = 0x484 -MSR_IA32_VMX_MISC_CTLS = 0x485 -MSR_IA32_VMX_PROCBASED_CTLS2 = 0x48B -MSR_IA32_VMX_EPT_VPID_CAP = 0x48C -MSR_IA32_VMX_TRUE_PINBASED_CTLS = 0x48D -MSR_IA32_VMX_TRUE_PROCBASED_CTLS = 0x48E -MSR_IA32_VMX_TRUE_EXIT_CTLS = 0x48F -MSR_IA32_VMX_TRUE_ENTRY_CTLS = 0x490 -MSR_IA32_VMX_VMFUNC = 0x491 - -class msr(object): - def __init__(self): - try: - self.f = open('/dev/cpu/0/msr', 'r', 0) - except: - self.f = open('/dev/msr0', 'r', 0) - def read(self, index, default = None): - import struct - self.f.seek(index) - try: - return struct.unpack('Q', self.f.read(8))[0] - except: - return default - -class Control(object): - def __init__(self, name, bits, cap_msr, true_cap_msr = None): - self.name = name - self.bits = bits - self.cap_msr = cap_msr - self.true_cap_msr = true_cap_msr - def read2(self, nr): - m = msr() - val = m.read(nr, 0) - return (val & 0xffffffff, val >> 32) - def show(self): - print self.name - mbz, mb1 = self.read2(self.cap_msr) - tmbz, tmb1 = 0, 0 - if self.true_cap_msr: - tmbz, tmb1 = self.read2(self.true_cap_msr) - for bit in sorted(self.bits.keys()): - zero = not (mbz & (1 << bit)) - one = mb1 & (1 << bit) - true_zero = not (tmbz & (1 << bit)) - true_one = tmb1 & (1 << bit) - s= '?' - if (self.true_cap_msr and true_zero and true_one - and one and not zero): - s = 'default' - elif zero and not one: - s = 'no' - elif one and not zero: - s = 'forced' - elif one and zero: - s = 'yes' - print ' %-40s %s' % (self.bits[bit], s) - -class Misc(object): - def __init__(self, name, bits, msr): - self.name = name - self.bits = bits - self.msr = msr - def show(self): - print self.name - value = msr().read(self.msr, 0) - def first_bit(key): - if type(key) is tuple: - return key[0] - else: - return key - for bits in sorted(self.bits.keys(), key = first_bit): - if type(bits) is tuple: - lo, hi = bits - fmt = int - else: - lo = hi = bits - def fmt(x): - return { True: 'yes', False: 'no' }[x] - v = (value >> lo) & ((1 << (hi - lo + 1)) - 1) - print ' %-40s %s' % (self.bits[bits], fmt(v)) - -controls = [ - Misc( - name = 'Basic VMX Information', - bits = { - (0, 30): 'Revision', - (32,44): 'VMCS size', - 48: 'VMCS restricted to 32 bit addresses', - 49: 'Dual-monitor support', - (50, 53): 'VMCS memory type', - 54: 'INS/OUTS instruction information', - 55: 'IA32_VMX_TRUE_*_CTLS support', - }, - msr = MSR_IA32_VMX_BASIC, - ), - Control( - name = 'pin-based controls', - bits = { - 0: 'External interrupt exiting', - 3: 'NMI exiting', - 5: 'Virtual NMIs', - 6: 'Activate VMX-preemption timer', - 7: 'Process posted interrupts', - }, - cap_msr = MSR_IA32_VMX_PINBASED_CTLS, - true_cap_msr = MSR_IA32_VMX_TRUE_PINBASED_CTLS, - ), - - Control( - name = 'primary processor-based controls', - bits = { - 2: 'Interrupt window exiting', - 3: 'Use TSC offsetting', - 7: 'HLT exiting', - 9: 'INVLPG exiting', - 10: 'MWAIT exiting', - 11: 'RDPMC exiting', - 12: 'RDTSC exiting', - 15: 'CR3-load exiting', - 16: 'CR3-store exiting', - 19: 'CR8-load exiting', - 20: 'CR8-store exiting', - 21: 'Use TPR shadow', - 22: 'NMI-window exiting', - 23: 'MOV-DR exiting', - 24: 'Unconditional I/O exiting', - 25: 'Use I/O bitmaps', - 27: 'Monitor trap flag', - 28: 'Use MSR bitmaps', - 29: 'MONITOR exiting', - 30: 'PAUSE exiting', - 31: 'Activate secondary control', - }, - cap_msr = MSR_IA32_VMX_PROCBASED_CTLS, - true_cap_msr = MSR_IA32_VMX_TRUE_PROCBASED_CTLS, - ), - - Control( - name = 'secondary processor-based controls', - bits = { - 0: 'Virtualize APIC accesses', - 1: 'Enable EPT', - 2: 'Descriptor-table exiting', - 3: 'Enable RDTSCP', - 4: 'Virtualize x2APIC mode', - 5: 'Enable VPID', - 6: 'WBINVD exiting', - 7: 'Unrestricted guest', - 8: 'APIC register emulation', - 9: 'Virtual interrupt delivery', - 10: 'PAUSE-loop exiting', - 11: 'RDRAND exiting', - 12: 'Enable INVPCID', - 13: 'Enable VM functions', - 14: 'VMCS shadowing', - 16: 'RDSEED exiting', - 18: 'EPT-violation #VE', - 20: 'Enable XSAVES/XRSTORS', - }, - cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2, - ), - - Control( - name = 'VM-Exit controls', - bits = { - 2: 'Save debug controls', - 9: 'Host address-space size', - 12: 'Load IA32_PERF_GLOBAL_CTRL', - 15: 'Acknowledge interrupt on exit', - 18: 'Save IA32_PAT', - 19: 'Load IA32_PAT', - 20: 'Save IA32_EFER', - 21: 'Load IA32_EFER', - 22: 'Save VMX-preemption timer value', - }, - cap_msr = MSR_IA32_VMX_EXIT_CTLS, - true_cap_msr = MSR_IA32_VMX_TRUE_EXIT_CTLS, - ), - - Control( - name = 'VM-Entry controls', - bits = { - 2: 'Load debug controls', - 9: 'IA-32e mode guest', - 10: 'Entry to SMM', - 11: 'Deactivate dual-monitor treatment', - 13: 'Load IA32_PERF_GLOBAL_CTRL', - 14: 'Load IA32_PAT', - 15: 'Load IA32_EFER', - }, - cap_msr = MSR_IA32_VMX_ENTRY_CTLS, - true_cap_msr = MSR_IA32_VMX_TRUE_ENTRY_CTLS, - ), - - Misc( - name = 'Miscellaneous data', - bits = { - (0,4): 'VMX-preemption timer scale (log2)', - 5: 'Store EFER.LMA into IA-32e mode guest control', - 6: 'HLT activity state', - 7: 'Shutdown activity state', - 8: 'Wait-for-SIPI activity state', - 15: 'IA32_SMBASE support', - (16,24): 'Number of CR3-target values', - (25,27): 'MSR-load/store count recommendation', - 28: 'IA32_SMM_MONITOR_CTL[2] can be set to 1', - 29: 'VMWRITE to VM-exit information fields', - (32,63): 'MSEG revision identifier', - }, - msr = MSR_IA32_VMX_MISC_CTLS, - ), - - Misc( - name = 'VPID and EPT capabilities', - bits = { - 0: 'Execute-only EPT translations', - 6: 'Page-walk length 4', - 8: 'Paging-structure memory type UC', - 14: 'Paging-structure memory type WB', - 16: '2MB EPT pages', - 17: '1GB EPT pages', - 20: 'INVEPT supported', - 21: 'EPT accessed and dirty flags', - 25: 'Single-context INVEPT', - 26: 'All-context INVEPT', - 32: 'INVVPID supported', - 40: 'Individual-address INVVPID', - 41: 'Single-context INVVPID', - 42: 'All-context INVVPID', - 43: 'Single-context-retaining-globals INVVPID', - }, - msr = MSR_IA32_VMX_EPT_VPID_CAP, - ), - Misc( - name = 'VM Functions', - bits = { - 0: 'EPTP Switching', - }, - msr = MSR_IA32_VMX_VMFUNC, - ), - ] - -for c in controls: - c.show() diff --git a/qemu/scripts/make-release b/qemu/scripts/make-release deleted file mode 100755 index fa6323fda..000000000 --- a/qemu/scripts/make-release +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -e -# -# QEMU Release Script -# -# Copyright IBM, Corp. 2012 -# -# Authors: -# Anthony Liguori <aliguori@us.ibm.com> -# -# This work is licensed under the terms of the GNU GPLv2 or later. -# See the COPYING file in the top-level directory. - -src="$1" -version="$2" -destination=qemu-${version} - -git clone "${src}" ${destination} -pushd ${destination} -git checkout "v${version}" -git submodule update --init -(cd roms/seabios && git describe --tags --long --dirty > .version) -rm -rf .git roms/*/.git dtc/.git pixman/.git -popd -tar cfj ${destination}.tar.bz2 ${destination} -rm -rf ${destination} diff --git a/qemu/scripts/make_device_config.sh b/qemu/scripts/make_device_config.sh deleted file mode 100644 index c1afb3ffa..000000000 --- a/qemu/scripts/make_device_config.sh +++ /dev/null @@ -1,30 +0,0 @@ -#! /bin/sh -# Writes a target device config file to stdout, from a default and from -# include directives therein. Also emits Makefile dependencies. -# -# Usage: make_device_config.sh SRC DEPFILE-NAME DEPFILE-TARGET > DEST - -src=$1 -dep=$2 -target=$3 -src_dir=`dirname $src` -all_includes= - -process_includes () { - cat $1 | grep '^include' | \ - while read include file ; do - all_includes="$all_includes $src_dir/$file" - process_includes $src_dir/$file - done -} - -f=$src -while [ -n "$f" ] ; do - f=`cat $f | tr -d '\r' | awk '/^include / {printf "'$src_dir'/%s ", $2}'` - [ $? = 0 ] || exit 1 - all_includes="$all_includes $f" -done -process_includes $src - -cat $src $all_includes | grep -v '^include' -echo "$target: $all_includes" > $dep diff --git a/qemu/scripts/ordereddict.py b/qemu/scripts/ordereddict.py deleted file mode 100644 index 2d1d81370..000000000 --- a/qemu/scripts/ordereddict.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (c) 2009 Raymond Hettinger -# -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation files -# (the "Software"), to deal in the Software without restriction, -# including without limitation the rights to use, copy, modify, merge, -# publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. - -from UserDict import DictMixin - - -class OrderedDict(dict, DictMixin): - - def __init__(self, *args, **kwds): - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - try: - self.__end - except AttributeError: - self.clear() - self.update(*args, **kwds) - - def clear(self): - self.__end = end = [] - end += [None, end, end] # sentinel node for doubly linked list - self.__map = {} # key --> [key, prev, next] - dict.clear(self) - - def __setitem__(self, key, value): - if key not in self: - end = self.__end - curr = end[1] - curr[2] = end[1] = self.__map[key] = [key, curr, end] - dict.__setitem__(self, key, value) - - def __delitem__(self, key): - dict.__delitem__(self, key) - key, prev, next = self.__map.pop(key) - prev[2] = next - next[1] = prev - - def __iter__(self): - end = self.__end - curr = end[2] - while curr is not end: - yield curr[0] - curr = curr[2] - - def __reversed__(self): - end = self.__end - curr = end[1] - while curr is not end: - yield curr[0] - curr = curr[1] - - def popitem(self, last=True): - if not self: - raise KeyError('dictionary is empty') - if last: - key = reversed(self).next() - else: - key = iter(self).next() - value = self.pop(key) - return key, value - - def __reduce__(self): - items = [[k, self[k]] for k in self] - tmp = self.__map, self.__end - del self.__map, self.__end - inst_dict = vars(self).copy() - self.__map, self.__end = tmp - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - - def keys(self): - return list(self) - - setdefault = DictMixin.setdefault - update = DictMixin.update - pop = DictMixin.pop - values = DictMixin.values - items = DictMixin.items - iterkeys = DictMixin.iterkeys - itervalues = DictMixin.itervalues - iteritems = DictMixin.iteritems - - def __repr__(self): - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) - - def copy(self): - return self.__class__(self) - - @classmethod - def fromkeys(cls, iterable, value=None): - d = cls() - for key in iterable: - d[key] = value - return d - - def __eq__(self, other): - if isinstance(other, OrderedDict): - if len(self) != len(other): - return False - for p, q in zip(self.items(), other.items()): - if p != q: - return False - return True - return dict.__eq__(self, other) - - def __ne__(self, other): - return not self == other diff --git a/qemu/scripts/qapi-commands.py b/qemu/scripts/qapi-commands.py deleted file mode 100644 index b570069fa..000000000 --- a/qemu/scripts/qapi-commands.py +++ /dev/null @@ -1,299 +0,0 @@ -# -# QAPI command marshaller generator -# -# Copyright IBM, Corp. 2011 -# Copyright (C) 2014-2016 Red Hat, Inc. -# -# Authors: -# Anthony Liguori <aliguori@us.ibm.com> -# Michael Roth <mdroth@linux.vnet.ibm.com> -# Markus Armbruster <armbru@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. -# See the COPYING file in the top-level directory. - -from qapi import * -import re - - -def gen_command_decl(name, arg_type, ret_type): - return mcgen(''' -%(c_type)s qmp_%(c_name)s(%(params)s); -''', - c_type=(ret_type and ret_type.c_type()) or 'void', - c_name=c_name(name), - params=gen_params(arg_type, 'Error **errp')) - - -def gen_call(name, arg_type, ret_type): - ret = '' - - argstr = '' - if arg_type: - assert not arg_type.variants - for memb in arg_type.members: - if memb.optional: - argstr += 'arg.has_%s, ' % c_name(memb.name) - argstr += 'arg.%s, ' % c_name(memb.name) - - lhs = '' - if ret_type: - lhs = 'retval = ' - - ret = mcgen(''' - - %(lhs)sqmp_%(c_name)s(%(args)s&err); -''', - c_name=c_name(name), args=argstr, lhs=lhs) - if ret_type: - ret += gen_err_check() - ret += mcgen(''' - - qmp_marshal_output_%(c_name)s(retval, ret, &err); -''', - c_name=ret_type.c_name()) - return ret - - -def gen_marshal_output(ret_type): - return mcgen(''' - -static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp) -{ - Error *err = NULL; - QmpOutputVisitor *qov = qmp_output_visitor_new(); - QapiDeallocVisitor *qdv; - Visitor *v; - - v = qmp_output_get_visitor(qov); - visit_type_%(c_name)s(v, "unused", &ret_in, &err); - if (err) { - goto out; - } - *ret_out = qmp_output_get_qobject(qov); - -out: - error_propagate(errp, err); - qmp_output_visitor_cleanup(qov); - qdv = qapi_dealloc_visitor_new(); - v = qapi_dealloc_get_visitor(qdv); - visit_type_%(c_name)s(v, "unused", &ret_in, NULL); - qapi_dealloc_visitor_cleanup(qdv); -} -''', - c_type=ret_type.c_type(), c_name=ret_type.c_name()) - - -def gen_marshal_proto(name): - ret = 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name) - if not middle_mode: - ret = 'static ' + ret - return ret - - -def gen_marshal_decl(name): - return mcgen(''' -%(proto)s; -''', - proto=gen_marshal_proto(name)) - - -def gen_marshal(name, arg_type, ret_type): - ret = mcgen(''' - -%(proto)s -{ - Error *err = NULL; -''', - proto=gen_marshal_proto(name)) - - if ret_type: - ret += mcgen(''' - %(c_type)s retval; -''', - c_type=ret_type.c_type()) - - if arg_type and arg_type.members: - ret += mcgen(''' - QmpInputVisitor *qiv = qmp_input_visitor_new_strict(QOBJECT(args)); - QapiDeallocVisitor *qdv; - Visitor *v; - %(c_name)s arg = {0}; - - v = qmp_input_get_visitor(qiv); - visit_type_%(c_name)s_members(v, &arg, &err); - if (err) { - goto out; - } -''', - c_name=arg_type.c_name()) - - else: - ret += mcgen(''' - - (void)args; -''') - - ret += gen_call(name, arg_type, ret_type) - - # 'goto out' produced above for arg_type, and by gen_call() for ret_type - if (arg_type and arg_type.members) or ret_type: - ret += mcgen(''' - -out: -''') - ret += mcgen(''' - error_propagate(errp, err); -''') - if arg_type and arg_type.members: - ret += mcgen(''' - qmp_input_visitor_cleanup(qiv); - qdv = qapi_dealloc_visitor_new(); - v = qapi_dealloc_get_visitor(qdv); - visit_type_%(c_name)s_members(v, &arg, NULL); - qapi_dealloc_visitor_cleanup(qdv); -''', - c_name=arg_type.c_name()) - - ret += mcgen(''' -} -''') - return ret - - -def gen_register_command(name, success_response): - options = 'QCO_NO_OPTIONS' - if not success_response: - options = 'QCO_NO_SUCCESS_RESP' - - ret = mcgen(''' - qmp_register_command("%(name)s", qmp_marshal_%(c_name)s, %(opts)s); -''', - name=name, c_name=c_name(name), - opts=options) - return ret - - -def gen_registry(registry): - ret = mcgen(''' - -static void qmp_init_marshal(void) -{ -''') - ret += registry - ret += mcgen(''' -} - -qapi_init(qmp_init_marshal); -''') - return ret - - -class QAPISchemaGenCommandVisitor(QAPISchemaVisitor): - def __init__(self): - self.decl = None - self.defn = None - self._regy = None - self._visited_ret_types = None - - def visit_begin(self, schema): - self.decl = '' - self.defn = '' - self._regy = '' - self._visited_ret_types = set() - - def visit_end(self): - if not middle_mode: - self.defn += gen_registry(self._regy) - self._regy = None - self._visited_ret_types = None - - def visit_command(self, name, info, arg_type, ret_type, - gen, success_response): - if not gen: - return - self.decl += gen_command_decl(name, arg_type, ret_type) - if ret_type and ret_type not in self._visited_ret_types: - self._visited_ret_types.add(ret_type) - self.defn += gen_marshal_output(ret_type) - if middle_mode: - self.decl += gen_marshal_decl(name) - self.defn += gen_marshal(name, arg_type, ret_type) - if not middle_mode: - self._regy += gen_register_command(name, success_response) - - -middle_mode = False - -(input_file, output_dir, do_c, do_h, prefix, opts) = \ - parse_command_line("m", ["middle"]) - -for o, a in opts: - if o in ("-m", "--middle"): - middle_mode = True - -c_comment = ''' -/* - * schema-defined QMP->QAPI command dispatch - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ -''' -h_comment = ''' -/* - * schema-defined QAPI function prototypes - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ -''' - -(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, - 'qmp-marshal.c', 'qmp-commands.h', - c_comment, h_comment) - -fdef.write(mcgen(''' -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "qemu/module.h" -#include "qapi/qmp/types.h" -#include "qapi/qmp/dispatch.h" -#include "qapi/visitor.h" -#include "qapi/qmp-output-visitor.h" -#include "qapi/qmp-input-visitor.h" -#include "qapi/dealloc-visitor.h" -#include "%(prefix)sqapi-types.h" -#include "%(prefix)sqapi-visit.h" -#include "%(prefix)sqmp-commands.h" - -''', - prefix=prefix)) - -fdecl.write(mcgen(''' -#include "%(prefix)sqapi-types.h" -#include "qapi/qmp/qdict.h" -#include "qapi/error.h" - -''', - prefix=prefix)) - -schema = QAPISchema(input_file) -gen = QAPISchemaGenCommandVisitor() -schema.visit(gen) -fdef.write(gen.defn) -fdecl.write(gen.decl) - -close_output(fdef, fdecl) diff --git a/qemu/scripts/qapi-event.py b/qemu/scripts/qapi-event.py deleted file mode 100644 index 9b5c5b535..000000000 --- a/qemu/scripts/qapi-event.py +++ /dev/null @@ -1,213 +0,0 @@ -# -# QAPI event generator -# -# Copyright (c) 2014 Wenchao Xia -# Copyright (c) 2015-2016 Red Hat Inc. -# -# Authors: -# Wenchao Xia <wenchaoqemu@gmail.com> -# Markus Armbruster <armbru@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. -# See the COPYING file in the top-level directory. - -from qapi import * - - -def gen_event_send_proto(name, arg_type): - return 'void qapi_event_send_%(c_name)s(%(param)s)' % { - 'c_name': c_name(name.lower()), - 'param': gen_params(arg_type, 'Error **errp')} - - -def gen_event_send_decl(name, arg_type): - return mcgen(''' - -%(proto)s; -''', - proto=gen_event_send_proto(name, arg_type)) - - -# Declare and initialize an object 'qapi' using parameters from gen_params() -def gen_param_var(typ): - assert not typ.variants - ret = mcgen(''' - %(c_name)s param = { -''', - c_name=typ.c_name()) - sep = ' ' - for memb in typ.members: - ret += sep - sep = ', ' - if memb.optional: - ret += 'has_' + c_name(memb.name) + sep - if memb.type.name == 'str': - # Cast away const added in gen_params() - ret += '(char *)' - ret += c_name(memb.name) - ret += mcgen(''' - - }; -''') - return ret - - -def gen_event_send(name, arg_type): - # FIXME: Our declaration of local variables (and of 'errp' in the - # parameter list) can collide with exploded members of the event's - # data type passed in as parameters. If this collision ever hits in - # practice, we can rename our local variables with a leading _ prefix, - # or split the code into a wrapper function that creates a boxed - # 'param' object then calls another to do the real work. - ret = mcgen(''' - -%(proto)s -{ - QDict *qmp; - Error *err = NULL; - QMPEventFuncEmit emit; -''', - proto=gen_event_send_proto(name, arg_type)) - - if arg_type and arg_type.members: - ret += mcgen(''' - QmpOutputVisitor *qov; - Visitor *v; -''') - ret += gen_param_var(arg_type) - - ret += mcgen(''' - - emit = qmp_event_get_func_emit(); - if (!emit) { - return; - } - - qmp = qmp_event_build_dict("%(name)s"); - -''', - name=name) - - if arg_type and arg_type.members: - ret += mcgen(''' - qov = qmp_output_visitor_new(); - v = qmp_output_get_visitor(qov); - - visit_start_struct(v, "%(name)s", NULL, 0, &err); - if (err) { - goto out; - } - visit_type_%(c_name)s_members(v, ¶m, &err); - visit_end_struct(v, err ? NULL : &err); - if (err) { - goto out; - } - - qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov)); -''', - name=name, c_name=arg_type.c_name()) - - ret += mcgen(''' - emit(%(c_enum)s, qmp, &err); - -''', - c_enum=c_enum_const(event_enum_name, name)) - - if arg_type and arg_type.members: - ret += mcgen(''' -out: - qmp_output_visitor_cleanup(qov); -''') - ret += mcgen(''' - error_propagate(errp, err); - QDECREF(qmp); -} -''') - return ret - - -class QAPISchemaGenEventVisitor(QAPISchemaVisitor): - def __init__(self): - self.decl = None - self.defn = None - self._event_names = None - - def visit_begin(self, schema): - self.decl = '' - self.defn = '' - self._event_names = [] - - def visit_end(self): - self.decl += gen_enum(event_enum_name, self._event_names) - self.defn += gen_enum_lookup(event_enum_name, self._event_names) - self._event_names = None - - def visit_event(self, name, info, arg_type): - self.decl += gen_event_send_decl(name, arg_type) - self.defn += gen_event_send(name, arg_type) - self._event_names.append(name) - - -(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line() - -c_comment = ''' -/* - * schema-defined QAPI event functions - * - * Copyright (c) 2014 Wenchao Xia - * - * Authors: - * Wenchao Xia <wenchaoqemu@gmail.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ -''' -h_comment = ''' -/* - * schema-defined QAPI event functions - * - * Copyright (c) 2014 Wenchao Xia - * - * Authors: - * Wenchao Xia <wenchaoqemu@gmail.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ -''' - -(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, - 'qapi-event.c', 'qapi-event.h', - c_comment, h_comment) - -fdef.write(mcgen(''' -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "%(prefix)sqapi-event.h" -#include "%(prefix)sqapi-visit.h" -#include "qapi/qmp-output-visitor.h" -#include "qapi/qmp-event.h" - -''', - prefix=prefix)) - -fdecl.write(mcgen(''' -#include "qapi/error.h" -#include "qapi/qmp/qdict.h" -#include "%(prefix)sqapi-types.h" - -''', - prefix=prefix)) - -event_enum_name = c_name(prefix + "QAPIEvent", protect=False) - -schema = QAPISchema(input_file) -gen = QAPISchemaGenEventVisitor() -schema.visit(gen) -fdef.write(gen.defn) -fdecl.write(gen.decl) - -close_output(fdef, fdecl) diff --git a/qemu/scripts/qapi-introspect.py b/qemu/scripts/qapi-introspect.py deleted file mode 100644 index e0f926be0..000000000 --- a/qemu/scripts/qapi-introspect.py +++ /dev/null @@ -1,219 +0,0 @@ -# -# QAPI introspection generator -# -# Copyright (C) 2015-2016 Red Hat, Inc. -# -# Authors: -# Markus Armbruster <armbru@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. -# See the COPYING file in the top-level directory. - -from qapi import * - - -# Caveman's json.dumps() replacement (we're stuck at Python 2.4) -# TODO try to use json.dumps() once we get unstuck -def to_json(obj, level=0): - if obj is None: - ret = 'null' - elif isinstance(obj, str): - ret = '"' + obj.replace('"', r'\"') + '"' - elif isinstance(obj, list): - elts = [to_json(elt, level + 1) - for elt in obj] - ret = '[' + ', '.join(elts) + ']' - elif isinstance(obj, dict): - elts = ['"%s": %s' % (key.replace('"', r'\"'), - to_json(obj[key], level + 1)) - for key in sorted(obj.keys())] - ret = '{' + ', '.join(elts) + '}' - else: - assert False # not implemented - if level == 1: - ret = '\n' + ret - return ret - - -def to_c_string(string): - return '"' + string.replace('\\', r'\\').replace('"', r'\"') + '"' - - -class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor): - def __init__(self, unmask): - self._unmask = unmask - self.defn = None - self.decl = None - self._schema = None - self._jsons = None - self._used_types = None - self._name_map = None - - def visit_begin(self, schema): - self._schema = schema - self._jsons = [] - self._used_types = [] - self._name_map = {} - - def visit_end(self): - # visit the types that are actually used - jsons = self._jsons - self._jsons = [] - for typ in self._used_types: - typ.visit(self) - # generate C - # TODO can generate awfully long lines - jsons.extend(self._jsons) - name = prefix + 'qmp_schema_json' - self.decl = mcgen(''' -extern const char %(c_name)s[]; -''', - c_name=c_name(name)) - lines = to_json(jsons).split('\n') - c_string = '\n '.join([to_c_string(line) for line in lines]) - self.defn = mcgen(''' -const char %(c_name)s[] = %(c_string)s; -''', - c_name=c_name(name), - c_string=c_string) - self._schema = None - self._jsons = None - self._used_types = None - self._name_map = None - - def visit_needed(self, entity): - # Ignore types on first pass; visit_end() will pick up used types - return not isinstance(entity, QAPISchemaType) - - def _name(self, name): - if self._unmask: - return name - if name not in self._name_map: - self._name_map[name] = '%d' % len(self._name_map) - return self._name_map[name] - - def _use_type(self, typ): - # Map the various integer types to plain int - if typ.json_type() == 'int': - typ = self._schema.lookup_type('int') - elif (isinstance(typ, QAPISchemaArrayType) and - typ.element_type.json_type() == 'int'): - typ = self._schema.lookup_type('intList') - # Add type to work queue if new - if typ not in self._used_types: - self._used_types.append(typ) - # Clients should examine commands and events, not types. Hide - # type names to reduce the temptation. Also saves a few - # characters. - if isinstance(typ, QAPISchemaBuiltinType): - return typ.name - if isinstance(typ, QAPISchemaArrayType): - return '[' + self._use_type(typ.element_type) + ']' - return self._name(typ.name) - - def _gen_json(self, name, mtype, obj): - if mtype not in ('command', 'event', 'builtin', 'array'): - name = self._name(name) - obj['name'] = name - obj['meta-type'] = mtype - self._jsons.append(obj) - - def _gen_member(self, member): - ret = {'name': member.name, 'type': self._use_type(member.type)} - if member.optional: - ret['default'] = None - return ret - - def _gen_variants(self, tag_name, variants): - return {'tag': tag_name, - 'variants': [self._gen_variant(v) for v in variants]} - - def _gen_variant(self, variant): - return {'case': variant.name, 'type': self._use_type(variant.type)} - - def visit_builtin_type(self, name, info, json_type): - self._gen_json(name, 'builtin', {'json-type': json_type}) - - def visit_enum_type(self, name, info, values, prefix): - self._gen_json(name, 'enum', {'values': values}) - - def visit_array_type(self, name, info, element_type): - element = self._use_type(element_type) - self._gen_json('[' + element + ']', 'array', {'element-type': element}) - - def visit_object_type_flat(self, name, info, members, variants): - obj = {'members': [self._gen_member(m) for m in members]} - if variants: - obj.update(self._gen_variants(variants.tag_member.name, - variants.variants)) - self._gen_json(name, 'object', obj) - - def visit_alternate_type(self, name, info, variants): - self._gen_json(name, 'alternate', - {'members': [{'type': self._use_type(m.type)} - for m in variants.variants]}) - - def visit_command(self, name, info, arg_type, ret_type, - gen, success_response): - arg_type = arg_type or self._schema.the_empty_object_type - ret_type = ret_type or self._schema.the_empty_object_type - self._gen_json(name, 'command', - {'arg-type': self._use_type(arg_type), - 'ret-type': self._use_type(ret_type)}) - - def visit_event(self, name, info, arg_type): - arg_type = arg_type or self._schema.the_empty_object_type - self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)}) - -# Debugging aid: unmask QAPI schema's type names -# We normally mask them, because they're not QMP wire ABI -opt_unmask = False - -(input_file, output_dir, do_c, do_h, prefix, opts) = \ - parse_command_line("u", ["unmask-non-abi-names"]) - -for o, a in opts: - if o in ("-u", "--unmask-non-abi-names"): - opt_unmask = True - -c_comment = ''' -/* - * QAPI/QMP schema introspection - * - * Copyright (C) 2015 Red Hat, Inc. - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ -''' -h_comment = ''' -/* - * QAPI/QMP schema introspection - * - * Copyright (C) 2015 Red Hat, Inc. - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ -''' - -(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, - 'qmp-introspect.c', 'qmp-introspect.h', - c_comment, h_comment) - -fdef.write(mcgen(''' -#include "qemu/osdep.h" -#include "%(prefix)sqmp-introspect.h" - -''', - prefix=prefix)) - -schema = QAPISchema(input_file) -gen = QAPISchemaGenIntrospectVisitor(opt_unmask) -schema.visit(gen) -fdef.write(gen.defn) -fdecl.write(gen.decl) - -close_output(fdef, fdecl) diff --git a/qemu/scripts/qapi-types.py b/qemu/scripts/qapi-types.py deleted file mode 100644 index 437cf6c8e..000000000 --- a/qemu/scripts/qapi-types.py +++ /dev/null @@ -1,303 +0,0 @@ -# -# QAPI types generator -# -# Copyright IBM, Corp. 2011 -# Copyright (c) 2013-2016 Red Hat Inc. -# -# Authors: -# Anthony Liguori <aliguori@us.ibm.com> -# Markus Armbruster <armbru@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. -# See the COPYING file in the top-level directory. - -from qapi import * - - -# variants must be emitted before their container; track what has already -# been output -objects_seen = set() - - -def gen_fwd_object_or_array(name): - return mcgen(''' - -typedef struct %(c_name)s %(c_name)s; -''', - c_name=c_name(name)) - - -def gen_array(name, element_type): - return mcgen(''' - -struct %(c_name)s { - %(c_name)s *next; - %(c_type)s value; -}; -''', - c_name=c_name(name), c_type=element_type.c_type()) - - -def gen_struct_members(members): - ret = '' - for memb in members: - if memb.optional: - ret += mcgen(''' - bool has_%(c_name)s; -''', - c_name=c_name(memb.name)) - ret += mcgen(''' - %(c_type)s %(c_name)s; -''', - c_type=memb.type.c_type(), c_name=c_name(memb.name)) - return ret - - -def gen_object(name, base, members, variants): - if name in objects_seen: - return '' - objects_seen.add(name) - - ret = '' - if variants: - for v in variants.variants: - if isinstance(v.type, QAPISchemaObjectType): - ret += gen_object(v.type.name, v.type.base, - v.type.local_members, v.type.variants) - - ret += mcgen(''' - -struct %(c_name)s { -''', - c_name=c_name(name)) - - if base: - if not base.is_implicit(): - ret += mcgen(''' - /* Members inherited from %(c_name)s: */ -''', - c_name=base.c_name()) - ret += gen_struct_members(base.members) - if not base.is_implicit(): - ret += mcgen(''' - /* Own members: */ -''') - ret += gen_struct_members(members) - - if variants: - ret += gen_variants(variants) - - # Make sure that all structs have at least one member; this avoids - # potential issues with attempting to malloc space for zero-length - # structs in C, and also incompatibility with C++ (where an empty - # struct is size 1). - if not (base and base.members) and not members and not variants: - ret += mcgen(''' - char qapi_dummy_for_empty_struct; -''') - - ret += mcgen(''' -}; -''') - - return ret - - -def gen_upcast(name, base): - # C makes const-correctness ugly. We have to cast away const to let - # this function work for both const and non-const obj. - return mcgen(''' - -static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj) -{ - return (%(base)s *)obj; -} -''', - c_name=c_name(name), base=base.c_name()) - - -def gen_variants(variants): - ret = mcgen(''' - union { /* union tag is @%(c_name)s */ -''', - c_name=c_name(variants.tag_member.name)) - - for var in variants.variants: - ret += mcgen(''' - %(c_type)s %(c_name)s; -''', - c_type=var.type.c_unboxed_type(), - c_name=c_name(var.name)) - - ret += mcgen(''' - } u; -''') - - return ret - - -def gen_type_cleanup_decl(name): - ret = mcgen(''' - -void qapi_free_%(c_name)s(%(c_name)s *obj); -''', - c_name=c_name(name)) - return ret - - -def gen_type_cleanup(name): - ret = mcgen(''' - -void qapi_free_%(c_name)s(%(c_name)s *obj) -{ - QapiDeallocVisitor *qdv; - Visitor *v; - - if (!obj) { - return; - } - - qdv = qapi_dealloc_visitor_new(); - v = qapi_dealloc_get_visitor(qdv); - visit_type_%(c_name)s(v, NULL, &obj, NULL); - qapi_dealloc_visitor_cleanup(qdv); -} -''', - c_name=c_name(name)) - return ret - - -class QAPISchemaGenTypeVisitor(QAPISchemaVisitor): - def __init__(self): - self.decl = None - self.defn = None - self._fwdecl = None - self._btin = None - - def visit_begin(self, schema): - # gen_object() is recursive, ensure it doesn't visit the empty type - objects_seen.add(schema.the_empty_object_type.name) - self.decl = '' - self.defn = '' - self._fwdecl = '' - self._btin = guardstart('QAPI_TYPES_BUILTIN') - - def visit_end(self): - self.decl = self._fwdecl + self.decl - self._fwdecl = None - # To avoid header dependency hell, we always generate - # declarations for built-in types in our header files and - # simply guard them. See also do_builtins (command line - # option -b). - self._btin += guardend('QAPI_TYPES_BUILTIN') - self.decl = self._btin + self.decl - self._btin = None - - def _gen_type_cleanup(self, name): - self.decl += gen_type_cleanup_decl(name) - self.defn += gen_type_cleanup(name) - - def visit_enum_type(self, name, info, values, prefix): - # Special case for our lone builtin enum type - # TODO use something cleaner than existence of info - if not info: - self._btin += gen_enum(name, values, prefix) - if do_builtins: - self.defn += gen_enum_lookup(name, values, prefix) - else: - self._fwdecl += gen_enum(name, values, prefix) - self.defn += gen_enum_lookup(name, values, prefix) - - def visit_array_type(self, name, info, element_type): - if isinstance(element_type, QAPISchemaBuiltinType): - self._btin += gen_fwd_object_or_array(name) - self._btin += gen_array(name, element_type) - self._btin += gen_type_cleanup_decl(name) - if do_builtins: - self.defn += gen_type_cleanup(name) - else: - self._fwdecl += gen_fwd_object_or_array(name) - self.decl += gen_array(name, element_type) - self._gen_type_cleanup(name) - - def visit_object_type(self, name, info, base, members, variants): - # Nothing to do for the special empty builtin - if name == 'q_empty': - return - self._fwdecl += gen_fwd_object_or_array(name) - self.decl += gen_object(name, base, members, variants) - if base and not base.is_implicit(): - self.decl += gen_upcast(name, base) - # TODO Worth changing the visitor signature, so we could - # directly use rather than repeat type.is_implicit()? - if not name.startswith('q_'): - # implicit types won't be directly allocated/freed - self._gen_type_cleanup(name) - - def visit_alternate_type(self, name, info, variants): - self._fwdecl += gen_fwd_object_or_array(name) - self.decl += gen_object(name, None, [variants.tag_member], variants) - self._gen_type_cleanup(name) - -# If you link code generated from multiple schemata, you want only one -# instance of the code for built-in types. Generate it only when -# do_builtins, enabled by command line option -b. See also -# QAPISchemaGenTypeVisitor.visit_end(). -do_builtins = False - -(input_file, output_dir, do_c, do_h, prefix, opts) = \ - parse_command_line("b", ["builtins"]) - -for o, a in opts: - if o in ("-b", "--builtins"): - do_builtins = True - -c_comment = ''' -/* - * deallocation functions for schema-defined QAPI types - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * Michael Roth <mdroth@linux.vnet.ibm.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ -''' -h_comment = ''' -/* - * schema-defined QAPI types - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ -''' - -(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, - 'qapi-types.c', 'qapi-types.h', - c_comment, h_comment) - -fdef.write(mcgen(''' -#include "qemu/osdep.h" -#include "qapi/dealloc-visitor.h" -#include "%(prefix)sqapi-types.h" -#include "%(prefix)sqapi-visit.h" -''', - prefix=prefix)) - -schema = QAPISchema(input_file) -gen = QAPISchemaGenTypeVisitor() -schema.visit(gen) -fdef.write(gen.defn) -fdecl.write(gen.decl) - -close_output(fdef, fdecl) diff --git a/qemu/scripts/qapi-visit.py b/qemu/scripts/qapi-visit.py deleted file mode 100644 index 31d233035..000000000 --- a/qemu/scripts/qapi-visit.py +++ /dev/null @@ -1,377 +0,0 @@ -# -# QAPI visitor generator -# -# Copyright IBM, Corp. 2011 -# Copyright (C) 2014-2016 Red Hat, Inc. -# -# Authors: -# Anthony Liguori <aliguori@us.ibm.com> -# Michael Roth <mdroth@linux.vnet.ibm.com> -# Markus Armbruster <armbru@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. -# See the COPYING file in the top-level directory. - -from qapi import * -import re - - -def gen_visit_decl(name, scalar=False): - c_type = c_name(name) + ' *' - if not scalar: - c_type += '*' - return mcgen(''' -void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_type)sobj, Error **errp); -''', - c_name=c_name(name), c_type=c_type) - - -def gen_visit_members_decl(name): - return mcgen(''' - -void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp); -''', - c_name=c_name(name)) - - -def gen_visit_object_members(name, base, members, variants): - ret = mcgen(''' - -void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) -{ - Error *err = NULL; - -''', - c_name=c_name(name)) - - if base: - ret += mcgen(''' - visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, &err); -''', - c_type=base.c_name()) - ret += gen_err_check() - - for memb in members: - if memb.optional: - ret += mcgen(''' - if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) { -''', - name=memb.name, c_name=c_name(memb.name)) - push_indent() - ret += mcgen(''' - visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, &err); -''', - c_type=memb.type.c_name(), name=memb.name, - c_name=c_name(memb.name)) - ret += gen_err_check() - if memb.optional: - pop_indent() - ret += mcgen(''' - } -''') - - if variants: - ret += mcgen(''' - switch (obj->%(c_name)s) { -''', - c_name=c_name(variants.tag_member.name)) - - for var in variants.variants: - ret += mcgen(''' - case %(case)s: - visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err); - break; -''', - case=c_enum_const(variants.tag_member.type.name, - var.name, - variants.tag_member.type.prefix), - c_type=var.type.c_name(), c_name=c_name(var.name)) - - ret += mcgen(''' - default: - abort(); - } -''') - - # 'goto out' produced for base, for each member, and if variants were - # present - if base or members or variants: - ret += mcgen(''' - -out: -''') - ret += mcgen(''' - error_propagate(errp, err); -} -''') - return ret - - -def gen_visit_list(name, element_type): - # FIXME: if *obj is NULL on entry, and the first visit_next_list() - # assigns to *obj, while a later one fails, we should clean up *obj - # rather than leaving it non-NULL. As currently written, the caller must - # call qapi_free_FOOList() to avoid a memory leak of the partial FOOList. - return mcgen(''' - -void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) -{ - Error *err = NULL; - GenericList *i, **prev; - - visit_start_list(v, name, &err); - if (err) { - goto out; - } - - for (prev = (GenericList **)obj; - !err && (i = visit_next_list(v, prev, sizeof(**obj))) != NULL; - prev = &i) { - %(c_name)s *native_i = (%(c_name)s *)i; - visit_type_%(c_elt_type)s(v, NULL, &native_i->value, &err); - } - - visit_end_list(v); -out: - error_propagate(errp, err); -} -''', - c_name=c_name(name), c_elt_type=element_type.c_name()) - - -def gen_visit_enum(name): - return mcgen(''' - -void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s *obj, Error **errp) -{ - int value = *obj; - visit_type_enum(v, name, &value, %(c_name)s_lookup, errp); - *obj = value; -} -''', - c_name=c_name(name)) - - -def gen_visit_alternate(name, variants): - promote_int = 'true' - ret = '' - for var in variants.variants: - if var.type.alternate_qtype() == 'QTYPE_QINT': - promote_int = 'false' - - ret += mcgen(''' - -void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) -{ - Error *err = NULL; - - visit_start_alternate(v, name, (GenericAlternate **)obj, sizeof(**obj), - %(promote_int)s, &err); - if (err) { - goto out; - } - switch ((*obj)->type) { -''', - c_name=c_name(name), promote_int=promote_int) - - for var in variants.variants: - ret += mcgen(''' - case %(case)s: -''', - case=var.type.alternate_qtype()) - if isinstance(var.type, QAPISchemaObjectType): - ret += mcgen(''' - visit_start_struct(v, name, NULL, 0, &err); - if (err) { - break; - } - visit_type_%(c_type)s_members(v, &(*obj)->u.%(c_name)s, &err); - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); -''', - c_type=var.type.c_name(), - c_name=c_name(var.name)) - else: - ret += mcgen(''' - visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, &err); -''', - c_type=var.type.c_name(), - c_name=c_name(var.name)) - ret += mcgen(''' - break; -''') - - ret += mcgen(''' - default: - error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "%(name)s"); - } - visit_end_alternate(v); -out: - error_propagate(errp, err); -} -''', - name=name) - - return ret - - -def gen_visit_object(name, base, members, variants): - # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to - # *obj, but then visit_type_FOO_members() fails, we should clean up *obj - # rather than leaving it non-NULL. As currently written, the caller must - # call qapi_free_FOO() to avoid a memory leak of the partial FOO. - return mcgen(''' - -void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) -{ - Error *err = NULL; - - visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), &err); - if (err) { - goto out; - } - if (!*obj) { - goto out_obj; - } - visit_type_%(c_name)s_members(v, *obj, &err); - error_propagate(errp, err); - err = NULL; -out_obj: - visit_end_struct(v, &err); -out: - error_propagate(errp, err); -} -''', - c_name=c_name(name)) - - -class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): - def __init__(self): - self.decl = None - self.defn = None - self._btin = None - - def visit_begin(self, schema): - self.decl = '' - self.defn = '' - self._btin = guardstart('QAPI_VISIT_BUILTIN') - - def visit_end(self): - # To avoid header dependency hell, we always generate - # declarations for built-in types in our header files and - # simply guard them. See also do_builtins (command line - # option -b). - self._btin += guardend('QAPI_VISIT_BUILTIN') - self.decl = self._btin + self.decl - self._btin = None - - def visit_enum_type(self, name, info, values, prefix): - # Special case for our lone builtin enum type - # TODO use something cleaner than existence of info - if not info: - self._btin += gen_visit_decl(name, scalar=True) - if do_builtins: - self.defn += gen_visit_enum(name) - else: - self.decl += gen_visit_decl(name, scalar=True) - self.defn += gen_visit_enum(name) - - def visit_array_type(self, name, info, element_type): - decl = gen_visit_decl(name) - defn = gen_visit_list(name, element_type) - if isinstance(element_type, QAPISchemaBuiltinType): - self._btin += decl - if do_builtins: - self.defn += defn - else: - self.decl += decl - self.defn += defn - - def visit_object_type(self, name, info, base, members, variants): - # Nothing to do for the special empty builtin - if name == 'q_empty': - return - self.decl += gen_visit_members_decl(name) - self.defn += gen_visit_object_members(name, base, members, variants) - # TODO Worth changing the visitor signature, so we could - # directly use rather than repeat type.is_implicit()? - if not name.startswith('q_'): - # only explicit types need an allocating visit - self.decl += gen_visit_decl(name) - self.defn += gen_visit_object(name, base, members, variants) - - def visit_alternate_type(self, name, info, variants): - self.decl += gen_visit_decl(name) - self.defn += gen_visit_alternate(name, variants) - -# If you link code generated from multiple schemata, you want only one -# instance of the code for built-in types. Generate it only when -# do_builtins, enabled by command line option -b. See also -# QAPISchemaGenVisitVisitor.visit_end(). -do_builtins = False - -(input_file, output_dir, do_c, do_h, prefix, opts) = \ - parse_command_line("b", ["builtins"]) - -for o, a in opts: - if o in ("-b", "--builtins"): - do_builtins = True - -c_comment = ''' -/* - * schema-defined QAPI visitor functions - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ -''' -h_comment = ''' -/* - * schema-defined QAPI visitor functions - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ -''' - -(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, - 'qapi-visit.c', 'qapi-visit.h', - c_comment, h_comment) - -fdef.write(mcgen(''' -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "qapi/error.h" -#include "%(prefix)sqapi-visit.h" -''', - prefix=prefix)) - -fdecl.write(mcgen(''' -#include "qapi/visitor.h" -#include "qapi/qmp/qerror.h" -#include "%(prefix)sqapi-types.h" - -''', - prefix=prefix)) - -schema = QAPISchema(input_file) -gen = QAPISchemaGenVisitVisitor() -schema.visit(gen) -fdef.write(gen.defn) -fdecl.write(gen.decl) - -close_output(fdef, fdecl) diff --git a/qemu/scripts/qapi.py b/qemu/scripts/qapi.py deleted file mode 100644 index b13ae4789..000000000 --- a/qemu/scripts/qapi.py +++ /dev/null @@ -1,1757 +0,0 @@ -# -# QAPI helper library -# -# Copyright IBM, Corp. 2011 -# Copyright (c) 2013-2016 Red Hat Inc. -# -# Authors: -# Anthony Liguori <aliguori@us.ibm.com> -# Markus Armbruster <armbru@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. -# See the COPYING file in the top-level directory. - -import re -from ordereddict import OrderedDict -import errno -import getopt -import os -import sys -import string - -builtin_types = { - 'str': 'QTYPE_QSTRING', - 'int': 'QTYPE_QINT', - 'number': 'QTYPE_QFLOAT', - 'bool': 'QTYPE_QBOOL', - 'int8': 'QTYPE_QINT', - 'int16': 'QTYPE_QINT', - 'int32': 'QTYPE_QINT', - 'int64': 'QTYPE_QINT', - 'uint8': 'QTYPE_QINT', - 'uint16': 'QTYPE_QINT', - 'uint32': 'QTYPE_QINT', - 'uint64': 'QTYPE_QINT', - 'size': 'QTYPE_QINT', - 'any': None, # any QType possible, actually - 'QType': 'QTYPE_QSTRING', -} - -# Whitelist of commands allowed to return a non-dictionary -returns_whitelist = [ - # From QMP: - 'human-monitor-command', - 'qom-get', - 'query-migrate-cache-size', - 'query-tpm-models', - 'query-tpm-types', - 'ringbuf-read', - - # From QGA: - 'guest-file-open', - 'guest-fsfreeze-freeze', - 'guest-fsfreeze-freeze-list', - 'guest-fsfreeze-status', - 'guest-fsfreeze-thaw', - 'guest-get-time', - 'guest-set-vcpus', - 'guest-sync', - 'guest-sync-delimited', -] - -# Whitelist of entities allowed to violate case conventions -case_whitelist = [ - # From QMP: - 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status - 'CpuInfoMIPS', # PC, visible through query-cpu - 'CpuInfoTricore', # PC, visible through query-cpu - 'QapiErrorClass', # all members, visible through errors - 'UuidInfo', # UUID, visible through query-uuid - 'X86CPURegister32', # all members, visible indirectly through qom-get - 'q_obj_CpuInfo-base', # CPU, visible through query-cpu -] - -enum_types = [] -struct_types = [] -union_types = [] -events = [] -all_names = {} - -# -# Parsing the schema into expressions -# - - -def error_path(parent): - res = "" - while parent: - res = ("In file included from %s:%d:\n" % (parent['file'], - parent['line'])) + res - parent = parent['parent'] - return res - - -class QAPISchemaError(Exception): - def __init__(self, schema, msg): - Exception.__init__(self) - self.fname = schema.fname - self.msg = msg - self.col = 1 - self.line = schema.line - for ch in schema.src[schema.line_pos:schema.pos]: - if ch == '\t': - self.col = (self.col + 7) % 8 + 1 - else: - self.col += 1 - self.info = schema.incl_info - - def __str__(self): - return error_path(self.info) + \ - "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg) - - -class QAPIExprError(Exception): - def __init__(self, expr_info, msg): - Exception.__init__(self) - assert expr_info - self.info = expr_info - self.msg = msg - - def __str__(self): - return error_path(self.info['parent']) + \ - "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg) - - -class QAPISchemaParser(object): - - def __init__(self, fp, previously_included=[], incl_info=None): - abs_fname = os.path.abspath(fp.name) - fname = fp.name - self.fname = fname - previously_included.append(abs_fname) - self.incl_info = incl_info - self.src = fp.read() - if self.src == '' or self.src[-1] != '\n': - self.src += '\n' - self.cursor = 0 - self.line = 1 - self.line_pos = 0 - self.exprs = [] - self.accept() - - while self.tok is not None: - expr_info = {'file': fname, 'line': self.line, - 'parent': self.incl_info} - expr = self.get_expr(False) - if isinstance(expr, dict) and "include" in expr: - if len(expr) != 1: - raise QAPIExprError(expr_info, - "Invalid 'include' directive") - include = expr["include"] - if not isinstance(include, str): - raise QAPIExprError(expr_info, - "Value of 'include' must be a string") - incl_abs_fname = os.path.join(os.path.dirname(abs_fname), - include) - # catch inclusion cycle - inf = expr_info - while inf: - if incl_abs_fname == os.path.abspath(inf['file']): - raise QAPIExprError(expr_info, "Inclusion loop for %s" - % include) - inf = inf['parent'] - # skip multiple include of the same file - if incl_abs_fname in previously_included: - continue - try: - fobj = open(incl_abs_fname, 'r') - except IOError as e: - raise QAPIExprError(expr_info, - '%s: %s' % (e.strerror, include)) - exprs_include = QAPISchemaParser(fobj, previously_included, - expr_info) - self.exprs.extend(exprs_include.exprs) - else: - expr_elem = {'expr': expr, - 'info': expr_info} - self.exprs.append(expr_elem) - - def accept(self): - while True: - self.tok = self.src[self.cursor] - self.pos = self.cursor - self.cursor += 1 - self.val = None - - if self.tok == '#': - self.cursor = self.src.find('\n', self.cursor) - elif self.tok in "{}:,[]": - return - elif self.tok == "'": - string = '' - esc = False - while True: - ch = self.src[self.cursor] - self.cursor += 1 - if ch == '\n': - raise QAPISchemaError(self, - 'Missing terminating "\'"') - if esc: - if ch == 'b': - string += '\b' - elif ch == 'f': - string += '\f' - elif ch == 'n': - string += '\n' - elif ch == 'r': - string += '\r' - elif ch == 't': - string += '\t' - elif ch == 'u': - value = 0 - for _ in range(0, 4): - ch = self.src[self.cursor] - self.cursor += 1 - if ch not in "0123456789abcdefABCDEF": - raise QAPISchemaError(self, - '\\u escape needs 4 ' - 'hex digits') - value = (value << 4) + int(ch, 16) - # If Python 2 and 3 didn't disagree so much on - # how to handle Unicode, then we could allow - # Unicode string defaults. But most of QAPI is - # ASCII-only, so we aren't losing much for now. - if not value or value > 0x7f: - raise QAPISchemaError(self, - 'For now, \\u escape ' - 'only supports non-zero ' - 'values up to \\u007f') - string += chr(value) - elif ch in "\\/'\"": - string += ch - else: - raise QAPISchemaError(self, - "Unknown escape \\%s" % ch) - esc = False - elif ch == "\\": - esc = True - elif ch == "'": - self.val = string - return - else: - string += ch - elif self.src.startswith("true", self.pos): - self.val = True - self.cursor += 3 - return - elif self.src.startswith("false", self.pos): - self.val = False - self.cursor += 4 - return - elif self.src.startswith("null", self.pos): - self.val = None - self.cursor += 3 - return - elif self.tok == '\n': - if self.cursor == len(self.src): - self.tok = None - return - self.line += 1 - self.line_pos = self.cursor - elif not self.tok.isspace(): - raise QAPISchemaError(self, 'Stray "%s"' % self.tok) - - def get_members(self): - expr = OrderedDict() - if self.tok == '}': - self.accept() - return expr - if self.tok != "'": - raise QAPISchemaError(self, 'Expected string or "}"') - while True: - key = self.val - self.accept() - if self.tok != ':': - raise QAPISchemaError(self, 'Expected ":"') - self.accept() - if key in expr: - raise QAPISchemaError(self, 'Duplicate key "%s"' % key) - expr[key] = self.get_expr(True) - if self.tok == '}': - self.accept() - return expr - if self.tok != ',': - raise QAPISchemaError(self, 'Expected "," or "}"') - self.accept() - if self.tok != "'": - raise QAPISchemaError(self, 'Expected string') - - def get_values(self): - expr = [] - if self.tok == ']': - self.accept() - return expr - if self.tok not in "{['tfn": - raise QAPISchemaError(self, 'Expected "{", "[", "]", string, ' - 'boolean or "null"') - while True: - expr.append(self.get_expr(True)) - if self.tok == ']': - self.accept() - return expr - if self.tok != ',': - raise QAPISchemaError(self, 'Expected "," or "]"') - self.accept() - - def get_expr(self, nested): - if self.tok != '{' and not nested: - raise QAPISchemaError(self, 'Expected "{"') - if self.tok == '{': - self.accept() - expr = self.get_members() - elif self.tok == '[': - self.accept() - expr = self.get_values() - elif self.tok in "'tfn": - expr = self.val - self.accept() - else: - raise QAPISchemaError(self, 'Expected "{", "[" or string') - return expr - -# -# Semantic analysis of schema expressions -# TODO fold into QAPISchema -# TODO catching name collisions in generated code would be nice -# - - -def find_base_members(base): - if isinstance(base, dict): - return base - base_struct_define = find_struct(base) - if not base_struct_define: - return None - return base_struct_define['data'] - - -# Return the qtype of an alternate branch, or None on error. -def find_alternate_member_qtype(qapi_type): - if qapi_type in builtin_types: - return builtin_types[qapi_type] - elif find_struct(qapi_type): - return "QTYPE_QDICT" - elif find_enum(qapi_type): - return "QTYPE_QSTRING" - elif find_union(qapi_type): - return "QTYPE_QDICT" - return None - - -# Return the discriminator enum define if discriminator is specified as an -# enum type, otherwise return None. -def discriminator_find_enum_define(expr): - base = expr.get('base') - discriminator = expr.get('discriminator') - - if not (discriminator and base): - return None - - base_members = find_base_members(base) - if not base_members: - return None - - discriminator_type = base_members.get(discriminator) - if not discriminator_type: - return None - - return find_enum(discriminator_type) - - -# Names must be letters, numbers, -, and _. They must start with letter, -# except for downstream extensions which must start with __RFQDN_. -# Dots are only valid in the downstream extension prefix. -valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?' - '[a-zA-Z][a-zA-Z0-9_-]*$') - - -def check_name(expr_info, source, name, allow_optional=False, - enum_member=False): - global valid_name - membername = name - - if not isinstance(name, str): - raise QAPIExprError(expr_info, - "%s requires a string name" % source) - if name.startswith('*'): - membername = name[1:] - if not allow_optional: - raise QAPIExprError(expr_info, - "%s does not allow optional name '%s'" - % (source, name)) - # Enum members can start with a digit, because the generated C - # code always prefixes it with the enum name - if enum_member and membername[0].isdigit(): - membername = 'D' + membername - # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty' - # and 'q_obj_*' implicit type names. - if not valid_name.match(membername) or \ - c_name(membername, False).startswith('q_'): - raise QAPIExprError(expr_info, - "%s uses invalid name '%s'" % (source, name)) - - -def add_name(name, info, meta, implicit=False): - global all_names - check_name(info, "'%s'" % meta, name) - # FIXME should reject names that differ only in '_' vs. '.' - # vs. '-', because they're liable to clash in generated C. - if name in all_names: - raise QAPIExprError(info, - "%s '%s' is already defined" - % (all_names[name], name)) - if not implicit and (name.endswith('Kind') or name.endswith('List')): - raise QAPIExprError(info, - "%s '%s' should not end in '%s'" - % (meta, name, name[-4:])) - all_names[name] = meta - - -def add_struct(definition, info): - global struct_types - name = definition['struct'] - add_name(name, info, 'struct') - struct_types.append(definition) - - -def find_struct(name): - global struct_types - for struct in struct_types: - if struct['struct'] == name: - return struct - return None - - -def add_union(definition, info): - global union_types - name = definition['union'] - add_name(name, info, 'union') - union_types.append(definition) - - -def find_union(name): - global union_types - for union in union_types: - if union['union'] == name: - return union - return None - - -def add_enum(name, info, enum_values=None, implicit=False): - global enum_types - add_name(name, info, 'enum', implicit) - enum_types.append({"enum_name": name, "enum_values": enum_values}) - - -def find_enum(name): - global enum_types - for enum in enum_types: - if enum['enum_name'] == name: - return enum - return None - - -def is_enum(name): - return find_enum(name) is not None - - -def check_type(expr_info, source, value, allow_array=False, - allow_dict=False, allow_optional=False, - allow_metas=[]): - global all_names - - if value is None: - return - - # Check if array type for value is okay - if isinstance(value, list): - if not allow_array: - raise QAPIExprError(expr_info, - "%s cannot be an array" % source) - if len(value) != 1 or not isinstance(value[0], str): - raise QAPIExprError(expr_info, - "%s: array type must contain single type name" - % source) - value = value[0] - - # Check if type name for value is okay - if isinstance(value, str): - if value not in all_names: - raise QAPIExprError(expr_info, - "%s uses unknown type '%s'" - % (source, value)) - if not all_names[value] in allow_metas: - raise QAPIExprError(expr_info, - "%s cannot use %s type '%s'" - % (source, all_names[value], value)) - return - - if not allow_dict: - raise QAPIExprError(expr_info, - "%s should be a type name" % source) - - if not isinstance(value, OrderedDict): - raise QAPIExprError(expr_info, - "%s should be a dictionary or type name" % source) - - # value is a dictionary, check that each member is okay - for (key, arg) in value.items(): - check_name(expr_info, "Member of %s" % source, key, - allow_optional=allow_optional) - if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'): - raise QAPIExprError(expr_info, - "Member of %s uses reserved name '%s'" - % (source, key)) - # Todo: allow dictionaries to represent default values of - # an optional argument. - check_type(expr_info, "Member '%s' of %s" % (key, source), arg, - allow_array=True, - allow_metas=['built-in', 'union', 'alternate', 'struct', - 'enum']) - - -def check_command(expr, expr_info): - name = expr['command'] - - check_type(expr_info, "'data' for command '%s'" % name, - expr.get('data'), allow_dict=True, allow_optional=True, - allow_metas=['struct']) - returns_meta = ['union', 'struct'] - if name in returns_whitelist: - returns_meta += ['built-in', 'alternate', 'enum'] - check_type(expr_info, "'returns' for command '%s'" % name, - expr.get('returns'), allow_array=True, - allow_optional=True, allow_metas=returns_meta) - - -def check_event(expr, expr_info): - global events - name = expr['event'] - - events.append(name) - check_type(expr_info, "'data' for event '%s'" % name, - expr.get('data'), allow_dict=True, allow_optional=True, - allow_metas=['struct']) - - -def check_union(expr, expr_info): - name = expr['union'] - base = expr.get('base') - discriminator = expr.get('discriminator') - members = expr['data'] - - # Two types of unions, determined by discriminator. - - # With no discriminator it is a simple union. - if discriminator is None: - enum_define = None - allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum'] - if base is not None: - raise QAPIExprError(expr_info, - "Simple union '%s' must not have a base" - % name) - - # Else, it's a flat union. - else: - # The object must have a string or dictionary 'base'. - check_type(expr_info, "'base' for union '%s'" % name, - base, allow_dict=True, allow_optional=True, - allow_metas=['struct']) - if not base: - raise QAPIExprError(expr_info, - "Flat union '%s' must have a base" - % name) - base_members = find_base_members(base) - assert base_members - - # The value of member 'discriminator' must name a non-optional - # member of the base struct. - check_name(expr_info, "Discriminator of flat union '%s'" % name, - discriminator) - discriminator_type = base_members.get(discriminator) - if not discriminator_type: - raise QAPIExprError(expr_info, - "Discriminator '%s' is not a member of base " - "struct '%s'" - % (discriminator, base)) - enum_define = find_enum(discriminator_type) - allow_metas = ['struct'] - # Do not allow string discriminator - if not enum_define: - raise QAPIExprError(expr_info, - "Discriminator '%s' must be of enumeration " - "type" % discriminator) - - # Check every branch; don't allow an empty union - if len(members) == 0: - raise QAPIExprError(expr_info, - "Union '%s' cannot have empty 'data'" % name) - for (key, value) in members.items(): - check_name(expr_info, "Member of union '%s'" % name, key) - - # Each value must name a known type - check_type(expr_info, "Member '%s' of union '%s'" % (key, name), - value, allow_array=not base, allow_metas=allow_metas) - - # If the discriminator names an enum type, then all members - # of 'data' must also be members of the enum type. - if enum_define: - if key not in enum_define['enum_values']: - raise QAPIExprError(expr_info, - "Discriminator value '%s' is not found in " - "enum '%s'" % - (key, enum_define["enum_name"])) - - -def check_alternate(expr, expr_info): - name = expr['alternate'] - members = expr['data'] - types_seen = {} - - # Check every branch; require at least two branches - if len(members) < 2: - raise QAPIExprError(expr_info, - "Alternate '%s' should have at least two branches " - "in 'data'" % name) - for (key, value) in members.items(): - check_name(expr_info, "Member of alternate '%s'" % name, key) - - # Ensure alternates have no type conflicts. - check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name), - value, - allow_metas=['built-in', 'union', 'struct', 'enum']) - qtype = find_alternate_member_qtype(value) - if not qtype: - raise QAPIExprError(expr_info, - "Alternate '%s' member '%s' cannot use " - "type '%s'" % (name, key, value)) - if qtype in types_seen: - raise QAPIExprError(expr_info, - "Alternate '%s' member '%s' can't " - "be distinguished from member '%s'" - % (name, key, types_seen[qtype])) - types_seen[qtype] = key - - -def check_enum(expr, expr_info): - name = expr['enum'] - members = expr.get('data') - prefix = expr.get('prefix') - - if not isinstance(members, list): - raise QAPIExprError(expr_info, - "Enum '%s' requires an array for 'data'" % name) - if prefix is not None and not isinstance(prefix, str): - raise QAPIExprError(expr_info, - "Enum '%s' requires a string for 'prefix'" % name) - for member in members: - check_name(expr_info, "Member of enum '%s'" % name, member, - enum_member=True) - - -def check_struct(expr, expr_info): - name = expr['struct'] - members = expr['data'] - - check_type(expr_info, "'data' for struct '%s'" % name, members, - allow_dict=True, allow_optional=True) - check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'), - allow_metas=['struct']) - - -def check_keys(expr_elem, meta, required, optional=[]): - expr = expr_elem['expr'] - info = expr_elem['info'] - name = expr[meta] - if not isinstance(name, str): - raise QAPIExprError(info, - "'%s' key must have a string value" % meta) - required = required + [meta] - for (key, value) in expr.items(): - if key not in required and key not in optional: - raise QAPIExprError(info, - "Unknown key '%s' in %s '%s'" - % (key, meta, name)) - if (key == 'gen' or key == 'success-response') and value is not False: - raise QAPIExprError(info, - "'%s' of %s '%s' should only use false value" - % (key, meta, name)) - for key in required: - if key not in expr: - raise QAPIExprError(info, - "Key '%s' is missing from %s '%s'" - % (key, meta, name)) - - -def check_exprs(exprs): - global all_names - - # Learn the types and check for valid expression keys - for builtin in builtin_types.keys(): - all_names[builtin] = 'built-in' - for expr_elem in exprs: - expr = expr_elem['expr'] - info = expr_elem['info'] - if 'enum' in expr: - check_keys(expr_elem, 'enum', ['data'], ['prefix']) - add_enum(expr['enum'], info, expr['data']) - elif 'union' in expr: - check_keys(expr_elem, 'union', ['data'], - ['base', 'discriminator']) - add_union(expr, info) - elif 'alternate' in expr: - check_keys(expr_elem, 'alternate', ['data']) - add_name(expr['alternate'], info, 'alternate') - elif 'struct' in expr: - check_keys(expr_elem, 'struct', ['data'], ['base']) - add_struct(expr, info) - elif 'command' in expr: - check_keys(expr_elem, 'command', [], - ['data', 'returns', 'gen', 'success-response']) - add_name(expr['command'], info, 'command') - elif 'event' in expr: - check_keys(expr_elem, 'event', [], ['data']) - add_name(expr['event'], info, 'event') - else: - raise QAPIExprError(expr_elem['info'], - "Expression is missing metatype") - - # Try again for hidden UnionKind enum - for expr_elem in exprs: - expr = expr_elem['expr'] - if 'union' in expr: - if not discriminator_find_enum_define(expr): - add_enum('%sKind' % expr['union'], expr_elem['info'], - implicit=True) - elif 'alternate' in expr: - add_enum('%sKind' % expr['alternate'], expr_elem['info'], - implicit=True) - - # Validate that exprs make sense - for expr_elem in exprs: - expr = expr_elem['expr'] - info = expr_elem['info'] - - if 'enum' in expr: - check_enum(expr, info) - elif 'union' in expr: - check_union(expr, info) - elif 'alternate' in expr: - check_alternate(expr, info) - elif 'struct' in expr: - check_struct(expr, info) - elif 'command' in expr: - check_command(expr, info) - elif 'event' in expr: - check_event(expr, info) - else: - assert False, 'unexpected meta type' - - return exprs - - -# -# Schema compiler frontend -# - -class QAPISchemaEntity(object): - def __init__(self, name, info): - assert isinstance(name, str) - self.name = name - # For explicitly defined entities, info points to the (explicit) - # definition. For builtins (and their arrays), info is None. - # For implicitly defined entities, info points to a place that - # triggered the implicit definition (there may be more than one - # such place). - self.info = info - - def c_name(self): - return c_name(self.name) - - def check(self, schema): - pass - - def is_implicit(self): - return not self.info - - def visit(self, visitor): - pass - - -class QAPISchemaVisitor(object): - def visit_begin(self, schema): - pass - - def visit_end(self): - pass - - def visit_needed(self, entity): - # Default to visiting everything - return True - - def visit_builtin_type(self, name, info, json_type): - pass - - def visit_enum_type(self, name, info, values, prefix): - pass - - def visit_array_type(self, name, info, element_type): - pass - - def visit_object_type(self, name, info, base, members, variants): - pass - - def visit_object_type_flat(self, name, info, members, variants): - pass - - def visit_alternate_type(self, name, info, variants): - pass - - def visit_command(self, name, info, arg_type, ret_type, - gen, success_response): - pass - - def visit_event(self, name, info, arg_type): - pass - - -class QAPISchemaType(QAPISchemaEntity): - # Return the C type for common use. - # For the types we commonly box, this is a pointer type. - def c_type(self): - pass - - # Return the C type to be used in a parameter list. - def c_param_type(self): - return self.c_type() - - # Return the C type to be used where we suppress boxing. - def c_unboxed_type(self): - return self.c_type() - - def json_type(self): - pass - - def alternate_qtype(self): - json2qtype = { - 'string': 'QTYPE_QSTRING', - 'number': 'QTYPE_QFLOAT', - 'int': 'QTYPE_QINT', - 'boolean': 'QTYPE_QBOOL', - 'object': 'QTYPE_QDICT' - } - return json2qtype.get(self.json_type()) - - -class QAPISchemaBuiltinType(QAPISchemaType): - def __init__(self, name, json_type, c_type): - QAPISchemaType.__init__(self, name, None) - assert not c_type or isinstance(c_type, str) - assert json_type in ('string', 'number', 'int', 'boolean', 'null', - 'value') - self._json_type_name = json_type - self._c_type_name = c_type - - def c_name(self): - return self.name - - def c_type(self): - return self._c_type_name - - def c_param_type(self): - if self.name == 'str': - return 'const ' + self._c_type_name - return self._c_type_name - - def json_type(self): - return self._json_type_name - - def visit(self, visitor): - visitor.visit_builtin_type(self.name, self.info, self.json_type()) - - -class QAPISchemaEnumType(QAPISchemaType): - def __init__(self, name, info, values, prefix): - QAPISchemaType.__init__(self, name, info) - for v in values: - assert isinstance(v, QAPISchemaMember) - v.set_owner(name) - assert prefix is None or isinstance(prefix, str) - self.values = values - self.prefix = prefix - - def check(self, schema): - seen = {} - for v in self.values: - v.check_clash(self.info, seen) - - def is_implicit(self): - # See QAPISchema._make_implicit_enum_type() - return self.name.endswith('Kind') - - def c_type(self): - return c_name(self.name) - - def member_names(self): - return [v.name for v in self.values] - - def json_type(self): - return 'string' - - def visit(self, visitor): - visitor.visit_enum_type(self.name, self.info, - self.member_names(), self.prefix) - - -class QAPISchemaArrayType(QAPISchemaType): - def __init__(self, name, info, element_type): - QAPISchemaType.__init__(self, name, info) - assert isinstance(element_type, str) - self._element_type_name = element_type - self.element_type = None - - def check(self, schema): - self.element_type = schema.lookup_type(self._element_type_name) - assert self.element_type - - def is_implicit(self): - return True - - def c_type(self): - return c_name(self.name) + pointer_suffix - - def json_type(self): - return 'array' - - def visit(self, visitor): - visitor.visit_array_type(self.name, self.info, self.element_type) - - -class QAPISchemaObjectType(QAPISchemaType): - def __init__(self, name, info, base, local_members, variants): - # struct has local_members, optional base, and no variants - # flat union has base, variants, and no local_members - # simple union has local_members, variants, and no base - QAPISchemaType.__init__(self, name, info) - assert base is None or isinstance(base, str) - for m in local_members: - assert isinstance(m, QAPISchemaObjectTypeMember) - m.set_owner(name) - if variants is not None: - assert isinstance(variants, QAPISchemaObjectTypeVariants) - variants.set_owner(name) - self._base_name = base - self.base = None - self.local_members = local_members - self.variants = variants - self.members = None - - def check(self, schema): - if self.members is False: # check for cycles - raise QAPIExprError(self.info, - "Object %s contains itself" % self.name) - if self.members: - return - self.members = False # mark as being checked - seen = OrderedDict() - if self._base_name: - self.base = schema.lookup_type(self._base_name) - assert isinstance(self.base, QAPISchemaObjectType) - self.base.check(schema) - self.base.check_clash(schema, self.info, seen) - for m in self.local_members: - m.check(schema) - m.check_clash(self.info, seen) - self.members = seen.values() - if self.variants: - self.variants.check(schema, seen) - assert self.variants.tag_member in self.members - self.variants.check_clash(schema, self.info, seen) - - # Check that the members of this type do not cause duplicate JSON members, - # and update seen to track the members seen so far. Report any errors - # on behalf of info, which is not necessarily self.info - def check_clash(self, schema, info, seen): - assert not self.variants # not implemented - for m in self.members: - m.check_clash(info, seen) - - def is_implicit(self): - # See QAPISchema._make_implicit_object_type(), as well as - # _def_predefineds() - return self.name.startswith('q_') - - def c_name(self): - return QAPISchemaType.c_name(self) - - def c_type(self): - assert not self.is_implicit() - return c_name(self.name) + pointer_suffix - - def c_unboxed_type(self): - return c_name(self.name) - - def json_type(self): - return 'object' - - def visit(self, visitor): - visitor.visit_object_type(self.name, self.info, - self.base, self.local_members, self.variants) - visitor.visit_object_type_flat(self.name, self.info, - self.members, self.variants) - - -class QAPISchemaMember(object): - role = 'member' - - def __init__(self, name): - assert isinstance(name, str) - self.name = name - self.owner = None - - def set_owner(self, name): - assert not self.owner - self.owner = name - - def check_clash(self, info, seen): - cname = c_name(self.name) - if cname.lower() != cname and self.owner not in case_whitelist: - raise QAPIExprError(info, - "%s should not use uppercase" % self.describe()) - if cname in seen: - raise QAPIExprError(info, - "%s collides with %s" - % (self.describe(), seen[cname].describe())) - seen[cname] = self - - def _pretty_owner(self): - owner = self.owner - if owner.startswith('q_obj_'): - # See QAPISchema._make_implicit_object_type() - reverse the - # mapping there to create a nice human-readable description - owner = owner[6:] - if owner.endswith('-arg'): - return '(parameter of %s)' % owner[:-4] - elif owner.endswith('-base'): - return '(base of %s)' % owner[:-5] - else: - assert owner.endswith('-wrapper') - # Unreachable and not implemented - assert False - if owner.endswith('Kind'): - # See QAPISchema._make_implicit_enum_type() - return '(branch of %s)' % owner[:-4] - return '(%s of %s)' % (self.role, owner) - - def describe(self): - return "'%s' %s" % (self.name, self._pretty_owner()) - - -class QAPISchemaObjectTypeMember(QAPISchemaMember): - def __init__(self, name, typ, optional): - QAPISchemaMember.__init__(self, name) - assert isinstance(typ, str) - assert isinstance(optional, bool) - self._type_name = typ - self.type = None - self.optional = optional - - def check(self, schema): - assert self.owner - self.type = schema.lookup_type(self._type_name) - assert self.type - - -class QAPISchemaObjectTypeVariants(object): - def __init__(self, tag_name, tag_member, variants): - # Flat unions pass tag_name but not tag_member. - # Simple unions and alternates pass tag_member but not tag_name. - # After check(), tag_member is always set, and tag_name remains - # a reliable witness of being used by a flat union. - assert bool(tag_member) != bool(tag_name) - assert (isinstance(tag_name, str) or - isinstance(tag_member, QAPISchemaObjectTypeMember)) - assert len(variants) > 0 - for v in variants: - assert isinstance(v, QAPISchemaObjectTypeVariant) - self.tag_name = tag_name - self.tag_member = tag_member - self.variants = variants - - def set_owner(self, name): - for v in self.variants: - v.set_owner(name) - - def check(self, schema, seen): - if not self.tag_member: # flat union - self.tag_member = seen[c_name(self.tag_name)] - assert self.tag_name == self.tag_member.name - assert isinstance(self.tag_member.type, QAPISchemaEnumType) - for v in self.variants: - v.check(schema) - # Union names must match enum values; alternate names are - # checked separately. Use 'seen' to tell the two apart. - if seen: - assert v.name in self.tag_member.type.member_names() - assert isinstance(v.type, QAPISchemaObjectType) - v.type.check(schema) - - def check_clash(self, schema, info, seen): - for v in self.variants: - # Reset seen map for each variant, since qapi names from one - # branch do not affect another branch - assert isinstance(v.type, QAPISchemaObjectType) - v.type.check_clash(schema, info, dict(seen)) - - -class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember): - role = 'branch' - - def __init__(self, name, typ): - QAPISchemaObjectTypeMember.__init__(self, name, typ, False) - - -class QAPISchemaAlternateType(QAPISchemaType): - def __init__(self, name, info, variants): - QAPISchemaType.__init__(self, name, info) - assert isinstance(variants, QAPISchemaObjectTypeVariants) - assert not variants.tag_name - variants.set_owner(name) - variants.tag_member.set_owner(self.name) - self.variants = variants - - def check(self, schema): - self.variants.tag_member.check(schema) - # Not calling self.variants.check_clash(), because there's nothing - # to clash with - self.variants.check(schema, {}) - # Alternate branch names have no relation to the tag enum values; - # so we have to check for potential name collisions ourselves. - seen = {} - for v in self.variants.variants: - v.check_clash(self.info, seen) - - def c_type(self): - return c_name(self.name) + pointer_suffix - - def json_type(self): - return 'value' - - def visit(self, visitor): - visitor.visit_alternate_type(self.name, self.info, self.variants) - - -class QAPISchemaCommand(QAPISchemaEntity): - def __init__(self, name, info, arg_type, ret_type, gen, success_response): - QAPISchemaEntity.__init__(self, name, info) - assert not arg_type or isinstance(arg_type, str) - assert not ret_type or isinstance(ret_type, str) - self._arg_type_name = arg_type - self.arg_type = None - self._ret_type_name = ret_type - self.ret_type = None - self.gen = gen - self.success_response = success_response - - def check(self, schema): - if self._arg_type_name: - self.arg_type = schema.lookup_type(self._arg_type_name) - assert isinstance(self.arg_type, QAPISchemaObjectType) - assert not self.arg_type.variants # not implemented - if self._ret_type_name: - self.ret_type = schema.lookup_type(self._ret_type_name) - assert isinstance(self.ret_type, QAPISchemaType) - - def visit(self, visitor): - visitor.visit_command(self.name, self.info, - self.arg_type, self.ret_type, - self.gen, self.success_response) - - -class QAPISchemaEvent(QAPISchemaEntity): - def __init__(self, name, info, arg_type): - QAPISchemaEntity.__init__(self, name, info) - assert not arg_type or isinstance(arg_type, str) - self._arg_type_name = arg_type - self.arg_type = None - - def check(self, schema): - if self._arg_type_name: - self.arg_type = schema.lookup_type(self._arg_type_name) - assert isinstance(self.arg_type, QAPISchemaObjectType) - assert not self.arg_type.variants # not implemented - - def visit(self, visitor): - visitor.visit_event(self.name, self.info, self.arg_type) - - -class QAPISchema(object): - def __init__(self, fname): - try: - self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs) - self._entity_dict = {} - self._predefining = True - self._def_predefineds() - self._predefining = False - self._def_exprs() - self.check() - except (QAPISchemaError, QAPIExprError) as err: - print >>sys.stderr, err - exit(1) - - def _def_entity(self, ent): - # Only the predefined types are allowed to not have info - assert ent.info or self._predefining - assert ent.name not in self._entity_dict - self._entity_dict[ent.name] = ent - - def lookup_entity(self, name, typ=None): - ent = self._entity_dict.get(name) - if typ and not isinstance(ent, typ): - return None - return ent - - def lookup_type(self, name): - return self.lookup_entity(name, QAPISchemaType) - - def _def_builtin_type(self, name, json_type, c_type): - self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type)) - # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple - # qapi-types.h from a single .c, all arrays of builtins must be - # declared in the first file whether or not they are used. Nicer - # would be to use lazy instantiation, while figuring out how to - # avoid compilation issues with multiple qapi-types.h. - self._make_array_type(name, None) - - def _def_predefineds(self): - for t in [('str', 'string', 'char' + pointer_suffix), - ('number', 'number', 'double'), - ('int', 'int', 'int64_t'), - ('int8', 'int', 'int8_t'), - ('int16', 'int', 'int16_t'), - ('int32', 'int', 'int32_t'), - ('int64', 'int', 'int64_t'), - ('uint8', 'int', 'uint8_t'), - ('uint16', 'int', 'uint16_t'), - ('uint32', 'int', 'uint32_t'), - ('uint64', 'int', 'uint64_t'), - ('size', 'int', 'uint64_t'), - ('bool', 'boolean', 'bool'), - ('any', 'value', 'QObject' + pointer_suffix)]: - self._def_builtin_type(*t) - self.the_empty_object_type = QAPISchemaObjectType('q_empty', None, - None, [], None) - self._def_entity(self.the_empty_object_type) - qtype_values = self._make_enum_members(['none', 'qnull', 'qint', - 'qstring', 'qdict', 'qlist', - 'qfloat', 'qbool']) - self._def_entity(QAPISchemaEnumType('QType', None, qtype_values, - 'QTYPE')) - - def _make_enum_members(self, values): - return [QAPISchemaMember(v) for v in values] - - def _make_implicit_enum_type(self, name, info, values): - # See also QAPISchemaObjectTypeMember._pretty_owner() - name = name + 'Kind' # Use namespace reserved by add_name() - self._def_entity(QAPISchemaEnumType( - name, info, self._make_enum_members(values), None)) - return name - - def _make_array_type(self, element_type, info): - name = element_type + 'List' # Use namespace reserved by add_name() - if not self.lookup_type(name): - self._def_entity(QAPISchemaArrayType(name, info, element_type)) - return name - - def _make_implicit_object_type(self, name, info, role, members): - if not members: - return None - # See also QAPISchemaObjectTypeMember._pretty_owner() - name = 'q_obj_%s-%s' % (name, role) - if not self.lookup_entity(name, QAPISchemaObjectType): - self._def_entity(QAPISchemaObjectType(name, info, None, - members, None)) - return name - - def _def_enum_type(self, expr, info): - name = expr['enum'] - data = expr['data'] - prefix = expr.get('prefix') - self._def_entity(QAPISchemaEnumType( - name, info, self._make_enum_members(data), prefix)) - - def _make_member(self, name, typ, info): - optional = False - if name.startswith('*'): - name = name[1:] - optional = True - if isinstance(typ, list): - assert len(typ) == 1 - typ = self._make_array_type(typ[0], info) - return QAPISchemaObjectTypeMember(name, typ, optional) - - def _make_members(self, data, info): - return [self._make_member(key, value, info) - for (key, value) in data.iteritems()] - - def _def_struct_type(self, expr, info): - name = expr['struct'] - base = expr.get('base') - data = expr['data'] - self._def_entity(QAPISchemaObjectType(name, info, base, - self._make_members(data, info), - None)) - - def _make_variant(self, case, typ): - return QAPISchemaObjectTypeVariant(case, typ) - - def _make_simple_variant(self, case, typ, info): - if isinstance(typ, list): - assert len(typ) == 1 - typ = self._make_array_type(typ[0], info) - typ = self._make_implicit_object_type( - typ, info, 'wrapper', [self._make_member('data', typ, info)]) - return QAPISchemaObjectTypeVariant(case, typ) - - def _def_union_type(self, expr, info): - name = expr['union'] - data = expr['data'] - base = expr.get('base') - tag_name = expr.get('discriminator') - tag_member = None - if isinstance(base, dict): - base = (self._make_implicit_object_type( - name, info, 'base', self._make_members(base, info))) - if tag_name: - variants = [self._make_variant(key, value) - for (key, value) in data.iteritems()] - members = [] - else: - variants = [self._make_simple_variant(key, value, info) - for (key, value) in data.iteritems()] - typ = self._make_implicit_enum_type(name, info, - [v.name for v in variants]) - tag_member = QAPISchemaObjectTypeMember('type', typ, False) - members = [tag_member] - self._def_entity( - QAPISchemaObjectType(name, info, base, members, - QAPISchemaObjectTypeVariants(tag_name, - tag_member, - variants))) - - def _def_alternate_type(self, expr, info): - name = expr['alternate'] - data = expr['data'] - variants = [self._make_variant(key, value) - for (key, value) in data.iteritems()] - tag_member = QAPISchemaObjectTypeMember('type', 'QType', False) - self._def_entity( - QAPISchemaAlternateType(name, info, - QAPISchemaObjectTypeVariants(None, - tag_member, - variants))) - - def _def_command(self, expr, info): - name = expr['command'] - data = expr.get('data') - rets = expr.get('returns') - gen = expr.get('gen', True) - success_response = expr.get('success-response', True) - if isinstance(data, OrderedDict): - data = self._make_implicit_object_type( - name, info, 'arg', self._make_members(data, info)) - if isinstance(rets, list): - assert len(rets) == 1 - rets = self._make_array_type(rets[0], info) - self._def_entity(QAPISchemaCommand(name, info, data, rets, gen, - success_response)) - - def _def_event(self, expr, info): - name = expr['event'] - data = expr.get('data') - if isinstance(data, OrderedDict): - data = self._make_implicit_object_type( - name, info, 'arg', self._make_members(data, info)) - self._def_entity(QAPISchemaEvent(name, info, data)) - - def _def_exprs(self): - for expr_elem in self.exprs: - expr = expr_elem['expr'] - info = expr_elem['info'] - if 'enum' in expr: - self._def_enum_type(expr, info) - elif 'struct' in expr: - self._def_struct_type(expr, info) - elif 'union' in expr: - self._def_union_type(expr, info) - elif 'alternate' in expr: - self._def_alternate_type(expr, info) - elif 'command' in expr: - self._def_command(expr, info) - elif 'event' in expr: - self._def_event(expr, info) - else: - assert False - - def check(self): - for ent in self._entity_dict.values(): - ent.check(self) - - def visit(self, visitor): - visitor.visit_begin(self) - for (name, entity) in sorted(self._entity_dict.items()): - if visitor.visit_needed(entity): - entity.visit(visitor) - visitor.visit_end() - - -# -# Code generation helpers -# - -def camel_case(name): - new_name = '' - first = True - for ch in name: - if ch in ['_', '-']: - first = True - elif first: - new_name += ch.upper() - first = False - else: - new_name += ch.lower() - return new_name - - -# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1 -# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2 -# ENUM24_Name -> ENUM24_NAME -def camel_to_upper(value): - c_fun_str = c_name(value, False) - if value.isupper(): - return c_fun_str - - new_name = '' - l = len(c_fun_str) - for i in range(l): - c = c_fun_str[i] - # When c is upper and no "_" appears before, do more checks - if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_": - if i < l - 1 and c_fun_str[i + 1].islower(): - new_name += '_' - elif c_fun_str[i - 1].isdigit(): - new_name += '_' - new_name += c - return new_name.lstrip('_').upper() - - -def c_enum_const(type_name, const_name, prefix=None): - if prefix is not None: - type_name = prefix - return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper() - -c_name_trans = string.maketrans('.-', '__') - - -# Map @name to a valid C identifier. -# If @protect, avoid returning certain ticklish identifiers (like -# C keywords) by prepending "q_". -# -# Used for converting 'name' from a 'name':'type' qapi definition -# into a generated struct member, as well as converting type names -# into substrings of a generated C function name. -# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo' -# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int' -def c_name(name, protect=True): - # ANSI X3J11/88-090, 3.1.1 - c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue', - 'default', 'do', 'double', 'else', 'enum', 'extern', - 'float', 'for', 'goto', 'if', 'int', 'long', 'register', - 'return', 'short', 'signed', 'sizeof', 'static', - 'struct', 'switch', 'typedef', 'union', 'unsigned', - 'void', 'volatile', 'while']) - # ISO/IEC 9899:1999, 6.4.1 - c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary']) - # ISO/IEC 9899:2011, 6.4.1 - c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic', - '_Noreturn', '_Static_assert', '_Thread_local']) - # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html - # excluding _.* - gcc_words = set(['asm', 'typeof']) - # C++ ISO/IEC 14882:2003 2.11 - cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete', - 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable', - 'namespace', 'new', 'operator', 'private', 'protected', - 'public', 'reinterpret_cast', 'static_cast', 'template', - 'this', 'throw', 'true', 'try', 'typeid', 'typename', - 'using', 'virtual', 'wchar_t', - # alternative representations - 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not', - 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq']) - # namespace pollution: - polluted_words = set(['unix', 'errno', 'mips', 'sparc']) - name = name.translate(c_name_trans) - if protect and (name in c89_words | c99_words | c11_words | gcc_words - | cpp_words | polluted_words): - return "q_" + name - return name - -eatspace = '\033EATSPACE.' -pointer_suffix = ' *' + eatspace - - -def genindent(count): - ret = "" - for _ in range(count): - ret += " " - return ret - -indent_level = 0 - - -def push_indent(indent_amount=4): - global indent_level - indent_level += indent_amount - - -def pop_indent(indent_amount=4): - global indent_level - indent_level -= indent_amount - - -# Generate @code with @kwds interpolated. -# Obey indent_level, and strip eatspace. -def cgen(code, **kwds): - raw = code % kwds - if indent_level: - indent = genindent(indent_level) - # re.subn() lacks flags support before Python 2.7, use re.compile() - raw = re.subn(re.compile("^.", re.MULTILINE), - indent + r'\g<0>', raw) - raw = raw[0] - return re.sub(re.escape(eatspace) + ' *', '', raw) - - -def mcgen(code, **kwds): - if code[0] == '\n': - code = code[1:] - return cgen(code, **kwds) - - -def guardname(filename): - return c_name(filename, protect=False).upper() - - -def guardstart(name): - return mcgen(''' - -#ifndef %(name)s -#define %(name)s - -''', - name=guardname(name)) - - -def guardend(name): - return mcgen(''' - -#endif /* %(name)s */ - -''', - name=guardname(name)) - - -def gen_enum_lookup(name, values, prefix=None): - ret = mcgen(''' - -const char *const %(c_name)s_lookup[] = { -''', - c_name=c_name(name)) - for value in values: - index = c_enum_const(name, value, prefix) - ret += mcgen(''' - [%(index)s] = "%(value)s", -''', - index=index, value=value) - - max_index = c_enum_const(name, '_MAX', prefix) - ret += mcgen(''' - [%(max_index)s] = NULL, -}; -''', - max_index=max_index) - return ret - - -def gen_enum(name, values, prefix=None): - # append automatically generated _MAX value - enum_values = values + ['_MAX'] - - ret = mcgen(''' - -typedef enum %(c_name)s { -''', - c_name=c_name(name)) - - i = 0 - for value in enum_values: - ret += mcgen(''' - %(c_enum)s = %(i)d, -''', - c_enum=c_enum_const(name, value, prefix), - i=i) - i += 1 - - ret += mcgen(''' -} %(c_name)s; -''', - c_name=c_name(name)) - - ret += mcgen(''' - -extern const char *const %(c_name)s_lookup[]; -''', - c_name=c_name(name)) - return ret - - -def gen_params(arg_type, extra): - if not arg_type: - return extra - assert not arg_type.variants - ret = '' - sep = '' - for memb in arg_type.members: - ret += sep - sep = ', ' - if memb.optional: - ret += 'bool has_%s, ' % c_name(memb.name) - ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name)) - if extra: - ret += sep + extra - return ret - - -def gen_err_check(): - return mcgen(''' - if (err) { - goto out; - } -''') - - -# -# Common command line parsing -# - - -def parse_command_line(extra_options="", extra_long_options=[]): - - try: - opts, args = getopt.gnu_getopt(sys.argv[1:], - "chp:o:" + extra_options, - ["source", "header", "prefix=", - "output-dir="] + extra_long_options) - except getopt.GetoptError as err: - print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err)) - sys.exit(1) - - output_dir = "" - prefix = "" - do_c = False - do_h = False - extra_opts = [] - - for oa in opts: - o, a = oa - if o in ("-p", "--prefix"): - match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a) - if match.end() != len(a): - print >>sys.stderr, \ - "%s: 'funny character '%s' in argument of --prefix" \ - % (sys.argv[0], a[match.end()]) - sys.exit(1) - prefix = a - elif o in ("-o", "--output-dir"): - output_dir = a + "/" - elif o in ("-c", "--source"): - do_c = True - elif o in ("-h", "--header"): - do_h = True - else: - extra_opts.append(oa) - - if not do_c and not do_h: - do_c = True - do_h = True - - if len(args) != 1: - print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0] - sys.exit(1) - fname = args[0] - - return (fname, output_dir, do_c, do_h, prefix, extra_opts) - -# -# Generate output files with boilerplate -# - - -def open_output(output_dir, do_c, do_h, prefix, c_file, h_file, - c_comment, h_comment): - guard = guardname(prefix + h_file) - c_file = output_dir + prefix + c_file - h_file = output_dir + prefix + h_file - - if output_dir: - try: - os.makedirs(output_dir) - except os.error as e: - if e.errno != errno.EEXIST: - raise - - def maybe_open(really, name, opt): - if really: - return open(name, opt) - else: - import StringIO - return StringIO.StringIO() - - fdef = maybe_open(do_c, c_file, 'w') - fdecl = maybe_open(do_h, h_file, 'w') - - fdef.write(mcgen(''' -/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ -%(comment)s -''', - comment=c_comment)) - - fdecl.write(mcgen(''' -/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ -%(comment)s -#ifndef %(guard)s -#define %(guard)s - -''', - comment=h_comment, guard=guard)) - - return (fdef, fdecl) - - -def close_output(fdef, fdecl): - fdecl.write(''' -#endif -''') - fdecl.close() - fdef.close() diff --git a/qemu/scripts/qemu-binfmt-conf.sh b/qemu/scripts/qemu-binfmt-conf.sh deleted file mode 100644 index 289b1a396..000000000 --- a/qemu/scripts/qemu-binfmt-conf.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/sh -# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC/s390 program execution by the kernel - -# load the binfmt_misc module -if [ ! -d /proc/sys/fs/binfmt_misc ]; then - /sbin/modprobe binfmt_misc -fi -if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then - mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc -fi - -# probe cpu type -cpu=`uname -m` -case "$cpu" in - i386|i486|i586|i686|i86pc|BePC|x86_64) - cpu="i386" - ;; - m68k) - cpu="m68k" - ;; - mips*) - cpu="mips" - ;; - "Power Macintosh"|ppc|ppc64) - cpu="ppc" - ;; - armv[4-9]*) - cpu="arm" - ;; -esac - -# register the interpreter for each cpu except for the native one -if [ $cpu != "i386" ] ; then - echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register - echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "alpha" ] ; then - echo ':alpha:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-alpha:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "arm" ] ; then - echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register - echo ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "aarch64" ] ; then - echo ':aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-aarch64:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "sparc" ] ; then - echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "ppc" ] ; then - echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "m68k" ] ; then - echo 'Please check cpu value and header information for m68k!' - echo ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-m68k:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "mips" ] ; then - # FIXME: We could use the other endianness on a MIPS host. - echo ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsn32:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mipsn32:' > /proc/sys/fs/binfmt_misc/register - echo ':mipsn32el:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsn32el:' > /proc/sys/fs/binfmt_misc/register - echo ':mips64:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips64:' > /proc/sys/fs/binfmt_misc/register - echo ':mips64el:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mips64el:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "sh" ] ; then - echo ':sh4:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-sh4:' > /proc/sys/fs/binfmt_misc/register - echo ':sh4eb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sh4eb:' > /proc/sys/fs/binfmt_misc/register -fi -if [ $cpu != "s390x" ] ; then - echo ':s390x:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-s390x:' > /proc/sys/fs/binfmt_misc/register -fi diff --git a/qemu/scripts/qemu-gdb.py b/qemu/scripts/qemu-gdb.py deleted file mode 100644 index b3f8e04f7..000000000 --- a/qemu/scripts/qemu-gdb.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/python - -# GDB debugging support -# -# Copyright 2012 Red Hat, Inc. and/or its affiliates -# -# Authors: -# Avi Kivity <avi@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. -# -# Contributions after 2012-01-13 are licensed under the terms of the -# GNU GPL, version 2 or (at your option) any later version. - -# Usage: -# At the (gdb) prompt, type "source scripts/qemu-gdb.py". -# "help qemu" should then list the supported QEMU debug support commands. - -import gdb - -import os, sys - -# Annoyingly, gdb doesn't put the directory of scripts onto the -# module search path. Do it manually. - -sys.path.append(os.path.dirname(__file__)) - -from qemugdb import aio, mtree, coroutine - -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) - -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. -gdb.execute('handle SIGUSR1 pass noprint nostop') diff --git a/qemu/scripts/qemu-guest-agent/fsfreeze-hook b/qemu/scripts/qemu-guest-agent/fsfreeze-hook deleted file mode 100755 index c27b29f28..000000000 --- a/qemu/scripts/qemu-guest-agent/fsfreeze-hook +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -# This script is executed when a guest agent receives fsfreeze-freeze and -# fsfreeze-thaw command, if it is specified in --fsfreeze-hook (-F) -# option of qemu-ga or placed in default path (/etc/qemu/fsfreeze-hook). -# When the agent receives fsfreeze-freeze request, this script is issued with -# "freeze" argument before the filesystem is frozen. And for fsfreeze-thaw -# request, it is issued with "thaw" argument after filesystem is thawed. - -LOGFILE=/var/log/qga-fsfreeze-hook.log -FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d - -# Check whether file $1 is a backup or rpm-generated file and should be ignored -is_ignored_file() { - case "$1" in - *~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave | *.sample) - return 0 ;; - esac - return 1 -} - -# Iterate executables in directory "fsfreeze-hook.d" with the specified args -[ ! -d "$FSFREEZE_D" ] && exit 0 -for file in "$FSFREEZE_D"/* ; do - is_ignored_file "$file" && continue - [ -x "$file" ] || continue - printf "$(date): execute $file $@\n" >>$LOGFILE - "$file" "$@" >>$LOGFILE 2>&1 - STATUS=$? - printf "$(date): $file finished with status=$STATUS\n" >>$LOGFILE -done - -exit 0 diff --git a/qemu/scripts/qemu-guest-agent/fsfreeze-hook.d/mysql-flush.sh.sample b/qemu/scripts/qemu-guest-agent/fsfreeze-hook.d/mysql-flush.sh.sample deleted file mode 100755 index 2b4fa3aeb..000000000 --- a/qemu/scripts/qemu-guest-agent/fsfreeze-hook.d/mysql-flush.sh.sample +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh - -# Flush MySQL tables to the disk before the filesystem is frozen. -# At the same time, this keeps a read lock in order to avoid write accesses -# from the other clients until the filesystem is thawed. - -MYSQL="/usr/bin/mysql" -MYSQL_OPTS="-uroot" #"-prootpassword" -FIFO=/var/run/mysql-flush.fifo - -# Check mysql is installed and the server running -[ -x "$MYSQL" ] && "$MYSQL" $MYSQL_OPTS < /dev/null || exit 0 - -flush_and_wait() { - printf "FLUSH TABLES WITH READ LOCK \\G\n" - trap 'printf "$(date): $0 is killed\n">&2' HUP INT QUIT ALRM TERM - read < $FIFO - printf "UNLOCK TABLES \\G\n" - rm -f $FIFO -} - -case "$1" in - freeze) - mkfifo $FIFO || exit 1 - flush_and_wait | "$MYSQL" $MYSQL_OPTS & - # wait until every block is flushed - while [ "$(echo 'SHOW STATUS LIKE "Key_blocks_not_flushed"' |\ - "$MYSQL" $MYSQL_OPTS | tail -1 | cut -f 2)" -gt 0 ]; do - sleep 1 - done - # for InnoDB, wait until every log is flushed - INNODB_STATUS=$(mktemp /tmp/mysql-flush.XXXXXX) - [ $? -ne 0 ] && exit 2 - trap "rm -f $INNODB_STATUS; exit 1" HUP INT QUIT ALRM TERM - while :; do - printf "SHOW ENGINE INNODB STATUS \\G" |\ - "$MYSQL" $MYSQL_OPTS > $INNODB_STATUS - LOG_CURRENT=$(grep 'Log sequence number' $INNODB_STATUS |\ - tr -s ' ' | cut -d' ' -f4) - LOG_FLUSHED=$(grep 'Log flushed up to' $INNODB_STATUS |\ - tr -s ' ' | cut -d' ' -f5) - [ "$LOG_CURRENT" = "$LOG_FLUSHED" ] && break - sleep 1 - done - rm -f $INNODB_STATUS - ;; - - thaw) - [ ! -p $FIFO ] && exit 1 - echo > $FIFO - ;; - - *) - exit 1 - ;; -esac diff --git a/qemu/scripts/qemugdb/__init__.py b/qemu/scripts/qemugdb/__init__.py deleted file mode 100644 index 969f552b2..000000000 --- a/qemu/scripts/qemugdb/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/python - -# GDB debugging support -# -# Copyright (c) 2015 Linaro Ltd -# -# 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/gpl-2.0.html> -# - -# We don't need to do anything in our init file currently. - -""" -Support routines for debugging QEMU under GDB -""" - -__license__ = "GPL version 2 or (at your option) any later version" diff --git a/qemu/scripts/qemugdb/aio.py b/qemu/scripts/qemugdb/aio.py deleted file mode 100644 index 2ba00c444..000000000 --- a/qemu/scripts/qemugdb/aio.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/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/qemu/scripts/qemugdb/coroutine.py b/qemu/scripts/qemugdb/coroutine.py deleted file mode 100644 index ab699794a..000000000 --- a/qemu/scripts/qemugdb/coroutine.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/python - -# GDB debugging support -# -# Copyright 2012 Red Hat, Inc. and/or its affiliates -# -# Authors: -# Avi Kivity <avi@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. -# -# Contributions after 2012-01-13 are licensed under the terms of the -# GNU GPL, version 2 or (at your option) any later version. - -import gdb - -VOID_PTR = gdb.lookup_type('void').pointer() - -def get_fs_base(): - '''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) - 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 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 = 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 get_jmpbuf_regs(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 - - pointer_guard = get_glibc_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') - - 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): - '''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 - - 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) diff --git a/qemu/scripts/qemugdb/mtree.py b/qemu/scripts/qemugdb/mtree.py deleted file mode 100644 index cc8131c2e..000000000 --- a/qemu/scripts/qemugdb/mtree.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/python - -# GDB debugging support -# -# Copyright 2012 Red Hat, Inc. and/or its affiliates -# -# Authors: -# Avi Kivity <avi@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. -# -# Contributions after 2012-01-13 are licensed under the terms of the -# GNU GPL, version 2 or (at your option) any later version. - -# 'qemu mtree' -- display the memory hierarchy - -import gdb - -def isnull(ptr): - return ptr == gdb.Value(0).cast(ptr.type) - -def int128(p): - return int(p['lo']) + (int(p['hi']) << 64) - -class MtreeCommand(gdb.Command): - '''Display the memory tree hierarchy''' - def __init__(self): - gdb.Command.__init__(self, 'qemu mtree', gdb.COMMAND_DATA, - gdb.COMPLETE_NONE) - self.queue = [] - def invoke(self, arg, from_tty): - self.seen = set() - self.queue_root('address_space_memory') - self.queue_root('address_space_io') - self.process_queue() - def queue_root(self, varname): - ptr = gdb.parse_and_eval(varname)['root'] - self.queue.append(ptr) - def process_queue(self): - while self.queue: - ptr = self.queue.pop(0) - if int(ptr) in self.seen: - continue - self.print_item(ptr) - def print_item(self, ptr, offset = gdb.Value(0), level = 0): - self.seen.add(int(ptr)) - addr = ptr['addr'] - addr += offset - size = int128(ptr['size']) - alias = ptr['alias'] - klass = '' - if not isnull(alias): - klass = ' (alias)' - elif not isnull(ptr['ops']): - klass = ' (I/O)' - elif bool(ptr['ram']): - klass = ' (RAM)' - gdb.write('%s%016x-%016x %s%s (@ %s)\n' - % (' ' * level, - int(addr), - int(addr + (size - 1)), - ptr['name'].string(), - klass, - ptr, - ), - gdb.STDOUT) - if not isnull(alias): - gdb.write('%s alias: %s@%016x (@ %s)\n' % - (' ' * level, - alias['name'].string(), - ptr['alias_offset'], - alias, - ), - gdb.STDOUT) - self.queue.append(alias) - subregion = ptr['subregions']['tqh_first'] - level += 1 - while not isnull(subregion): - self.print_item(subregion, addr, level) - subregion = subregion['subregions_link']['tqe_next'] - diff --git a/qemu/scripts/qmp/qemu-ga-client b/qemu/scripts/qmp/qemu-ga-client deleted file mode 100755 index fd056056f..000000000 --- a/qemu/scripts/qmp/qemu-ga-client +++ /dev/null @@ -1,301 +0,0 @@ -#!/usr/bin/python - -# QEMU Guest Agent Client -# -# Copyright (C) 2012 Ryota Ozaki <ozaki.ryota@gmail.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. -# -# Usage: -# -# Start QEMU with: -# -# # qemu [...] -chardev socket,path=/tmp/qga.sock,server,nowait,id=qga0 \ -# -device virtio-serial -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 -# -# Run the script: -# -# $ qemu-ga-client --address=/tmp/qga.sock <command> [args...] -# -# or -# -# $ export QGA_CLIENT_ADDRESS=/tmp/qga.sock -# $ qemu-ga-client <command> [args...] -# -# For example: -# -# $ qemu-ga-client cat /etc/resolv.conf -# # Generated by NetworkManager -# nameserver 10.0.2.3 -# $ qemu-ga-client fsfreeze status -# thawed -# $ qemu-ga-client fsfreeze freeze -# 2 filesystems frozen -# -# See also: http://wiki.qemu-project.org/Features/QAPI/GuestAgent -# - -import base64 -import random - -import qmp - - -class QemuGuestAgent(qmp.QEMUMonitorProtocol): - def __getattr__(self, name): - def wrapper(**kwds): - return self.command('guest-' + name.replace('_', '-'), **kwds) - return wrapper - - -class QemuGuestAgentClient: - error = QemuGuestAgent.error - - def __init__(self, address): - self.qga = QemuGuestAgent(address) - self.qga.connect(negotiate=False) - - def sync(self, timeout=3): - # Avoid being blocked forever - if not self.ping(timeout): - raise EnvironmentError('Agent seems not alive') - uid = random.randint(0, (1 << 32) - 1) - while True: - ret = self.qga.sync(id=uid) - if isinstance(ret, int) and int(ret) == uid: - break - - def __file_read_all(self, handle): - eof = False - data = '' - while not eof: - ret = self.qga.file_read(handle=handle, count=1024) - _data = base64.b64decode(ret['buf-b64']) - data += _data - eof = ret['eof'] - return data - - def read(self, path): - handle = self.qga.file_open(path=path) - try: - data = self.__file_read_all(handle) - finally: - self.qga.file_close(handle=handle) - return data - - def info(self): - info = self.qga.info() - - msgs = [] - msgs.append('version: ' + info['version']) - msgs.append('supported_commands:') - enabled = [c['name'] for c in info['supported_commands'] if c['enabled']] - msgs.append('\tenabled: ' + ', '.join(enabled)) - disabled = [c['name'] for c in info['supported_commands'] if not c['enabled']] - msgs.append('\tdisabled: ' + ', '.join(disabled)) - - return '\n'.join(msgs) - - def __gen_ipv4_netmask(self, prefixlen): - mask = int('1' * prefixlen + '0' * (32 - prefixlen), 2) - return '.'.join([str(mask >> 24), - str((mask >> 16) & 0xff), - str((mask >> 8) & 0xff), - str(mask & 0xff)]) - - def ifconfig(self): - nifs = self.qga.network_get_interfaces() - - msgs = [] - for nif in nifs: - msgs.append(nif['name'] + ':') - if 'ip-addresses' in nif: - for ipaddr in nif['ip-addresses']: - if ipaddr['ip-address-type'] == 'ipv4': - addr = ipaddr['ip-address'] - mask = self.__gen_ipv4_netmask(int(ipaddr['prefix'])) - msgs.append("\tinet %s netmask %s" % (addr, mask)) - elif ipaddr['ip-address-type'] == 'ipv6': - addr = ipaddr['ip-address'] - prefix = ipaddr['prefix'] - msgs.append("\tinet6 %s prefixlen %s" % (addr, prefix)) - if nif['hardware-address'] != '00:00:00:00:00:00': - msgs.append("\tether " + nif['hardware-address']) - - return '\n'.join(msgs) - - def ping(self, timeout): - self.qga.settimeout(timeout) - try: - self.qga.ping() - except self.qga.timeout: - return False - return True - - def fsfreeze(self, cmd): - if cmd not in ['status', 'freeze', 'thaw']: - raise StandardError('Invalid command: ' + cmd) - - return getattr(self.qga, 'fsfreeze' + '_' + cmd)() - - def fstrim(self, minimum=0): - return getattr(self.qga, 'fstrim')(minimum=minimum) - - def suspend(self, mode): - if mode not in ['disk', 'ram', 'hybrid']: - raise StandardError('Invalid mode: ' + mode) - - try: - getattr(self.qga, 'suspend' + '_' + mode)() - # On error exception will raise - except self.qga.timeout: - # On success command will timed out - return - - def shutdown(self, mode='powerdown'): - if mode not in ['powerdown', 'halt', 'reboot']: - raise StandardError('Invalid mode: ' + mode) - - try: - self.qga.shutdown(mode=mode) - except self.qga.timeout: - return - - -def _cmd_cat(client, args): - if len(args) != 1: - print('Invalid argument') - print('Usage: cat <file>') - sys.exit(1) - print(client.read(args[0])) - - -def _cmd_fsfreeze(client, args): - usage = 'Usage: fsfreeze status|freeze|thaw' - if len(args) != 1: - print('Invalid argument') - print(usage) - sys.exit(1) - if args[0] not in ['status', 'freeze', 'thaw']: - print('Invalid command: ' + args[0]) - print(usage) - sys.exit(1) - cmd = args[0] - ret = client.fsfreeze(cmd) - if cmd == 'status': - print(ret) - elif cmd == 'freeze': - print("%d filesystems frozen" % ret) - else: - print("%d filesystems thawed" % ret) - - -def _cmd_fstrim(client, args): - if len(args) == 0: - minimum = 0 - else: - minimum = int(args[0]) - print(client.fstrim(minimum)) - - -def _cmd_ifconfig(client, args): - print(client.ifconfig()) - - -def _cmd_info(client, args): - print(client.info()) - - -def _cmd_ping(client, args): - if len(args) == 0: - timeout = 3 - else: - timeout = float(args[0]) - alive = client.ping(timeout) - if not alive: - print("Not responded in %s sec" % args[0]) - sys.exit(1) - - -def _cmd_suspend(client, args): - usage = 'Usage: suspend disk|ram|hybrid' - if len(args) != 1: - print('Less argument') - print(usage) - sys.exit(1) - if args[0] not in ['disk', 'ram', 'hybrid']: - print('Invalid command: ' + args[0]) - print(usage) - sys.exit(1) - client.suspend(args[0]) - - -def _cmd_shutdown(client, args): - client.shutdown() -_cmd_powerdown = _cmd_shutdown - - -def _cmd_halt(client, args): - client.shutdown('halt') - - -def _cmd_reboot(client, args): - client.shutdown('reboot') - - -commands = [m.replace('_cmd_', '') for m in dir() if '_cmd_' in m] - - -def main(address, cmd, args): - if not os.path.exists(address): - print('%s not found' % address) - sys.exit(1) - - if cmd not in commands: - print('Invalid command: ' + cmd) - print('Available commands: ' + ', '.join(commands)) - sys.exit(1) - - try: - client = QemuGuestAgentClient(address) - except QemuGuestAgent.error as e: - import errno - - print(e) - if e.errno == errno.ECONNREFUSED: - print('Hint: qemu is not running?') - sys.exit(1) - - if cmd == 'fsfreeze' and args[0] == 'freeze': - client.sync(60) - elif cmd != 'ping': - client.sync() - - globals()['_cmd_' + cmd](client, args) - - -if __name__ == '__main__': - import sys - import os - import optparse - - address = os.environ['QGA_CLIENT_ADDRESS'] if 'QGA_CLIENT_ADDRESS' in os.environ else None - - usage = "%prog [--address=<unix_path>|<ipv4_address>] <command> [args...]\n" - usage += '<command>: ' + ', '.join(commands) - parser = optparse.OptionParser(usage=usage) - parser.add_option('--address', action='store', type='string', - default=address, help='Specify a ip:port pair or a unix socket path') - options, args = parser.parse_args() - - address = options.address - if address is None: - parser.error('address is not specified') - sys.exit(1) - - if len(args) == 0: - parser.error('Less argument') - sys.exit(1) - - main(address, args[0], args[1:]) diff --git a/qemu/scripts/qmp/qmp b/qemu/scripts/qmp/qmp deleted file mode 100755 index 514b539a6..000000000 --- a/qemu/scripts/qmp/qmp +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/python -# -# QMP command line tool -# -# Copyright IBM, Corp. 2011 -# -# Authors: -# Anthony Liguori <aliguori@us.ibm.com> -# -# This work is licensed under the terms of the GNU GPLv2 or later. -# See the COPYING file in the top-level directory. - -import sys, os -from qmp import QEMUMonitorProtocol - -def print_response(rsp, prefix=[]): - if type(rsp) == list: - i = 0 - for item in rsp: - if prefix == []: - prefix = ['item'] - print_response(item, prefix[:-1] + ['%s[%d]' % (prefix[-1], i)]) - i += 1 - elif type(rsp) == dict: - for key in rsp.keys(): - print_response(rsp[key], prefix + [key]) - else: - if len(prefix): - print '%s: %s' % ('.'.join(prefix), rsp) - else: - print '%s' % (rsp) - -def main(args): - path = None - - # Use QMP_PATH if it's set - if os.environ.has_key('QMP_PATH'): - path = os.environ['QMP_PATH'] - - while len(args): - arg = args[0] - - if arg.startswith('--'): - arg = arg[2:] - if arg.find('=') == -1: - value = True - else: - arg, value = arg.split('=', 1) - - if arg in ['path']: - if type(value) == str: - path = value - elif arg in ['help']: - os.execlp('man', 'man', 'qmp') - else: - print 'Unknown argument "%s"' % arg - - args = args[1:] - else: - break - - if not path: - print "QMP path isn't set, use --path=qmp-monitor-address or set QMP_PATH" - return 1 - - if len(args): - command, args = args[0], args[1:] - else: - print 'No command found' - print 'Usage: "qmp [--path=qmp-monitor-address] qmp-cmd arguments"' - return 1 - - if command in ['help']: - os.execlp('man', 'man', 'qmp') - - srv = QEMUMonitorProtocol(path) - srv.connect() - - def do_command(srv, cmd, **kwds): - rsp = srv.cmd(cmd, kwds) - if rsp.has_key('error'): - raise Exception(rsp['error']['desc']) - return rsp['return'] - - commands = map(lambda x: x['name'], do_command(srv, 'query-commands')) - - srv.close() - - if command not in commands: - fullcmd = 'qmp-%s' % command - try: - os.environ['QMP_PATH'] = path - os.execvp(fullcmd, [fullcmd] + args) - except OSError as exc: - if exc.errno == 2: - print 'Command "%s" not found.' % (fullcmd) - return 1 - raise - return 0 - - srv = QEMUMonitorProtocol(path) - srv.connect() - - arguments = {} - for arg in args: - if not arg.startswith('--'): - print 'Unknown argument "%s"' % arg - return 1 - - arg = arg[2:] - if arg.find('=') == -1: - value = True - else: - arg, value = arg.split('=', 1) - - if arg in ['help']: - os.execlp('man', 'man', 'qmp-%s' % command) - return 1 - - arguments[arg] = value - - rsp = do_command(srv, command, **arguments) - print_response(rsp) - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) diff --git a/qemu/scripts/qmp/qmp-shell b/qemu/scripts/qmp/qmp-shell deleted file mode 100755 index 0373b24b2..000000000 --- a/qemu/scripts/qmp/qmp-shell +++ /dev/null @@ -1,422 +0,0 @@ -#!/usr/bin/python -# -# Low-level QEMU shell on top of QMP. -# -# Copyright (C) 2009, 2010 Red Hat Inc. -# -# Authors: -# Luiz Capitulino <lcapitulino@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. -# -# Usage: -# -# Start QEMU with: -# -# # qemu [...] -qmp unix:./qmp-sock,server -# -# Run the shell: -# -# $ qmp-shell ./qmp-sock -# -# Commands have the following format: -# -# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ] -# -# For example: -# -# (QEMU) device_add driver=e1000 id=net1 -# {u'return': {}} -# (QEMU) -# -# key=value pairs also support Python or JSON object literal subset notations, -# without spaces. Dictionaries/objects {} are supported as are arrays []. -# -# example-command arg-name1={'key':'value','obj'={'prop':"value"}} -# -# Both JSON and Python formatting should work, including both styles of -# string literal quotes. Both paradigms of literal values should work, -# including null/true/false for JSON and None/True/False for Python. -# -# -# Transactions have the following multi-line format: -# -# transaction( -# action-name1 [ arg-name1=arg1 ] ... [arg-nameN=argN ] -# ... -# action-nameN [ arg-name1=arg1 ] ... [arg-nameN=argN ] -# ) -# -# One line transactions are also supported: -# -# transaction( action-name1 ... ) -# -# For example: -# -# (QEMU) transaction( -# TRANS> block-dirty-bitmap-add node=drive0 name=bitmap1 -# TRANS> block-dirty-bitmap-clear node=drive0 name=bitmap0 -# TRANS> ) -# {"return": {}} -# (QEMU) -# -# Use the -v and -p options to activate the verbose and pretty-print options, -# which will echo back the properly formatted JSON-compliant QMP that is being -# sent to QEMU, which is useful for debugging and documentation generation. - -import qmp -import json -import ast -import readline -import sys - -class QMPCompleter(list): - def complete(self, text, state): - for cmd in self: - if cmd.startswith(text): - if not state: - return cmd - else: - state -= 1 - -class QMPShellError(Exception): - pass - -class QMPShellBadPort(QMPShellError): - pass - -class FuzzyJSON(ast.NodeTransformer): - '''This extension of ast.NodeTransformer filters literal "true/false/null" - values in an AST and replaces them by proper "True/False/None" values that - Python can properly evaluate.''' - def visit_Name(self, node): - if node.id == 'true': - node.id = 'True' - if node.id == 'false': - node.id = 'False' - if node.id == 'null': - node.id = 'None' - return node - -# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and -# _execute_cmd()). Let's design a better one. -class QMPShell(qmp.QEMUMonitorProtocol): - def __init__(self, address, pretty=False): - qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address)) - self._greeting = None - self._completer = None - self._pretty = pretty - self._transmode = False - self._actions = list() - - def __get_address(self, arg): - """ - Figure out if the argument is in the port:host form, if it's not it's - probably a file path. - """ - addr = arg.split(':') - if len(addr) == 2: - try: - port = int(addr[1]) - except ValueError: - raise QMPShellBadPort - return ( addr[0], port ) - # socket path - return arg - - def _fill_completion(self): - for cmd in self.cmd('query-commands')['return']: - self._completer.append(cmd['name']) - - def __completer_setup(self): - self._completer = QMPCompleter() - self._fill_completion() - readline.set_completer(self._completer.complete) - readline.parse_and_bind("tab: complete") - # XXX: default delimiters conflict with some command names (eg. query-), - # clearing everything as it doesn't seem to matter - readline.set_completer_delims('') - - def __parse_value(self, val): - try: - return int(val) - except ValueError: - pass - - if val.lower() == 'true': - return True - if val.lower() == 'false': - return False - if val.startswith(('{', '[')): - # Try first as pure JSON: - try: - return json.loads(val) - except ValueError: - pass - # Try once again as FuzzyJSON: - try: - st = ast.parse(val, mode='eval') - return ast.literal_eval(FuzzyJSON().visit(st)) - except SyntaxError: - pass - except ValueError: - pass - return val - - def __cli_expr(self, tokens, parent): - for arg in tokens: - (key, _, val) = arg.partition('=') - if not val: - raise QMPShellError("Expected a key=value pair, got '%s'" % arg) - - value = self.__parse_value(val) - optpath = key.split('.') - curpath = [] - for p in optpath[:-1]: - curpath.append(p) - d = parent.get(p, {}) - if type(d) is not dict: - raise QMPShellError('Cannot use "%s" as both leaf and non-leaf key' % '.'.join(curpath)) - parent[p] = d - parent = d - if optpath[-1] in parent: - if type(parent[optpath[-1]]) is dict: - raise QMPShellError('Cannot use "%s" as both leaf and non-leaf key' % '.'.join(curpath)) - else: - raise QMPShellError('Cannot set "%s" multiple times' % key) - parent[optpath[-1]] = value - - def __build_cmd(self, cmdline): - """ - Build a QMP input object from a user provided command-line in the - following format: - - < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ] - """ - cmdargs = cmdline.split() - - # Transactional CLI entry/exit: - if cmdargs[0] == 'transaction(': - self._transmode = True - cmdargs.pop(0) - elif cmdargs[0] == ')' and self._transmode: - self._transmode = False - if len(cmdargs) > 1: - raise QMPShellError("Unexpected input after close of Transaction sub-shell") - qmpcmd = { 'execute': 'transaction', - 'arguments': { 'actions': self._actions } } - self._actions = list() - return qmpcmd - - # Nothing to process? - if not cmdargs: - return None - - # Parse and then cache this Transactional Action - if self._transmode: - finalize = False - action = { 'type': cmdargs[0], 'data': {} } - if cmdargs[-1] == ')': - cmdargs.pop(-1) - finalize = True - self.__cli_expr(cmdargs[1:], action['data']) - self._actions.append(action) - return self.__build_cmd(')') if finalize else None - - # Standard command: parse and return it to be executed. - qmpcmd = { 'execute': cmdargs[0], 'arguments': {} } - self.__cli_expr(cmdargs[1:], qmpcmd['arguments']) - return qmpcmd - - def _print(self, qmp): - indent = None - if self._pretty: - indent = 4 - jsobj = json.dumps(qmp, indent=indent) - print str(jsobj) - - def _execute_cmd(self, cmdline): - try: - qmpcmd = self.__build_cmd(cmdline) - except Exception as e: - print 'Error while parsing command line: %s' % e - print 'command format: <command-name> ', - print '[arg-name1=arg1] ... [arg-nameN=argN]' - return True - # For transaction mode, we may have just cached the action: - if qmpcmd is None: - return True - if self._verbose: - self._print(qmpcmd) - resp = self.cmd_obj(qmpcmd) - if resp is None: - print 'Disconnected' - return False - self._print(resp) - return True - - def connect(self): - self._greeting = qmp.QEMUMonitorProtocol.connect(self) - self.__completer_setup() - - def show_banner(self, msg='Welcome to the QMP low-level shell!'): - print msg - version = self._greeting['QMP']['version']['qemu'] - print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro']) - - def get_prompt(self): - if self._transmode: - return "TRANS> " - return "(QEMU) " - - def read_exec_command(self, prompt): - """ - Read and execute a command. - - @return True if execution was ok, return False if disconnected. - """ - try: - cmdline = raw_input(prompt) - except EOFError: - print - return False - if cmdline == '': - for ev in self.get_events(): - print ev - self.clear_events() - return True - else: - return self._execute_cmd(cmdline) - - def set_verbosity(self, verbose): - self._verbose = verbose - -class HMPShell(QMPShell): - def __init__(self, address): - QMPShell.__init__(self, address) - self.__cpu_index = 0 - - def __cmd_completion(self): - for cmd in self.__cmd_passthrough('help')['return'].split('\r\n'): - if cmd and cmd[0] != '[' and cmd[0] != '\t': - name = cmd.split()[0] # drop help text - if name == 'info': - continue - if name.find('|') != -1: - # Command in the form 'foobar|f' or 'f|foobar', take the - # full name - opt = name.split('|') - if len(opt[0]) == 1: - name = opt[1] - else: - name = opt[0] - self._completer.append(name) - self._completer.append('help ' + name) # help completion - - def __info_completion(self): - for cmd in self.__cmd_passthrough('info')['return'].split('\r\n'): - if cmd: - self._completer.append('info ' + cmd.split()[1]) - - def __other_completion(self): - # special cases - self._completer.append('help info') - - def _fill_completion(self): - self.__cmd_completion() - self.__info_completion() - self.__other_completion() - - def __cmd_passthrough(self, cmdline, cpu_index = 0): - return self.cmd_obj({ 'execute': 'human-monitor-command', 'arguments': - { 'command-line': cmdline, - 'cpu-index': cpu_index } }) - - def _execute_cmd(self, cmdline): - if cmdline.split()[0] == "cpu": - # trap the cpu command, it requires special setting - try: - idx = int(cmdline.split()[1]) - if not 'return' in self.__cmd_passthrough('info version', idx): - print 'bad CPU index' - return True - self.__cpu_index = idx - except ValueError: - print 'cpu command takes an integer argument' - return True - resp = self.__cmd_passthrough(cmdline, self.__cpu_index) - if resp is None: - print 'Disconnected' - return False - assert 'return' in resp or 'error' in resp - if 'return' in resp: - # Success - if len(resp['return']) > 0: - print resp['return'], - else: - # Error - print '%s: %s' % (resp['error']['class'], resp['error']['desc']) - return True - - def show_banner(self): - QMPShell.show_banner(self, msg='Welcome to the HMP shell!') - -def die(msg): - sys.stderr.write('ERROR: %s\n' % msg) - sys.exit(1) - -def fail_cmdline(option=None): - if option: - sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option) - sys.stderr.write('qemu-shell [ -v ] [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n') - sys.exit(1) - -def main(): - addr = '' - qemu = None - hmp = False - pretty = False - verbose = False - - try: - for arg in sys.argv[1:]: - if arg == "-H": - if qemu is not None: - fail_cmdline(arg) - hmp = True - elif arg == "-p": - pretty = True - elif arg == "-v": - verbose = True - else: - if qemu is not None: - fail_cmdline(arg) - if hmp: - qemu = HMPShell(arg) - else: - qemu = QMPShell(arg, pretty) - addr = arg - - if qemu is None: - fail_cmdline() - except QMPShellBadPort: - die('bad port number in command-line') - - try: - qemu.connect() - except qmp.QMPConnectError: - die('Didn\'t get QMP greeting message') - except qmp.QMPCapabilitiesError: - die('Could not negotiate capabilities') - except qemu.error: - die('Could not connect to %s' % addr) - - qemu.show_banner() - qemu.set_verbosity(verbose) - while qemu.read_exec_command(qemu.get_prompt()): - pass - qemu.close() - -if __name__ == '__main__': - main() diff --git a/qemu/scripts/qmp/qmp.py b/qemu/scripts/qmp/qmp.py deleted file mode 100644 index 779332f32..000000000 --- a/qemu/scripts/qmp/qmp.py +++ /dev/null @@ -1,236 +0,0 @@ -# QEMU Monitor Protocol Python class -# -# Copyright (C) 2009, 2010 Red Hat Inc. -# -# Authors: -# Luiz Capitulino <lcapitulino@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. - -import json -import errno -import socket - -class QMPError(Exception): - pass - -class QMPConnectError(QMPError): - pass - -class QMPCapabilitiesError(QMPError): - pass - -class QMPTimeoutError(QMPError): - pass - -class QEMUMonitorProtocol: - def __init__(self, address, server=False): - """ - Create a QEMUMonitorProtocol class. - - @param address: QEMU address, can be either a unix socket path (string) - or a tuple in the form ( address, port ) for a TCP - connection - @param server: server mode listens on the socket (bool) - @raise socket.error on socket connection errors - @note No connection is established, this is done by the connect() or - accept() methods - """ - self.__events = [] - self.__address = address - self.__sock = self.__get_sock() - if server: - self.__sock.bind(self.__address) - self.__sock.listen(1) - - def __get_sock(self): - if isinstance(self.__address, tuple): - family = socket.AF_INET - else: - family = socket.AF_UNIX - return socket.socket(family, socket.SOCK_STREAM) - - def __negotiate_capabilities(self): - greeting = self.__json_read() - if greeting is None or not greeting.has_key('QMP'): - raise QMPConnectError - # Greeting seems ok, negotiate capabilities - resp = self.cmd('qmp_capabilities') - if "return" in resp: - return greeting - raise QMPCapabilitiesError - - def __json_read(self, only_event=False): - while True: - data = self.__sockfile.readline() - if not data: - return - resp = json.loads(data) - if 'event' in resp: - self.__events.append(resp) - if not only_event: - continue - return resp - - 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 as 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. - - @return QMP greeting dict - @raise socket.error on socket connection errors - @raise QMPConnectError if the greeting is not received - @raise QMPCapabilitiesError if fails to negotiate capabilities - """ - self.__sock.connect(self.__address) - self.__sockfile = self.__sock.makefile() - if negotiate: - return self.__negotiate_capabilities() - - def accept(self): - """ - Await connection from QMP Monitor and perform capabilities negotiation. - - @return QMP greeting dict - @raise socket.error on socket connection errors - @raise QMPConnectError if the greeting is not received - @raise QMPCapabilitiesError if fails to negotiate capabilities - """ - self.__sock, _ = self.__sock.accept() - self.__sockfile = self.__sock.makefile() - return self.__negotiate_capabilities() - - def cmd_obj(self, qmp_cmd): - """ - Send a QMP command to the QMP Monitor. - - @param qmp_cmd: QMP command to be sent as a Python dict - @return QMP response as a Python dict or None if the connection has - been closed - """ - try: - self.__sock.sendall(json.dumps(qmp_cmd)) - except socket.error as err: - if err[0] == errno.EPIPE: - return - raise socket.error(err) - return self.__json_read() - - def cmd(self, name, args=None, id=None): - """ - Build a QMP command and send it to the QMP Monitor. - - @param name: command name (string) - @param args: command arguments (dict) - @param id: command id (dict, list, string or int) - """ - qmp_cmd = { 'execute': name } - if args: - qmp_cmd['arguments'] = args - if id: - qmp_cmd['id'] = id - return self.cmd_obj(qmp_cmd) - - def command(self, cmd, **kwds): - ret = self.cmd(cmd, kwds) - if ret.has_key('error'): - raise Exception(ret['error']['desc']) - return ret['return'] - - def pull_event(self, wait=False): - """ - Get and delete the first available QMP event. - - @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.__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 (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): - """ - Clear current list of pending events. - """ - self.__events = [] - - def close(self): - self.__sock.close() - self.__sockfile.close() - - timeout = socket.timeout - - def settimeout(self, timeout): - self.__sock.settimeout(timeout) - - def get_sock_fd(self): - return self.__sock.fileno() - - def is_scm_available(self): - return self.__sock.family == socket.AF_UNIX diff --git a/qemu/scripts/qmp/qom-fuse b/qemu/scripts/qmp/qom-fuse deleted file mode 100755 index 5c6754aa6..000000000 --- a/qemu/scripts/qmp/qom-fuse +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/python -## -# QEMU Object Model test tools -# -# Copyright IBM, Corp. 2012 -# -# Authors: -# Anthony Liguori <aliguori@us.ibm.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 fuse, stat -from fuse import Fuse -import os, posix -from errno import * -from qmp import QEMUMonitorProtocol - -fuse.fuse_python_api = (0, 2) - -class QOMFS(Fuse): - def __init__(self, qmp, *args, **kwds): - Fuse.__init__(self, *args, **kwds) - self.qmp = qmp - self.qmp.connect() - self.ino_map = {} - self.ino_count = 1 - - def get_ino(self, path): - if self.ino_map.has_key(path): - return self.ino_map[path] - self.ino_map[path] = self.ino_count - self.ino_count += 1 - return self.ino_map[path] - - def is_object(self, path): - try: - items = self.qmp.command('qom-list', path=path) - return True - except: - return False - - def is_property(self, path): - try: - path, prop = path.rsplit('/', 1) - for item in self.qmp.command('qom-list', path=path): - if item['name'] == prop: - return True - return False - except: - return False - - def is_link(self, path): - try: - path, prop = path.rsplit('/', 1) - for item in self.qmp.command('qom-list', path=path): - if item['name'] == prop: - if item['type'].startswith('link<'): - return True - return False - return False - except: - return False - - def read(self, path, length, offset): - if not self.is_property(path): - return -ENOENT - - path, prop = path.rsplit('/', 1) - try: - data = str(self.qmp.command('qom-get', path=path, property=prop)) - data += '\n' # make values shell friendly - except: - return -EPERM - - if offset > len(data): - return '' - - return str(data[offset:][:length]) - - def readlink(self, path): - if not self.is_link(path): - return False - path, prop = path.rsplit('/', 1) - prefix = '/'.join(['..'] * (len(path.split('/')) - 1)) - return prefix + str(self.qmp.command('qom-get', path=path, - property=prop)) - - def getattr(self, path): - if self.is_link(path): - value = posix.stat_result((0755 | stat.S_IFLNK, - self.get_ino(path), - 0, - 2, - 1000, - 1000, - 4096, - 0, - 0, - 0)) - elif self.is_object(path): - value = posix.stat_result((0755 | stat.S_IFDIR, - self.get_ino(path), - 0, - 2, - 1000, - 1000, - 4096, - 0, - 0, - 0)) - elif self.is_property(path): - value = posix.stat_result((0644 | stat.S_IFREG, - self.get_ino(path), - 0, - 1, - 1000, - 1000, - 4096, - 0, - 0, - 0)) - else: - value = -ENOENT - return value - - def readdir(self, path, offset): - yield fuse.Direntry('.') - yield fuse.Direntry('..') - for item in self.qmp.command('qom-list', path=path): - yield fuse.Direntry(str(item['name'])) - -if __name__ == '__main__': - import sys, os - - fs = QOMFS(QEMUMonitorProtocol(os.environ['QMP_SOCKET'])) - fs.main(sys.argv) diff --git a/qemu/scripts/qmp/qom-get b/qemu/scripts/qmp/qom-get deleted file mode 100755 index 0172c6944..000000000 --- a/qemu/scripts/qmp/qom-get +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/python -## -# QEMU Object Model test tools -# -# Copyright IBM, Corp. 2011 -# -# Authors: -# Anthony Liguori <aliguori@us.ibm.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 sys -import os -from qmp import QEMUMonitorProtocol - -cmd, args = sys.argv[0], sys.argv[1:] -socket_path = None -path = None -prop = None - -def usage(): - return '''environment variables: - QMP_SOCKET=<path | addr:port> -usage: - %s [-h] [-s <QMP socket path | addr:port>] <path>.<property> -''' % cmd - -def usage_error(error_msg = "unspecified error"): - sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg)) - exit(1) - -if len(args) > 0: - if args[0] == "-h": - print usage() - exit(0); - elif args[0] == "-s": - try: - socket_path = args[1] - except: - usage_error("missing argument: QMP socket path or address"); - args = args[2:] - -if not socket_path: - if os.environ.has_key('QMP_SOCKET'): - socket_path = os.environ['QMP_SOCKET'] - else: - usage_error("no QMP socket path or address given"); - -if len(args) > 0: - try: - path, prop = args[0].rsplit('.', 1) - except: - usage_error("invalid format for path/property/value") -else: - usage_error("not enough arguments") - -srv = QEMUMonitorProtocol(socket_path) -srv.connect() - -rsp = srv.command('qom-get', path=path, property=prop) -if type(rsp) == dict: - for i in rsp.keys(): - print '%s: %s' % (i, rsp[i]) -else: - print rsp diff --git a/qemu/scripts/qmp/qom-list b/qemu/scripts/qmp/qom-list deleted file mode 100755 index 1e7cc6cb2..000000000 --- a/qemu/scripts/qmp/qom-list +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/python -## -# QEMU Object Model test tools -# -# Copyright IBM, Corp. 2011 -# -# Authors: -# Anthony Liguori <aliguori@us.ibm.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 sys -import os -from qmp import QEMUMonitorProtocol - -cmd, args = sys.argv[0], sys.argv[1:] -socket_path = None -path = None -prop = None - -def usage(): - return '''environment variables: - QMP_SOCKET=<path | addr:port> -usage: - %s [-h] [-s <QMP socket path | addr:port>] [<path>] -''' % cmd - -def usage_error(error_msg = "unspecified error"): - sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg)) - exit(1) - -if len(args) > 0: - if args[0] == "-h": - print usage() - exit(0); - elif args[0] == "-s": - try: - socket_path = args[1] - except: - usage_error("missing argument: QMP socket path or address"); - args = args[2:] - -if not socket_path: - if os.environ.has_key('QMP_SOCKET'): - socket_path = os.environ['QMP_SOCKET'] - else: - usage_error("no QMP socket path or address given"); - -srv = QEMUMonitorProtocol(socket_path) -srv.connect() - -if len(args) == 0: - print '/' - sys.exit(0) - -for item in srv.command('qom-list', path=args[0]): - if item['type'].startswith('child<'): - print '%s/' % item['name'] - elif item['type'].startswith('link<'): - print '@%s/' % item['name'] - else: - print '%s' % item['name'] diff --git a/qemu/scripts/qmp/qom-set b/qemu/scripts/qmp/qom-set deleted file mode 100755 index 54ecfecc5..000000000 --- a/qemu/scripts/qmp/qom-set +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/python -## -# QEMU Object Model test tools -# -# Copyright IBM, Corp. 2011 -# -# Authors: -# Anthony Liguori <aliguori@us.ibm.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 sys -import os -from qmp import QEMUMonitorProtocol - -cmd, args = sys.argv[0], sys.argv[1:] -socket_path = None -path = None -prop = None -value = None - -def usage(): - return '''environment variables: - QMP_SOCKET=<path | addr:port> -usage: - %s [-h] [-s <QMP socket path | addr:port>] <path>.<property> <value> -''' % cmd - -def usage_error(error_msg = "unspecified error"): - sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg)) - exit(1) - -if len(args) > 0: - if args[0] == "-h": - print usage() - exit(0); - elif args[0] == "-s": - try: - socket_path = args[1] - except: - usage_error("missing argument: QMP socket path or address"); - args = args[2:] - -if not socket_path: - if os.environ.has_key('QMP_SOCKET'): - socket_path = os.environ['QMP_SOCKET'] - else: - usage_error("no QMP socket path or address given"); - -if len(args) > 1: - try: - path, prop = args[0].rsplit('.', 1) - except: - usage_error("invalid format for path/property/value") - value = args[1] -else: - usage_error("not enough arguments") - -srv = QEMUMonitorProtocol(socket_path) -srv.connect() - -print srv.command('qom-set', path=path, property=prop, value=sys.argv[2]) diff --git a/qemu/scripts/qmp/qom-tree b/qemu/scripts/qmp/qom-tree deleted file mode 100755 index 906fcd264..000000000 --- a/qemu/scripts/qmp/qom-tree +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/python -## -# QEMU Object Model test tools -# -# Copyright IBM, Corp. 2011 -# Copyright (c) 2013 SUSE LINUX Products GmbH -# -# Authors: -# Anthony Liguori <aliguori@amazon.com> -# Andreas Faerber <afaerber@suse.de> -# -# 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 sys -import os -from qmp import QEMUMonitorProtocol - -cmd, args = sys.argv[0], sys.argv[1:] -socket_path = None -path = None -prop = None - -def usage(): - return '''environment variables: - QMP_SOCKET=<path | addr:port> -usage: - %s [-h] [-s <QMP socket path | addr:port>] [<path>] -''' % cmd - -def usage_error(error_msg = "unspecified error"): - sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg)) - exit(1) - -if len(args) > 0: - if args[0] == "-h": - print usage() - exit(0); - elif args[0] == "-s": - try: - socket_path = args[1] - except: - usage_error("missing argument: QMP socket path or address"); - args = args[2:] - -if not socket_path: - if os.environ.has_key('QMP_SOCKET'): - socket_path = os.environ['QMP_SOCKET'] - else: - usage_error("no QMP socket path or address given"); - -srv = QEMUMonitorProtocol(socket_path) -srv.connect() - -def list_node(path): - print '%s' % path - items = srv.command('qom-list', path=path) - for item in items: - if not item['type'].startswith('child<'): - try: - print ' %s: %s (%s)' % (item['name'], srv.command('qom-get', path=path, property=item['name']), item['type']) - except: - print ' %s: <EXCEPTION> (%s)' % (item['name'], item['type']) - print '' - for item in items: - if item['type'].startswith('child<'): - list_node((path if (path != '/') else '') + '/' + item['name']) - -if len(args) == 0: - path = '/' -else: - path = args[0] - -list_node(path) diff --git a/qemu/scripts/qtest.py b/qemu/scripts/qtest.py deleted file mode 100644 index a9714453a..000000000 --- a/qemu/scripts/qtest.py +++ /dev/null @@ -1,71 +0,0 @@ -# QEMU qtest library -# -# Copyright (C) 2015 Red Hat Inc. -# -# Authors: -# Fam Zheng <famz@redhat.com> -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. -# -# Based on qmp.py. -# - -import errno -import socket - -class QEMUQtestProtocol(object): - def __init__(self, address, server=False): - """ - Create a QEMUQtestProtocol object. - - @param address: QEMU address, can be either a unix socket path (string) - or a tuple in the form ( address, port ) for a TCP - connection - @param server: server mode, listens on the socket (bool) - @raise socket.error on socket connection errors - @note No connection is established, this is done by the connect() or - accept() methods - """ - self._address = address - self._sock = self._get_sock() - if server: - self._sock.bind(self._address) - self._sock.listen(1) - - def _get_sock(self): - if isinstance(self._address, tuple): - family = socket.AF_INET - else: - family = socket.AF_UNIX - return socket.socket(family, socket.SOCK_STREAM) - - def connect(self): - """ - Connect to the qtest socket. - - @raise socket.error on socket connection errors - """ - self._sock.connect(self._address) - - def accept(self): - """ - Await connection from QEMU. - - @raise socket.error on socket connection errors - """ - self._sock, _ = self._sock.accept() - - def cmd(self, qtest_cmd): - """ - Send a qtest command on the wire. - - @param qtest_cmd: qtest command text to be sent - """ - self._sock.sendall(qtest_cmd + "\n") - - def close(self): - self._sock.close() - - def settimeout(self, timeout): - self._sock.settimeout(timeout) diff --git a/qemu/scripts/refresh-pxe-roms.sh b/qemu/scripts/refresh-pxe-roms.sh deleted file mode 100755 index 90fc0b374..000000000 --- a/qemu/scripts/refresh-pxe-roms.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -# PXE ROM build script -# -# 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/>. -# -# Copyright (C) 2011 Red Hat, Inc. -# Authors: Alex Williamson <alex.williamson@redhat.com> -# -# Usage: Run from root of qemu tree -# ./scripts/refresh-pxe-roms.sh - -targets="pxerom" -if test -x "$(which EfiRom 2>/dev/null)"; then - targets="$targets efirom" -fi - -cd roms -make -j4 $targets || exit 1 -make clean diff --git a/qemu/scripts/shaderinclude.pl b/qemu/scripts/shaderinclude.pl deleted file mode 100644 index 81b514633..000000000 --- a/qemu/scripts/shaderinclude.pl +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/perl -use strict; -use warnings; - -my $file = shift; -open FILE, "<", $file or die "open $file: $!"; -my $name = $file; -$name =~ s|.*/||; -$name =~ s/[-.]/_/g; -print "static GLchar ${name}_src[] =\n"; -while (<FILE>) { - chomp; - printf " \"%s\\n\"\n", $_; -} -print " \"\\n\";\n"; -close FILE; diff --git a/qemu/scripts/signrom.py b/qemu/scripts/signrom.py deleted file mode 100644 index f9c35ccfc..000000000 --- a/qemu/scripts/signrom.py +++ /dev/null @@ -1,40 +0,0 @@ -# -# Option ROM signing utility -# -# Authors: -# Jan Kiszka <jan.kiszka@siemens.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 sys -import struct - -if len(sys.argv) < 3: - print('usage: signrom.py input output') - sys.exit(1) - -fin = open(sys.argv[1], 'rb') -fout = open(sys.argv[2], 'wb') - -fin.seek(2) -size = ord(fin.read(1)) * 512 - 1 - -fin.seek(0) -data = fin.read(size) -fout.write(data) - -checksum = 0 -for b in data: - # catch Python 2 vs. 3 differences - if isinstance(b, int): - checksum += b - else: - checksum += ord(b) -checksum = (256 - checksum) % 256 - -# Python 3 no longer allows chr(checksum) -fout.write(struct.pack('B', checksum)) - -fin.close() -fout.close() diff --git a/qemu/scripts/simpletrace.py b/qemu/scripts/simpletrace.py deleted file mode 100755 index 3916c6d14..000000000 --- a/qemu/scripts/simpletrace.py +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env python -# -# Pretty-printer for simple trace backend binary trace files -# -# Copyright IBM, Corp. 2010 -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. -# -# For help see docs/tracing.txt - -import struct -import re -import inspect -from tracetool import _read_events, Event -from tracetool.backend.simple import is_string - -header_event_id = 0xffffffffffffffff -header_magic = 0xf2b177cb0aa429b4 -dropped_event_id = 0xfffffffffffffffe - -log_header_fmt = '=QQQ' -rec_header_fmt = '=QQII' - -def read_header(fobj, hfmt): - '''Read a trace record header''' - hlen = struct.calcsize(hfmt) - hdr = fobj.read(hlen) - if len(hdr) != hlen: - return None - return struct.unpack(hfmt, hdr) - -def get_record(edict, rechdr, fobj): - """Deserialize a trace record from a file into a tuple (event_num, timestamp, pid, arg1, ..., arg6).""" - if rechdr is None: - return None - rec = (rechdr[0], rechdr[1], rechdr[3]) - if rechdr[0] != dropped_event_id: - event_id = rechdr[0] - event = edict[event_id] - for type, name in event.args: - if is_string(type): - l = fobj.read(4) - (len,) = struct.unpack('=L', l) - s = fobj.read(len) - rec = rec + (s,) - else: - (value,) = struct.unpack('=Q', fobj.read(8)) - rec = rec + (value,) - else: - (value,) = struct.unpack('=Q', fobj.read(8)) - rec = rec + (value,) - return rec - - -def read_record(edict, fobj): - """Deserialize a trace record from a file into a tuple (event_num, timestamp, pid, arg1, ..., arg6).""" - rechdr = read_header(fobj, rec_header_fmt) - return get_record(edict, rechdr, fobj) # return tuple of record elements - -def read_trace_header(fobj): - """Read and verify trace file header""" - header = read_header(fobj, log_header_fmt) - if header is None or \ - header[0] != header_event_id or \ - header[1] != header_magic: - raise ValueError('Not a valid trace file!') - - log_version = header[2] - if log_version not in [0, 2, 3]: - raise ValueError('Unknown version of tracelog format!') - if log_version != 3: - raise ValueError('Log format %d not supported with this QEMU release!' - % log_version) - -def read_trace_records(edict, fobj): - """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, pid, arg1, ..., arg6).""" - while True: - rec = read_record(edict, fobj) - if rec is None: - break - - yield rec - -class Analyzer(object): - """A trace file analyzer which processes trace records. - - An analyzer can be passed to run() or process(). The begin() method is - invoked, then each trace record is processed, and finally the end() method - is invoked. - - If a method matching a trace event name exists, it is invoked to process - that trace record. Otherwise the catchall() method is invoked.""" - - def begin(self): - """Called at the start of the trace.""" - pass - - def catchall(self, event, rec): - """Called if no specific method for processing a trace event has been found.""" - pass - - def end(self): - """Called at the end of the trace.""" - pass - -def process(events, log, analyzer, read_header=True): - """Invoke an analyzer on each event in a log.""" - if isinstance(events, str): - events = _read_events(open(events, 'r')) - if isinstance(log, str): - log = open(log, 'rb') - - if read_header: - read_trace_header(log) - - dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)") - edict = {dropped_event_id: dropped_event} - - for num, event in enumerate(events): - edict[num] = event - - def build_fn(analyzer, event): - if isinstance(event, str): - return analyzer.catchall - - fn = getattr(analyzer, event.name, None) - if fn is None: - return analyzer.catchall - - event_argcount = len(event.args) - fn_argcount = len(inspect.getargspec(fn)[0]) - 1 - if fn_argcount == event_argcount + 1: - # Include timestamp as first argument - return lambda _, rec: fn(*((rec[1:2],) + rec[3:3 + event_argcount])) - elif fn_argcount == event_argcount + 2: - # Include timestamp and pid - return lambda _, rec: fn(*rec[1:3 + event_argcount]) - else: - # Just arguments, no timestamp or pid - return lambda _, rec: fn(*rec[3:3 + event_argcount]) - - analyzer.begin() - fn_cache = {} - for rec in read_trace_records(edict, log): - event_num = rec[0] - event = edict[event_num] - if event_num not in fn_cache: - fn_cache[event_num] = build_fn(analyzer, event) - fn_cache[event_num](event, rec) - analyzer.end() - -def run(analyzer): - """Execute an analyzer on a trace file given on the command-line. - - This function is useful as a driver for simple analysis scripts. More - advanced scripts will want to call process() instead.""" - import sys - - read_header = True - if len(sys.argv) == 4 and sys.argv[1] == '--no-header': - read_header = False - del sys.argv[1] - elif len(sys.argv) != 3: - sys.stderr.write('usage: %s [--no-header] <trace-events> ' \ - '<trace-file>\n' % sys.argv[0]) - sys.exit(1) - - events = _read_events(open(sys.argv[1], 'r')) - process(events, sys.argv[2], analyzer, read_header=read_header) - -if __name__ == '__main__': - class Formatter(Analyzer): - def __init__(self): - self.last_timestamp = None - - def catchall(self, event, rec): - timestamp = rec[1] - if self.last_timestamp is None: - self.last_timestamp = timestamp - delta_ns = timestamp - self.last_timestamp - self.last_timestamp = timestamp - - fields = [event.name, '%0.3f' % (delta_ns / 1000.0), - 'pid=%d' % rec[2]] - i = 3 - for type, name in event.args: - if is_string(type): - fields.append('%s=%s' % (name, rec[i])) - else: - fields.append('%s=0x%x' % (name, rec[i])) - i += 1 - print ' '.join(fields) - - run(Formatter()) diff --git a/qemu/scripts/switch-timer-api b/qemu/scripts/switch-timer-api deleted file mode 100755 index b0e230b9f..000000000 --- a/qemu/scripts/switch-timer-api +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -use Getopt::Long; -use FindBin; - -my @legacy = qw(qemu_clock_ptr qemu_get_clock_ns qemu_get_clock_ms qemu_register_clock_reset_notifier qemu_unregister_clock_reset_notifier qemu_new_timer qemu_free_timer qemu_del_timer qemu_mod_timer_ns qemu_mod_timer qemu_run_timers qemu_new_timer_ns qemu_new_timer_us qemu_new_timer_ms); -my $legacyre = '\b('.join('|', @legacy).')\b'; -my $option_git; -my $option_dryrun; -my $option_quiet; -my $option_rtc; -my $suffix=".tmp.$$"; -my @files; -my $getfiles = 'git grep -l -E \'\b((host|rt|vm|rtc)_clock\b|qemu_\w*timer)\' | egrep \'\.[ch]$\' | egrep -v \'qemu-timer\.c$|include/qemu/timer\.h$\''; - -sub Syntax -{ - print STDERR <<STOP; -Usage: $FindBin::Script [options] FILE ... - -Translate each FILE to the new QEMU timer API. If no files -are passed, a reasonable guess is taken. - -Options: - -q, --quiet Do not show warnings etc - -d, --dry-run Do a dry run - -g, --git Generate a git commit for each change - -r, --rtc Only fix up rtc usage - -h, --help Print this message - -STOP -return; -} - -sub ParseOptions -{ - if (!GetOptions ( - "dry-run|d" => \$option_dryrun, - "git|g" => \$option_git, - "quiet|q" => \$option_quiet, - "rtc|r" => \$option_rtc, - "help|h" => sub { Syntax(); exit(0); } - )) - { - Syntax(); - die "Bad options"; - } - - if ($#ARGV >=0) - { - @files = @ARGV; - } - else - { - @files = split(/\s+/, `$getfiles`); - } - - foreach my $file (@files) - { - die "Cannot find $file" unless (-f $file && -r $file); - } -} - -sub DoWarn -{ - my $text = shift @_; - my $line = shift @_; - return if ($option_quiet); - chomp ($line); - print STDERR "$text\n"; - print STDERR "$line\n\n"; -} - -sub Process -{ - my $ifn = shift @_; - my $ofn = $ifn.$suffix; - - my $intext; - my $outtext; - my $linenum = 0; - - open my $input, "<", $ifn || die "Cannot open $ifn for read: $!"; - - while (<$input>) - { - my $line = $_; - $intext .= $line; - $linenum++; - - # fix the specific uses - unless ($option_rtc) - { - $line =~ s/\bqemu_new_timer(_[num]s)\s*\((vm_|rt_|host_)clock\b/timer_new$1(XXX_$2clock/g; - $line =~ s/\bqemu_new_timer\s*\((vm_|rt_|host_)clock\b/timer_new(XXX_$1clock/g; - $line =~ s/\bqemu_get_clock(_[num]s)\s*\((vm_|rt_|host_)clock\b/qemu_clock_get$1(XXX_$2clock/g; - } - - # rtc is different - $line =~ s/\bqemu_new_timer(_[num]s)\s*\(rtc_clock\b/timer_new$1(rtc_clock/g; - $line =~ s/\bqemu_new_timer\s*\(rtc_clock\b/timer_new(rtc_clock/g; - $line =~ s/\bqemu_get_clock(_[num]s)\s*\(rtc_clock\b/qemu_clock_get$1(rtc_clock/g; - $line =~ s/\bqemu_register_clock_reset_notifier\s*\(rtc_clock\b/qemu_register_clock_reset_notifier(qemu_clock_ptr(rtc_clock)/g; - - unless ($option_rtc) - { - # fix up comments - $line =~ s/\b(vm_|rt_|host_)clock\b/XXX_$1clock/g if ($line =~ m,^[/ ]+\*,); - - # spurious fprintf error reporting - $line =~ s/: qemu_new_timer_ns failed/: timer_new_ns failed/g; - - # these have just changed name - $line =~ s/\bqemu_mod_timer\b/timer_mod/g; - $line =~ s/\bqemu_mod_timer_(ns|us|ms)\b/timer_mod_$1/g; - $line =~ s/\bqemu_free_timer\b/timer_free/g; - $line =~ s/\bqemu_del_timer\b/timer_del/g; - } - - # fix up rtc_clock - $line =~ s/QEMUClock \*rtc_clock;/QEMUClockType rtc_clock;/g; - $line =~ s/\brtc_clock = (vm_|rt_|host_)clock\b/rtc_clock = XXX_$1clock/g; - - unless ($option_rtc) - { - # replace any more general uses - $line =~ s/\b(vm_|rt_|host_)clock\b/qemu_clock_ptr(XXX_$1clock)/g; - } - - # fix up the place holders - $line =~ s/\bXXX_vm_clock\b/QEMU_CLOCK_VIRTUAL/g; - $line =~ s/\bXXX_rt_clock\b/QEMU_CLOCK_REALTIME/g; - $line =~ s/\bXXX_host_clock\b/QEMU_CLOCK_HOST/g; - - unless ($option_rtc) - { - DoWarn("$ifn:$linenum WARNING: timer $1 not fixed up", $line) if ($line =~ /\b((vm_|rt_|host_)clock)\b/); - DoWarn("$ifn:$linenum WARNING: function $1 not fixed up", $line) if ($line =~ /\b(qemu_new_timer\w+)\b/); - DoWarn("$ifn:$linenum WARNING: legacy function $1 remains", $line) if ($line =~ /$legacyre/o); - } - - $outtext .= $line; - } - - close $input; - - if ($intext ne $outtext) - { - print STDERR "Patching $ifn\n" unless ($option_quiet); - unless ($option_dryrun) - { - open my $output, ">", $ofn || die "Cannot open $ofn for write: $!"; - print $output $outtext; - close $output; - rename ($ofn, $ifn) || die "Cannot rename temp file to $ifn: $!"; - return 1; - } - } - return 0; -} - -sub DoCommit -{ - my $file = shift @_; - open (my $git, "| git commit -F - $file") || die "Cannot run git commit on $file: $!"; - print $git "timers api: use new timer api in $file\n\nConvert $file to use new timer API.\nThis is an automated commit made by scripts/switch-timer-api\n"; - close ($git); -} - -ParseOptions; - -foreach my $file (@files) -{ - my $changed = Process ($file); - DoCommit($file) if ($changed && $option_git); -} diff --git a/qemu/scripts/texi2pod.pl b/qemu/scripts/texi2pod.pl deleted file mode 100755 index 8767662d3..000000000 --- a/qemu/scripts/texi2pod.pl +++ /dev/null @@ -1,486 +0,0 @@ -#! /usr/bin/perl -w - -# Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc. - -# This file is part of GCC. - -# GCC 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, or (at your option) -# any later version. - -# GCC 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 GCC; see the file COPYING. If not, -# see <http://www.gnu.org/licenses/>. - -# This does trivial (and I mean _trivial_) conversion of Texinfo -# markup to Perl POD format. It's intended to be used to extract -# something suitable for a manpage from a Texinfo document. - -$output = 0; -$skipping = 0; -%sects = (); -$section = ""; -@icstack = (); -@endwstack = (); -@skstack = (); -@instack = (); -$shift = ""; -%defs = (); -$fnno = 1; -$inf = ""; -$ibase = ""; -@ipath = (); -$encoding = undef; - -while ($_ = shift) { - if (/^-D(.*)$/) { - if ($1 ne "") { - $flag = $1; - } else { - $flag = shift; - } - $value = ""; - ($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/); - die "no flag specified for -D\n" - unless $flag ne ""; - die "flags may only contain letters, digits, hyphens, dashes and underscores\n" - unless $flag =~ /^[a-zA-Z0-9_-]+$/; - $defs{$flag} = $value; - } elsif (/^-I(.*)$/) { - if ($1 ne "") { - $flag = $1; - } else { - $flag = shift; - } - push (@ipath, $flag); - } elsif (/^-/) { - usage(); - } else { - $in = $_, next unless defined $in; - $out = $_, next unless defined $out; - usage(); - } -} - -if (defined $in) { - $inf = gensym(); - open($inf, "<$in") or die "opening \"$in\": $!\n"; - $ibase = $1 if $in =~ m|^(.+)/[^/]+$|; -} else { - $inf = \*STDIN; -} - -if (defined $out) { - open(STDOUT, ">$out") or die "opening \"$out\": $!\n"; -} - -while(defined $inf) { -while(<$inf>) { - # Certain commands are discarded without further processing. - /^\@(?: - [a-z]+index # @*index: useful only in complete manual - |need # @need: useful only in printed manual - |(?:end\s+)?group # @group .. @end group: ditto - |page # @page: ditto - |node # @node: useful only in .info file - |(?:end\s+)?ifnottex # @ifnottex .. @end ifnottex: use contents - )\b/x and next; - - chomp; - - # Look for filename and title markers. - /^\@setfilename\s+([^.]+)/ and $fn = $1, next; - /^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next; - - # Look for document encoding - /^\@documentencoding\s+([^.]+)/ and do { - $encoding = $1 unless defined $encoding; - next; - }; - - # Identify a man title but keep only the one we are interested in. - /^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do { - if (exists $defs{$1}) { - $fn = $1; - $tl = postprocess($2); - } - next; - }; - - # Look for blocks surrounded by @c man begin SECTION ... @c man end. - # This really oughta be @ifman ... @end ifman and the like, but such - # would require rev'ing all other Texinfo translators. - /^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do { - $output = 1 if exists $defs{$2}; - $sect = $1; - next; - }; - /^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next; - /^\@c\s+man\s+end/ and do { - $sects{$sect} = "" unless exists $sects{$sect}; - $sects{$sect} .= postprocess($section); - $section = ""; - $output = 0; - next; - }; - - # handle variables - /^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do { - $defs{$1} = $2; - next; - }; - /^\@clear\s+([a-zA-Z0-9_-]+)/ and do { - delete $defs{$1}; - next; - }; - - next unless $output; - - # Discard comments. (Can't do it above, because then we'd never see - # @c man lines.) - /^\@c\b/ and next; - - # End-block handler goes up here because it needs to operate even - # if we are skipping. - /^\@end\s+([a-z]+)/ and do { - # Ignore @end foo, where foo is not an operation which may - # cause us to skip, if we are presently skipping. - my $ended = $1; - next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex|copying)$/; - - die "\@end $ended without \@$ended at line $.\n" unless defined $endw; - die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw; - - $endw = pop @endwstack; - - if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) { - $skipping = pop @skstack; - next; - } elsif ($ended =~ /^(?:example|smallexample|display)$/) { - $shift = ""; - $_ = ""; # need a paragraph break - } elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) { - $_ = "\n=back\n"; - $ic = pop @icstack; - } elsif ($ended eq "multitable") { - $_ = "\n=back\n"; - } else { - die "unknown command \@end $ended at line $.\n"; - } - }; - - # We must handle commands which can cause skipping even while we - # are skipping, otherwise we will not process nested conditionals - # correctly. - /^\@ifset\s+([a-zA-Z0-9_-]+)/ and do { - push @endwstack, $endw; - push @skstack, $skipping; - $endw = "ifset"; - $skipping = 1 unless exists $defs{$1}; - next; - }; - - /^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do { - push @endwstack, $endw; - push @skstack, $skipping; - $endw = "ifclear"; - $skipping = 1 if exists $defs{$1}; - next; - }; - - /^\@(ignore|menu|iftex|copying)\b/ and do { - push @endwstack, $endw; - push @skstack, $skipping; - $endw = $1; - $skipping = 1; - next; - }; - - next if $skipping; - - # Character entities. First the ones that can be replaced by raw text - # or discarded outright: - s/\@copyright\{\}/(c)/g; - s/\@dots\{\}/.../g; - s/\@enddots\{\}/..../g; - s/\@([.!? ])/$1/g; - s/\@[:-]//g; - s/\@bullet(?:\{\})?/*/g; - s/\@TeX\{\}/TeX/g; - s/\@pounds\{\}/\#/g; - s/\@minus(?:\{\})?/-/g; - s/\\,/,/g; - - # Now the ones that have to be replaced by special escapes - # (which will be turned back into text by unmunge()) - s/&/&/g; - s/\@\{/{/g; - s/\@\}/}/g; - s/\@\@/&at;/g; - - # Inside a verbatim block, handle @var specially. - if ($shift ne "") { - s/\@var\{([^\}]*)\}/<$1>/g; - } - - # POD doesn't interpret E<> inside a verbatim block. - if ($shift eq "") { - s/</</g; - s/>/>/g; - } else { - s/</</g; - s/>/>/g; - } - - # Single line command handlers. - - /^\@include\s+(.+)$/ and do { - push @instack, $inf; - $inf = gensym(); - $file = postprocess($1); - - # Try cwd and $ibase, then explicit -I paths. - $done = 0; - foreach $path ("", $ibase, @ipath) { - $mypath = $file; - $mypath = $path . "/" . $mypath if ($path ne ""); - open($inf, "<" . $mypath) and ($done = 1, last); - } - die "cannot find $file" if !$done; - next; - }; - - /^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/ - and $_ = "\n=head2 $1\n"; - /^\@subsection\s+(.+)$/ - and $_ = "\n=head3 $1\n"; - /^\@subsubsection\s+(.+)$/ - and $_ = "\n=head4 $1\n"; - - # Block command handlers: - /^\@itemize(?:\s+(\@[a-z]+|\*|-))?/ and do { - push @endwstack, $endw; - push @icstack, $ic; - if (defined $1) { - $ic = $1; - } else { - $ic = '*'; - } - $_ = "\n=over 4\n"; - $endw = "itemize"; - }; - - /^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do { - push @endwstack, $endw; - push @icstack, $ic; - if (defined $1) { - $ic = $1 . "."; - } else { - $ic = "1."; - } - $_ = "\n=over 4\n"; - $endw = "enumerate"; - }; - - /^\@multitable\s.*/ and do { - push @endwstack, $endw; - $endw = "multitable"; - $_ = "\n=over 4\n"; - }; - - /^\@([fv]?table)\s+(\@[a-z]+)/ and do { - push @endwstack, $endw; - push @icstack, $ic; - $endw = $1; - $ic = $2; - $ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/; - $ic =~ s/\@(?:code|kbd)/C/; - $ic =~ s/\@(?:dfn|var|emph|cite|i)/I/; - $ic =~ s/\@(?:file)/F/; - $_ = "\n=over 4\n"; - }; - - /^\@((?:small)?example|display)/ and do { - push @endwstack, $endw; - $endw = $1; - $shift = "\t"; - $_ = ""; # need a paragraph break - }; - - /^\@item\s+(.*\S)\s*$/ and $endw eq "multitable" and do { - @columns = (); - for $column (split (/\s*\@tab\s*/, $1)) { - # @strong{...} is used a @headitem work-alike - $column =~ s/^\@strong\{(.*)\}$/$1/; - push @columns, $column; - } - $_ = "\n=item ".join (" : ", @columns)."\n"; - }; - - /^\@itemx?\s*(.+)?$/ and do { - if (defined $1) { - # Entity escapes prevent munging by the <> processing below. - $_ = "\n=item $ic\<$1\>\n"; - } else { - $_ = "\n=item $ic\n"; - $ic =~ y/A-Ya-y/B-Zb-z/; - $ic =~ s/(\d+)/$1 + 1/eg; - } - }; - - $section .= $shift.$_."\n"; -} -# End of current file. -close($inf); -$inf = pop @instack; -} - -die "No filename or title\n" unless defined $fn && defined $tl; - -print "=encoding $encoding\n\n" if defined $encoding; - -$sects{NAME} = "$fn \- $tl\n"; -$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES}; - -for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES - BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) { - if(exists $sects{$sect}) { - $head = $sect; - $head =~ s/SEEALSO/SEE ALSO/; - print "=head1 $head\n\n"; - print scalar unmunge ($sects{$sect}); - print "\n"; - } -} - -sub usage -{ - die "usage: $0 [-D toggle...] [infile [outfile]]\n"; -} - -sub postprocess -{ - local $_ = $_[0]; - - # @value{foo} is replaced by whatever 'foo' is defined as. - while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) { - if (! exists $defs{$2}) { - print STDERR "Option $2 not defined\n"; - s/\Q$1\E//; - } else { - $value = $defs{$2}; - s/\Q$1\E/$value/; - } - } - - # Formatting commands. - # Temporary escape for @r. - s/\@r\{([^\}]*)\}/R<$1>/g; - s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g; - s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g; - s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g; - s/\@sc\{([^\}]*)\}/\U$1/g; - s/\@file\{([^\}]*)\}/F<$1>/g; - s/\@w\{([^\}]*)\}/S<$1>/g; - s/\@(?:dmn|math)\{([^\}]*)\}/$1/g; - - # keep references of the form @ref{...}, print them bold - s/\@(?:ref)\{([^\}]*)\}/B<$1>/g; - - # Change double single quotes to double quotes. - s/''/"/g; - s/``/"/g; - - # Cross references are thrown away, as are @noindent and @refill. - # (@noindent is impossible in .pod, and @refill is unnecessary.) - # @* is also impossible in .pod; we discard it and any newline that - # follows it. Similarly, our macro @gol must be discarded. - - s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g; - s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g; - s/;\s+\@pxref\{(?:[^\}]*)\}//g; - s/\@noindent\s*//g; - s/\@refill//g; - s/\@gol//g; - s/\@\*\s*\n?//g; - - # Anchors are thrown away - s/\@anchor\{(?:[^\}]*)\}//g; - - # @uref can take one, two, or three arguments, with different - # semantics each time. @url and @email are just like @uref with - # one argument, for our purposes. - s/\@(?:uref|url|email)\{([^\},]*)\}/<B<$1>>/g; - s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g; - s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g; - - # Un-escape <> at this point. - s/</</g; - s/>/>/g; - - # Now un-nest all B<>, I<>, R<>. Theoretically we could have - # indefinitely deep nesting; in practice, one level suffices. - 1 while s/([BIR])<([^<>]*)([BIR])<([^<>]*)>/$1<$2>$3<$4>$1</g; - - # Replace R<...> with bare ...; eliminate empty markup, B<>; - # shift white space at the ends of [BI]<...> expressions outside - # the expression. - s/R<([^<>]*)>/$1/g; - s/[BI]<>//g; - s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g; - s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g; - - # Extract footnotes. This has to be done after all other - # processing because otherwise the regexp will choke on formatting - # inside @footnote. - while (/\@footnote/g) { - s/\@footnote\{([^\}]+)\}/[$fnno]/; - add_footnote($1, $fnno); - $fnno++; - } - - return $_; -} - -sub unmunge -{ - # Replace escaped symbols with their equivalents. - local $_ = $_[0]; - - s/</E<lt>/g; - s/>/E<gt>/g; - s/{/\{/g; - s/}/\}/g; - s/&at;/\@/g; - s/&/&/g; - return $_; -} - -sub add_footnote -{ - unless (exists $sects{FOOTNOTES}) { - $sects{FOOTNOTES} = "\n=over 4\n\n"; - } - - $sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++; - $sects{FOOTNOTES} .= $_[0]; - $sects{FOOTNOTES} .= "\n\n"; -} - -# stolen from Symbol.pm -{ - my $genseq = 0; - sub gensym - { - my $name = "GEN" . $genseq++; - my $ref = \*{$name}; - delete $::{$name}; - return $ref; - } -} diff --git a/qemu/scripts/tracetool.py b/qemu/scripts/tracetool.py deleted file mode 100755 index 7b82959e8..000000000 --- a/qemu/scripts/tracetool.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Command-line wrapper for the tracetool machinery. -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -import sys -import getopt - -from tracetool import error_write, out -import tracetool.backend -import tracetool.format - - -_SCRIPT = "" - -def error_opt(msg = None): - if msg is not None: - error_write("Error: " + msg + "\n") - - backend_descr = "\n".join([ " %-15s %s" % (n, d) - for n,d in tracetool.backend.get_list() ]) - format_descr = "\n".join([ " %-15s %s" % (n, d) - for n,d in tracetool.format.get_list() ]) - error_write("""\ -Usage: %(script)s --format=<format> --backends=<backends> [<options>] - -Backends: -%(backends)s - -Formats: -%(formats)s - -Options: - --help This help message. - --list-backends Print list of available backends. - --check-backends Check if the given backend is valid. - --binary <path> Full path to QEMU binary. - --target-type <type> QEMU emulator target type ('system' or 'user'). - --target-name <name> QEMU emulator target name. - --probe-prefix <prefix> Prefix for dtrace probe names - (default: qemu-<target-type>-<target-name>).\ -""" % { - "script" : _SCRIPT, - "backends" : backend_descr, - "formats" : format_descr, - }) - - if msg is None: - sys.exit(0) - else: - sys.exit(1) - - -def main(args): - global _SCRIPT - _SCRIPT = args[0] - - long_opts = ["backends=", "format=", "help", "list-backends", - "check-backends"] - long_opts += ["binary=", "target-type=", "target-name=", "probe-prefix="] - - try: - opts, args = getopt.getopt(args[1:], "", long_opts) - except getopt.GetoptError as err: - error_opt(str(err)) - - check_backends = False - arg_backends = [] - arg_format = "" - binary = None - target_type = None - target_name = None - probe_prefix = None - for opt, arg in opts: - if opt == "--help": - error_opt() - - elif opt == "--backends": - arg_backends = arg.split(",") - elif opt == "--format": - arg_format = arg - - elif opt == "--list-backends": - public_backends = tracetool.backend.get_list(only_public = True) - out(", ".join([ b for b,_ in public_backends ])) - sys.exit(0) - elif opt == "--check-backends": - check_backends = True - - elif opt == "--binary": - binary = arg - elif opt == '--target-type': - target_type = arg - elif opt == '--target-name': - target_name = arg - elif opt == '--probe-prefix': - probe_prefix = arg - - else: - error_opt("unhandled option: %s" % opt) - - if len(arg_backends) == 0: - error_opt("no backends specified") - - if check_backends: - for backend in arg_backends: - if not tracetool.backend.exists(backend): - sys.exit(1) - sys.exit(0) - - if arg_format == "stap": - if binary is None: - error_opt("--binary is required for SystemTAP tapset generator") - if probe_prefix is None and target_type is None: - error_opt("--target-type is required for SystemTAP tapset generator") - if probe_prefix is None and target_name is None: - error_opt("--target-name is required for SystemTAP tapset generator") - - if probe_prefix is None: - probe_prefix = ".".join(["qemu", target_type, target_name]) - - try: - tracetool.generate(sys.stdin, arg_format, arg_backends, - binary=binary, probe_prefix=probe_prefix) - except tracetool.TracetoolError as e: - error_opt(str(e)) - -if __name__ == "__main__": - main(sys.argv) diff --git a/qemu/scripts/tracetool/__init__.py b/qemu/scripts/tracetool/__init__.py deleted file mode 100644 index be24039c5..000000000 --- a/qemu/scripts/tracetool/__init__.py +++ /dev/null @@ -1,394 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Machinery for generating tracing-related intermediate files. -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -import re -import sys -import weakref - -import tracetool.format -import tracetool.backend -import tracetool.transform - - -def error_write(*lines): - """Write a set of error lines.""" - sys.stderr.writelines("\n".join(lines) + "\n") - -def error(*lines): - """Write a set of error lines and exit.""" - error_write(*lines) - sys.exit(1) - - -def out(*lines, **kwargs): - """Write a set of output lines. - - You can use kwargs as a shorthand for mapping variables when formating all - the strings in lines. - """ - lines = [ l % kwargs for l in lines ] - sys.stdout.writelines("\n".join(lines) + "\n") - - -class Arguments: - """Event arguments description.""" - - def __init__(self, args): - """ - Parameters - ---------- - args : - List of (type, name) tuples or Arguments objects. - """ - self._args = [] - for arg in args: - if isinstance(arg, Arguments): - self._args.extend(arg._args) - else: - self._args.append(arg) - - def copy(self): - """Create a new copy.""" - return Arguments(list(self._args)) - - @staticmethod - def build(arg_str): - """Build and Arguments instance from an argument string. - - Parameters - ---------- - arg_str : str - String describing the event arguments. - """ - res = [] - for arg in arg_str.split(","): - arg = arg.strip() - if arg == 'void': - continue - - if '*' in arg: - arg_type, identifier = arg.rsplit('*', 1) - arg_type += '*' - identifier = identifier.strip() - else: - arg_type, identifier = arg.rsplit(None, 1) - - res.append((arg_type, identifier)) - return Arguments(res) - - def __getitem__(self, index): - if isinstance(index, slice): - return Arguments(self._args[index]) - else: - return self._args[index] - - def __iter__(self): - """Iterate over the (type, name) pairs.""" - return iter(self._args) - - def __len__(self): - """Number of arguments.""" - return len(self._args) - - def __str__(self): - """String suitable for declaring function arguments.""" - if len(self._args) == 0: - return "void" - else: - return ", ".join([ " ".join([t, n]) for t,n in self._args ]) - - def __repr__(self): - """Evaluable string representation for this object.""" - return "Arguments(\"%s\")" % str(self) - - def names(self): - """List of argument names.""" - return [ name for _, name in self._args ] - - def types(self): - """List of argument types.""" - return [ type_ for type_, _ in self._args ] - - def casted(self): - """List of argument names casted to their type.""" - return ["(%s)%s" % (type_, name) for type_, name in self._args] - - def transform(self, *trans): - """Return a new Arguments instance with transformed types. - - The types in the resulting Arguments instance are transformed according - to tracetool.transform.transform_type. - """ - res = [] - for type_, name in self._args: - res.append((tracetool.transform.transform_type(type_, *trans), - name)) - return Arguments(res) - - -class Event(object): - """Event description. - - Attributes - ---------- - name : str - The event name. - fmt : str - The event format string. - properties : set(str) - Properties of the event. - args : Arguments - The event arguments. - - """ - - _CRE = re.compile("((?P<props>[\w\s]+)\s+)?" - "(?P<name>\w+)" - "\((?P<args>[^)]*)\)" - "\s*" - "(?:(?:(?P<fmt_trans>\".+),)?\s*(?P<fmt>\".+))?" - "\s*") - - _VALID_PROPS = set(["disable", "tcg", "tcg-trans", "tcg-exec", "vcpu"]) - - def __init__(self, name, props, fmt, args, orig=None, - event_trans=None, event_exec=None): - """ - Parameters - ---------- - name : string - Event name. - props : list of str - Property names. - fmt : str, list of str - Event printing format (or formats). - args : Arguments - Event arguments. - orig : Event or None - Original Event before transformation/generation. - event_trans : Event or None - Generated translation-time event ("tcg" property). - event_exec : Event or None - Generated execution-time event ("tcg" property). - - """ - self.name = name - self.properties = props - self.fmt = fmt - self.args = args - self.event_trans = event_trans - self.event_exec = event_exec - - if orig is None: - self.original = weakref.ref(self) - else: - self.original = orig - - unknown_props = set(self.properties) - self._VALID_PROPS - if len(unknown_props) > 0: - raise ValueError("Unknown properties: %s" - % ", ".join(unknown_props)) - assert isinstance(self.fmt, str) or len(self.fmt) == 2 - - def copy(self): - """Create a new copy.""" - return Event(self.name, list(self.properties), self.fmt, - self.args.copy(), self, self.event_trans, self.event_exec) - - @staticmethod - def build(line_str): - """Build an Event instance from a string. - - Parameters - ---------- - line_str : str - Line describing the event. - """ - m = Event._CRE.match(line_str) - assert m is not None - groups = m.groupdict('') - - name = groups["name"] - props = groups["props"].split() - fmt = groups["fmt"] - fmt_trans = groups["fmt_trans"] - if len(fmt_trans) > 0: - fmt = [fmt_trans, fmt] - args = Arguments.build(groups["args"]) - - if "tcg-trans" in props: - raise ValueError("Invalid property 'tcg-trans'") - if "tcg-exec" in props: - raise ValueError("Invalid property 'tcg-exec'") - if "tcg" not in props and not isinstance(fmt, str): - raise ValueError("Only events with 'tcg' property can have two formats") - if "tcg" in props and isinstance(fmt, str): - raise ValueError("Events with 'tcg' property must have two formats") - - event = Event(name, props, fmt, args) - - # add implicit arguments when using the 'vcpu' property - import tracetool.vcpu - event = tracetool.vcpu.transform_event(event) - - return event - - def __repr__(self): - """Evaluable string representation for this object.""" - if isinstance(self.fmt, str): - fmt = self.fmt - else: - fmt = "%s, %s" % (self.fmt[0], self.fmt[1]) - return "Event('%s %s(%s) %s')" % (" ".join(self.properties), - self.name, - self.args, - fmt) - - _FMT = re.compile("(%[\d\.]*\w+|%.*PRI\S+)") - - def formats(self): - """List of argument print formats.""" - assert not isinstance(self.fmt, list) - return self._FMT.findall(self.fmt) - - QEMU_TRACE = "trace_%(name)s" - QEMU_TRACE_TCG = QEMU_TRACE + "_tcg" - - def api(self, fmt=None): - if fmt is None: - fmt = Event.QEMU_TRACE - return fmt % {"name": self.name} - - def transform(self, *trans): - """Return a new Event with transformed Arguments.""" - return Event(self.name, - list(self.properties), - self.fmt, - self.args.transform(*trans), - self) - - -def _read_events(fobj): - events = [] - for line in fobj: - if not line.strip(): - continue - if line.lstrip().startswith('#'): - continue - - event = Event.build(line) - - # transform TCG-enabled events - if "tcg" not in event.properties: - events.append(event) - else: - event_trans = event.copy() - event_trans.name += "_trans" - event_trans.properties += ["tcg-trans"] - event_trans.fmt = event.fmt[0] - # ignore TCG arguments - args_trans = [] - for atrans, aorig in zip( - event_trans.transform(tracetool.transform.TCG_2_HOST).args, - event.args): - if atrans == aorig: - args_trans.append(atrans) - event_trans.args = Arguments(args_trans) - - event_exec = event.copy() - event_exec.name += "_exec" - event_exec.properties += ["tcg-exec"] - event_exec.fmt = event.fmt[1] - event_exec.args = event_exec.args.transform(tracetool.transform.TCG_2_HOST) - - new_event = [event_trans, event_exec] - event.event_trans, event.event_exec = new_event - - events.extend(new_event) - - return events - - -class TracetoolError (Exception): - """Exception for calls to generate.""" - pass - - -def try_import(mod_name, attr_name=None, attr_default=None): - """Try to import a module and get an attribute from it. - - Parameters - ---------- - mod_name : str - Module name. - attr_name : str, optional - Name of an attribute in the module. - attr_default : optional - Default value if the attribute does not exist in the module. - - Returns - ------- - A pair indicating whether the module could be imported and the module or - object or attribute value. - """ - try: - module = __import__(mod_name, globals(), locals(), ["__package__"]) - if attr_name is None: - return True, module - return True, getattr(module, str(attr_name), attr_default) - except ImportError: - return False, None - - -def generate(fevents, format, backends, - binary=None, probe_prefix=None): - """Generate the output for the given (format, backends) pair. - - Parameters - ---------- - fevents : file - Event description file. - format : str - Output format name. - backends : list - Output backend names. - binary : str or None - See tracetool.backend.dtrace.BINARY. - probe_prefix : str or None - See tracetool.backend.dtrace.PROBEPREFIX. - """ - # fix strange python error (UnboundLocalError tracetool) - import tracetool - - format = str(format) - if len(format) is 0: - raise TracetoolError("format not set") - if not tracetool.format.exists(format): - raise TracetoolError("unknown format: %s" % format) - - if len(backends) is 0: - raise TracetoolError("no backends specified") - for backend in backends: - if not tracetool.backend.exists(backend): - raise TracetoolError("unknown backend: %s" % backend) - backend = tracetool.backend.Wrapper(backends, format) - - import tracetool.backend.dtrace - tracetool.backend.dtrace.BINARY = binary - tracetool.backend.dtrace.PROBEPREFIX = probe_prefix - - events = _read_events(fevents) - - tracetool.format.generate(events, format, backend) diff --git a/qemu/scripts/tracetool/backend/__init__.py b/qemu/scripts/tracetool/backend/__init__.py deleted file mode 100644 index d4b6dab9c..000000000 --- a/qemu/scripts/tracetool/backend/__init__.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Backend management. - - -Creating new backends ---------------------- - -A new backend named 'foo-bar' corresponds to Python module -'tracetool/backend/foo_bar.py'. - -A backend module should provide a docstring, whose first non-empty line will be -considered its short description. - -All backends must generate their contents through the 'tracetool.out' routine. - - -Backend attributes ------------------- - -========= ==================================================================== -Attribute Description -========= ==================================================================== -PUBLIC If exists and is set to 'True', the backend is considered "public". -========= ==================================================================== - - -Backend functions ------------------ - -All the following functions are optional, and no output will be generated if -they do not exist. - -=============================== ============================================== -Function Description -=============================== ============================================== -generate_<format>_begin(events) Generate backend- and format-specific file - header contents. -generate_<format>_end(events) Generate backend- and format-specific file - footer contents. -generate_<format>(event) Generate backend- and format-specific contents - for the given event. -=============================== ============================================== - -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -import os - -import tracetool - - -def get_list(only_public = False): - """Get a list of (name, description) pairs.""" - res = [("nop", "Tracing disabled.")] - modnames = [] - for filename in os.listdir(tracetool.backend.__path__[0]): - if filename.endswith('.py') and filename != '__init__.py': - modnames.append(filename.rsplit('.', 1)[0]) - for modname in sorted(modnames): - module = tracetool.try_import("tracetool.backend." + modname) - - # just in case; should never fail unless non-module files are put there - if not module[0]: - continue - module = module[1] - - public = getattr(module, "PUBLIC", False) - if only_public and not public: - continue - - doc = module.__doc__ - if doc is None: - doc = "" - doc = doc.strip().split("\n")[0] - - name = modname.replace("_", "-") - res.append((name, doc)) - return res - - -def exists(name): - """Return whether the given backend exists.""" - if len(name) == 0: - return False - if name == "nop": - return True - name = name.replace("-", "_") - return tracetool.try_import("tracetool.backend." + name)[1] - - -class Wrapper: - def __init__(self, backends, format): - self._backends = [backend.replace("-", "_") for backend in backends] - self._format = format.replace("-", "_") - for backend in self._backends: - assert exists(backend) - assert tracetool.format.exists(self._format) - - def _run_function(self, name, *args, **kwargs): - for backend in self._backends: - func = tracetool.try_import("tracetool.backend." + backend, - name % self._format, None)[1] - if func is not None: - func(*args, **kwargs) - - def generate_begin(self, events): - self._run_function("generate_%s_begin", events) - - def generate(self, event): - self._run_function("generate_%s", event) - - def generate_end(self, events): - self._run_function("generate_%s_end", events) diff --git a/qemu/scripts/tracetool/backend/dtrace.py b/qemu/scripts/tracetool/backend/dtrace.py deleted file mode 100644 index fabfe9988..000000000 --- a/qemu/scripts/tracetool/backend/dtrace.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -DTrace/SystemTAP backend. -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out - - -PUBLIC = True - - -PROBEPREFIX = None - -def probeprefix(): - if PROBEPREFIX is None: - raise ValueError("you must set PROBEPREFIX") - return PROBEPREFIX - - -BINARY = None - -def binary(): - if BINARY is None: - raise ValueError("you must set BINARY") - return BINARY - - -def generate_h_begin(events): - out('#include "trace/generated-tracers-dtrace.h"', - '') - - -def generate_h(event): - out(' QEMU_%(uppername)s(%(argnames)s);', - uppername=event.name.upper(), - argnames=", ".join(event.args.names())) diff --git a/qemu/scripts/tracetool/backend/ftrace.py b/qemu/scripts/tracetool/backend/ftrace.py deleted file mode 100644 index d798c7134..000000000 --- a/qemu/scripts/tracetool/backend/ftrace.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Ftrace built-in backend. -""" - -__author__ = "Eiichi Tsukata <eiichi.tsukata.xh@hitachi.com>" -__copyright__ = "Copyright (C) 2013 Hitachi, Ltd." -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@redhat.com" - - -from tracetool import out - - -PUBLIC = True - - -def generate_h_begin(events): - out('#include "trace/ftrace.h"', - '#include "trace/control.h"', - '') - - -def generate_h(event): - argnames = ", ".join(event.args.names()) - if len(event.args) > 0: - argnames = ", " + argnames - - out(' {', - ' char ftrace_buf[MAX_TRACE_STRLEN];', - ' int unused __attribute__ ((unused));', - ' int trlen;', - ' if (trace_event_get_state(%(event_id)s)) {', - ' trlen = snprintf(ftrace_buf, MAX_TRACE_STRLEN,', - ' "%(name)s " %(fmt)s "\\n" %(argnames)s);', - ' trlen = MIN(trlen, MAX_TRACE_STRLEN - 1);', - ' unused = write(trace_marker_fd, ftrace_buf, trlen);', - ' }', - ' }', - name=event.name, - args=event.args, - event_id="TRACE_" + event.name.upper(), - fmt=event.fmt.rstrip("\n"), - argnames=argnames) diff --git a/qemu/scripts/tracetool/backend/log.py b/qemu/scripts/tracetool/backend/log.py deleted file mode 100644 index e409b7326..000000000 --- a/qemu/scripts/tracetool/backend/log.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Stderr built-in backend. -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out - - -PUBLIC = True - - -def generate_h_begin(events): - out('#include "trace/control.h"', - '#include "qemu/log.h"', - '') - - -def generate_h(event): - argnames = ", ".join(event.args.names()) - if len(event.args) > 0: - argnames = ", " + argnames - - out(' if (trace_event_get_state(%(event_id)s)) {', - ' struct timeval _now;', - ' gettimeofday(&_now, NULL);', - ' qemu_log_mask(LOG_TRACE, "%%d@%%zd.%%06zd:%(name)s " %(fmt)s "\\n",', - ' getpid(),', - ' (size_t)_now.tv_sec, (size_t)_now.tv_usec', - ' %(argnames)s);', - ' }', - event_id="TRACE_" + event.name.upper(), - name=event.name, - fmt=event.fmt.rstrip("\n"), - argnames=argnames) diff --git a/qemu/scripts/tracetool/backend/simple.py b/qemu/scripts/tracetool/backend/simple.py deleted file mode 100644 index 3246c2001..000000000 --- a/qemu/scripts/tracetool/backend/simple.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Simple built-in backend. -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out - - -PUBLIC = True - - -def is_string(arg): - strtype = ('const char*', 'char*', 'const char *', 'char *') - if arg.lstrip().startswith(strtype): - return True - else: - return False - - -def generate_h_begin(events): - for event in events: - out('void _simple_%(api)s(%(args)s);', - api=event.api(), - args=event.args) - out('') - - -def generate_h(event): - out(' _simple_%(api)s(%(args)s);', - api=event.api(), - args=", ".join(event.args.names())) - - -def generate_c_begin(events): - out('#include "qemu/osdep.h"', - '#include "trace.h"', - '#include "trace/control.h"', - '#include "trace/simple.h"', - '') - - -def generate_c(event): - out('void _simple_%(api)s(%(args)s)', - '{', - ' TraceBufferRecord rec;', - api=event.api(), - args=event.args) - sizes = [] - for type_, name in event.args: - if is_string(type_): - out(' size_t arg%(name)s_len = %(name)s ? MIN(strlen(%(name)s), MAX_TRACE_STRLEN) : 0;', - name=name) - strsizeinfo = "4 + arg%s_len" % name - sizes.append(strsizeinfo) - else: - sizes.append("8") - sizestr = " + ".join(sizes) - if len(event.args) == 0: - sizestr = '0' - - - out('', - ' if (!trace_event_get_state(%(event_id)s)) {', - ' return;', - ' }', - '', - ' if (trace_record_start(&rec, %(event_id)s, %(size_str)s)) {', - ' return; /* Trace Buffer Full, Event Dropped ! */', - ' }', - event_id='TRACE_' + event.name.upper(), - size_str=sizestr) - - if len(event.args) > 0: - for type_, name in event.args: - # string - if is_string(type_): - out(' trace_record_write_str(&rec, %(name)s, arg%(name)s_len);', - name=name) - # pointer var (not string) - elif type_.endswith('*'): - out(' trace_record_write_u64(&rec, (uintptr_t)(uint64_t *)%(name)s);', - name=name) - # primitive data type - else: - out(' trace_record_write_u64(&rec, (uint64_t)%(name)s);', - name=name) - - out(' trace_record_finish(&rec);', - '}', - '') diff --git a/qemu/scripts/tracetool/backend/ust.py b/qemu/scripts/tracetool/backend/ust.py deleted file mode 100644 index 2f8f44abd..000000000 --- a/qemu/scripts/tracetool/backend/ust.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -LTTng User Space Tracing backend. -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out - - -PUBLIC = True - - -def generate_h_begin(events): - out('#include <lttng/tracepoint.h>', - '#include "trace/generated-ust-provider.h"', - '') - - -def generate_h(event): - argnames = ", ".join(event.args.names()) - if len(event.args) > 0: - argnames = ", " + argnames - - out(' tracepoint(qemu, %(name)s%(tp_args)s);', - name=event.name, - tp_args=argnames) diff --git a/qemu/scripts/tracetool/format/__init__.py b/qemu/scripts/tracetool/format/__init__.py deleted file mode 100644 index 812570ff6..000000000 --- a/qemu/scripts/tracetool/format/__init__.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Format management. - - -Creating new formats --------------------- - -A new format named 'foo-bar' corresponds to Python module -'tracetool/format/foo_bar.py'. - -A format module should provide a docstring, whose first non-empty line will be -considered its short description. - -All formats must generate their contents through the 'tracetool.out' routine. - - -Format functions ----------------- - -======== ================================================================== -Function Description -======== ================================================================== -generate Called to generate a format-specific file. -======== ================================================================== - -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -import os - -import tracetool - - -def get_list(): - """Get a list of (name, description) pairs.""" - res = [] - modnames = [] - for filename in os.listdir(tracetool.format.__path__[0]): - if filename.endswith('.py') and filename != '__init__.py': - modnames.append(filename.rsplit('.', 1)[0]) - for modname in sorted(modnames): - module = tracetool.try_import("tracetool.format." + modname) - - # just in case; should never fail unless non-module files are put there - if not module[0]: - continue - module = module[1] - - doc = module.__doc__ - if doc is None: - doc = "" - doc = doc.strip().split("\n")[0] - - name = modname.replace("_", "-") - res.append((name, doc)) - return res - - -def exists(name): - """Return whether the given format exists.""" - if len(name) == 0: - return False - name = name.replace("-", "_") - return tracetool.try_import("tracetool.format." + name)[1] - - -def generate(events, format, backend): - if not exists(format): - raise ValueError("unknown format: %s" % format) - format = format.replace("-", "_") - func = tracetool.try_import("tracetool.format." + format, - "generate")[1] - if func is None: - raise AttributeError("format has no 'generate': %s" % format) - func(events, backend) diff --git a/qemu/scripts/tracetool/format/c.py b/qemu/scripts/tracetool/format/c.py deleted file mode 100644 index 699598fb0..000000000 --- a/qemu/scripts/tracetool/format/c.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -trace/generated-tracers.c -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out - - -def generate(events, backend): - events = [e for e in events - if "disable" not in e.properties] - - out('/* This file is autogenerated by tracetool, do not edit. */', - '') - backend.generate_begin(events) - for event in events: - backend.generate(event) - backend.generate_end(events) diff --git a/qemu/scripts/tracetool/format/d.py b/qemu/scripts/tracetool/format/d.py deleted file mode 100644 index c77d5b7ab..000000000 --- a/qemu/scripts/tracetool/format/d.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -trace/generated-tracers.dtrace (DTrace only). -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out - - -# Reserved keywords from -# https://wikis.oracle.com/display/DTrace/Types,+Operators+and+Expressions -RESERVED_WORDS = ( - 'auto', 'goto', 'sizeof', 'break', 'if', 'static', 'case', 'import', - 'string', 'char', 'inline', 'stringof', 'const', 'int', 'struct', - 'continue', 'long', 'switch', 'counter', 'offsetof', 'this', - 'default', 'probe', 'translator', 'do', 'provider', 'typedef', - 'double', 'register', 'union', 'else', 'restrict', 'unsigned', - 'enum', 'return', 'void', 'extern', 'self', 'volatile', 'float', - 'short', 'while', 'for', 'signed', 'xlate', -) - - -def generate(events, backend): - events = [e for e in events - if "disable" not in e.properties] - - out('/* This file is autogenerated by tracetool, do not edit. */' - '', - 'provider qemu {') - - for e in events: - args = [] - for type_, name in e.args: - if name in RESERVED_WORDS: - name += '_' - args.append(type_ + ' ' + name) - - # Define prototype for probe arguments - out('', - 'probe %(name)s(%(args)s);', - name=e.name, - args=','.join(args)) - - out('', - '};') diff --git a/qemu/scripts/tracetool/format/events_c.py b/qemu/scripts/tracetool/format/events_c.py deleted file mode 100644 index 1cc6a49a7..000000000 --- a/qemu/scripts/tracetool/format/events_c.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -trace/generated-events.c -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out - - -def generate(events, backend): - out('/* This file is autogenerated by tracetool, do not edit. */', - '', - '#include "qemu/osdep.h"', - '#include "trace.h"', - '#include "trace/generated-events.h"', - '#include "trace/control.h"', - '') - - out('TraceEvent trace_events[TRACE_EVENT_COUNT] = {') - - for e in events: - out(' { .id = %(id)s, .name = \"%(name)s\", .sstate = %(sstate)s },', - id = "TRACE_" + e.name.upper(), - name = e.name, - sstate = "TRACE_%s_ENABLED" % e.name.upper()) - - out('};', - '') diff --git a/qemu/scripts/tracetool/format/events_h.py b/qemu/scripts/tracetool/format/events_h.py deleted file mode 100644 index 4529263e0..000000000 --- a/qemu/scripts/tracetool/format/events_h.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -trace/generated-events.h -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out - - -def generate(events, backend): - out('/* This file is autogenerated by tracetool, do not edit. */', - '', - '#ifndef TRACE__GENERATED_EVENTS_H', - '#define TRACE__GENERATED_EVENTS_H', - '') - - # event identifiers - out('typedef enum {') - - for e in events: - out(' TRACE_%s,' % e.name.upper()) - - out(' TRACE_EVENT_COUNT', - '} TraceEventID;') - - # static state - for e in events: - if 'disable' in e.properties: - enabled = 0 - else: - enabled = 1 - if "tcg-trans" in e.properties: - # a single define for the two "sub-events" - out('#define TRACE_%(name)s_ENABLED %(enabled)d', - name=e.original.name.upper(), - enabled=enabled) - out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled)) - - out('#include "trace/event-internal.h"', - '', - '#endif /* TRACE__GENERATED_EVENTS_H */') diff --git a/qemu/scripts/tracetool/format/h.py b/qemu/scripts/tracetool/format/h.py deleted file mode 100644 index 083540621..000000000 --- a/qemu/scripts/tracetool/format/h.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -trace/generated-tracers.h -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out - - -def generate(events, backend): - out('/* This file is autogenerated by tracetool, do not edit. */', - '', - '#ifndef TRACE__GENERATED_TRACERS_H', - '#define TRACE__GENERATED_TRACERS_H', - '', - '#include "qemu-common.h"', - '') - - backend.generate_begin(events) - - for e in events: - out('', - 'static inline void %(api)s(%(args)s)', - '{', - api=e.api(), - args=e.args) - - if "disable" not in e.properties: - backend.generate(e) - - out('}') - - backend.generate_end(events) - - out('#endif /* TRACE__GENERATED_TRACERS_H */') diff --git a/qemu/scripts/tracetool/format/simpletrace_stap.py b/qemu/scripts/tracetool/format/simpletrace_stap.py deleted file mode 100644 index 7e44bc181..000000000 --- a/qemu/scripts/tracetool/format/simpletrace_stap.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Generate .stp file that outputs simpletrace binary traces (DTrace with SystemTAP only). -""" - -__author__ = "Stefan Hajnoczi <redhat.com>" -__copyright__ = "Copyright (C) 2014, Red Hat, Inc." -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@redhat.com" - - -from tracetool import out -from tracetool.backend.dtrace import binary, probeprefix -from tracetool.backend.simple import is_string -from tracetool.format.stap import stap_escape - - -def generate(events, backend): - out('/* This file is autogenerated by tracetool, do not edit. */', - '') - - for event_id, e in enumerate(events): - if 'disable' in e.properties: - continue - - out('probe %(probeprefix)s.simpletrace.%(name)s = %(probeprefix)s.%(name)s ?', - '{', - probeprefix=probeprefix(), - name=e.name) - - # Calculate record size - sizes = ['24'] # sizeof(TraceRecord) - for type_, name in e.args: - name = stap_escape(name) - if is_string(type_): - out(' try {', - ' arg%(name)s_str = %(name)s ? user_string_n(%(name)s, 512) : "<null>"', - ' } catch {}', - ' arg%(name)s_len = strlen(arg%(name)s_str)', - name=name) - sizes.append('4 + arg%s_len' % name) - else: - sizes.append('8') - sizestr = ' + '.join(sizes) - - # Generate format string and value pairs for record header and arguments - fields = [('8b', str(event_id)), - ('8b', 'gettimeofday_ns()'), - ('4b', sizestr), - ('4b', 'pid()')] - for type_, name in e.args: - name = stap_escape(name) - if is_string(type_): - fields.extend([('4b', 'arg%s_len' % name), - ('.*s', 'arg%s_len, arg%s_str' % (name, name))]) - else: - fields.append(('8b', name)) - - # Emit the entire record in a single SystemTap printf() - fmt_str = '%'.join(fmt for fmt, _ in fields) - arg_str = ', '.join(arg for _, arg in fields) - out(' printf("%%%(fmt_str)s", %(arg_str)s)', - fmt_str=fmt_str, arg_str=arg_str) - - out('}') - - out() diff --git a/qemu/scripts/tracetool/format/stap.py b/qemu/scripts/tracetool/format/stap.py deleted file mode 100644 index 9e780f1b0..000000000 --- a/qemu/scripts/tracetool/format/stap.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Generate .stp file (DTrace with SystemTAP only). -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out -from tracetool.backend.dtrace import binary, probeprefix - - -# Technically 'self' is not used by systemtap yet, but -# they recommended we keep it in the reserved list anyway -RESERVED_WORDS = ( - 'break', 'catch', 'continue', 'delete', 'else', 'for', - 'foreach', 'function', 'global', 'if', 'in', 'limit', - 'long', 'next', 'probe', 'return', 'self', 'string', - 'try', 'while' - ) - - -def stap_escape(identifier): - # Append underscore to reserved keywords - if identifier in RESERVED_WORDS: - return identifier + '_' - return identifier - - -def generate(events, backend): - events = [e for e in events - if "disable" not in e.properties] - - out('/* This file is autogenerated by tracetool, do not edit. */', - '') - - for e in events: - # Define prototype for probe arguments - out('probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")', - '{', - probeprefix=probeprefix(), - name=e.name, - binary=binary()) - - i = 1 - if len(e.args) > 0: - for name in e.args.names(): - name = stap_escape(name) - out(' %s = $arg%d;' % (name, i)) - i += 1 - - out('}') - - out() diff --git a/qemu/scripts/tracetool/format/tcg_h.py b/qemu/scripts/tracetool/format/tcg_h.py deleted file mode 100644 index e2331f251..000000000 --- a/qemu/scripts/tracetool/format/tcg_h.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Generate .h file for TCG code generation. -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out, Arguments -import tracetool.vcpu - - -def vcpu_transform_args(args): - assert len(args) == 1 - return Arguments([ - args, - # NOTE: this name must be kept in sync with the one in "tcg_h" - # NOTE: Current helper code uses TCGv_env (CPUArchState*) - ("TCGv_env", "__tcg_" + args.names()[0]), - ]) - - -def generate(events, backend): - out('/* This file is autogenerated by tracetool, do not edit. */', - '/* You must include this file after the inclusion of helper.h */', - '', - '#ifndef TRACE__GENERATED_TCG_TRACERS_H', - '#define TRACE__GENERATED_TCG_TRACERS_H', - '', - '#include "trace.h"', - '#include "exec/helper-proto.h"', - '', - ) - - for e in events: - # just keep one of them - if "tcg-trans" not in e.properties: - continue - - out('static inline void %(name_tcg)s(%(args)s)', - '{', - name_tcg=e.original.api(e.QEMU_TRACE_TCG), - args=tracetool.vcpu.transform_args("tcg_h", e.original)) - - if "disable" not in e.properties: - args_trans = e.original.event_trans.args - args_exec = tracetool.vcpu.transform_args( - "tcg_helper_c", e.original.event_exec, "wrapper") - out(' %(name_trans)s(%(argnames_trans)s);', - ' gen_helper_%(name_exec)s(%(argnames_exec)s);', - name_trans=e.original.event_trans.api(e.QEMU_TRACE), - name_exec=e.original.event_exec.api(e.QEMU_TRACE), - argnames_trans=", ".join(args_trans.names()), - argnames_exec=", ".join(args_exec.names())) - - out('}') - - out('', - '#endif /* TRACE__GENERATED_TCG_TRACERS_H */') diff --git a/qemu/scripts/tracetool/format/tcg_helper_c.py b/qemu/scripts/tracetool/format/tcg_helper_c.py deleted file mode 100644 index a089b0bf0..000000000 --- a/qemu/scripts/tracetool/format/tcg_helper_c.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Generate trace/generated-helpers.c. -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import Arguments, out -from tracetool.transform import * -import tracetool.vcpu - - -def vcpu_transform_args(args, mode): - assert len(args) == 1 - # NOTE: this name must be kept in sync with the one in "tcg_h" - args = Arguments([(args.types()[0], "__tcg_" + args.names()[0])]) - if mode == "code": - return Arguments([ - # Does cast from helper requirements to tracing types - ("CPUState *", "ENV_GET_CPU(%s)" % args.names()[0]), - ]) - else: - args = Arguments([ - # NOTE: Current helper code uses TCGv_env (CPUArchState*) - ("CPUArchState *", args.names()[0]), - ]) - if mode == "header": - return args - elif mode == "wrapper": - return args.transform(HOST_2_TCG) - else: - assert False - - -def generate(events, backend): - events = [e for e in events - if "disable" not in e.properties] - - out('/* This file is autogenerated by tracetool, do not edit. */', - '', - '#include "qemu/osdep.h"', - '#include "qemu-common.h"', - '#include "trace.h"', - '#include "exec/helper-proto.h"', - '', - ) - - for e in events: - if "tcg-exec" not in e.properties: - continue - - e_args_api = tracetool.vcpu.transform_args( - "tcg_helper_c", e.original, "header").transform( - HOST_2_TCG_COMPAT, TCG_2_TCG_HELPER_DEF) - e_args_call = tracetool.vcpu.transform_args( - "tcg_helper_c", e, "code") - - out('void %(name_tcg)s(%(args_api)s)', - '{', - ' %(name)s(%(args_call)s);', - '}', - name_tcg="helper_%s_proxy" % e.api(), - name=e.api(), - args_api=e_args_api, - args_call=", ".join(e_args_call.casted()), - ) diff --git a/qemu/scripts/tracetool/format/tcg_helper_h.py b/qemu/scripts/tracetool/format/tcg_helper_h.py deleted file mode 100644 index dc76c15eb..000000000 --- a/qemu/scripts/tracetool/format/tcg_helper_h.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Generate trace/generated-helpers.h. -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out -from tracetool.transform import * -import tracetool.vcpu - - -def generate(events, backend): - events = [e for e in events - if "disable" not in e.properties] - - out('/* This file is autogenerated by tracetool, do not edit. */', - '', - ) - - for e in events: - if "tcg-exec" not in e.properties: - continue - - # TCG helper proxy declaration - fmt = "DEF_HELPER_FLAGS_%(argc)d(%(name)s, %(flags)svoid%(types)s)" - e_args = tracetool.vcpu.transform_args("tcg_helper_c", e.original, "header") - args = e_args.transform(HOST_2_TCG_COMPAT, HOST_2_TCG, - TCG_2_TCG_HELPER_DECL) - types = ", ".join(args.types()) - if types != "": - types = ", " + types - - flags = "TCG_CALL_NO_RWG, " - - out(fmt, - flags=flags, - argc=len(args), - name=e.api() + "_proxy", - types=types, - ) diff --git a/qemu/scripts/tracetool/format/tcg_helper_wrapper_h.py b/qemu/scripts/tracetool/format/tcg_helper_wrapper_h.py deleted file mode 100644 index 020f4422a..000000000 --- a/qemu/scripts/tracetool/format/tcg_helper_wrapper_h.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Generate trace/generated-helpers-wrappers.h. -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out -from tracetool.transform import * -import tracetool.vcpu - - -def generate(events, backend): - events = [e for e in events - if "disable" not in e.properties] - - out('/* This file is autogenerated by tracetool, do not edit. */', - '', - '#define tcg_temp_new_nop(v) (v)', - '#define tcg_temp_free_nop(v)', - '', - ) - - for e in events: - if "tcg-exec" not in e.properties: - continue - - # tracetool.generate always transforms types to host - e_args = tracetool.vcpu.transform_args("tcg_helper_c", e.original, "wrapper") - - # mixed-type to TCG helper bridge - args_tcg_compat = e_args.transform(HOST_2_TCG_COMPAT) - - code_new = [ - "%(tcg_type)s __%(name)s = %(tcg_func)s(%(name)s);" % - {"tcg_type": transform_type(type_, HOST_2_TCG), - "tcg_func": transform_type(type_, HOST_2_TCG_TMP_NEW), - "name": name} - for (type_, name) in args_tcg_compat - ] - - code_free = [ - "%(tcg_func)s(__%(name)s);" % - {"tcg_func": transform_type(type_, HOST_2_TCG_TMP_FREE), - "name": name} - for (type_, name) in args_tcg_compat - ] - - gen_name = "gen_helper_" + e.api() - - out('static inline void %(name)s(%(args)s)', - '{', - ' %(code_new)s', - ' %(proxy_name)s(%(tmp_names)s);', - ' %(code_free)s', - '}', - name=gen_name, - args=e_args, - proxy_name=gen_name + "_proxy", - code_new="\n ".join(code_new), - code_free="\n ".join(code_free), - tmp_names=", ".join(["__%s" % name for _, name in e_args]), - ) diff --git a/qemu/scripts/tracetool/format/ust_events_c.py b/qemu/scripts/tracetool/format/ust_events_c.py deleted file mode 100644 index 9967c7a82..000000000 --- a/qemu/scripts/tracetool/format/ust_events_c.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -trace/generated-ust.c -""" - -__author__ = "Mohamad Gebai <mohamad.gebai@polymtl.ca>" -__copyright__ = "Copyright 2012, Mohamad Gebai <mohamad.gebai@polymtl.ca>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@redhat.com" - - -from tracetool import out - - -def generate(events, backend): - events = [e for e in events - if "disabled" not in e.properties] - - out('/* This file is autogenerated by tracetool, do not edit. */', - '', - '#include "qemu/osdep.h"', - '', - '#define TRACEPOINT_DEFINE', - '#define TRACEPOINT_CREATE_PROBES', - '', - '/* If gcc version 4.7 or older is used, LTTng ust gives a warning when compiling with', - ' -Wredundant-decls.', - ' */', - '#pragma GCC diagnostic ignored "-Wredundant-decls"', - '', - '#include "generated-ust-provider.h"') diff --git a/qemu/scripts/tracetool/format/ust_events_h.py b/qemu/scripts/tracetool/format/ust_events_h.py deleted file mode 100644 index 3e8a7cdf1..000000000 --- a/qemu/scripts/tracetool/format/ust_events_h.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -trace/generated-ust-provider.h -""" - -__author__ = "Mohamad Gebai <mohamad.gebai@polymtl.ca>" -__copyright__ = "Copyright 2012, Mohamad Gebai <mohamad.gebai@polymtl.ca>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@redhat.com" - - -from tracetool import out - - -def generate(events, backend): - events = [e for e in events - if "disabled" not in e.properties] - - out('/* This file is autogenerated by tracetool, do not edit. */', - '', - '#undef TRACEPOINT_PROVIDER', - '#define TRACEPOINT_PROVIDER qemu', - '', - '#undef TRACEPOINT_INCLUDE_FILE', - '#define TRACEPOINT_INCLUDE_FILE ./generated-ust-provider.h', - '', - '#if !defined (TRACE__GENERATED_UST_H) || defined(TRACEPOINT_HEADER_MULTI_READ)', - '#define TRACE__GENERATED_UST_H', - '', - '#include "qemu-common.h"', - '#include <lttng/tracepoint.h>', - '', - '/*', - ' * LTTng ust 2.0 does not allow you to use TP_ARGS(void) for tracepoints', - ' * requiring no arguments. We define these macros introduced in more recent' - ' * versions of LTTng ust as a workaround', - ' */', - '#ifndef _TP_EXPROTO1', - '#define _TP_EXPROTO1(a) void', - '#endif', - '#ifndef _TP_EXDATA_PROTO1', - '#define _TP_EXDATA_PROTO1(a) void *__tp_data', - '#endif', - '#ifndef _TP_EXDATA_VAR1', - '#define _TP_EXDATA_VAR1(a) __tp_data', - '#endif', - '#ifndef _TP_EXVAR1', - '#define _TP_EXVAR1(a)', - '#endif', - '') - - for e in events: - if len(e.args) > 0: - out('TRACEPOINT_EVENT(', - ' qemu,', - ' %(name)s,', - ' TP_ARGS(%(args)s),', - ' TP_FIELDS(', - name=e.name, - args=", ".join(", ".join(i) for i in e.args)) - - types = e.args.types() - names = e.args.names() - fmts = e.formats() - for t,n,f in zip(types, names, fmts): - if ('char *' in t) or ('char*' in t): - out(' ctf_string(' + n + ', ' + n + ')') - elif ("%p" in f) or ("x" in f) or ("PRIx" in f): - out(' ctf_integer_hex('+ t + ', ' + n + ', ' + n + ')') - elif ("ptr" in t) or ("*" in t): - out(' ctf_integer_hex('+ t + ', ' + n + ', ' + n + ')') - elif ('int' in t) or ('long' in t) or ('unsigned' in t) or ('size_t' in t): - out(' ctf_integer(' + t + ', ' + n + ', ' + n + ')') - elif ('double' in t) or ('float' in t): - out(' ctf_float(' + t + ', ' + n + ', ' + n + ')') - elif ('void *' in t) or ('void*' in t): - out(' ctf_integer_hex(unsigned long, ' + n + ', ' + n + ')') - - out(' )', - ')', - '') - - else: - out('TRACEPOINT_EVENT(', - ' qemu,', - ' %(name)s,', - ' TP_ARGS(void),', - ' TP_FIELDS()', - ')', - '', - name=e.name) - - out('#endif /* TRACE__GENERATED_UST_H */', - '', - '/* This part must be outside ifdef protection */', - '#include <lttng/tracepoint-event.h>') diff --git a/qemu/scripts/tracetool/transform.py b/qemu/scripts/tracetool/transform.py deleted file mode 100644 index e18b05315..000000000 --- a/qemu/scripts/tracetool/transform.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Type-transformation rules. -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2012-2016, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -def _transform_type(type_, trans): - if isinstance(trans, str): - return trans - elif isinstance(trans, dict): - if type_ in trans: - return _transform_type(type_, trans[type_]) - elif None in trans: - return _transform_type(type_, trans[None]) - else: - return type_ - elif callable(trans): - return trans(type_) - else: - raise ValueError("Invalid type transformation rule: %s" % trans) - - -def transform_type(type_, *trans): - """Return a new type transformed according to the given rules. - - Applies each of the transformation rules in trans in order. - - If an element of trans is a string, return it. - - If an element of trans is a function, call it with type_ as its only - argument. - - If an element of trans is a dict, search type_ in its keys. If type_ is - a key, use the value as a transformation rule for type_. Otherwise, if - None is a key use the value as a transformation rule for type_. - - Otherwise, return type_. - - Parameters - ---------- - type_ : str - Type to transform. - trans : list of function or dict - Type transformation rules. - """ - if len(trans) == 0: - raise ValueError - res = type_ - for t in trans: - res = _transform_type(res, t) - return res - - -################################################## -# tcg -> host - -def _tcg_2_host(type_): - if type_ == "TCGv": - # force a fixed-size type (target-independent) - return "uint64_t" - else: - return type_ - -TCG_2_HOST = { - "TCGv_i32": "uint32_t", - "TCGv_i64": "uint64_t", - "TCGv_ptr": "void *", - None: _tcg_2_host, - } - - -################################################## -# host -> host compatible with tcg sizes - -HOST_2_TCG_COMPAT = { - "uint8_t": "uint32_t", - } - - -################################################## -# host/tcg -> tcg - -def _host_2_tcg(type_): - if type_.startswith("TCGv"): - return type_ - raise ValueError("Don't know how to translate '%s' into a TCG type\n" % type_) - -HOST_2_TCG = { - "uint32_t": "TCGv_i32", - "uint64_t": "TCGv_i64", - "void *" : "TCGv_ptr", - "CPUArchState *": "TCGv_env", - None: _host_2_tcg, - } - - -################################################## -# tcg -> tcg helper definition - -def _tcg_2_helper_def(type_): - if type_ == "TCGv": - return "target_ulong" - else: - return type_ - -TCG_2_TCG_HELPER_DEF = { - "TCGv_i32": "uint32_t", - "TCGv_i64": "uint64_t", - "TCGv_ptr": "void *", - None: _tcg_2_helper_def, - } - - -################################################## -# tcg -> tcg helper declaration - -def _tcg_2_tcg_helper_decl_error(type_): - raise ValueError("Don't know how to translate type '%s' into a TCG helper declaration type\n" % type_) - -TCG_2_TCG_HELPER_DECL = { - "TCGv" : "tl", - "TCGv_ptr": "ptr", - "TCGv_i32": "i32", - "TCGv_i64": "i64", - "TCGv_env": "env", - None: _tcg_2_tcg_helper_decl_error, - } - - -################################################## -# host/tcg -> tcg temporal constant allocation - -def _host_2_tcg_tmp_new(type_): - if type_.startswith("TCGv"): - return "tcg_temp_new_nop" - raise ValueError("Don't know how to translate type '%s' into a TCG temporal allocation" % type_) - -HOST_2_TCG_TMP_NEW = { - "uint32_t": "tcg_const_i32", - "uint64_t": "tcg_const_i64", - "void *" : "tcg_const_ptr", - None: _host_2_tcg_tmp_new, - } - - -################################################## -# host/tcg -> tcg temporal constant deallocation - -def _host_2_tcg_tmp_free(type_): - if type_.startswith("TCGv"): - return "tcg_temp_free_nop" - raise ValueError("Don't know how to translate type '%s' into a TCG temporal deallocation" % type_) - -HOST_2_TCG_TMP_FREE = { - "uint32_t": "tcg_temp_free_i32", - "uint64_t": "tcg_temp_free_i64", - "void *" : "tcg_temp_free_ptr", - None: _host_2_tcg_tmp_free, - } diff --git a/qemu/scripts/tracetool/vcpu.py b/qemu/scripts/tracetool/vcpu.py deleted file mode 100644 index 452c7f589..000000000 --- a/qemu/scripts/tracetool/vcpu.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Generic management for the 'vcpu' property. - -""" - -__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>" -__copyright__ = "Copyright 2016, Lluís Vilanova <vilanova@ac.upc.edu>" -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import Arguments, try_import - - -def transform_event(event): - """Transform event to comply with the 'vcpu' property (if present).""" - if "vcpu" in event.properties: - # events with 'tcg-trans' and 'tcg-exec' are auto-generated from - # already-patched events - assert "tcg-trans" not in event.properties - assert "tcg-exec" not in event.properties - - event.args = Arguments([("CPUState *", "__cpu"), event.args]) - if "tcg" in event.properties: - fmt = "\"cpu=%p \"" - event.fmt = [fmt + event.fmt[0], - fmt + event.fmt[1]] - else: - fmt = "\"cpu=%p \"" - event.fmt = fmt + event.fmt - return event - - -def transform_args(format, event, *args, **kwargs): - """Transforms the arguments to suit the specified format. - - The format module must implement function 'vcpu_args', which receives the - implicit arguments added by the 'vcpu' property, and must return suitable - arguments for the given format. - - The function is only called for events with the 'vcpu' property. - - Parameters - ========== - format : str - Format module name. - event : Event - args, kwargs - Passed to 'vcpu_transform_args'. - - Returns - ======= - Arguments - The transformed arguments, including the non-implicit ones. - - """ - if "vcpu" in event.properties: - ok, func = try_import("tracetool.format." + format, - "vcpu_transform_args") - assert ok - assert func - return Arguments([func(event.args[:1], *args, **kwargs), - event.args[1:]]) - else: - return event.args diff --git a/qemu/scripts/update-linux-headers.sh b/qemu/scripts/update-linux-headers.sh deleted file mode 100755 index f7d62d974..000000000 --- a/qemu/scripts/update-linux-headers.sh +++ /dev/null @@ -1,147 +0,0 @@ -#!/bin/sh -e -# -# Update Linux kernel headers QEMU requires from a specified kernel tree. -# -# Copyright (C) 2011 Siemens AG -# -# Authors: -# Jan Kiszka <jan.kiszka@siemens.com> -# -# This work is licensed under the terms of the GNU GPL version 2. -# See the COPYING file in the top-level directory. - -tmpdir=`mktemp -d` -linux="$1" -output="$2" - -if [ -z "$linux" ] || ! [ -d "$linux" ]; then - cat << EOF -usage: update-kernel-headers.sh LINUX_PATH [OUTPUT_PATH] - -LINUX_PATH Linux kernel directory to obtain the headers from -OUTPUT_PATH output directory, usually the qemu source tree (default: $PWD) -EOF - exit 1 -fi - -if [ -z "$output" ]; then - output="$PWD" -fi - -cp_portable() { - f=$1 - to=$2 - if - grep '#include' "$f" | grep -v -e 'linux/virtio' \ - -e 'linux/types' \ - -e 'stdint' \ - -e 'linux/if_ether' \ - -e 'input-event-codes' \ - -e 'sys/' \ - > /dev/null - then - echo "Unexpected #include in input file $f". - exit 2 - fi - - header=$(basename "$f"); - sed -e 's/__u\([0-9][0-9]*\)/uint\1_t/g' \ - -e 's/__s\([0-9][0-9]*\)/int\1_t/g' \ - -e 's/__le\([0-9][0-9]*\)/uint\1_t/g' \ - -e 's/__be\([0-9][0-9]*\)/uint\1_t/g' \ - -e 's/"\(input-event-codes\.h\)"/"standard-headers\/linux\/\1"/' \ - -e 's/<linux\/\([^>]*\)>/"standard-headers\/linux\/\1"/' \ - -e 's/__bitwise__//' \ - -e 's/__attribute__((packed))/QEMU_PACKED/' \ - -e 's/__inline__/inline/' \ - -e '/sys\/ioctl.h/d' \ - -e 's/SW_MAX/SW_MAX_/' \ - "$f" > "$to/$header"; -} - -# This will pick up non-directories too (eg "Kconfig") but we will -# ignore them in the next loop. -ARCHLIST=$(cd "$linux/arch" && echo *) - -for arch in $ARCHLIST; do - # Discard anything which isn't a KVM-supporting architecture - if ! [ -e "$linux/arch/$arch/include/asm/kvm.h" ] && - ! [ -e "$linux/arch/$arch/include/uapi/asm/kvm.h" ] ; then - continue - fi - - # Blacklist architectures which have KVM headers but are actually dead - if [ "$arch" = "ia64" -o "$arch" = "mips" ]; then - continue - fi - - make -C "$linux" INSTALL_HDR_PATH="$tmpdir" SRCARCH=$arch headers_install - - rm -rf "$output/linux-headers/asm-$arch" - mkdir -p "$output/linux-headers/asm-$arch" - for header in kvm.h kvm_para.h unistd.h; do - cp "$tmpdir/include/asm/$header" "$output/linux-headers/asm-$arch" - done - if [ $arch = powerpc ]; then - cp "$tmpdir/include/asm/epapr_hcalls.h" "$output/linux-headers/asm-powerpc/" - fi - - rm -rf "$output/include/standard-headers/asm-$arch" - mkdir -p "$output/include/standard-headers/asm-$arch" - if [ $arch = s390 ]; then - cp_portable "$tmpdir/include/asm/kvm_virtio.h" "$output/include/standard-headers/asm-s390/" - cp_portable "$tmpdir/include/asm/virtio-ccw.h" "$output/include/standard-headers/asm-s390/" - fi - if [ $arch = x86 ]; then - cp_portable "$tmpdir/include/asm/hyperv.h" "$output/include/standard-headers/asm-x86/" - cp "$tmpdir/include/asm/unistd_32.h" "$output/linux-headers/asm-x86/" - cp "$tmpdir/include/asm/unistd_x32.h" "$output/linux-headers/asm-x86/" - cp "$tmpdir/include/asm/unistd_64.h" "$output/linux-headers/asm-x86/" - fi -done - -rm -rf "$output/linux-headers/linux" -mkdir -p "$output/linux-headers/linux" -for header in kvm.h kvm_para.h vfio.h vhost.h \ - psci.h userfaultfd.h; do - cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux" -done -rm -rf "$output/linux-headers/asm-generic" -mkdir -p "$output/linux-headers/asm-generic" -for header in kvm_para.h; do - cp "$tmpdir/include/asm-generic/$header" "$output/linux-headers/asm-generic" -done -if [ -L "$linux/source" ]; then - cp "$linux/source/COPYING" "$output/linux-headers" -else - cp "$linux/COPYING" "$output/linux-headers" -fi - -cat <<EOF >$output/linux-headers/asm-x86/hyperv.h -#include "standard-headers/asm-x86/hyperv.h" -EOF -cat <<EOF >$output/linux-headers/linux/virtio_config.h -#include "standard-headers/linux/virtio_config.h" -EOF -cat <<EOF >$output/linux-headers/linux/virtio_ring.h -#include "standard-headers/linux/virtio_ring.h" -EOF - -rm -rf "$output/include/standard-headers/linux" -mkdir -p "$output/include/standard-headers/linux" -for i in "$tmpdir"/include/linux/*virtio*.h "$tmpdir/include/linux/input.h" \ - "$tmpdir/include/linux/input-event-codes.h" \ - "$tmpdir/include/linux/pci_regs.h"; do - cp_portable "$i" "$output/include/standard-headers/linux" -done - -cat <<EOF >$output/include/standard-headers/linux/types.h -/* For QEMU all types are already defined via osdep.h, so this - * header does not need to do anything. - */ -EOF -cat <<EOF >$output/include/standard-headers/linux/if_ether.h -#define ETH_ALEN 6 -EOF - -rm -rf "$tmpdir" diff --git a/qemu/scripts/vmstate-static-checker.py b/qemu/scripts/vmstate-static-checker.py deleted file mode 100755 index b5ecaf644..000000000 --- a/qemu/scripts/vmstate-static-checker.py +++ /dev/null @@ -1,425 +0,0 @@ -#!/usr/bin/python -# -# Compares vmstate information stored in JSON format, obtained from -# the -dump-vmstate QEMU command. -# -# Copyright 2014 Amit Shah <amit.shah@redhat.com> -# Copyright 2014 Red Hat, Inc. -# -# 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/>. - -import argparse -import json -import sys - -# Count the number of errors found -taint = 0 - -def bump_taint(): - global taint - - # Ensure we don't wrap around or reset to 0 -- the shell only has - # an 8-bit return value. - if taint < 255: - taint = taint + 1 - - -def check_fields_match(name, s_field, d_field): - if s_field == d_field: - return True - - # Some fields changed names between qemu versions. This list - # is used to whitelist such changes in each section / description. - changed_names = { - 'apic': ['timer', 'timer_expiry'], - 'e1000': ['dev', 'parent_obj'], - 'ehci': ['dev', 'pcidev'], - 'I440FX': ['dev', 'parent_obj'], - 'ich9_ahci': ['card', 'parent_obj'], - 'ich9-ahci': ['ahci', 'ich9_ahci'], - 'ioh3420': ['PCIDevice', 'PCIEDevice'], - 'ioh-3240-express-root-port': ['port.br.dev', - 'parent_obj.parent_obj.parent_obj', - 'port.br.dev.exp.aer_log', - 'parent_obj.parent_obj.parent_obj.exp.aer_log'], - 'cirrus_vga': ['hw_cursor_x', 'vga.hw_cursor_x', - 'hw_cursor_y', 'vga.hw_cursor_y'], - 'lsiscsi': ['dev', 'parent_obj'], - 'mch': ['d', 'parent_obj'], - 'pci_bridge': ['bridge.dev', 'parent_obj', 'bridge.dev.shpc', 'shpc'], - 'pcnet': ['pci_dev', 'parent_obj'], - 'PIIX3': ['pci_irq_levels', 'pci_irq_levels_vmstate'], - 'piix4_pm': ['dev', 'parent_obj', 'pci0_status', - 'acpi_pci_hotplug.acpi_pcihp_pci_status[0x0]', - 'pm1a.sts', 'ar.pm1.evt.sts', 'pm1a.en', 'ar.pm1.evt.en', - 'pm1_cnt.cnt', 'ar.pm1.cnt.cnt', - 'tmr.timer', 'ar.tmr.timer', - 'tmr.overflow_time', 'ar.tmr.overflow_time', - 'gpe', 'ar.gpe'], - 'rtl8139': ['dev', 'parent_obj'], - 'qxl': ['num_surfaces', 'ssd.num_surfaces'], - 'usb-ccid': ['abProtocolDataStructure', 'abProtocolDataStructure.data'], - 'usb-host': ['dev', 'parent_obj'], - 'usb-mouse': ['usb-ptr-queue', 'HIDPointerEventQueue'], - 'usb-tablet': ['usb-ptr-queue', 'HIDPointerEventQueue'], - 'vmware_vga': ['card', 'parent_obj'], - 'vmware_vga_internal': ['depth', 'new_depth'], - 'xhci': ['pci_dev', 'parent_obj'], - 'x3130-upstream': ['PCIDevice', 'PCIEDevice'], - 'xio3130-express-downstream-port': ['port.br.dev', - 'parent_obj.parent_obj.parent_obj', - 'port.br.dev.exp.aer_log', - 'parent_obj.parent_obj.parent_obj.exp.aer_log'], - 'xio3130-downstream': ['PCIDevice', 'PCIEDevice'], - 'xio3130-express-upstream-port': ['br.dev', 'parent_obj.parent_obj', - 'br.dev.exp.aer_log', - 'parent_obj.parent_obj.exp.aer_log'], - } - - if not name in changed_names: - return False - - if s_field in changed_names[name] and d_field in changed_names[name]: - return True - - return False - -def get_changed_sec_name(sec): - # Section names can change -- see commit 292b1634 for an example. - changes = { - "ICH9 LPC": "ICH9-LPC", - "e1000-82540em": "e1000", - } - - for item in changes: - if item == sec: - return changes[item] - if changes[item] == sec: - return item - return "" - -def exists_in_substruct(fields, item): - # Some QEMU versions moved a few fields inside a substruct. This - # kept the on-wire format the same. This function checks if - # something got shifted inside a substruct. For example, the - # change in commit 1f42d22233b4f3d1a2933ff30e8d6a6d9ee2d08f - - if not "Description" in fields: - return False - - if not "Fields" in fields["Description"]: - return False - - substruct_fields = fields["Description"]["Fields"] - - if substruct_fields == []: - return False - - return check_fields_match(fields["Description"]["name"], - substruct_fields[0]["field"], item) - - -def check_fields(src_fields, dest_fields, desc, sec): - # This function checks for all the fields in a section. If some - # fields got embedded into a substruct, this function will also - # attempt to check inside the substruct. - - d_iter = iter(dest_fields) - s_iter = iter(src_fields) - - # Using these lists as stacks to store previous value of s_iter - # and d_iter, so that when time comes to exit out of a substruct, - # we can go back one level up and continue from where we left off. - - s_iter_list = [] - d_iter_list = [] - - advance_src = True - advance_dest = True - unused_count = 0 - - while True: - if advance_src: - try: - s_item = s_iter.next() - except StopIteration: - if s_iter_list == []: - break - - s_iter = s_iter_list.pop() - continue - else: - if unused_count == 0: - # We want to avoid advancing just once -- when entering a - # dest substruct, or when exiting one. - advance_src = True - - if advance_dest: - try: - d_item = d_iter.next() - except StopIteration: - if d_iter_list == []: - # We were not in a substruct - print "Section \"" + sec + "\",", - print "Description " + "\"" + desc + "\":", - print "expected field \"" + s_item["field"] + "\",", - print "while dest has no further fields" - bump_taint() - break - - d_iter = d_iter_list.pop() - advance_src = False - continue - else: - if unused_count == 0: - advance_dest = True - - if unused_count > 0: - if advance_dest == False: - unused_count = unused_count - s_item["size"] - if unused_count == 0: - advance_dest = True - continue - if unused_count < 0: - print "Section \"" + sec + "\",", - print "Description \"" + desc + "\":", - print "unused size mismatch near \"", - print s_item["field"] + "\"" - bump_taint() - break - continue - - if advance_src == False: - unused_count = unused_count - d_item["size"] - if unused_count == 0: - advance_src = True - continue - if unused_count < 0: - print "Section \"" + sec + "\",", - print "Description \"" + desc + "\":", - print "unused size mismatch near \"", - print d_item["field"] + "\"" - bump_taint() - break - continue - - if not check_fields_match(desc, s_item["field"], d_item["field"]): - # Some fields were put in substructs, keeping the - # on-wire format the same, but breaking static tools - # like this one. - - # First, check if dest has a new substruct. - if exists_in_substruct(d_item, s_item["field"]): - # listiterators don't have a prev() function, so we - # have to store our current location, descend into the - # substruct, and ensure we come out as if nothing - # happened when the substruct is over. - # - # Essentially we're opening the substructs that got - # added which didn't change the wire format. - d_iter_list.append(d_iter) - substruct_fields = d_item["Description"]["Fields"] - d_iter = iter(substruct_fields) - advance_src = False - continue - - # Next, check if src has substruct that dest removed - # (can happen in backward migration: 2.0 -> 1.5) - if exists_in_substruct(s_item, d_item["field"]): - s_iter_list.append(s_iter) - substruct_fields = s_item["Description"]["Fields"] - s_iter = iter(substruct_fields) - advance_dest = False - continue - - if s_item["field"] == "unused" or d_item["field"] == "unused": - if s_item["size"] == d_item["size"]: - continue - - if d_item["field"] == "unused": - advance_dest = False - unused_count = d_item["size"] - s_item["size"] - continue - - if s_item["field"] == "unused": - advance_src = False - unused_count = s_item["size"] - d_item["size"] - continue - - print "Section \"" + sec + "\",", - print "Description \"" + desc + "\":", - print "expected field \"" + s_item["field"] + "\",", - print "got \"" + d_item["field"] + "\"; skipping rest" - bump_taint() - break - - check_version(s_item, d_item, sec, desc) - - if not "Description" in s_item: - # Check size of this field only if it's not a VMSTRUCT entry - check_size(s_item, d_item, sec, desc, s_item["field"]) - - check_description_in_list(s_item, d_item, sec, desc) - - -def check_subsections(src_sub, dest_sub, desc, sec): - for s_item in src_sub: - found = False - for d_item in dest_sub: - if s_item["name"] != d_item["name"]: - continue - - found = True - check_descriptions(s_item, d_item, sec) - - if not found: - print "Section \"" + sec + "\", Description \"" + desc + "\":", - print "Subsection \"" + s_item["name"] + "\" not found" - bump_taint() - - -def check_description_in_list(s_item, d_item, sec, desc): - if not "Description" in s_item: - return - - if not "Description" in d_item: - print "Section \"" + sec + "\", Description \"" + desc + "\",", - print "Field \"" + s_item["field"] + "\": missing description" - bump_taint() - return - - check_descriptions(s_item["Description"], d_item["Description"], sec) - - -def check_descriptions(src_desc, dest_desc, sec): - check_version(src_desc, dest_desc, sec, src_desc["name"]) - - if not check_fields_match(sec, src_desc["name"], dest_desc["name"]): - print "Section \"" + sec + "\":", - print "Description \"" + src_desc["name"] + "\"", - print "missing, got \"" + dest_desc["name"] + "\" instead; skipping" - bump_taint() - return - - for f in src_desc: - if not f in dest_desc: - print "Section \"" + sec + "\"", - print "Description \"" + src_desc["name"] + "\":", - print "Entry \"" + f + "\" missing" - bump_taint() - continue - - if f == 'Fields': - check_fields(src_desc[f], dest_desc[f], src_desc["name"], sec) - - if f == 'Subsections': - check_subsections(src_desc[f], dest_desc[f], src_desc["name"], sec) - - -def check_version(s, d, sec, desc=None): - if s["version_id"] > d["version_id"]: - print "Section \"" + sec + "\"", - if desc: - print "Description \"" + desc + "\":", - print "version error:", s["version_id"], ">", d["version_id"] - bump_taint() - - if not "minimum_version_id" in d: - return - - if s["version_id"] < d["minimum_version_id"]: - print "Section \"" + sec + "\"", - if desc: - print "Description \"" + desc + "\":", - print "minimum version error:", s["version_id"], "<", - print d["minimum_version_id"] - bump_taint() - - -def check_size(s, d, sec, desc=None, field=None): - if s["size"] != d["size"]: - print "Section \"" + sec + "\"", - if desc: - print "Description \"" + desc + "\"", - if field: - print "Field \"" + field + "\"", - print "size mismatch:", s["size"], ",", d["size"] - bump_taint() - - -def check_machine_type(s, d): - if s["Name"] != d["Name"]: - print "Warning: checking incompatible machine types:", - print "\"" + s["Name"] + "\", \"" + d["Name"] + "\"" - return - - -def main(): - help_text = "Parse JSON-formatted vmstate dumps from QEMU in files SRC and DEST. Checks whether migration from SRC to DEST QEMU versions would break based on the VMSTATE information contained within the JSON outputs. The JSON output is created from a QEMU invocation with the -dump-vmstate parameter and a filename argument to it. Other parameters to QEMU do not matter, except the -M (machine type) parameter." - - parser = argparse.ArgumentParser(description=help_text) - parser.add_argument('-s', '--src', type=file, required=True, - help='json dump from src qemu') - parser.add_argument('-d', '--dest', type=file, required=True, - help='json dump from dest qemu') - parser.add_argument('--reverse', required=False, default=False, - action='store_true', - help='reverse the direction') - args = parser.parse_args() - - src_data = json.load(args.src) - dest_data = json.load(args.dest) - args.src.close() - args.dest.close() - - if args.reverse: - temp = src_data - src_data = dest_data - dest_data = temp - - for sec in src_data: - dest_sec = sec - if not dest_sec in dest_data: - # Either the section name got changed, or the section - # doesn't exist in dest. - dest_sec = get_changed_sec_name(sec) - if not dest_sec in dest_data: - print "Section \"" + sec + "\" does not exist in dest" - bump_taint() - continue - - s = src_data[sec] - d = dest_data[dest_sec] - - if sec == "vmschkmachine": - check_machine_type(s, d) - continue - - check_version(s, d, sec) - - for entry in s: - if not entry in d: - print "Section \"" + sec + "\": Entry \"" + entry + "\"", - print "missing" - bump_taint() - continue - - if entry == "Description": - check_descriptions(s[entry], d[entry], sec) - - return taint - - -if __name__ == '__main__': - sys.exit(main()) |