diff options
author | 2023-10-10 11:40:56 +0000 | |
---|---|---|
committer | 2023-10-10 11:40:56 +0000 | |
commit | e02cda008591317b1625707ff8e115a4841aa889 (patch) | |
tree | aee302e3cf8b59ec2d32ec481be3d1afddfc8968 /scripts/coccinelle | |
parent | cc668e6b7e0ffd8c9d130513d12053cf5eda1d3b (diff) |
Introduce Virtio-loopback epsilon release:
Epsilon release introduces a new compatibility layer which make virtio-loopback
design to work with QEMU and rust-vmm vhost-user backend without require any
changes.
Signed-off-by: Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
Change-Id: I52e57563e08a7d0bdc002f8e928ee61ba0c53dd9
Diffstat (limited to 'scripts/coccinelle')
22 files changed, 1186 insertions, 0 deletions
diff --git a/scripts/coccinelle/cpu-reset.cocci b/scripts/coccinelle/cpu-reset.cocci new file mode 100644 index 000000000..396a724e5 --- /dev/null +++ b/scripts/coccinelle/cpu-reset.cocci @@ -0,0 +1,47 @@ +// Convert targets using the old CPUState reset to DeviceState reset +// +// Copyright Linaro Ltd 2020 +// This work is licensed under the terms of the GNU GPLv2 or later. +// +// spatch --macro-file scripts/cocci-macro-file.h \ +// --sp-file scripts/coccinelle/cpu-reset.cocci \ +// --keep-comments --smpl-spacing --in-place --include-headers --dir target +// +// For simplicity we assume some things about the code we're modifying +// that happen to be true for all our targets: +// * all cpu_class_set_parent_reset() callsites have a 'DeviceClass *dc' local +// * the parent reset field in the target CPU class is 'parent_reset' +// * no reset function already has a 'dev' local + +@@ +identifier cpu, x; +typedef CPUState; +@@ +struct x { +... +- void (*parent_reset)(CPUState *cpu); ++ DeviceReset parent_reset; +... +}; +@ rule1 @ +identifier resetfn; +expression resetfield; +identifier cc; +@@ +- cpu_class_set_parent_reset(cc, resetfn, resetfield) ++ device_class_set_parent_reset(dc, resetfn, resetfield) +@@ +identifier rule1.resetfn; +identifier cpu, cc; +typedef CPUState, DeviceState; +@@ +-resetfn(CPUState *cpu) +-{ ++resetfn(DeviceState *dev) ++{ ++ CPUState *cpu = CPU(dev); +<... +- cc->parent_reset(cpu); ++ cc->parent_reset(dev); +...> +} diff --git a/scripts/coccinelle/cpu_restore_state.cocci b/scripts/coccinelle/cpu_restore_state.cocci new file mode 100644 index 000000000..61bc749d1 --- /dev/null +++ b/scripts/coccinelle/cpu_restore_state.cocci @@ -0,0 +1,19 @@ +// Remove unneeded tests before calling cpu_restore_state +// +// spatch --macro-file scripts/cocci-macro-file.h \ +// --sp-file ./scripts/coccinelle/cpu_restore_state.cocci \ +// --keep-comments --in-place --use-gitgrep --dir target +@@ +expression A; +expression C; +@@ +-if (A) { + cpu_restore_state(C, A); +-} +@@ +expression A; +expression C; +@@ +- cpu_restore_state(C, A); +- cpu_loop_exit(C); ++ cpu_loop_exit_restore(C, A); diff --git a/scripts/coccinelle/err-bad-newline.cocci b/scripts/coccinelle/err-bad-newline.cocci new file mode 100644 index 000000000..539442187 --- /dev/null +++ b/scripts/coccinelle/err-bad-newline.cocci @@ -0,0 +1,49 @@ +// Error messages should not contain newlines. This script finds +// messages that do. Fixing them is manual. +@r@ +expression errp, err, eno, cls, fmt, ap; +position p; +@@ +( +error_vreport(fmt, ap)@p +| +warn_vreport(fmt, ap)@p +| +info_vreport(fmt, ap)@p +| +error_report(fmt, ...)@p +| +warn_report(fmt, ...)@p +| +info_report(fmt, ...)@p +| +error_report_once(fmt, ...)@p +| +warn_report_once(fmt, ...)@p +| +error_setg(errp, fmt, ...)@p +| +error_setg_errno(errp, eno, fmt, ...)@p +| +error_setg_win32(errp, eno, cls, fmt, ...)@p +| +error_propagate_prepend(errp, err, fmt, ...)@p +| +error_vprepend(errp, fmt, ap)@p +| +error_prepend(errp, fmt, ...)@p +| +error_setg_file_open(errp, eno, cls, fmt, ...)@p +| +warn_reportf_err(errp, fmt, ...)@p +| +error_reportf_err(errp, fmt, ...)@p +| +error_set(errp, cls, fmt, ...)@p +) +@script:python@ +fmt << r.fmt; +p << r.p; +@@ +if "\\n" in str(fmt): + print("%s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt)) diff --git a/scripts/coccinelle/error-use-after-free.cocci b/scripts/coccinelle/error-use-after-free.cocci new file mode 100644 index 000000000..72ae9fdeb --- /dev/null +++ b/scripts/coccinelle/error-use-after-free.cocci @@ -0,0 +1,52 @@ +// Find and fix trivial use-after-free of Error objects +// +// Copyright (c) 2020 Virtuozzo International GmbH. +// +// 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/>. +// +// How to use: +// spatch --sp-file scripts/coccinelle/error-use-after-free.cocci \ +// --macro-file scripts/cocci-macro-file.h --in-place \ +// --no-show-diff ( FILES... | --use-gitgrep . ) + +@ exists@ +identifier fn, fn2; +expression err; +@@ + + fn(...) + { + <... +( + error_free(err); ++ err = NULL; +| + error_report_err(err); ++ err = NULL; +| + error_reportf_err(err, ...); ++ err = NULL; +| + warn_report_err(err); ++ err = NULL; +| + warn_reportf_err(err, ...); ++ err = NULL; +) + ... when != err = NULL + when != exit(...) + fn2(..., err, ...) + ...> + } diff --git a/scripts/coccinelle/error_propagate_null.cocci b/scripts/coccinelle/error_propagate_null.cocci new file mode 100644 index 000000000..c23638007 --- /dev/null +++ b/scripts/coccinelle/error_propagate_null.cocci @@ -0,0 +1,10 @@ +// error_propagate() already ignores local_err==NULL, so there's +// no need to check it before calling. + +@@ +identifier L; +expression E; +@@ +-if (L) { + error_propagate(E, L); +-} diff --git a/scripts/coccinelle/errp-guard.cocci b/scripts/coccinelle/errp-guard.cocci new file mode 100644 index 000000000..6e789acf2 --- /dev/null +++ b/scripts/coccinelle/errp-guard.cocci @@ -0,0 +1,336 @@ +// Use ERRP_GUARD() (see include/qapi/error.h) +// +// Copyright (c) 2020 Virtuozzo International GmbH. +// +// 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/>. +// +// Usage example: +// spatch --sp-file scripts/coccinelle/errp-guard.cocci \ +// --macro-file scripts/cocci-macro-file.h --in-place \ +// --no-show-diff --max-width 80 FILES... +// +// Note: --max-width 80 is needed because coccinelle default is less +// than 80, and without this parameter coccinelle may reindent some +// lines which fit into 80 characters but not to coccinelle default, +// which in turn produces extra patch hunks for no reason. + +// Switch unusual Error ** parameter names to errp +// (this is necessary to use ERRP_GUARD). +// +// Disable optional_qualifier to skip functions with +// "Error *const *errp" parameter. +// +// Skip functions with "assert(_errp && *_errp)" statement, because +// that signals unusual semantics, and the parameter name may well +// serve a purpose. (like nbd_iter_channel_error()). +// +// Skip util/error.c to not touch, for example, error_propagate() and +// error_propagate_prepend(). +@ depends on !(file in "util/error.c") disable optional_qualifier@ +identifier fn; +identifier _errp != errp; +@@ + + fn(..., +- Error **_errp ++ Error **errp + ,...) + { +( + ... when != assert(_errp && *_errp) +& + <... +- _errp ++ errp + ...> +) + } + +// Add invocation of ERRP_GUARD() to errp-functions where // necessary +// +// Note, that without "when any" the final "..." does not mach +// something matched by previous pattern, i.e. the rule will not match +// double error_prepend in control flow like in +// vfio_set_irq_signaling(). +// +// Note, "exists" says that we want apply rule even if it does not +// match on all possible control flows (otherwise, it will not match +// standard pattern when error_propagate() call is in if branch). +@ disable optional_qualifier exists@ +identifier fn, local_err; +symbol errp; +@@ + + fn(..., Error **errp, ...) + { ++ ERRP_GUARD(); + ... when != ERRP_GUARD(); +( +( + error_append_hint(errp, ...); +| + error_prepend(errp, ...); +| + error_vprepend(errp, ...); +) + ... when any +| + Error *local_err = NULL; + ... +( + error_propagate_prepend(errp, local_err, ...); +| + error_propagate(errp, local_err); +) + ... +) + } + +// Warn when several Error * definitions are in the control flow. +// This rule is not chained to rule1 and less restrictive, to cover more +// functions to warn (even those we are not going to convert). +// +// Note, that even with one (or zero) Error * definition in the each +// control flow we may have several (in total) Error * definitions in +// the function. This case deserves attention too, but I don't see +// simple way to match with help of coccinelle. +@check1 disable optional_qualifier exists@ +identifier fn, _errp, local_err, local_err2; +position p1, p2; +@@ + + fn(..., Error **_errp, ...) + { + ... + Error *local_err = NULL;@p1 + ... when any + Error *local_err2 = NULL;@p2 + ... when any + } + +@ script:python @ +fn << check1.fn; +p1 << check1.p1; +p2 << check1.p2; +@@ + +print('Warning: function {} has several definitions of ' + 'Error * local variable: at {}:{} and then at {}:{}'.format( + fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line)) + +// Warn when several propagations are in the control flow. +@check2 disable optional_qualifier exists@ +identifier fn, _errp; +position p1, p2; +@@ + + fn(..., Error **_errp, ...) + { + ... +( + error_propagate_prepend(_errp, ...);@p1 +| + error_propagate(_errp, ...);@p1 +) + ... +( + error_propagate_prepend(_errp, ...);@p2 +| + error_propagate(_errp, ...);@p2 +) + ... when any + } + +@ script:python @ +fn << check2.fn; +p1 << check2.p1; +p2 << check2.p2; +@@ + +print('Warning: function {} propagates to errp several times in ' + 'one control flow: at {}:{} and then at {}:{}'.format( + fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line)) + +// Match functions with propagation of local error to errp. +// We want to refer these functions in several following rules, but I +// don't know a proper way to inherit a function, not just its name +// (to not match another functions with same name in following rules). +// Not-proper way is as follows: rename errp parameter in functions +// header and match it in following rules. Rename it back after all +// transformations. +// +// The common case is a single definition of local_err with at most one +// error_propagate_prepend() or error_propagate() on each control-flow +// path. Functions with multiple definitions or propagates we want to +// examine manually. Rules check1 and check2 emit warnings to guide us +// to them. +// +// Note that we match not only this "common case", but any function, +// which has the "common case" on at least one control-flow path. +@rule1 disable optional_qualifier exists@ +identifier fn, local_err; +symbol errp; +@@ + + fn(..., Error ** +- errp ++ ____ + , ...) + { + ... + Error *local_err = NULL; + ... +( + error_propagate_prepend(errp, local_err, ...); +| + error_propagate(errp, local_err); +) + ... + } + +// Convert special case with goto separately. +// I tried merging this into the following rule the obvious way, but +// it made Coccinelle hang on block.c +// +// Note interesting thing: if we don't do it here, and try to fixup +// "out: }" things later after all transformations (the rule will be +// the same, just without error_propagate() call), coccinelle fails to +// match this "out: }". +@ disable optional_qualifier@ +identifier rule1.fn, rule1.local_err, out; +symbol errp; +@@ + + fn(..., Error ** ____, ...) + { + <... +- goto out; ++ return; + ...> +- out: +- error_propagate(errp, local_err); + } + +// Convert most of local_err related stuff. +// +// Note, that we inherit rule1.fn and rule1.local_err names, not +// objects themselves. We may match something not related to the +// pattern matched by rule1. For example, local_err may be defined with +// the same name in different blocks inside one function, and in one +// block follow the propagation pattern and in other block doesn't. +// +// Note also that errp-cleaning functions +// error_free_errp +// error_report_errp +// error_reportf_errp +// warn_report_errp +// warn_reportf_errp +// are not yet implemented. They must call corresponding Error* - +// freeing function and then set *errp to NULL, to avoid further +// propagation to original errp (consider ERRP_GUARD in use). +// For example, error_free_errp may look like this: +// +// void error_free_errp(Error **errp) +// { +// error_free(*errp); +// *errp = NULL; +// } +@ disable optional_qualifier exists@ +identifier rule1.fn, rule1.local_err; +expression list args; +symbol errp; +@@ + + fn(..., Error ** ____, ...) + { + <... +( +- Error *local_err = NULL; +| + +// Convert error clearing functions +( +- error_free(local_err); ++ error_free_errp(errp); +| +- error_report_err(local_err); ++ error_report_errp(errp); +| +- error_reportf_err(local_err, args); ++ error_reportf_errp(errp, args); +| +- warn_report_err(local_err); ++ warn_report_errp(errp); +| +- warn_reportf_err(local_err, args); ++ warn_reportf_errp(errp, args); +) +?- local_err = NULL; + +| +- error_propagate_prepend(errp, local_err, args); ++ error_prepend(errp, args); +| +- error_propagate(errp, local_err); +| +- &local_err ++ errp +) + ...> + } + +// Convert remaining local_err usage. For example, different kinds of +// error checking in if conditionals. We can't merge this into +// previous hunk, as this conflicts with other substitutions in it (at +// least with "- local_err = NULL"). +@ disable optional_qualifier@ +identifier rule1.fn, rule1.local_err; +symbol errp; +@@ + + fn(..., Error ** ____, ...) + { + <... +- local_err ++ *errp + ...> + } + +// Always use the same pattern for checking error +@ disable optional_qualifier@ +identifier rule1.fn; +symbol errp; +@@ + + fn(..., Error ** ____, ...) + { + <... +- *errp != NULL ++ *errp + ...> + } + +// Revert temporary ___ identifier. +@ disable optional_qualifier@ +identifier rule1.fn; +@@ + + fn(..., Error ** +- ____ ++ errp + , ...) + { + ... + } diff --git a/scripts/coccinelle/exec_rw_const.cocci b/scripts/coccinelle/exec_rw_const.cocci new file mode 100644 index 000000000..1a2029695 --- /dev/null +++ b/scripts/coccinelle/exec_rw_const.cocci @@ -0,0 +1,111 @@ +/* + Usage: + + spatch \ + --macro-file scripts/cocci-macro-file.h \ + --sp-file scripts/coccinelle/exec_rw_const.cocci \ + --keep-comments \ + --in-place \ + --dir . +*/ + +// Convert to boolean +@@ +expression E1, E2, E3, E4, E5; +@@ +( +- address_space_rw(E1, E2, E3, E4, E5, 0) ++ address_space_rw(E1, E2, E3, E4, E5, false) +| +- address_space_rw(E1, E2, E3, E4, E5, 1) ++ address_space_rw(E1, E2, E3, E4, E5, true) +| + +- cpu_physical_memory_rw(E1, E2, E3, 0) ++ cpu_physical_memory_rw(E1, E2, E3, false) +| +- cpu_physical_memory_rw(E1, E2, E3, 1) ++ cpu_physical_memory_rw(E1, E2, E3, true) +| + +- cpu_physical_memory_map(E1, E2, 0) ++ cpu_physical_memory_map(E1, E2, false) +| +- cpu_physical_memory_map(E1, E2, 1) ++ cpu_physical_memory_map(E1, E2, true) +) + +// Use address_space_write instead of casting to non-const +@@ +type T; +const T *V; +expression E1, E2, E3, E4; +@@ +( +- address_space_rw(E1, E2, E3, (T *)V, E4, 1) ++ address_space_write(E1, E2, E3, V, E4) +| +- address_space_rw(E1, E2, E3, (void *)V, E4, 1) ++ address_space_write(E1, E2, E3, V, E4) +) + +// Avoid uses of address_space_rw() with a constant is_write argument. +@@ +expression E1, E2, E3, E4, E5; +symbol true, false; +@@ +( +- address_space_rw(E1, E2, E3, E4, E5, false) ++ address_space_read(E1, E2, E3, E4, E5) +| +- address_space_rw(E1, E2, E3, E4, E5, true) ++ address_space_write(E1, E2, E3, E4, E5) +) + +// Avoid uses of cpu_physical_memory_rw() with a constant is_write argument. +@@ +expression E1, E2, E3; +@@ +( +- cpu_physical_memory_rw(E1, E2, E3, false) ++ cpu_physical_memory_read(E1, E2, E3) +| +- cpu_physical_memory_rw(E1, E2, E3, true) ++ cpu_physical_memory_write(E1, E2, E3) +) + +// Remove useless cast +@@ +expression E1, E2, E3, E4, E5, E6; +type T; +@@ +( +- address_space_rw(E1, E2, E3, (T *)(E4), E5, E6) ++ address_space_rw(E1, E2, E3, E4, E5, E6) +| +- address_space_read(E1, E2, E3, (T *)(E4), E5) ++ address_space_read(E1, E2, E3, E4, E5) +| +- address_space_write(E1, E2, E3, (T *)(E4), E5) ++ address_space_write(E1, E2, E3, E4, E5) +| +- address_space_write_rom(E1, E2, E3, (T *)(E4), E5) ++ address_space_write_rom(E1, E2, E3, E4, E5) +| + +- cpu_physical_memory_rw(E1, (T *)(E2), E3, E4) ++ cpu_physical_memory_rw(E1, E2, E3, E4) +| +- cpu_physical_memory_read(E1, (T *)(E2), E3) ++ cpu_physical_memory_read(E1, E2, E3) +| +- cpu_physical_memory_write(E1, (T *)(E2), E3) ++ cpu_physical_memory_write(E1, E2, E3) +| + +- dma_memory_read(E1, E2, (T *)(E3), E4) ++ dma_memory_read(E1, E2, E3, E4) +| +- dma_memory_write(E1, E2, (T *)(E3), E4) ++ dma_memory_write(E1, E2, E3, E4) +) diff --git a/scripts/coccinelle/inplace-byteswaps.cocci b/scripts/coccinelle/inplace-byteswaps.cocci new file mode 100644 index 000000000..a869a90cb --- /dev/null +++ b/scripts/coccinelle/inplace-byteswaps.cocci @@ -0,0 +1,65 @@ +// Replace uses of in-place byteswapping functions with calls to the +// equivalent not-in-place functions. This is necessary to avoid +// undefined behaviour if the expression being swapped is a field in a +// packed struct. + +@@ +expression E; +@@ +-be16_to_cpus(&E); ++E = be16_to_cpu(E); +@@ +expression E; +@@ +-be32_to_cpus(&E); ++E = be32_to_cpu(E); +@@ +expression E; +@@ +-be64_to_cpus(&E); ++E = be64_to_cpu(E); +@@ +expression E; +@@ +-cpu_to_be16s(&E); ++E = cpu_to_be16(E); +@@ +expression E; +@@ +-cpu_to_be32s(&E); ++E = cpu_to_be32(E); +@@ +expression E; +@@ +-cpu_to_be64s(&E); ++E = cpu_to_be64(E); +@@ +expression E; +@@ +-le16_to_cpus(&E); ++E = le16_to_cpu(E); +@@ +expression E; +@@ +-le32_to_cpus(&E); ++E = le32_to_cpu(E); +@@ +expression E; +@@ +-le64_to_cpus(&E); ++E = le64_to_cpu(E); +@@ +expression E; +@@ +-cpu_to_le16s(&E); ++E = cpu_to_le16(E); +@@ +expression E; +@@ +-cpu_to_le32s(&E); ++E = cpu_to_le32(E); +@@ +expression E; +@@ +-cpu_to_le64s(&E); ++E = cpu_to_le64(E); diff --git a/scripts/coccinelle/memory-region-housekeeping.cocci b/scripts/coccinelle/memory-region-housekeeping.cocci new file mode 100644 index 000000000..29651ebde --- /dev/null +++ b/scripts/coccinelle/memory-region-housekeeping.cocci @@ -0,0 +1,159 @@ +/* + Usage: + + spatch \ + --macro-file scripts/cocci-macro-file.h \ + --sp-file scripts/coccinelle/memory-region-housekeeping.cocci \ + --keep-comments \ + --in-place \ + --dir . + +*/ + + +// Replace memory_region_init_ram(readonly) by memory_region_init_rom() +@@ +expression E1, E2, E3, E4, E5; +symbol true; +@@ +( +- memory_region_init_ram(E1, E2, E3, E4, E5); ++ memory_region_init_rom(E1, E2, E3, E4, E5); + ... WHEN != E1 +- memory_region_set_readonly(E1, true); +| +- memory_region_init_ram_nomigrate(E1, E2, E3, E4, E5); ++ memory_region_init_rom_nomigrate(E1, E2, E3, E4, E5); + ... WHEN != E1 +- memory_region_set_readonly(E1, true); +) + + +@possible_memory_region_init_rom@ +expression E1, E2, E3, E4, E5; +position p; +@@ +( + memory_region_init_ram@p(E1, E2, E3, E4, E5); + ... + memory_region_set_readonly(E1, true); +| + memory_region_init_ram_nomigrate@p(E1, E2, E3, E4, E5); + ... + memory_region_set_readonly(E1, true); +) +@script:python@ +p << possible_memory_region_init_rom.p; +@@ +cocci.print_main("potential use of memory_region_init_rom*() in ", p) + + +// Do not call memory_region_set_readonly() on ROM alias +@@ +expression ROM, E1, E2, E3, E4; +expression ALIAS, E5, E6, E7, E8; +@@ +( + memory_region_init_rom(ROM, E1, E2, E3, E4); +| + memory_region_init_rom_nomigrate(ROM, E1, E2, E3, E4); +) + ... + memory_region_init_alias(ALIAS, E5, E6, ROM, E7, E8); +- memory_region_set_readonly(ALIAS, true); + + +// Replace by-hand memory_region_init_ram_nomigrate/vmstate_register_ram +// code sequences with use of the new memory_region_init_ram function. +// Similarly for the _rom and _rom_device functions. +// We don't try to replace sequences with a non-NULL owner, because +// there are none in the tree that can be automatically converted +// (and only a handful that can be manually converted). +@@ +expression MR; +expression NAME; +expression SIZE; +expression ERRP; +@@ +-memory_region_init_ram_nomigrate(MR, NULL, NAME, SIZE, ERRP); ++memory_region_init_ram(MR, NULL, NAME, SIZE, ERRP); + ... +-vmstate_register_ram_global(MR); +@@ +expression MR; +expression NAME; +expression SIZE; +expression ERRP; +@@ +-memory_region_init_rom_nomigrate(MR, NULL, NAME, SIZE, ERRP); ++memory_region_init_rom(MR, NULL, NAME, SIZE, ERRP); + ... +-vmstate_register_ram_global(MR); +@@ +expression MR; +expression OPS; +expression OPAQUE; +expression NAME; +expression SIZE; +expression ERRP; +@@ +-memory_region_init_rom_device_nomigrate(MR, NULL, OPS, OPAQUE, NAME, SIZE, ERRP); ++memory_region_init_rom_device(MR, NULL, OPS, OPAQUE, NAME, SIZE, ERRP); + ... +-vmstate_register_ram_global(MR); + + +// Device is owner +@@ +typedef DeviceState; +identifier device_fn, dev, obj; +expression E1, E2, E3, E4, E5; +@@ +static void device_fn(DeviceState *dev, ...) +{ + ... + Object *obj = OBJECT(dev); + <+... +( +- memory_region_init(E1, NULL, E2, E3); ++ memory_region_init(E1, obj, E2, E3); +| +- memory_region_init_io(E1, NULL, E2, E3, E4, E5); ++ memory_region_init_io(E1, obj, E2, E3, E4, E5); +| +- memory_region_init_alias(E1, NULL, E2, E3, E4, E5); ++ memory_region_init_alias(E1, obj, E2, E3, E4, E5); +| +- memory_region_init_rom(E1, NULL, E2, E3, E4); ++ memory_region_init_rom(E1, obj, E2, E3, E4); +| +- memory_region_init_ram_flags_nomigrate(E1, NULL, E2, E3, E4, E5); ++ memory_region_init_ram_flags_nomigrate(E1, obj, E2, E3, E4, E5); +) + ...+> +} +@@ +identifier device_fn, dev; +expression E1, E2, E3, E4, E5; +@@ +static void device_fn(DeviceState *dev, ...) +{ + <+... +( +- memory_region_init(E1, NULL, E2, E3); ++ memory_region_init(E1, OBJECT(dev), E2, E3); +| +- memory_region_init_io(E1, NULL, E2, E3, E4, E5); ++ memory_region_init_io(E1, OBJECT(dev), E2, E3, E4, E5); +| +- memory_region_init_alias(E1, NULL, E2, E3, E4, E5); ++ memory_region_init_alias(E1, OBJECT(dev), E2, E3, E4, E5); +| +- memory_region_init_rom(E1, NULL, E2, E3, E4); ++ memory_region_init_rom(E1, OBJECT(dev), E2, E3, E4); +| +- memory_region_init_ram_flags_nomigrate(E1, NULL, E2, E3, E4, E5); ++ memory_region_init_ram_flags_nomigrate(E1, OBJECT(dev), E2, E3, E4, E5); +) + ...+> +} diff --git a/scripts/coccinelle/overflow_muldiv64.cocci b/scripts/coccinelle/overflow_muldiv64.cocci new file mode 100644 index 000000000..08ec4a8de --- /dev/null +++ b/scripts/coccinelle/overflow_muldiv64.cocci @@ -0,0 +1,16 @@ +// Find muldiv64(i64, i64, x) for potential overflow +@filter@ +typedef uint64_t; +typedef int64_t; +{ uint64_t, int64_t, long, unsigned long } a, b; +expression c; +position p; +@@ + +muldiv64(a,b,c)@p + +@script:python@ +p << filter.p; +@@ + +cocci.print_main("potential muldiv64() overflow", p) diff --git a/scripts/coccinelle/qobject.cocci b/scripts/coccinelle/qobject.cocci new file mode 100644 index 000000000..9fee9c0d9 --- /dev/null +++ b/scripts/coccinelle/qobject.cocci @@ -0,0 +1,47 @@ +// Use QDict macros where they make sense +@@ +expression Obj, Key, E; +@@ +( +- qobject_ref(QOBJECT(E)); ++ qobject_ref(E); +| +- qobject_unref(QOBJECT(E)); ++ qobject_unref(E); +| +- qdict_put_obj(Obj, Key, QOBJECT(E)); ++ qdict_put(Obj, Key, E); +| +- qdict_put(Obj, Key, qnum_from_int(E)); ++ qdict_put_int(Obj, Key, E); +| +- qdict_put(Obj, Key, qbool_from_bool(E)); ++ qdict_put_bool(Obj, Key, E); +| +- qdict_put(Obj, Key, qstring_from_str(E)); ++ qdict_put_str(Obj, Key, E); +| +- qdict_put(Obj, Key, qnull()); ++ qdict_put_null(Obj, Key); +) + +// Use QList macros where they make sense +@@ +expression Obj, E; +@@ +( +- qlist_append_obj(Obj, QOBJECT(E)); ++ qlist_append(Obj, E); +| +- qlist_append(Obj, qnum_from_int(E)); ++ qlist_append_int(Obj, E); +| +- qlist_append(Obj, qbool_from_bool(E)); ++ qlist_append_bool(Obj, E); +| +- qlist_append(Obj, qstring_from_str(E)); ++ qlist_append_str(Obj, E); +| +- qlist_append(Obj, qnull()); ++ qlist_append_null(Obj); +) diff --git a/scripts/coccinelle/qom-parent-type.cocci b/scripts/coccinelle/qom-parent-type.cocci new file mode 100644 index 000000000..9afb3edd9 --- /dev/null +++ b/scripts/coccinelle/qom-parent-type.cocci @@ -0,0 +1,26 @@ +// Highlight object declarations that don't look like object class but +// accidentally inherit from it. + +@match@ +identifier obj_t, fld; +type parent_t =~ ".*Class$"; +@@ +struct obj_t { + parent_t fld; + ... +}; + +@script:python filter depends on match@ +obj_t << match.obj_t; +@@ +is_class_obj = obj_t.endswith('Class') +cocci.include_match(not is_class_obj) + +@replacement depends on filter@ +identifier match.obj_t, match.fld; +type match.parent_t; +@@ +struct obj_t { +* parent_t fld; + ... +}; diff --git a/scripts/coccinelle/remove_local_err.cocci b/scripts/coccinelle/remove_local_err.cocci new file mode 100644 index 000000000..9261c9968 --- /dev/null +++ b/scripts/coccinelle/remove_local_err.cocci @@ -0,0 +1,29 @@ +// Replace unnecessary usage of local_err variable with +// direct usage of errp argument + +@@ +identifier F; +expression list ARGS; +expression F2; +identifier LOCAL_ERR; +identifier ERRP; +idexpression V; +typedef Error; +@@ + F(..., Error **ERRP) + { + ... +- Error *LOCAL_ERR; + ... when != LOCAL_ERR + when != ERRP +( +- F2(ARGS, &LOCAL_ERR); +- error_propagate(ERRP, LOCAL_ERR); ++ F2(ARGS, ERRP); +| +- V = F2(ARGS, &LOCAL_ERR); +- error_propagate(ERRP, LOCAL_ERR); ++ V = F2(ARGS, ERRP); +) + ... when != LOCAL_ERR + } diff --git a/scripts/coccinelle/remove_muldiv64.cocci b/scripts/coccinelle/remove_muldiv64.cocci new file mode 100644 index 000000000..4c10bd57d --- /dev/null +++ b/scripts/coccinelle/remove_muldiv64.cocci @@ -0,0 +1,6 @@ +// replace muldiv64(a, 1, b) by "a / b" +@@ +expression a, b; +@@ +-muldiv64(a, 1, b) ++a / b diff --git a/scripts/coccinelle/return_directly.cocci b/scripts/coccinelle/return_directly.cocci new file mode 100644 index 000000000..4cf50e75e --- /dev/null +++ b/scripts/coccinelle/return_directly.cocci @@ -0,0 +1,19 @@ +// replace 'R = X; return R;' with 'return X;' +@@ +identifier VAR; +expression E; +type T; +identifier F; +@@ + T F(...) + { + ... +- T VAR; + ... when != VAR + +- VAR = ++ return + E; +- return VAR; + ... when != VAR + } diff --git a/scripts/coccinelle/round.cocci b/scripts/coccinelle/round.cocci new file mode 100644 index 000000000..ed0677328 --- /dev/null +++ b/scripts/coccinelle/round.cocci @@ -0,0 +1,19 @@ +// Use macro DIV_ROUND_UP instead of (((n) + (d) - 1) /(d)) +@@ +expression e1; +expression e2; +@@ +( +- ((e1) + e2 - 1) / (e2) ++ DIV_ROUND_UP(e1,e2) +| +- ((e1) + (e2 - 1)) / (e2) ++ DIV_ROUND_UP(e1,e2) +) + +@@ +expression e1; +expression e2; +@@ +-(DIV_ROUND_UP(e1,e2)) ++DIV_ROUND_UP(e1,e2) diff --git a/scripts/coccinelle/simplify_muldiv64.cocci b/scripts/coccinelle/simplify_muldiv64.cocci new file mode 100644 index 000000000..3d7c9744a --- /dev/null +++ b/scripts/coccinelle/simplify_muldiv64.cocci @@ -0,0 +1,11 @@ +// replace muldiv64(i32, i32, x) by (uint64_t)i32 * i32 / x +@@ +typedef uint32_t; +typedef int32_t; +{ uint32_t, int32_t, int, unsigned int } a, b; +typedef uint64_t; +expression c; +@@ + +-muldiv64(a,b,c) ++(uint64_t) a * b / c diff --git a/scripts/coccinelle/swap_muldiv64.cocci b/scripts/coccinelle/swap_muldiv64.cocci new file mode 100644 index 000000000..b48b0d084 --- /dev/null +++ b/scripts/coccinelle/swap_muldiv64.cocci @@ -0,0 +1,13 @@ +// replace muldiv64(i32, i64, x) by muldiv64(i64, i32, x) +@@ +typedef uint64_t; +typedef int64_t; +typedef uint32_t; +typedef int32_t; +{ uint32_t, int32_t, int, unsigned int } a; +{ uint64_t, int64_t, long, unsigned long } b; +expression c; +@@ + +-muldiv64(a,b,c) ++muldiv64(b,a,c) diff --git a/scripts/coccinelle/tcg_gen_extract.cocci b/scripts/coccinelle/tcg_gen_extract.cocci new file mode 100644 index 000000000..c10c86348 --- /dev/null +++ b/scripts/coccinelle/tcg_gen_extract.cocci @@ -0,0 +1,107 @@ +// optimize TCG using extract op +// +// Copyright: (C) 2017 Philippe Mathieu-Daudé. GPLv2+. +// Confidence: High +// Options: --macro-file scripts/cocci-macro-file.h +// +// Nikunj A Dadhania optimization: +// http://lists.nongnu.org/archive/html/qemu-devel/2017-02/msg05211.html +// Aurelien Jarno optimization: +// http://lists.nongnu.org/archive/html/qemu-devel/2017-05/msg01466.html +// +// This script can be run either using spatch locally or via a docker image: +// +// $ spatch \ +// --macro-file scripts/cocci-macro-file.h \ +// --sp-file scripts/coccinelle/tcg_gen_extract.cocci \ +// --keep-comments --in-place \ +// --use-gitgrep --dir target +// +// $ docker run --rm -v $PWD:$PWD -w $PWD philmd/coccinelle \ +// --macro-file scripts/cocci-macro-file.h \ +// --sp-file scripts/coccinelle/tcg_gen_extract.cocci \ +// --keep-comments --in-place \ +// --use-gitgrep --dir target + +@initialize:python@ +@@ +import sys +fd = sys.stderr +def debug(msg="", trailer="\n"): + fd.write("[DBG] " + msg + trailer) +def low_bits_count(value): + bits_count = 0 + while (value & (1 << bits_count)): + bits_count += 1 + return bits_count +def Mn(order): # Mersenne number + return (1 << order) - 1 + +@match@ +identifier ret; +metavariable arg; +constant ofs, msk; +position shr_p, and_p; +@@ +( + tcg_gen_shri_i32@shr_p +| + tcg_gen_shri_i64@shr_p +| + tcg_gen_shri_tl@shr_p +)(ret, arg, ofs); +... WHEN != ret +( + tcg_gen_andi_i32@and_p +| + tcg_gen_andi_i64@and_p +| + tcg_gen_andi_tl@and_p +)(ret, ret, msk); + +@script:python verify_len depends on match@ +ret_s << match.ret; +msk_s << match.msk; +shr_p << match.shr_p; +extract_len; +@@ +is_optimizable = False +debug("candidate at %s:%s" % (shr_p[0].file, shr_p[0].line)) +try: # only eval integer, no #define like 'SR_M' (cpp did this, else some headers are missing). + msk_v = long(msk_s.strip("UL"), 0) + msk_b = low_bits_count(msk_v) + if msk_b == 0: + debug(" value: 0x%x low_bits: %d" % (msk_v, msk_b)) + else: + debug(" value: 0x%x low_bits: %d [Mersenne number: 0x%x]" % (msk_v, msk_b, Mn(msk_b))) + is_optimizable = Mn(msk_b) == msk_v # check low_bits + coccinelle.extract_len = "%d" % msk_b + debug(" candidate %s optimizable" % ("IS" if is_optimizable else "is NOT")) +except: + debug(" ERROR (check included headers?)") +cocci.include_match(is_optimizable) +debug() + +@replacement depends on verify_len@ +identifier match.ret; +metavariable match.arg; +constant match.ofs, match.msk; +position match.shr_p, match.and_p; +identifier verify_len.extract_len; +@@ +( +-tcg_gen_shri_i32@shr_p(ret, arg, ofs); ++tcg_gen_extract_i32(ret, arg, ofs, extract_len); +... WHEN != ret +-tcg_gen_andi_i32@and_p(ret, ret, msk); +| +-tcg_gen_shri_i64@shr_p(ret, arg, ofs); ++tcg_gen_extract_i64(ret, arg, ofs, extract_len); +... WHEN != ret +-tcg_gen_andi_i64@and_p(ret, ret, msk); +| +-tcg_gen_shri_tl@shr_p(ret, arg, ofs); ++tcg_gen_extract_tl(ret, arg, ofs, extract_len); +... WHEN != ret +-tcg_gen_andi_tl@and_p(ret, ret, msk); +) diff --git a/scripts/coccinelle/timer-del-timer-free.cocci b/scripts/coccinelle/timer-del-timer-free.cocci new file mode 100644 index 000000000..c3cfd4280 --- /dev/null +++ b/scripts/coccinelle/timer-del-timer-free.cocci @@ -0,0 +1,18 @@ +// Remove superfluous timer_del() calls +// +// Copyright Linaro Limited 2020 +// This work is licensed under the terms of the GNU GPLv2 or later. +// +// spatch --macro-file scripts/cocci-macro-file.h \ +// --sp-file scripts/coccinelle/timer-del-timer-free.cocci \ +// --in-place --dir . +// +// The timer_free() function now implicitly calls timer_del() +// for you, so calls to timer_del() immediately before the +// timer_free() of the same timer can be deleted. + +@@ +expression T; +@@ +-timer_del(T); + timer_free(T); diff --git a/scripts/coccinelle/typecast.cocci b/scripts/coccinelle/typecast.cocci new file mode 100644 index 000000000..be2183ee4 --- /dev/null +++ b/scripts/coccinelle/typecast.cocci @@ -0,0 +1,7 @@ +// Remove useless casts +@@ +type T; +T v; +@@ +- (T *)&v ++ &v diff --git a/scripts/coccinelle/use-error_fatal.cocci b/scripts/coccinelle/use-error_fatal.cocci new file mode 100644 index 000000000..10fff0aec --- /dev/null +++ b/scripts/coccinelle/use-error_fatal.cocci @@ -0,0 +1,20 @@ +@@ +type T; +identifier FUN, RET; +expression list ARGS; +expression ERR, EC, FAIL; +@@ +( +- T RET = FUN(ARGS, &ERR); ++ T RET = FUN(ARGS, &error_fatal); +| +- RET = FUN(ARGS, &ERR); ++ RET = FUN(ARGS, &error_fatal); +| +- FUN(ARGS, &ERR); ++ FUN(ARGS, &error_fatal); +) +- if (FAIL) { +- error_report_err(ERR); +- exit(EC); +- } |