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

iQEcBAABAgAGBQJapqP6AAoJEJykq7OBq3PIZasIAL+NKBQGa/e0FD28PYdLU/JE
 sKZZ0O6+eVTCejGXap4bzbKOy+qZyOXvaRk5KNREc5A9R8HFBt5GotMfE80Cw9Nt
 rryX+qVdf4w27u2jMqY4215jD5jy/nPijRQ0a8UBsi6z2PXVPPNeS3lMB8RSFEZS
 IZu+l3j1op1wUlM4GfZvLCjmgHC+73lk6a5xZLJ2UvH9UoqJepgVZnSs2YvOctzG
 LVGMhk6/yAy4hh3NWx/M2h2B2ASMJJya8XrLgelAVnr6CxKBeBII0bSPur+1YIH7
 OkJhNsk6QKSWNFKtzXE6N+y1ryWLnbE8vzKSZt+xSzUDjhnqTm5iFpZQ+Ed16qA=
 =nCAn
 -----END PGP SIGNATURE-----

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

# gpg: Signature made Mon 12 Mar 2018 15:59:54 GMT
# gpg:                using RSA key 9CA4ABB381AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"
# Primary key fingerprint: 8695 A8BF D3F9 7CDA AC35  775A 9CA4 ABB3 81AB 73C8

* remotes/stefanha/tags/tracing-pull-request:
  trace: only permit standard C types and fixed size integer types
  trace: remove use of QEMU specific types from trace probes
  trace: include filename when printing parser error messages
  simpletrace: fix timestamp argument type
  log-for-trace.h: Split out parts of log.h used by trace.h

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-03-13 09:43:43 +00:00
commit 73988d529e
7 changed files with 102 additions and 30 deletions

View File

@ -0,0 +1,35 @@
/* log-for-trace.h: logging basics required by the trace.h generated
* by the log trace backend.
*
* This should not be included directly by any .c file: if you
* need to use the logging functions include "qemu/log.h".
*
* The purpose of splitting these parts out into their own header
* is to catch the easy mistake where a .c file includes trace.h
* but forgets to include qemu/log.h. Without this split, that
* would result in the .c file compiling fine when the default
* trace backend is in use but failing to compile with any other
* backend.
*
* This code is licensed under the GNU General Public License,
* version 2 or (at your option) any later version.
*/
#ifndef QEMU_LOG_FOR_TRACE_H
#define QEMU_LOG_FOR_TRACE_H
/* Private global variable, don't use */
extern int qemu_loglevel;
#define LOG_TRACE (1 << 15)
/* Returns true if a bit is set in the current loglevel mask */
static inline bool qemu_loglevel_mask(int mask)
{
return (qemu_loglevel & mask) != 0;
}
/* main logging function */
int GCC_FMT_ATTR(1, 2) qemu_log(const char *fmt, ...);
#endif

View File

@ -1,10 +1,11 @@
#ifndef QEMU_LOG_H
#define QEMU_LOG_H
/* A small part of this API is split into its own header */
#include "qemu/log-for-trace.h"
/* Private global variables, don't use */
/* Private global variable, don't use */
extern FILE *qemu_logfile;
extern int qemu_loglevel;
/*
* The new API:
@ -41,16 +42,9 @@ static inline bool qemu_log_separate(void)
#define CPU_LOG_MMU (1 << 12)
#define CPU_LOG_TB_NOCHAIN (1 << 13)
#define CPU_LOG_PAGE (1 << 14)
#define LOG_TRACE (1 << 15)
/* LOG_TRACE (1 << 15) is defined in log-for-trace.h */
#define CPU_LOG_TB_OP_IND (1 << 16)
/* Returns true if a bit is set in the current loglevel mask
*/
static inline bool qemu_loglevel_mask(int mask)
{
return (qemu_loglevel & mask) != 0;
}
/* Lock output for a series of related logs. Since this is not needed
* for a single qemu_log / qemu_log_mask / qemu_log_mask_and_addr, we
* assume that qemu_loglevel_mask has already been tested, and that
@ -69,10 +63,6 @@ static inline void qemu_log_unlock(void)
/* Logging functions: */
/* main logging function
*/
int GCC_FMT_ATTR(1, 2) qemu_log(const char *fmt, ...);
/* vfprintf-like logging function
*/
static inline void GCC_FMT_ATTR(1, 0)

View File

