From 38ee454540b9b41d5cc173871dfbf7dd140e8abc Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 17 Jan 2025 10:39:46 +0100 Subject: 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 +-- 3 files changed, 52 insertions(+), 25 deletions(-) (limited to 'pkg/declextract') diff --git a/pkg/declextract/declextract.go b/pkg/declextract/declextract.go index 1f4592523..fdf06b373 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 266647ed8..8167d8b99 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 d69358679..571336097 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") -- cgit mrf-deployment