From 77778ab21af86ca3667210a163d8bb7d1ea26a01 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 17 Jan 2025 10:39:46 +0100 Subject: [PATCH 1/2] pkg/declextract: move const handling logic from the clang tool Export raw info about consts from the clang tool, and let the Go part handle it. The less logic is in the clang tool, the better. Also this will allow to remove unused includes when we know which consts we ended up using. The more includes we include, the higher the chances we include something that's broken. --- pkg/declextract/declextract.go | 53 ++++++++++++---- pkg/declextract/entity.go | 20 +++--- pkg/declextract/serialization.go | 4 +- .../syz-declextract/clangtool/declextract.cpp | 28 +++------ tools/syz-declextract/clangtool/output.h | 26 +++----- .../testdata/file_operations.c.json | 28 ++++++++- .../syz-declextract/testdata/io_uring.c.json | 23 ++++++- tools/syz-declextract/testdata/netlink.c.json | 62 ++++++++++++++++--- tools/syz-declextract/testdata/types.c.json | 11 ++-- 9 files changed, 178 insertions(+), 77 deletions(-) diff --git a/pkg/declextract/declextract.go b/pkg/declextract/declextract.go index 1f4592523a12..fdf06b373e51 100644 --- a/pkg/declextract/declextract.go +++ b/pkg/declextract/declextract.go @@ -29,7 +29,7 @@ func Run(out *Output, probe *ifaceprobe.Info, syscallRename map[string][]string, } ctx.processFunctions() ctx.processTypingFacts() - ctx.processIncludes() + ctx.processConsts() ctx.processEnums() ctx.processStructs() ctx.processSyscalls() @@ -47,6 +47,8 @@ type context struct { structs map[string]*Struct funcs map[string]*Function facts map[string]*typingNode + includes []string + defines []define uniqualizer map[string]int interfaces []*Interface descriptions *bytes.Buffer @@ -54,6 +56,11 @@ type context struct { errs []error } +type define struct { + Name string + Value string +} + func (ctx *context) error(msg string, args ...any) { ctx.errs = append(ctx.errs, fmt.Errorf(msg, args...)) } @@ -68,14 +75,7 @@ func (ctx *context) trace(msg string, args ...any) { } } -func (ctx *context) processIncludes() { - // These additional includes must be at the top, because other kernel headers - // are broken and won't compile without these additional ones included first. - ctx.Includes = append([]string{ - "vdso/bits.h", - "linux/types.h", - "net/netlink.h", - }, ctx.Includes...) +func (ctx *context) processConsts() { replaces := map[string]string{ // Arches may use some includes from asm-generic and some from arch/arm. // If the arch used for extract used asm-generic for a header, @@ -84,11 +84,40 @@ func (ctx *context) processIncludes() { "include/uapi/asm-generic/ioctls.h": "asm/ioctls.h", "include/uapi/asm-generic/sockios.h": "asm/sockios.h", } - for i, inc := range ctx.Includes { - if replace := replaces[inc]; replace != "" { - ctx.Includes[i] = replace + defineDedup := make(map[string]bool) + for _, ci := range ctx.Consts { + if strings.Contains(ci.Filename, "/uapi/") && !strings.Contains(ci.Filename, "arch/x86/") && + strings.HasSuffix(ci.Filename, ".h") { + filename := ci.Filename + if replace := replaces[filename]; replace != "" { + filename = replace + } + ctx.includes = append(ctx.includes, filename) + continue } + // Remove duplicate defines (even with different values). Unfortunately we get few of these. + // There are some syscall numbers (presumably for 32/64 bits), and some macros that + // are defined in different files to different values (e.g. WMI_DATA_BE_SVC). + // Ideally we somehow rename defines (chosing one random value is never correct). + // But for now this helps to prevent compilation errors. + if defineDedup[ci.Name] { + continue + } + defineDedup[ci.Name] = true + ctx.defines = append(ctx.defines, define{ + Name: ci.Name, + Value: fmt.Sprint(ci.Value), + }) } + ctx.includes = sortAndDedupSlice(ctx.includes) + ctx.defines = sortAndDedupSlice(ctx.defines) + // These additional includes must be at the top, because other kernel headers + // are broken and won't compile without these additional ones included first. + ctx.includes = append([]string{ + "vdso/bits.h", + "linux/types.h", + "net/netlink.h", + }, ctx.includes...) } func (ctx *context) processEnums() { diff --git a/pkg/declextract/entity.go b/pkg/declextract/entity.go index 266647ed8121..8167d8b990e7 100644 --- a/pkg/declextract/entity.go +++ b/pkg/declextract/entity.go @@ -12,8 +12,7 @@ import ( type Output struct { Functions []*Function `json:"functions,omitempty"` - Includes []string `json:"includes,omitempty"` - Defines []*Define `json:"defines,omitempty"` + Consts []*ConstInfo `json:"consts,omitempty"` Enums []*Enum `json:"enums,omitempty"` Structs []*Struct `json:"structs,omitempty"` Syscalls []*Syscall `json:"syscalls,omitempty"` @@ -36,9 +35,10 @@ type Function struct { facts map[string]*typingNode } -type Define struct { - Name string `json:"name,omitempty"` - Value string `json:"value,omitempty"` +type ConstInfo struct { + Name string `json:"name"` + Filename string `json:"filename"` + Value int64 `json:"value"` } type Field struct { @@ -199,8 +199,7 @@ type EntityGlobalAddr struct { func (out *Output) Merge(other *Output) { out.Functions = append(out.Functions, other.Functions...) - out.Includes = append(out.Includes, other.Includes...) - out.Defines = append(out.Defines, other.Defines...) + out.Consts = append(out.Consts, other.Consts...) out.Enums = append(out.Enums, other.Enums...) out.Structs = append(out.Structs, other.Structs...) out.Syscalls = append(out.Syscalls, other.Syscalls...) @@ -212,8 +211,7 @@ func (out *Output) Merge(other *Output) { func (out *Output) SortAndDedup() { out.Functions = sortAndDedupSlice(out.Functions) - out.Includes = sortAndDedupSlice(out.Includes) - out.Defines = sortAndDedupSlice(out.Defines) + out.Consts = sortAndDedupSlice(out.Consts) out.Enums = sortAndDedupSlice(out.Enums) out.Structs = sortAndDedupSlice(out.Structs) out.Syscalls = sortAndDedupSlice(out.Syscalls) @@ -229,8 +227,8 @@ func (out *Output) SetSourceFile(file string, updatePath func(string) string) { for _, fn := range out.Functions { fn.File = updatePath(fn.File) } - for i, inc := range out.Includes { - out.Includes[i] = updatePath(inc) + for _, ci := range out.Consts { + ci.Filename = updatePath(ci.Filename) } for _, call := range out.Syscalls { call.SourceFile = file diff --git a/pkg/declextract/serialization.go b/pkg/declextract/serialization.go index d69358679516..5713360974fb 100644 --- a/pkg/declextract/serialization.go +++ b/pkg/declextract/serialization.go @@ -39,14 +39,14 @@ func (ctx *context) fmt(msg string, args ...any) { } func (ctx *context) serializeIncludes() { - for _, inc := range ctx.Includes { + for _, inc := range ctx.includes { ctx.fmt("include <%s>\n", inc) } ctx.fmt("\n") } func (ctx *context) serializeDefines() { - for _, def := range ctx.Defines { + for _, def := range ctx.defines { ctx.fmt("define %v %v\n", def.Name, def.Value) } ctx.fmt("\n") diff --git a/tools/syz-declextract/clangtool/declextract.cpp b/tools/syz-declextract/clangtool/declextract.cpp index c41904d8b401..4012900d62a4 100644 --- a/tools/syz-declextract/clangtool/declextract.cpp +++ b/tools/syz-declextract/clangtool/declextract.cpp @@ -113,7 +113,7 @@ class Extractor : public MatchFinder, public tooling::SourceFileCallbacks { template const T* getResult(StringRef ID) const; FieldType extractRecord(QualType QT, const RecordType* Typ, const std::string& BackupName); std::string extractEnum(const EnumDecl* Decl); - void noteConstUse(const std::string& Name, int64_t Val, const SourceRange& Range); + void emitConst(const std::string& Name, int64_t Val, SourceLocation Loc); std::string getDeclName(const Expr* Expr); const ValueDecl* getValueDecl(const Expr* Expr); std::string getDeclFileID(const Decl* Decl); @@ -304,7 +304,7 @@ std::string Extractor::extractEnum(const EnumDecl* Decl) { std::vector Values; for (const auto* Enumerator : Decl->enumerators()) { const std::string& Name = Enumerator->getNameAsString(); - noteConstUse(Name, Enumerator->getInitVal().getExtValue(), Decl->getSourceRange()); + emitConst(Name, Enumerator->getInitVal().getExtValue(), Decl->getBeginLoc()); Values.push_back(Name); } Output.emit(Enum{ @@ -314,19 +314,11 @@ std::string Extractor::extractEnum(const EnumDecl* Decl) { return Name; } -void Extractor::noteConstUse(const std::string& Name, int64_t Val, const SourceRange& Range) { - const std::string& Filename = std::filesystem::relative(SourceManager->getFilename(Range.getBegin()).str()); - // Include only uapi headers. Some ioctl commands defined in internal headers, or even in .c files. - // They have high chances of breaking compilation during const extract. - // If it's not defined in uapi, emit define with concrete value. - // Note: the value may be wrong for other arches. - if (Filename.find("/uapi/") != std::string::npos && Filename.back() == 'h') { - Output.emit(Include{Filename}); - return; - } - Output.emit(Define{ +void Extractor::emitConst(const std::string& Name, int64_t Val, SourceLocation Loc) { + Output.emit(ConstInfo{ .Name = Name, - .Value = std::to_string(Val), + .Filename = std::filesystem::relative(SourceManager->getFilename(Loc).str()), + .Value = Val, }); } @@ -445,8 +437,8 @@ std::vector> Extractor::extractDesignatedInitConsts( for (auto* Match : Matches) { const int64_t Val = *Match->getAPValueResult().getInt().getRawData(); const auto& Name = Match->getEnumConstantDecl()->getNameAsString(); - const auto& SR = Match->getEnumConstantDecl()->getSourceRange(); - noteConstUse(Name, Val, SR); + const auto& Loc = Match->getEnumConstantDecl()->getBeginLoc(); + emitConst(Name, Val, Loc); Inits.emplace_back(Val, Name); } return Inits; @@ -523,7 +515,7 @@ void Extractor::matchNetlinkFamily() { if (!CmdInit) continue; const std::string& OpName = CmdInit->getNameAsString(); - noteConstUse(OpName, CmdInit->getInitVal().getExtValue(), CmdInit->getSourceRange()); + emitConst(OpName, CmdInit->getInitVal().getExtValue(), CmdInit->getBeginLoc()); std::string Policy; if (OpsFields.count("policy") != 0) { if (const auto* PolicyDecl = OpInit->getInit(OpsFields["policy"])->getAsBuiltinConstantDeclRef(*Context)) @@ -818,7 +810,7 @@ std::vector Extractor::extractIoctlCommands(const std::string& Ioctl) if (MacroDef == Macros.end()) continue; int64_t CmdVal = evaluate(Cmd); - noteConstUse(CmdStr, CmdVal, MacroDef->second.SourceRange); + emitConst(CmdStr, CmdVal, MacroDef->second.SourceRange.getBegin()); FieldType CmdType; const auto Dir = _IOC_DIR(CmdVal); if (Dir == _IOC_NONE) { diff --git a/tools/syz-declextract/clangtool/output.h b/tools/syz-declextract/clangtool/output.h index 24ab82f61918..d89d64afbed5 100644 --- a/tools/syz-declextract/clangtool/output.h +++ b/tools/syz-declextract/clangtool/output.h @@ -62,13 +62,10 @@ struct BufferType { bool IsNonTerminated = false; }; -struct Include { - std::string Filename; -}; - -struct Define { +struct ConstInfo { std::string Name; - std::string Value; + std::string Filename; + int64_t Value; }; struct Field { @@ -201,9 +198,10 @@ struct NetlinkPolicy { std::vector Attrs; }; -inline void print(JSONPrinter& Printer, const Define& V) { +inline void print(JSONPrinter& Printer, const ConstInfo& V) { JSONPrinter::Scope Scope(Printer); Printer.Field("name", V.Name); + Printer.Field("filename", V.Filename); Printer.Field("value", V.Value, true); } @@ -412,13 +410,8 @@ inline FieldType TodoType() { class Output { public: - void emit(Include&& Inc) { - if (IncludesDedup.insert(Inc.Filename).second) - Includes.push_back(Inc.Filename); - } - void emit(Function&& V) { Functions.push_back(std::move(V)); } - void emit(Define&& V) { Defines.push_back(std::move(V)); } + void emit(ConstInfo&& V) { Consts.push_back(std::move(V)); } void emit(Struct&& V) { Structs.push_back(std::move(V)); } void emit(Enum&& V) { Enums.push_back(std::move(V)); } void emit(Syscall&& V) { Syscalls.push_back(std::move(V)); } @@ -430,8 +423,7 @@ class Output { void print() const { JSONPrinter Printer; Printer.Field("functions", Functions); - Printer.Field("includes", Includes); - Printer.Field("defines", Defines); + Printer.Field("consts", Consts); Printer.Field("enums", Enums); Printer.Field("structs", Structs); Printer.Field("syscalls", Syscalls); @@ -443,9 +435,7 @@ class Output { private: std::vector Functions; - std::vector Includes; - std::unordered_set IncludesDedup; - std::vector Defines; + std::vector Consts; std::vector Enums; std::vector Structs; std::vector Syscalls; diff --git a/tools/syz-declextract/testdata/file_operations.c.json b/tools/syz-declextract/testdata/file_operations.c.json index 94ad7bef56e5..df1c9a20f1a9 100644 --- a/tools/syz-declextract/testdata/file_operations.c.json +++ b/tools/syz-declextract/testdata/file_operations.c.json @@ -47,8 +47,32 @@ "is_static": true } ], - "includes": [ - "include/uapi/file_operations.h" + "consts": [ + { + "name": "FOO_IOCTL1", + "filename": "include/uapi/file_operations.h", + "value": 25345 + }, + { + "name": "FOO_IOCTL2", + "filename": "include/uapi/file_operations.h", + "value": 2147771138 + }, + { + "name": "FOO_IOCTL3", + "filename": "include/uapi/file_operations.h", + "value": 2148033283 + }, + { + "name": "FOO_IOCTL4", + "filename": "include/uapi/file_operations.h", + "value": 1074291460 + }, + { + "name": "FOO_IOCTL5", + "filename": "include/uapi/file_operations.h", + "value": 3221775109 + } ], "structs": [ { diff --git a/tools/syz-declextract/testdata/io_uring.c.json b/tools/syz-declextract/testdata/io_uring.c.json index 3f0a74a9506b..da91ce1b689c 100644 --- a/tools/syz-declextract/testdata/io_uring.c.json +++ b/tools/syz-declextract/testdata/io_uring.c.json @@ -29,8 +29,27 @@ "file": "io_uring.c" } ], - "includes": [ - "include/uapi/io_uring.h" + "consts": [ + { + "name": "IORING_OP_NOP", + "filename": "include/uapi/io_uring.h", + "value": 0 + }, + { + "name": "IORING_OP_NOT_SUPPORTED", + "filename": "include/uapi/io_uring.h", + "value": 3 + }, + { + "name": "IORING_OP_READV", + "filename": "include/uapi/io_uring.h", + "value": 1 + }, + { + "name": "IORING_OP_WRITEV", + "filename": "include/uapi/io_uring.h", + "value": 2 + } ], "iouring_ops": [ { diff --git a/tools/syz-declextract/testdata/netlink.c.json b/tools/syz-declextract/testdata/netlink.c.json index 4233eab7d057..e1c2754b1d86 100644 --- a/tools/syz-declextract/testdata/netlink.c.json +++ b/tools/syz-declextract/testdata/netlink.c.json @@ -37,25 +37,71 @@ "is_static": true } ], - "includes": [ - "include/uapi/netlink_family.h" - ], - "defines": [ + "consts": [ { "name": "NETLINK_BAR_CMD_FOO", - "value": "0" + "filename": "netlink.c", + "value": 0 + }, + { + "name": "NETLINK_FOO_ATTR1", + "filename": "include/uapi/netlink_family.h", + "value": 0 + }, + { + "name": "NETLINK_FOO_ATTR2", + "filename": "include/uapi/netlink_family.h", + "value": 1 + }, + { + "name": "NETLINK_FOO_ATTR3", + "filename": "include/uapi/netlink_family.h", + "value": 4 + }, + { + "name": "NETLINK_FOO_ATTR4", + "filename": "include/uapi/netlink_family.h", + "value": 5 + }, + { + "name": "NETLINK_FOO_ATTR5", + "filename": "include/uapi/netlink_family.h", + "value": 6 + }, + { + "name": "NETLINK_FOO_ATTR6", + "filename": "include/uapi/netlink_family.h", + "value": 7 + }, + { + "name": "NETLINK_FOO_ATTR7", + "filename": "include/uapi/netlink_family.h", + "value": 8 + }, + { + "name": "NETLINK_FOO_CMD_BAR", + "filename": "include/uapi/netlink_family.h", + "value": 1 + }, + { + "name": "NETLINK_FOO_CMD_FOO", + "filename": "include/uapi/netlink_family.h", + "value": 0 }, { "name": "NETLINK_FOO_NESTED_ATTR1", - "value": "0" + "filename": "netlink.c", + "value": 0 }, { "name": "NETLINK_FOO_NESTED_ATTR2", - "value": "1" + "filename": "netlink.c", + "value": 1 }, { "name": "NETLINK_NOPOLICY_CMD", - "value": "0" + "filename": "netlink.c", + "value": 0 } ], "structs": [ diff --git a/tools/syz-declextract/testdata/types.c.json b/tools/syz-declextract/testdata/types.c.json index a5a7088db455..82d45e3fe08e 100644 --- a/tools/syz-declextract/testdata/types.c.json +++ b/tools/syz-declextract/testdata/types.c.json @@ -111,18 +111,21 @@ ] } ], - "defines": [ + "consts": [ { "name": "a", - "value": "0" + "filename": "types.c", + "value": 0 }, { "name": "b", - "value": "1" + "filename": "types.c", + "value": 1 }, { "name": "c", - "value": "2" + "filename": "types.c", + "value": 2 } ], "enums": [ From 75783afbacd6878d94d6a06c82be6a9323d888ba Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 17 Jan 2025 10:39:47 +0100 Subject: [PATCH 2/2] pkg/declextract: remove unused includes and defines This is nice on its own, but this will also help to prevent lots of problems when we export more info from the clang tool in future. The clang tool does not know what will end up in the final descriptions, so it exports info about all consts that it encounters. As the result we pull in lots of includes/defines, and lots of kernel includes/defines are broken or create problems. So the fewer we have, the better. --- pkg/ast/ast.go | 2 +- pkg/compiler/check.go | 38 +++++ pkg/compiler/consts.go | 13 +- pkg/declextract/declextract.go | 15 +- sys/linux/auto.txt | 151 +----------------- sys/linux/auto.txt.const | 48 ------ tools/syz-declextract/declextract.go | 21 ++- .../testdata/file_operations.c | 14 ++ .../testdata/file_operations.c.json | 41 +++++ .../testdata/file_operations.c.txt | 1 - .../syz-declextract/testdata/functions.c.txt | 4 - .../testdata/include/uapi/unused_ioctl.h | 6 + tools/syz-declextract/testdata/io_uring.c.txt | 5 - tools/syz-declextract/testdata/netlink.c.txt | 3 - tools/syz-declextract/testdata/syscall.c.txt | 4 - tools/syz-declextract/testdata/types.c.txt | 4 - 16 files changed, 138 insertions(+), 232 deletions(-) create mode 100644 tools/syz-declextract/testdata/include/uapi/unused_ioctl.h diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go index bd2d97c23256..7c1db28ead89 100644 --- a/pkg/ast/ast.go +++ b/pkg/ast/ast.go @@ -71,7 +71,7 @@ type Include struct { } func (n *Include) Info() (Pos, string, string) { - return n.Pos, tok2str[tokInclude], "" + return n.Pos, tok2str[tokInclude], n.File.Value } type Incdir struct { diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index 92e3e5e032ac..fbf84857dd6a 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -676,6 +676,44 @@ func CollectUnused(desc *ast.Description, target *targets.Target, eh ast.ErrorHa return nodes, nil } +// CollectUnusedConsts returns unused defines/includes. This is used only for auto-generated descriptions. +func CollectUnusedConsts(desc *ast.Description, target *targets.Target, includeUse map[string]string, + eh ast.ErrorHandler) ([]ast.Node, error) { + comp := createCompiler(desc, target, eh) + comp.typecheck() + if comp.errors > 0 { + return nil, errors.New("typecheck failed") + } + + var unused []ast.Node + for file, info := range comp.extractConsts() { + if !comp.fileMeta(ast.Pos{File: file}).Automatic { + continue + } + usedDefines := make(map[string]bool) + usedIncludes := make(map[string]bool) + for _, c := range info.Consts { + if c.Used { + usedDefines[c.Name] = true + usedIncludes[includeUse[c.Name]] = true + } + } + for _, decl := range comp.desc.Nodes { + switch n := decl.(type) { + case *ast.Define: + if n.Pos.File == file && !usedDefines[n.Name.Name] { + unused = append(unused, n) + } + case *ast.Include: + if n.Pos.File == file && !usedIncludes[n.File.Value] { + unused = append(unused, n) + } + } + } + } + return unused, nil +} + func (comp *compiler) collectUnused() []ast.Node { var unused []ast.Node diff --git a/pkg/compiler/consts.go b/pkg/compiler/consts.go index bcbd40e5217f..6ce3f81f163f 100644 --- a/pkg/compiler/consts.go +++ b/pkg/compiler/consts.go @@ -23,6 +23,7 @@ type ConstInfo struct { type Const struct { Name string Pos ast.Pos + Used bool // otherwise only defined } func ExtractConsts(desc *ast.Description, target *targets.Target, eh ast.ErrorHandler) map[string]*ConstInfo { @@ -86,7 +87,7 @@ func (comp *compiler) extractConsts() map[string]*ConstInfo { comp.error(pos, "redefining builtin const %v", name) } info.defines[name] = v - comp.addConst(ctx, pos, name) + ctx.addConst(pos, name, false) case *ast.Call: if comp.target.HasCallNumber(n.CallName) { comp.addConst(ctx, pos, comp.target.SyscallPrefix+n.CallName) @@ -178,10 +179,10 @@ func (comp *compiler) addConst(ctx *constContext, pos ast.Pos, name string) { if _, isFlag := comp.intFlags[name]; isFlag { return } - ctx.addConst(pos, name) + ctx.addConst(pos, name, true) for _, instantions := range ctx.instantionStack { for _, pos1 := range instantions { - ctx.addConst(pos1, name) + ctx.addConst(pos1, name, true) } } } @@ -193,11 +194,15 @@ type constInfo struct { incdirArray []string } -func (ctx *constContext) addConst(pos ast.Pos, name string) { +func (ctx *constContext) addConst(pos ast.Pos, name string, used bool) { info := ctx.getConstInfo(pos) + if c := info.consts[name]; c != nil && c.Used { + used = true + } info.consts[name] = &Const{ Pos: pos, Name: name, + Used: used, } } diff --git a/pkg/declextract/declextract.go b/pkg/declextract/declextract.go index fdf06b373e51..9df449b63e59 100644 --- a/pkg/declextract/declextract.go +++ b/pkg/declextract/declextract.go @@ -16,7 +16,7 @@ import ( ) func Run(out *Output, probe *ifaceprobe.Info, syscallRename map[string][]string, trace io.Writer) ( - []byte, []*Interface, error) { + []byte, []*Interface, map[string]string, error) { ctx := &context{ Output: out, probe: probe, @@ -29,7 +29,7 @@ func Run(out *Output, probe *ifaceprobe.Info, syscallRename map[string][]string, } ctx.processFunctions() ctx.processTypingFacts() - ctx.processConsts() + includeUse := ctx.processConsts() ctx.processEnums() ctx.processStructs() ctx.processSyscalls() @@ -37,7 +37,7 @@ func Run(out *Output, probe *ifaceprobe.Info, syscallRename map[string][]string, ctx.serialize() ctx.finishInterfaces() - return ctx.descriptions.Bytes(), ctx.interfaces, errors.Join(ctx.errs...) + return ctx.descriptions.Bytes(), ctx.interfaces, includeUse, errors.Join(ctx.errs...) } type context struct { @@ -75,7 +75,7 @@ func (ctx *context) trace(msg string, args ...any) { } } -func (ctx *context) processConsts() { +func (ctx *context) processConsts() map[string]string { replaces := map[string]string{ // Arches may use some includes from asm-generic and some from arch/arm. // If the arch used for extract used asm-generic for a header, @@ -85,6 +85,7 @@ func (ctx *context) processConsts() { "include/uapi/asm-generic/sockios.h": "asm/sockios.h", } defineDedup := make(map[string]bool) + includeUse := make(map[string]string) for _, ci := range ctx.Consts { if strings.Contains(ci.Filename, "/uapi/") && !strings.Contains(ci.Filename, "arch/x86/") && strings.HasSuffix(ci.Filename, ".h") { @@ -93,6 +94,7 @@ func (ctx *context) processConsts() { filename = replace } ctx.includes = append(ctx.includes, filename) + includeUse[ci.Name] = filename continue } // Remove duplicate defines (even with different values). Unfortunately we get few of these. @@ -118,6 +120,11 @@ func (ctx *context) processConsts() { "linux/types.h", "net/netlink.h", }, ctx.includes...) + // Also pretend they are used. + includeUse["__NR_read"] = "vdso/bits.h" + includeUse["__NR_write"] = "linux/types.h" + includeUse["__NR_close"] = "net/netlink.h" + return includeUse } func (ctx *context) processEnums() { diff --git a/sys/linux/auto.txt b/sys/linux/auto.txt index f2e97b77dbbb..2e5f8bc3e990 100644 --- a/sys/linux/auto.txt +++ b/sys/linux/auto.txt @@ -12,166 +12,65 @@ type auto_union[INFERRED, RAW] [ include include include -include -include include -include include include include include -include -include -include -include -include include include include include -include -include -include -include -include include include -include -include -include -include include include include include include -include -include include include -include -include -include -include include -include include -include -include include -include -include include include -include -include include include include include -include -include -include -include -include -include -include include include -include include -include include -include include -include -include -include -include -include -include -include -include -include -include -include -include include include include include include include -include -include -include include include -include include include include -include include -include -include include -include -include include include include include -include include -include -include -include -include -include -include -include -include -include -include -include -include -include -include -include -include -include -include -include -include include -include include -include include -include include -include -include -include -include -include include -include -include include -include -include -include include -include -include include -include -include include -include -include include NPmode$auto = NPMODE_PASS, NPMODE_DROP, NPMODE_ERROR, NPMODE_QUEUE @@ -6797,16 +6696,7 @@ define IEEE802154_SET_MACPARAMS 35 define IEEE802154_START_REQ 13 define IMADDTIMER 2147764544 define IMDELTIMER 2147764545 -define IOCNR_GET_BUS_ADDRESS 5 -define IOCNR_GET_DEVICE_ID 1 -define IOCNR_GET_PROTOCOLS 2 -define IOCNR_GET_VID_PID 6 -define IOCNR_HP_SET_CHANNEL 4 -define IOCNR_SET_PROTOCOL 3 -define IOCNR_SOFT_RESET 7 define IOCTL_CONFIG_SYS_RESOURCE_PARAMETERS 1074356480 -define IOCTL_GET_DRV_VERSION 2 -define IOCTL_GET_HARD_VERSION 1 define IOCTL_GET_NUM_DEVICES 1074028804 define IOCTL_START_ACCEL_DEV 1074356482 define IOCTL_STATUS_ACCEL_DEV 1074028803 @@ -6828,9 +6718,6 @@ define IOCTL_VMCI_QUEUEPAIR_SETVA 1956 define IOCTL_VMCI_SET_NOTIFY 1995 define IOCTL_VMCI_VERSION 1951 define IOCTL_VMCI_VERSION2 1959 -define IOW_GETINFO 2150154243 -define IOW_READ 1074315266 -define IOW_WRITE 1074315265 define MAC802154_HWSIM_ATTR_RADIO_EDGE 2 define MAC802154_HWSIM_ATTR_RADIO_EDGES 3 define MAC802154_HWSIM_ATTR_RADIO_ID 1 @@ -6840,8 +6727,6 @@ define MAC802154_HWSIM_CMD_GET_RADIO 1 define MAC802154_HWSIM_CMD_NEW_EDGE 8 define MAC802154_HWSIM_CMD_NEW_RADIO 3 define MAC802154_HWSIM_CMD_SET_EDGE 6 -define MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID 1 -define MAC802154_HWSIM_EDGE_ATTR_LQI 2 define MON_IOCG_STATS 2148045315 define MON_IOCH_MFLUSH 37384 define MON_IOCQ_RING_SIZE 37381 @@ -6875,8 +6760,6 @@ define NL802154_ATTR_PID 28 define NL802154_ATTR_SCAN_CHANNELS 33 define NL802154_ATTR_SCAN_DONE_REASON 37 define NL802154_ATTR_SCAN_DURATION 36 -define NL802154_ATTR_SCAN_MEAN_PRF 35 -define NL802154_ATTR_SCAN_PREAMBLE_CODES 34 define NL802154_ATTR_SCAN_TYPE 31 define NL802154_ATTR_SEC_DEVICE 46 define NL802154_ATTR_SEC_DEVKEY 47 @@ -6931,32 +6814,6 @@ define NL802154_CMD_SET_TX_POWER 12 define NL802154_CMD_SET_WPAN_PHY_NETNS 20 define NL802154_CMD_STOP_BEACONS 39 define NL802154_CMD_TRIGGER_SCAN 35 -define NL802154_DEVKEY_ATTR_EXTENDED_ADDR 2 -define NL802154_DEVKEY_ATTR_FRAME_COUNTER 1 -define NL802154_DEVKEY_ATTR_ID 3 -define NL802154_DEV_ADDR_ATTR_EXTENDED 4 -define NL802154_DEV_ADDR_ATTR_MODE 2 -define NL802154_DEV_ADDR_ATTR_PAN_ID 1 -define NL802154_DEV_ADDR_ATTR_SHORT 3 -define NL802154_DEV_ATTR_EXTENDED_ADDR 4 -define NL802154_DEV_ATTR_FRAME_COUNTER 1 -define NL802154_DEV_ATTR_KEY_MODE 6 -define NL802154_DEV_ATTR_PAN_ID 2 -define NL802154_DEV_ATTR_SECLEVEL_EXEMPT 5 -define NL802154_DEV_ATTR_SHORT_ADDR 3 -define NL802154_KEY_ATTR_BYTES 4 -define NL802154_KEY_ATTR_ID 1 -define NL802154_KEY_ATTR_USAGE_CMDS 3 -define NL802154_KEY_ATTR_USAGE_FRAMES 2 -define NL802154_KEY_ID_ATTR_IMPLICIT 3 -define NL802154_KEY_ID_ATTR_INDEX 2 -define NL802154_KEY_ID_ATTR_MODE 1 -define NL802154_KEY_ID_ATTR_SOURCE_EXTENDED 5 -define NL802154_KEY_ID_ATTR_SOURCE_SHORT 4 -define NL802154_SECLEVEL_ATTR_CMD_FRAME 3 -define NL802154_SECLEVEL_ATTR_DEV_OVERRIDE 4 -define NL802154_SECLEVEL_ATTR_FRAME 2 -define NL802154_SECLEVEL_ATTR_LEVELS 1 define NLBL_CALIPSO_A_DOI 1 define NLBL_CALIPSO_A_MTYPE 2 define NLBL_CALIPSO_C_ADD 1 @@ -7008,12 +6865,9 @@ define NLBL_UNLABEL_C_STATICLIST 5 define NLBL_UNLABEL_C_STATICLISTDEF 8 define NLBL_UNLABEL_C_STATICREMOVE 4 define NLBL_UNLABEL_C_STATICREMOVEDEF 7 -define QCA_WLAN_VENDOR_ATTR_MAX 8 -define ROCCATIOCGREPSIZE 2147764465 define SCSI_IOCTL_GET_BUS_NUMBER 21382 define SCSI_IOCTL_GET_IDLUN 21378 define SCSI_IOCTL_SEND_COMMAND 1 -define SECCOMP_IOCTL_NOTIF_ID_VALID_WRONG_DIR 2148016386 define SG_EMULATED_HOST 8707 define SG_GET_COMMAND_Q 8816 define SG_GET_RESERVED_SIZE 8818 @@ -7023,11 +6877,10 @@ define SG_IO 8837 define SG_SET_COMMAND_Q 8817 define SG_SET_RESERVED_SIZE 8821 define SG_SET_TIMEOUT 8705 -define SISUSB_COMMAND 3222074173 -define SISUSB_GET_CONFIG 2152002367 -define SISUSB_GET_CONFIG_SIZE 2147808062 define SNDRV_RAWMIDI_IOCTL_STATUS32 3223607072 define SNDRV_RAWMIDI_IOCTL_STATUS64 3224917792 define SW_SYNC_GET_DEADLINE 3222296322 define SW_SYNC_IOC_CREATE_FENCE 3223869184 define SW_SYNC_IOC_INC 1074026241 +define X86_IOC_RDMSR_REGS 3223348128 +define X86_IOC_WRMSR_REGS 3223348129 diff --git a/sys/linux/auto.txt.const b/sys/linux/auto.txt.const index 9c0077ba4b98..9d1a9bcc6efe 100644 --- a/sys/linux/auto.txt.const +++ b/sys/linux/auto.txt.const @@ -509,16 +509,7 @@ IOAM6_CMD_DEL_SCHEMA = 5 IOAM6_CMD_DUMP_NAMESPACES = 3 IOAM6_CMD_DUMP_SCHEMAS = 6 IOAM6_CMD_NS_SET_SCHEMA = 7 -IOCNR_GET_BUS_ADDRESS = 5 -IOCNR_GET_DEVICE_ID = 1 -IOCNR_GET_PROTOCOLS = 2 -IOCNR_GET_VID_PID = 6 -IOCNR_HP_SET_CHANNEL = 4 -IOCNR_SET_PROTOCOL = 3 -IOCNR_SOFT_RESET = 7 IOCTL_CONFIG_SYS_RESOURCE_PARAMETERS = 1074356480 -IOCTL_GET_DRV_VERSION = 2 -IOCTL_GET_HARD_VERSION = 1 IOCTL_GET_NUM_DEVICES = 1074028804 IOCTL_START_ACCEL_DEV = 1074356482 IOCTL_STATUS_ACCEL_DEV = 1074028803 @@ -540,9 +531,6 @@ IOCTL_VMCI_QUEUEPAIR_SETVA = 1956 IOCTL_VMCI_SET_NOTIFY = 1995 IOCTL_VMCI_VERSION = 1951 IOCTL_VMCI_VERSION2 = 1959 -IOW_GETINFO = 2150154243 -IOW_READ = 1074315266 -IOW_WRITE = 1074315265 IPVS_CMD_ATTR_DAEMON = 3 IPVS_CMD_ATTR_DEST = 2 IPVS_CMD_ATTR_SERVICE = 1 @@ -625,8 +613,6 @@ MAC802154_HWSIM_CMD_GET_RADIO = 1 MAC802154_HWSIM_CMD_NEW_EDGE = 8 MAC802154_HWSIM_CMD_NEW_RADIO = 3 MAC802154_HWSIM_CMD_SET_EDGE = 6 -MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID = 1 -MAC802154_HWSIM_EDGE_ATTR_LQI = 2 MACSEC_ATTR_IFINDEX = 1 MACSEC_ATTR_OFFLOAD = 9 MACSEC_ATTR_RXSC_CONFIG = 2 @@ -1283,8 +1269,6 @@ NL802154_ATTR_PID = 28 NL802154_ATTR_SCAN_CHANNELS = 33 NL802154_ATTR_SCAN_DONE_REASON = 37 NL802154_ATTR_SCAN_DURATION = 36 -NL802154_ATTR_SCAN_MEAN_PRF = 35 -NL802154_ATTR_SCAN_PREAMBLE_CODES = 34 NL802154_ATTR_SCAN_TYPE = 31 NL802154_ATTR_SEC_DEVICE = 46 NL802154_ATTR_SEC_DEVKEY = 47 @@ -1339,32 +1323,6 @@ NL802154_CMD_SET_TX_POWER = 12 NL802154_CMD_SET_WPAN_PHY_NETNS = 20 NL802154_CMD_STOP_BEACONS = 39 NL802154_CMD_TRIGGER_SCAN = 35 -NL802154_DEVKEY_ATTR_EXTENDED_ADDR = 2 -NL802154_DEVKEY_ATTR_FRAME_COUNTER = 1 -NL802154_DEVKEY_ATTR_ID = 3 -NL802154_DEV_ADDR_ATTR_EXTENDED = 4 -NL802154_DEV_ADDR_ATTR_MODE = 2 -NL802154_DEV_ADDR_ATTR_PAN_ID = 1 -NL802154_DEV_ADDR_ATTR_SHORT = 3 -NL802154_DEV_ATTR_EXTENDED_ADDR = 4 -NL802154_DEV_ATTR_FRAME_COUNTER = 1 -NL802154_DEV_ATTR_KEY_MODE = 6 -NL802154_DEV_ATTR_PAN_ID = 2 -NL802154_DEV_ATTR_SECLEVEL_EXEMPT = 5 -NL802154_DEV_ATTR_SHORT_ADDR = 3 -NL802154_KEY_ATTR_BYTES = 4 -NL802154_KEY_ATTR_ID = 1 -NL802154_KEY_ATTR_USAGE_CMDS = 3 -NL802154_KEY_ATTR_USAGE_FRAMES = 2 -NL802154_KEY_ID_ATTR_IMPLICIT = 3 -NL802154_KEY_ID_ATTR_INDEX = 2 -NL802154_KEY_ID_ATTR_MODE = 1 -NL802154_KEY_ID_ATTR_SOURCE_EXTENDED = 5 -NL802154_KEY_ID_ATTR_SOURCE_SHORT = 4 -NL802154_SECLEVEL_ATTR_CMD_FRAME = 3 -NL802154_SECLEVEL_ATTR_DEV_OVERRIDE = 4 -NL802154_SECLEVEL_ATTR_FRAME = 2 -NL802154_SECLEVEL_ATTR_LEVELS = 1 NLBL_CALIPSO_A_DOI = 1 NLBL_CALIPSO_A_MTYPE = 2 NLBL_CALIPSO_C_ADD = 1 @@ -1509,7 +1467,6 @@ PPPIOCSPASS = 1074820167, 386:arm:1074295879, mips64le:ppc64le:2148561991 PPPIOCUNBRIDGECHAN = 29748, mips64le:ppc64le:536900660 PROCMAP_QUERY = 3228067345 PSAMPLE_CMD_GET_GROUP = 1 -QCA_WLAN_VENDOR_ATTR_MAX = 8 RFKILL_IOC_MAX_SIZE = 2 RFKILL_IOC_NOINPUT = 1 RNDADDENTROPY = 1074287107, mips64le:ppc64le:2148028931 @@ -1518,7 +1475,6 @@ RNDCLEARPOOL = 20998, mips64le:ppc64le:536891910 RNDGETENTCNT = 2147766784, mips64le:ppc64le:1074024960 RNDRESEEDCRNG = 20999, mips64le:ppc64le:536891911 RNDZAPENTCNT = 20996, mips64le:ppc64le:536891908 -ROCCATIOCGREPSIZE = 2147764465 RTC_AIE_OFF = 28674, mips64le:ppc64le:536899586 RTC_AIE_ON = 28673, mips64le:ppc64le:536899585 RTC_ALM_READ = 2149871624, mips64le:ppc64le:1076129800 @@ -1541,7 +1497,6 @@ RTC_WKALM_SET = 1076391951, mips64le:ppc64le:2150133775 SCSI_IOCTL_GET_BUS_NUMBER = 21382 SCSI_IOCTL_GET_IDLUN = 21378 SCSI_IOCTL_SEND_COMMAND = 1 -SECCOMP_IOCTL_NOTIF_ID_VALID_WRONG_DIR = 2148016386 SEG6_ATTR_ALGID = 6 SEG6_ATTR_DST = 1 SEG6_ATTR_DSTLEN = 2 @@ -1564,9 +1519,6 @@ SG_SET_RESERVED_SIZE = 8821 SG_SET_TIMEOUT = 8705 SIOCGIFHWADDR = 35111 SIOCSIFHWADDR = 35108 -SISUSB_COMMAND = 3222074173 -SISUSB_GET_CONFIG = 2152002367 -SISUSB_GET_CONFIG_SIZE = 2147808062 SMC_NETLINK_ADD_UEID = 10 SMC_NETLINK_DISABLE_HS_LIMITATION = 18 SMC_NETLINK_DISABLE_SEID = 15 diff --git a/tools/syz-declextract/declextract.go b/tools/syz-declextract/declextract.go index 0853756bf5b0..7d85adaf8f9e 100644 --- a/tools/syz-declextract/declextract.go +++ b/tools/syz-declextract/declextract.go @@ -62,7 +62,7 @@ func run(autoFile string, loadProbeInfo func() (*ifaceprobe.Info, error), cfg *c if err != nil { return err } - descriptions, interfaces, err := declextract.Run(out, probeInfo, syscallRename, cfg.DebugTrace) + descriptions, interfaces, includeUse, err := declextract.Run(out, probeInfo, syscallRename, cfg.DebugTrace) if err != nil { return err } @@ -94,6 +94,20 @@ func run(autoFile string, loadProbeInfo func() (*ifaceprobe.Info, error), cfg *c if err := osutil.WriteFile(autoFile+".info", serialize(interfaces)); err != nil { return err } + removeUnused(desc, "", unusedNodes) + // Second pass to remove unused defines/includes. This needs to be done after removing + // other garbage b/c they may be used by other garbage. + unusedConsts, err := compiler.CollectUnusedConsts(desc.Clone(), target, includeUse, eh) + if err != nil { + return fmt.Errorf("failed to typecheck descriptions: %w\n%s", err, errors.Bytes()) + } + removeUnused(desc, autoFile, unusedConsts) + // We need re-parse them again b/c new lines are fixed up during parsing. + formatted := ast.Format(ast.Parse(ast.Format(desc), autoFile, nil)) + return osutil.WriteFile(autoFile, formatted) +} + +func removeUnused(desc *ast.Description, autoFile string, unusedNodes []ast.Node) { unused := make(map[string]bool) for _, n := range unusedNodes { _, typ, name := n.Info() @@ -101,11 +115,8 @@ func run(autoFile string, loadProbeInfo func() (*ifaceprobe.Info, error), cfg *c } desc.Nodes = slices.DeleteFunc(desc.Nodes, func(n ast.Node) bool { pos, typ, name := n.Info() - return pos.File != autoFile || unused[typ+name] + return autoFile != "" && pos.File != autoFile || unused[typ+name] }) - // We need re-parse them again b/c new lines are fixed up during parsing. - formatted := ast.Format(ast.Parse(ast.Format(desc), autoFile, nil)) - return osutil.WriteFile(autoFile, formatted) } func prepare(loadProbeInfo func() (*ifaceprobe.Info, error), cfg *clangtool.Config) ( diff --git a/tools/syz-declextract/testdata/file_operations.c b/tools/syz-declextract/testdata/file_operations.c index 04d548f98a67..0dd8b9b21676 100644 --- a/tools/syz-declextract/testdata/file_operations.c +++ b/tools/syz-declextract/testdata/file_operations.c @@ -3,6 +3,7 @@ #include "include/fs.h" #include "include/uapi/file_operations.h" +#include "include/uapi/unused_ioctl.h" static void foo_open() {} static void foo_read() {} @@ -43,3 +44,16 @@ const struct file_operations proc_ops[] = { .unlocked_ioctl = proc_ioctl, }, }; + +#define UNUSED_IOCTL2 _IO('c', 2) + +static void unused_ioctl(unsigned int cmd) { + switch (cmd) { + case UNUSED_IOCTL1: + case UNUSED_IOCTL2: + } +} + +const struct file_operations unused = { + .unlocked_ioctl = unused_ioctl, +}; diff --git a/tools/syz-declextract/testdata/file_operations.c.json b/tools/syz-declextract/testdata/file_operations.c.json index df1c9a20f1a9..716dbec38e27 100644 --- a/tools/syz-declextract/testdata/file_operations.c.json +++ b/tools/syz-declextract/testdata/file_operations.c.json @@ -45,6 +45,12 @@ "name": "proc_write", "file": "file_operations.c", "is_static": true + }, + { + "name": "unused_ioctl", + "file": "file_operations.c", + "is_static": true, + "loc": 4 } ], "consts": [ @@ -72,6 +78,16 @@ "name": "FOO_IOCTL5", "filename": "include/uapi/file_operations.h", "value": 3221775109 + }, + { + "name": "UNUSED_IOCTL1", + "filename": "include/uapi/unused_ioctl.h", + "value": 25345 + }, + { + "name": "UNUSED_IOCTL2", + "filename": "file_operations.c", + "value": 25346 } ], "structs": [ @@ -185,6 +201,31 @@ "mmap": "proc_open", "ioctl": "proc_ioctl", "source_file": "file_operations.c" + }, + { + "name": "unused_file_operations", + "ioctl": "unused_ioctl", + "ioctl_cmds": [ + { + "name": "UNUSED_IOCTL2", + "type": { + "int": { + "byte_size": 1, + "is_const": true + } + } + }, + { + "name": "UNUSED_IOCTL1", + "type": { + "int": { + "byte_size": 1, + "is_const": true + } + } + } + ], + "source_file": "file_operations.c" } ] } \ No newline at end of file diff --git a/tools/syz-declextract/testdata/file_operations.c.txt b/tools/syz-declextract/testdata/file_operations.c.txt index f2a0455bcead..e94856980690 100644 --- a/tools/syz-declextract/testdata/file_operations.c.txt +++ b/tools/syz-declextract/testdata/file_operations.c.txt @@ -6,7 +6,6 @@ type auto_todo int8 include include -include include resource fd_foo_file_operations[fd] diff --git a/tools/syz-declextract/testdata/functions.c.txt b/tools/syz-declextract/testdata/functions.c.txt index 6dc51303b2e4..8bd11c8fc915 100644 --- a/tools/syz-declextract/testdata/functions.c.txt +++ b/tools/syz-declextract/testdata/functions.c.txt @@ -4,8 +4,4 @@ meta automatic type auto_todo int8 -include -include -include - functions$auto(x fd) fd diff --git a/tools/syz-declextract/testdata/include/uapi/unused_ioctl.h b/tools/syz-declextract/testdata/include/uapi/unused_ioctl.h new file mode 100644 index 000000000000..6c3dbb036786 --- /dev/null +++ b/tools/syz-declextract/testdata/include/uapi/unused_ioctl.h @@ -0,0 +1,6 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +#include "ioctl.h" + +#define UNUSED_IOCTL1 _IO('c', 1) diff --git a/tools/syz-declextract/testdata/io_uring.c.txt b/tools/syz-declextract/testdata/io_uring.c.txt index 77183198f9ea..2829bcbf1b7c 100644 --- a/tools/syz-declextract/testdata/io_uring.c.txt +++ b/tools/syz-declextract/testdata/io_uring.c.txt @@ -3,8 +3,3 @@ meta automatic type auto_todo int8 - -include -include -include -include diff --git a/tools/syz-declextract/testdata/netlink.c.txt b/tools/syz-declextract/testdata/netlink.c.txt index e61244406130..6ceb9111efd8 100644 --- a/tools/syz-declextract/testdata/netlink.c.txt +++ b/tools/syz-declextract/testdata/netlink.c.txt @@ -4,9 +4,6 @@ meta automatic type auto_todo int8 -include -include -include include resource genl_bar_family_id$auto[int16] diff --git a/tools/syz-declextract/testdata/syscall.c.txt b/tools/syz-declextract/testdata/syscall.c.txt index de87f1866580..bb0cad8c4cc3 100644 --- a/tools/syz-declextract/testdata/syscall.c.txt +++ b/tools/syz-declextract/testdata/syscall.c.txt @@ -4,9 +4,5 @@ meta automatic type auto_todo int8 -include -include -include - chmod$auto(filename ptr[in, filename], mode int32) open$auto(filename ptr[in, filename], flags int32, mode int32) diff --git a/tools/syz-declextract/testdata/types.c.txt b/tools/syz-declextract/testdata/types.c.txt index 45d451d8a26f..04a160771a8a 100644 --- a/tools/syz-declextract/testdata/types.c.txt +++ b/tools/syz-declextract/testdata/types.c.txt @@ -4,10 +4,6 @@ meta automatic type auto_todo int8 -include -include -include - bitfield_enum$auto = a, b, c types_syscall$auto(p ptr[inout, anon_struct$auto], y ptr[inout, void], b ptr[inout, bitfields$auto], pid pid, f int32, v ptr[inout, various$auto])