@ -168,7 +168,7 @@ def end(self):
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'))
events = read_events(open(events, 'r'), events)
if isinstance(log, str):
log = open(log, 'rb')
@ -199,7 +199,7 @@ def build_fn(analyzer, event):
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]))
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])
@ -233,7 +233,7 @@ def run(analyzer):
'<trace-file>\n' % sys.argv[0])
sys.exit(1)
events = read_events(open(sys.argv[1], 'r'))
events = read_events(open(sys.argv[1], 'r'), sys.argv[1])
process(events, sys.argv[2], analyzer, read_header=read_header)
if __name__ == '__main__':

View File

@ -142,7 +142,7 @@ def main(args):
events = []
for arg in args:
with open(arg, "r") as fh:
events.extend(tracetool.read_events(fh))
events.extend(tracetool.read_events(fh, arg))
try:
tracetool.generate(events, arg_group, arg_format, arg_backends,

View File

@ -41,6 +41,51 @@ def out(*lines, **kwargs):
lines = [ l % kwargs for l in lines ]
sys.stdout.writelines("\n".join(lines) + "\n")
# We only want to allow standard C types or fixed sized
# integer types. We don't want QEMU specific types
# as we can't assume trace backends can resolve all the
# typedefs
ALLOWED_TYPES = [
"int",
"long",
"short",
"char",
"bool",
"unsigned",
"signed",
"float",
"double",
"int8_t",
"uint8_t",
"int16_t",
"uint16_t",
"int32_t",
"uint32_t",
"int64_t",
"uint64_t",
"void",
"size_t",
"ssize_t",
"uintptr_t",
"ptrdiff_t",
# Magic substitution is done by tracetool
"TCGv",
]
def validate_type(name):
bits = name.split(" ")
for bit in bits:
bit = re.sub("\*", "", bit)
if bit == "":
continue
if bit == "const":
continue
if bit not in ALLOWED_TYPES:
raise ValueError("Argument type '%s' is not in whitelist. "
"Only standard C types and fixed size integer "
"types should be used. struct, union, and "
"other complex pointer types should be "
"declared as 'void *'" % name)
class Arguments:
"""Event arguments description."""
@ -87,6 +132,7 @@ def build(arg_str):
else:
arg_type, identifier = arg.rsplit(None, 1)
validate_type(arg_type)
res.append((arg_type, identifier))
return Arguments(res)
@ -291,13 +337,15 @@ def transform(self, *trans):
self)
def read_events(fobj):
def read_events(fobj, fname):
"""Generate the output for the given (format, backends) pair.
Parameters
----------
fobj : file
Event description file.
fname : str
Name of event file
Returns a list of Event objects
"""
@ -312,7 +360,7 @@ def read_events(fobj):
try:
event = Event.build(line)
except ValueError as e:
arg0 = 'Error on line %d: %s' % (lineno, e.args[0])
arg0 = 'Error at %s:%d: %s' % (fname, lineno, e.args[0])
e.args = (arg0,) + e.args[1:]
raise

View File

@ -20,7 +20,7 @@
def generate_h_begin(events, group):
out('#include "qemu/log.h"',
out('#include "qemu/log-for-trace.h"',
'')
@ -35,14 +35,13 @@ def generate_h(event, group):
else:
cond = "trace_event_get_state(%s)" % ("TRACE_" + event.name.upper())
out(' if (%(cond)s) {',
out(' if (%(cond)s && qemu_loglevel_mask(LOG_TRACE)) {',
' 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);',
' qemu_log("%%d@%%zd.%%06zd:%(name)s " %(fmt)s "\\n",',
' getpid(),',
' (size_t)_now.tv_sec, (size_t)_now.tv_usec',
' %(argnames)s);',
' }',
cond=cond,
name=event.name,

View File

@ -68,9 +68,9 @@ memory_region_tb_read(int cpu_index, uint64_t addr, uint64_t value, unsigned siz
memory_region_tb_write(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_ram_device_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
flatview_new(FlatView *view, MemoryRegion *root) "%p (root %p)"
flatview_destroy(FlatView *view, MemoryRegion *root) "%p (root %p)"
flatview_destroy_rcu(FlatView *view, MemoryRegion *root) "%p (root %p)"
flatview_new(void *view, void *root) "%p (root %p)"
flatview_destroy(void *view, void *root) "%p (root %p)"
flatview_destroy_rcu(void *view, void *root) "%p (root %p)"
# gdbstub.c
gdbstub_op_start(const char *device) "Starting gdbstub using device %s"