From 810241190102eaf849f5744ca7eeb68ad34f01d7 Mon Sep 17 00:00:00 2001 From: Florent Revest Date: Tue, 4 Jul 2023 17:59:04 +0200 Subject: pkg/csource: annotate syscall() args with their pretty-printed values This factorizes const arguments into the shortest flags OR bitmask possible so they are easy to read. E.g: /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul --- pkg/csource/csource.go | 52 ++++++++++++++++++++++++++++++++++++++++++++- pkg/csource/csource_test.go | 19 +++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) (limited to 'pkg/csource') diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go index a56a738c5..b1cc2368b 100644 --- a/pkg/csource/csource.go +++ b/pkg/csource/csource.go @@ -26,6 +26,7 @@ package csource import ( "bytes" "fmt" + "math/bits" "regexp" "sort" "strconv" @@ -501,8 +502,57 @@ func (ctx *context) copyout(w *bytes.Buffer, call prog.ExecCall, resCopyout bool } } +func (ctx *context) factorizeAsFlags(value uint64, flags []string, attemptsLeft *int) ([]string, uint64) { + if len(flags) == 0 || value == 0 || *attemptsLeft == 0 { + return nil, value + } + + *attemptsLeft -= 1 + currentFlag := flags[0] + subset, remainder := ctx.factorizeAsFlags(value, flags[1:], attemptsLeft) + + if flagMask, ok := ctx.p.Target.ConstMap[currentFlag]; ok && (value&flagMask == flagMask) { + subsetIfTaken, remainderIfTaken := ctx.factorizeAsFlags(value & ^flagMask, flags[1:], attemptsLeft) + subsetIfTaken = append(subsetIfTaken, currentFlag) + + bits, bitsIfTaken := bits.OnesCount64(remainder), bits.OnesCount64(remainderIfTaken) + if (bitsIfTaken < bits) || (bits == bitsIfTaken && len(subsetIfTaken) < len(subset)) { + return subsetIfTaken, remainderIfTaken + } + } + + return subset, remainder +} + +func (ctx *context) prettyPrintValue(field prog.Field, arg prog.ExecArgConst) string { + mask := (uint64(1) << (arg.Size * 8)) - 1 + v := arg.Value & mask + + f := ctx.p.Target.FlagsMap[field.Type.Name()] + if len(f) == 0 { + return "" + } + + maxFactorizationAttempts := 256 + flags, remainder := ctx.factorizeAsFlags(v, f, &maxFactorizationAttempts) + if len(flags) == 0 { + return "" + } + if remainder != 0 { + flags = append(flags, fmt.Sprintf("0x%x", remainder)) + } + + return strings.Join(flags, "|") +} + func (ctx *context) argComment(field prog.Field, arg prog.ExecArg) string { - return "/*" + field.Name + "=" + "*/" + val := "" + constArg, isConstArg := arg.(prog.ExecArgConst) + if isConstArg { + val = ctx.prettyPrintValue(field, constArg) + } + + return "/*" + field.Name + "=" + val + "*/" } func (ctx *context) constArgToStr(arg prog.ExecArgConst, suffix string) string { diff --git a/pkg/csource/csource_test.go b/pkg/csource/csource_test.go index eb85fd77b..957d2ebc9 100644 --- a/pkg/csource/csource_test.go +++ b/pkg/csource/csource_test.go @@ -223,6 +223,24 @@ syscall(SYS_csource6, /*buf=*/0x%xul); target.DataOffset+0x100, target.DataOffset+0x100, target.DataOffset+0x140, target.DataOffset+0x140), }, + { + input: ` +csource7(0x0) +csource7(0x1) +csource7(0x2) +csource7(0x3) +csource7(0x4) +csource7(0x5) +`, + output: ` +syscall(SYS_csource7, /*flag=*/0ul); +syscall(SYS_csource7, /*flag=BIT_0*/1ul); +syscall(SYS_csource7, /*flag=BIT_1*/2ul); +syscall(SYS_csource7, /*flag=BIT_0_AND_1*/3ul); +syscall(SYS_csource7, /*flag=*/4ul); +syscall(SYS_csource7, /*flag=BIT_0|0x4*/5ul); +`, + }, } for i, test := range tests { t.Run(fmt.Sprint(i), func(t *testing.T) { @@ -231,6 +249,7 @@ syscall(SYS_csource6, /*buf=*/0x%xul); t.Fatal(err) } ctx := &context{ + p: p, target: target, sysTarget: targets.Get(target.OS, target.Arch), } -- cgit mrf-deployment