diff options
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/acpi_extract.py | 23 | ||||
-rwxr-xr-x | scripts/checkpatch.pl | 8 | ||||
-rwxr-xr-x | scripts/cleanup-trace-events.pl | 2 | ||||
-rwxr-xr-x | scripts/get_maintainer.pl | 28 | ||||
-rwxr-xr-x | scripts/kvm/kvm_stat | 150 | ||||
-rwxr-xr-x | scripts/kvm/vmxcap | 10 | ||||
-rw-r--r-- | scripts/qapi-types.py | 2 | ||||
-rw-r--r-- | scripts/qapi-visit.py | 9 | ||||
-rw-r--r-- | scripts/qapi.py | 8 | ||||
-rwxr-xr-x | scripts/qtest | 5 | ||||
-rwxr-xr-x | scripts/simpletrace.py | 24 | ||||
-rw-r--r-- | scripts/tracetool/__init__.py | 109 | ||||
-rw-r--r-- | scripts/tracetool/backend/__init__.py | 3 | ||||
-rw-r--r-- | scripts/tracetool/format/events_h.py | 5 | ||||
-rw-r--r-- | scripts/tracetool/format/simpletrace_stap.py | 71 | ||||
-rw-r--r-- | scripts/tracetool/format/stap.py | 11 | ||||
-rw-r--r-- | scripts/tracetool/format/tcg_h.py | 57 | ||||
-rw-r--r-- | scripts/tracetool/format/tcg_helper_c.py | 50 | ||||
-rw-r--r-- | scripts/tracetool/format/tcg_helper_h.py | 50 | ||||
-rw-r--r-- | scripts/tracetool/format/tcg_helper_wrapper_h.py | 70 | ||||
-rw-r--r-- | scripts/tracetool/format/ust_events_h.py | 15 | ||||
-rw-r--r-- | scripts/tracetool/transform.py | 166 | ||||
-rwxr-xr-x | scripts/vmstate-static-checker.py | 70 |
23 files changed, 830 insertions, 116 deletions
diff --git a/scripts/acpi_extract.py b/scripts/acpi_extract.py index 22ea46810..10c1ffb36 100755 --- a/scripts/acpi_extract.py +++ b/scripts/acpi_extract.py @@ -139,13 +139,16 @@ def aml_name_string(offset): offset += 1 return offset; -# Given data offset, find 8 byte buffer offset -def aml_data_buffer8(offset): - #0x08 NameOp NameString DataRef - expect = [0x11, 0x0B, 0x0A, 0x08] +# Given data offset, find variable length byte buffer offset +def aml_data_buffer(offset, length): + #0x11 PkgLength BufferSize ByteList + if (length > 63): + die( "Name offset 0x%x: expected a one byte PkgLength (length<=63)" % + (offset)); + expect = [0x11, length+3, 0x0A, length] if (aml[offset:offset+4] != expect): die( "Name offset 0x%x: expected %s actual %s" % - (offset, aml[offset:offset+4], expect)) + (offset, expect, aml[offset:offset+4])) return offset + len(expect) # Given data offset, find dword const offset @@ -172,9 +175,9 @@ def aml_data_byte_const(offset): (offset, aml[offset])); return offset + 1; -# Find name'd buffer8 -def aml_name_buffer8(offset): - return aml_data_buffer8(aml_name_string(offset) + 4) +# Find name'd buffer +def aml_name_buffer(offset, length): + return aml_data_buffer(aml_name_string(offset) + 4, length) # Given name offset, find dword const offset def aml_name_dword_const(offset): @@ -308,7 +311,9 @@ for i in range(len(asl)): output[array] = aml continue if (directive == "ACPI_EXTRACT_NAME_BUFFER8"): - offset = aml_name_buffer8(offset) + offset = aml_name_buffer(offset, 8) + elif (directive == "ACPI_EXTRACT_NAME_BUFFER16"): + offset = aml_name_buffer(offset, 16) elif (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"): offset = aml_name_dword_const(offset) elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"): diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 9d46e5a10..053e4320f 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -206,9 +206,13 @@ our $UTF8 = qr { | \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: - (?:__)?(?:u|s|be|le)(?:8|16|32|64)| - atomic_t + [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 $logFunctions = qr{(?x: diff --git a/scripts/cleanup-trace-events.pl b/scripts/cleanup-trace-events.pl index cffbf165d..7e808efb6 100755 --- a/scripts/cleanup-trace-events.pl +++ b/scripts/cleanup-trace-events.pl @@ -25,7 +25,7 @@ sub out { while (<>) { if (/^(disable )?([a-z_0-9]+)\(/) { - open GREP, '-|', 'git', 'grep', '-l', "trace_$2" + open GREP, '-|', 'git', 'grep', '-lw', "trace_$2" or die "run git grep: $!"; my $fname; while ($fname = <GREP>) { diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 38334de87..af68c6c92 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -651,18 +651,26 @@ sub get_maintainers { $email->[0] = deduplicate_email($email->[0]); } - foreach my $file (@files) { - if ($email && - ($email_git || ($email_git_fallback && - !$exact_pattern_match_hash{$file}))) { - vcs_file_signoffs($file); - } - if ($email && $email_git_blame) { - vcs_file_blame($file); + if ($email) { + if (! $interactive) { + $email_git_fallback = 0 if @email_to > 0 || @list_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); + } } - } - if ($email) { foreach my $chief (@penguin_chief) { if ($chief =~ m/^(.*):(.*)/) { my $email_address; diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat index d7e97e748..7b1437ca2 100755 --- a/scripts/kvm/kvm_stat +++ b/scripts/kvm/kvm_stat @@ -12,7 +12,7 @@ # the COPYING file in the top-level directory. import curses -import sys, os, time, optparse +import sys, os, time, optparse, ctypes class DebugfsProvider(object): def __init__(self): @@ -141,61 +141,97 @@ svm_exit_reasons = { 0x400: 'NPF', } -s390_exit_reasons = { - 0x000: 'UNKNOWN', - 0x001: 'EXCEPTION', - 0x002: 'IO', - 0x003: 'HYPERCALL', - 0x004: 'DEBUG', - 0x005: 'HLT', - 0x006: 'MMIO', - 0x007: 'IRQ_WINDOW_OPEN', - 0x008: 'SHUTDOWN', - 0x009: 'FAIL_ENTRY', - 0x010: 'INTR', - 0x011: 'SET_TPR', - 0x012: 'TPR_ACCESS', - 0x013: 'S390_SIEIC', - 0x014: 'S390_RESET', - 0x015: 'DCR', - 0x016: 'NMI', - 0x017: 'INTERNAL_ERROR', - 0x018: 'OSI', - 0x019: 'PAPR_HCALL', +# From include/uapi/linux/kvm.h, KVM_EXIT_xxx +userspace_exit_reasons = { + 0: 'UNKNOWN', + 1: 'EXCEPTION', + 2: 'IO', + 3: 'HYPERCALL', + 4: 'DEBUG', + 5: 'HLT', + 6: 'MMIO', + 7: 'IRQ_WINDOW_OPEN', + 8: 'SHUTDOWN', + 9: 'FAIL_ENTRY', + 10: 'INTR', + 11: 'SET_TPR', + 12: 'TPR_ACCESS', + 13: 'S390_SIEIC', + 14: 'S390_RESET', + 15: 'DCR', + 16: 'NMI', + 17: 'INTERNAL_ERROR', + 18: 'OSI', + 19: 'PAPR_HCALL', + 20: 'S390_UCONTROL', + 21: 'WATCHDOG', + 22: 'S390_TSCH', + 23: 'EPR', } -vendor_exit_reasons = { +x86_exit_reasons = { 'vmx': vmx_exit_reasons, 'svm': svm_exit_reasons, - 'IBM/S390': s390_exit_reasons, } -syscall_numbers = { - 'IBM/S390': 331, -} - -sc_perf_evt_open = 298 - +sc_perf_evt_open = None exit_reasons = None -for line in file('/proc/cpuinfo').readlines(): - if line.startswith('flags') or line.startswith('vendor_id'): - for flag in line.split(): - if flag in vendor_exit_reasons: - exit_reasons = vendor_exit_reasons[flag] - if flag in syscall_numbers: - sc_perf_evt_open = syscall_numbers[flag] -filters = { - 'kvm_exit': ('exit_reason', exit_reasons) +ioctl_numbers = { + 'SET_FILTER' : 0x40082406, + 'ENABLE' : 0x00002400, + 'DISABLE' : 0x00002401, } +def x86_init(flag): + globals().update({ + 'sc_perf_evt_open' : 298, + 'exit_reasons' : x86_exit_reasons[flag], + }) + +def s390_init(): + globals().update({ + 'sc_perf_evt_open' : 331 + }) + +def ppc_init(): + globals().update({ + 'sc_perf_evt_open' : 319, + 'ioctl_numbers' : { + 'SET_FILTER' : 0x80002406 | (ctypes.sizeof(ctypes.c_char_p) << 16), + 'ENABLE' : 0x20002400, + 'DISABLE' : 0x20002401, + } + }) + +def detect_platform(): + if os.uname()[4].startswith('ppc'): + ppc_init() + return + + for line in file('/proc/cpuinfo').readlines(): + if line.startswith('flags'): + for flag in line.split(): + if flag in x86_exit_reasons: + x86_init(flag) + return + elif line.startswith('vendor_id'): + for flag in line.split(): + if flag == 'IBM/S390': + s390_init() + return + +detect_platform() + def invert(d): return dict((x[1], x[0]) for x in d.iteritems()) -for f in filters: - filters[f] = (filters[f][0], invert(filters[f][1])) +filters = {} +filters['kvm_userspace_exit'] = ('reason', invert(userspace_exit_reasons)) +if exit_reasons: + filters['kvm_exit'] = ('exit_reason', invert(exit_reasons)) -import ctypes, struct, array +import struct, array libc = ctypes.CDLL('libc.so.6') syscall = libc.syscall @@ -285,14 +321,14 @@ class Event(object): raise Exception('perf_event_open failed') if filter: import fcntl - fcntl.ioctl(fd, 0x40082406, filter) + fcntl.ioctl(fd, ioctl_numbers['SET_FILTER'], filter) self.fd = fd def enable(self): import fcntl - fcntl.ioctl(self.fd, 0x00002400, 0) + fcntl.ioctl(self.fd, ioctl_numbers['ENABLE'], 0) def disable(self): import fcntl - fcntl.ioctl(self.fd, 0x00002401, 0) + fcntl.ioctl(self.fd, ioctl_numbers['DISABLE'], 0) class TracepointProvider(object): def __init__(self): @@ -311,18 +347,30 @@ class TracepointProvider(object): self.select(fields) def fields(self): return self._fields + + def _online_cpus(self): + l = [] + pattern = r'cpu([0-9]+)' + basedir = '/sys/devices/system/cpu' + for entry in os.listdir(basedir): + match = re.match(pattern, entry) + if not match: + continue + path = os.path.join(basedir, entry, 'online') + if os.path.exists(path) and open(path).read().strip() != '1': + continue + l.append(int(match.group(1))) + return l + def _setup(self, _fields): self._fields = _fields - cpure = r'cpu([0-9]+)' - self.cpus = [int(re.match(cpure, x).group(1)) - for x in os.listdir('/sys/devices/system/cpu') - if re.match(cpure, x)] + cpus = self._online_cpus() import resource - nfiles = len(self.cpus) * 1000 + nfiles = len(cpus) * 1000 resource.setrlimit(resource.RLIMIT_NOFILE, (nfiles, nfiles)) events = [] self.group_leaders = [] - for cpu in self.cpus: + for cpu in cpus: group = Group(cpu) for name in _fields: tracepoint = name diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap index c90eda497..8f0371f49 100755 --- a/scripts/kvm/vmxcap +++ b/scripts/kvm/vmxcap @@ -99,7 +99,7 @@ controls = [ Misc( name = 'Basic VMX Information', bits = { - (0, 31): 'Revision', + (0, 30): 'Revision', (32,44): 'VMCS size', 48: 'VMCS restricted to 32 bit addresses', 49: 'Dual-monitor support', @@ -169,7 +169,9 @@ controls = [ 12: 'Enable INVPCID', 13: 'Enable VM functions', 14: 'VMCS shadowing', - 18: 'EPT-violation #VE' + 16: 'RDSEED exiting', + 18: 'EPT-violation #VE', + 20: 'Enable XSAVES/XRSTORS', }, cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2, ), @@ -195,7 +197,7 @@ controls = [ name = 'VM-Entry controls', bits = { 2: 'Load debug controls', - 9: 'IA-64 mode guest', + 9: 'IA-32e mode guest', 10: 'Entry to SMM', 11: 'Deactivate dual-monitor treatment', 13: 'Load IA32_PERF_GLOBAL_CTRL', @@ -216,7 +218,7 @@ controls = [ 8: 'Wait-for-SIPI activity state', 15: 'IA32_SMBASE support', (16,24): 'Number of CR3-target values', - (25,27): 'MSR-load/store count recommenation', + (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', diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index b4632324a..d2f815bca 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -177,6 +177,8 @@ const int %(name)s_qtypes[QTYPE_MAX] = { qtype = "QTYPE_QDICT" elif find_union(qapi_type): qtype = "QTYPE_QDICT" + elif find_enum(qapi_type): + qtype = "QTYPE_QSTRING" else: assert False, "Invalid anonymous union member" diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index c12969721..8f845a2b2 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -263,7 +263,8 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e for key in members: assert (members[key] in builtin_types or find_struct(members[key]) - or find_union(members[key])), "Invalid anonymous union member" + or find_union(members[key]) + or find_enum(members[key])), "Invalid anonymous union member" enum_full_value = generate_enum_full_value(disc_type, key) ret += mcgen(''' @@ -357,6 +358,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e if (err) { goto out_obj; } + if (!visit_start_union(m, !!(*obj)->data, &err) || err) { + goto out_obj; + } switch ((*obj)->kind) { ''', disc_type = disc_type, @@ -385,6 +389,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e out_obj: error_propagate(errp, err); err = NULL; + visit_end_union(m, !!(*obj)->data, &err); + error_propagate(errp, err); + err = NULL; } visit_end_struct(m, &err); out: diff --git a/scripts/qapi.py b/scripts/qapi.py index f2c6d1f84..77d46aa99 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -107,10 +107,10 @@ class QAPISchema: 'Expected a file name (string), got: %s' % include) include_path = os.path.join(self.input_dir, include) - if any(include_path == elem[1] - for elem in self.include_hist): - raise QAPIExprError(expr_info, "Inclusion loop for %s" - % include) + for elem in self.include_hist: + if include_path == elem[1]: + raise QAPIExprError(expr_info, "Inclusion loop for %s" + % include) # skip multiple include of the same file if include_path in previously_included: continue diff --git a/scripts/qtest b/scripts/qtest deleted file mode 100755 index 4ef6c1c50..000000000 --- a/scripts/qtest +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -export QTEST_QEMU_BINARY=$1 -shift -"$@" diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 1aa9460e4..3916c6d14 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -58,8 +58,8 @@ def read_record(edict, fobj): rechdr = read_header(fobj, rec_header_fmt) return get_record(edict, rechdr, fobj) # return tuple of record elements -def read_trace_file(edict, fobj): - """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, pid, arg1, ..., arg6).""" +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 \ @@ -73,6 +73,8 @@ def read_trace_file(edict, fobj): 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: @@ -102,13 +104,16 @@ class Analyzer(object): """Called at the end of the trace.""" pass -def process(events, log, analyzer): +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} @@ -137,7 +142,7 @@ def process(events, log, analyzer): analyzer.begin() fn_cache = {} - for rec in read_trace_file(edict, log): + for rec in read_trace_records(edict, log): event_num = rec[0] event = edict[event_num] if event_num not in fn_cache: @@ -152,12 +157,17 @@ def run(analyzer): advanced scripts will want to call process() instead.""" import sys - if len(sys.argv) != 3: - sys.stderr.write('usage: %s <trace-events> <trace-file>\n' % sys.argv[0]) + 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) + process(events, sys.argv[2], analyzer, read_header=read_header) if __name__ == '__main__': class Formatter(Analyzer): diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index e8e8edcc4..181675f00 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -15,9 +15,11 @@ __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): @@ -108,6 +110,18 @@ class Arguments: """List of argument types.""" return [ type_ for type_, _ 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. @@ -122,13 +136,19 @@ class Event(object): Properties of the event. args : Arguments The event arguments. + """ - _CRE = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?") + _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"]) + _VALID_PROPS = set(["disable", "tcg", "tcg-trans", "tcg-exec"]) - def __init__(self, name, props, fmt, args): + def __init__(self, name, props, fmt, args, orig=None): """ Parameters ---------- @@ -136,20 +156,29 @@ class Event(object): Event name. props : list of str Property names. - fmt : str - Event printing format. + fmt : str, list of str + Event printing format (or formats). args : Arguments Event arguments. + orig : Event or None + Original Event before transformation. + """ self.name = name self.properties = props self.fmt = fmt self.args = args + 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.""" @@ -172,34 +201,96 @@ class Event(object): 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") + return Event(name, props, fmt, args) 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, - self.fmt) + 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): - res = [] + events = [] for line in fobj: if not line.strip(): continue if line.lstrip().startswith('#'): continue - res.append(Event.build(line)) - return res + + 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] + 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_trans = event_trans.copy() + + event_exec = event.copy() + event_exec.name += "_exec" + event_exec.properties += ["tcg-exec"] + event_exec.fmt = event.fmt[1] + event_exec = event_exec.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): diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py index 5bfa1efc5..d4b6dab9c 100644 --- a/scripts/tracetool/backend/__init__.py +++ b/scripts/tracetool/backend/__init__.py @@ -102,7 +102,8 @@ class Wrapper: def __init__(self, backends, format): self._backends = [backend.replace("-", "_") for backend in backends] self._format = format.replace("-", "_") - assert all(exists(backend) for backend in self._backends) + for backend in self._backends: + assert exists(backend) assert tracetool.format.exists(self._format) def _run_function(self, name, *args, **kwargs): diff --git a/scripts/tracetool/format/events_h.py b/scripts/tracetool/format/events_h.py index 25d913bb2..9f114a349 100644 --- a/scripts/tracetool/format/events_h.py +++ b/scripts/tracetool/format/events_h.py @@ -40,6 +40,11 @@ def generate(events, backend): 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.original.name.upper(), + enabled=enabled) out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled)) out('#include "trace/event-internal.h"', diff --git a/scripts/tracetool/format/simpletrace_stap.py b/scripts/tracetool/format/simpletrace_stap.py new file mode 100644 index 000000000..7e44bc181 --- /dev/null +++ b/scripts/tracetool/format/simpletrace_stap.py @@ -0,0 +1,71 @@ +#!/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/scripts/tracetool/format/stap.py b/scripts/tracetool/format/stap.py index e24abf7f1..9e780f1b0 100644 --- a/scripts/tracetool/format/stap.py +++ b/scripts/tracetool/format/stap.py @@ -27,6 +27,13 @@ RESERVED_WORDS = ( ) +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] @@ -45,9 +52,7 @@ def generate(events, backend): i = 1 if len(e.args) > 0: for name in e.args.names(): - # Append underscore to reserved keywords - if name in RESERVED_WORDS: - name += '_' + name = stap_escape(name) out(' %s = $arg%d;' % (name, i)) i += 1 diff --git a/scripts/tracetool/format/tcg_h.py b/scripts/tracetool/format/tcg_h.py new file mode 100644 index 000000000..f676b6662 --- /dev/null +++ b/scripts/tracetool/format/tcg_h.py @@ -0,0 +1,57 @@ +#!/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-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. */', + '/* You must include this file after the inclusion of helper.h */', + '', + '#ifndef TRACE__GENERATED_TCG_TRACERS_H', + '#define TRACE__GENERATED_TCG_TRACERS_H', + '', + '#include <stdint.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 + + # get the original event definition + e = e.original.original + + out('static inline void %(name_tcg)s(%(args)s)', + '{', + name_tcg=e.api(e.QEMU_TRACE_TCG), + args=e.args) + + if "disable" not in e.properties: + out(' %(name_trans)s(%(argnames_trans)s);', + ' gen_helper_%(name_exec)s(%(argnames_exec)s);', + name_trans=e.event_trans.api(e.QEMU_TRACE), + name_exec=e.event_exec.api(e.QEMU_TRACE), + argnames_trans=", ".join(e.event_trans.args.names()), + argnames_exec=", ".join(e.event_exec.args.names())) + + out('}') + + out('', + '#endif /* TRACE__GENERATED_TCG_TRACERS_H */') diff --git a/scripts/tracetool/format/tcg_helper_c.py b/scripts/tracetool/format/tcg_helper_c.py new file mode 100644 index 000000000..96655a059 --- /dev/null +++ b/scripts/tracetool/format/tcg_helper_c.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate trace/generated-helpers.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 +from tracetool.transform import * + + +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-common.h"', + '#include "trace.h"', + '#include "exec/helper-proto.h"', + '', + ) + + for e in events: + if "tcg-exec" not in e.properties: + continue + + # tracetool.generate always transforms types to host + e_args = e.original.args + + values = ["(%s)%s" % (t, n) + for t, n in e.args.transform(TCG_2_TCG_HELPER_DEF)] + + out('void %(name_tcg)s(%(args)s)', + '{', + ' %(name)s(%(values)s);', + '}', + name_tcg="helper_%s_proxy" % e.api(), + name=e.api(), + args=e_args.transform(HOST_2_TCG_COMPAT, TCG_2_TCG_HELPER_DEF), + values=", ".join(values), + ) diff --git a/scripts/tracetool/format/tcg_helper_h.py b/scripts/tracetool/format/tcg_helper_h.py new file mode 100644 index 000000000..a8ba7ba8e --- /dev/null +++ b/scripts/tracetool/format/tcg_helper_h.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate trace/generated-helpers.h. +""" + +__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.transform import * + + +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 + + # tracetool.generate always transforms types to host + e_args = e.original.args + + # TCG helper proxy declaration + fmt = "DEF_HELPER_FLAGS_%(argc)d(%(name)s, %(flags)svoid%(types)s)" + 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/scripts/tracetool/format/tcg_helper_wrapper_h.py b/scripts/tracetool/format/tcg_helper_wrapper_h.py new file mode 100644 index 000000000..cac5a878f --- /dev/null +++ b/scripts/tracetool/format/tcg_helper_wrapper_h.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Generate trace/generated-helpers-wrappers.h. +""" + +__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.transform import * + + +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 = e.original.args + + # 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/scripts/tracetool/format/ust_events_h.py b/scripts/tracetool/format/ust_events_h.py index 510256547..3e8a7cdf1 100644 --- a/scripts/tracetool/format/ust_events_h.py +++ b/scripts/tracetool/format/ust_events_h.py @@ -63,13 +63,20 @@ def generate(events, backend): name=e.name, args=", ".join(", ".join(i) for i in e.args)) - for t, n in e.args: - if ('int' in t) or ('long' in t) or ('unsigned' in t) or ('size_t' in t): + 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 ('char *' in t) or ('char*' in t): - out(' ctf_string(' + n + ', ' + n + ')') elif ('void *' in t) or ('void*' in t): out(' ctf_integer_hex(unsigned long, ' + n + ', ' + n + ')') diff --git a/scripts/tracetool/transform.py b/scripts/tracetool/transform.py new file mode 100644 index 000000000..fc5e679ed --- /dev/null +++ b/scripts/tracetool/transform.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Type-transformation rules. +""" + +__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" + + +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", + 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", + 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/scripts/vmstate-static-checker.py b/scripts/vmstate-static-checker.py index 3bae769a3..f7ce3fc48 100755 --- a/scripts/vmstate-static-checker.py +++ b/scripts/vmstate-static-checker.py @@ -42,30 +42,44 @@ def check_fields_match(name, s_field, d_field): # 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'], + '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]'], + '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'], @@ -130,6 +144,7 @@ def check_fields(src_fields, dest_fields, desc, sec): advance_src = True advance_dest = True + unused_count = 0 while True: if advance_src: @@ -142,9 +157,10 @@ def check_fields(src_fields, dest_fields, desc, sec): s_iter = s_iter_list.pop() continue else: - # We want to avoid advancing just once -- when entering a - # dest substruct, or when exiting one. - advance_src = True + 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: @@ -163,7 +179,37 @@ def check_fields(src_fields, dest_fields, desc, sec): advance_src = False continue else: - advance_dest = True + 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 @@ -194,6 +240,20 @@ def check_fields(src_fields, dest_fields, desc, sec): 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"] + "\",", |