aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS1
-rw-r--r--pkg/csource/csource.go58
-rw-r--r--pkg/csource/csource_test.go5
-rw-r--r--pkg/csource/options.go18
-rw-r--r--pkg/csource/syscall_generation_test.go201
-rw-r--r--pkg/csource/testdata/025
-rw-r--r--pkg/csource/testdata/180
-rw-r--r--pkg/csource/testdata/2144
-rw-r--r--prog/prog.go102
-rw-r--r--tools/syz-prog2c/prog2c.go1
10 files changed, 622 insertions, 13 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 0f1a890d6..0cb36092b 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -43,6 +43,7 @@ Google Inc.
Gabe Kirkpatrick
Kevin Krakauer
Pimyn Girgis
+ Ethan Graham
Baozeng Ding
Lorenzo Stoakes
Jeremy Huang
diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go
index a37040e8f..ecfca80ea 100644
--- a/pkg/csource/csource.go
+++ b/pkg/csource/csource.go
@@ -74,13 +74,17 @@ func generateSandboxFunctionSignature(sandboxName string, sandboxArg int) string
func (ctx *context) generateSource() ([]byte, error) {
ctx.filterCalls()
- calls, vars, err := ctx.generateProgCalls(ctx.p, ctx.opts.Trace)
+ calls, vars, err := ctx.generateProgCalls(ctx.p, ctx.opts.Trace, ctx.opts.CallComments)
if err != nil {
return nil, err
}
mmapProg := ctx.p.Target.DataMmapProg()
- mmapCalls, _, err := ctx.generateProgCalls(mmapProg, false)
+ // Disable comments on the mmap calls as they are part of the initial setup
+ // for a program and always very similar. Comments on these provide
+ // little-to-no additional context that can't be inferred from looking at
+ // the call arguments directly, and just make the source longer.
+ mmapCalls, _, err := ctx.generateProgCalls(mmapProg, false, false)
if err != nil {
return nil, err
}
@@ -236,7 +240,47 @@ func (ctx *context) generateSyscallDefines() string {
return buf.String()
}
-func (ctx *context) generateProgCalls(p *prog.Prog, trace bool) ([]string, []uint64, error) {
+const indent string = " " // Two spaces.
+// clang-format produces nicer comments with '//' prefixing versus '/* ... */' style comments.
+const commentPrefix string = "//"
+
+func linesToCStyleComment(lines []string) string {
+ var commentBuilder strings.Builder
+ for i, line := range lines {
+ commentBuilder.WriteString(commentPrefix + indent + line)
+ if i != len(lines)-1 {
+ commentBuilder.WriteString("\n")
+ }
+ }
+ return commentBuilder.String()
+}
+
+func generateComment(call *prog.Call) string {
+ lines := []string{fmt.Sprintf("%s arguments: [", call.Meta.Name)}
+ for i, arg := range call.Args {
+ argLines := prog.FormatArg(arg, call.Meta.Args[i].Name)
+ // Indent the formatted argument.
+ for i := range argLines {
+ argLines[i] = indent + argLines[i]
+ }
+ lines = append(lines, argLines...)
+ }
+ lines = append(lines, "]")
+ if call.Ret != nil {
+ lines = append(lines, "returns "+call.Ret.Type().Name())
+ }
+ return linesToCStyleComment(lines)
+}
+
+func (ctx *context) generateProgCalls(p *prog.Prog, trace, addComments bool) ([]string, []uint64, error) {
+ var comments []string
+ if addComments {
+ comments = make([]string, len(p.Calls))
+ for i, call := range p.Calls {
+ comments[i] = generateComment(call)
+ }
+ }
+
exec, err := p.SerializeForExec()
if err != nil {
return nil, nil, fmt.Errorf("failed to serialize program: %w", err)
@@ -245,15 +289,19 @@ func (ctx *context) generateProgCalls(p *prog.Prog, trace bool) ([]string, []uin
if err != nil {
return nil, nil, err
}
- calls, vars := ctx.generateCalls(decoded, trace)
+ calls, vars := ctx.generateCalls(decoded, trace, addComments, comments)
return calls, vars, nil
}
-func (ctx *context) generateCalls(p prog.ExecProg, trace bool) ([]string, []uint64) {
+func (ctx *context) generateCalls(p prog.ExecProg, trace, addComments bool,
+ callComments []string) ([]string, []uint64) {
var calls []string
csumSeq := 0
for ci, call := range p.Calls {
w := new(bytes.Buffer)
+ if addComments {
+ w.WriteString(callComments[ci] + "\n")
+ }
// Copyin.
for _, copyin := range call.Copyin {
ctx.copyin(w, &csumSeq, copyin)
diff --git a/pkg/csource/csource_test.go b/pkg/csource/csource_test.go
index 3c9cdc360..e48f197c3 100644
--- a/pkg/csource/csource_test.go
+++ b/pkg/csource/csource_test.go
@@ -285,7 +285,10 @@ syscall(SYS_csource8, /*num=*/(intptr_t)-1);
target: test.target,
sysTarget: targets.Get(test.target.OS, test.target.Arch),
}
- calls, _, err := ctx.generateProgCalls(p, false)
+ // Disable comment generation, as it's not the focus of these tests.
+ // This simplifies the expected output. For tests covering comments, see
+ // /pkg/csource/syscall_generation_test.go.
+ calls, _, err := ctx.generateProgCalls(p, false, false)
if err != nil {
t.Fatal(err)
}
diff --git a/pkg/csource/options.go b/pkg/csource/options.go
index 74d4a587a..4438e5df2 100644
--- a/pkg/csource/options.go
+++ b/pkg/csource/options.go
@@ -50,6 +50,9 @@ type Options struct {
HandleSegv bool `json:"segv,omitempty"`
Trace bool `json:"trace,omitempty"`
+
+ CallComments bool `json:"callcomments,omitempty"`
+
LegacyOptions
}
@@ -160,13 +163,14 @@ func (opts Options) checkLinuxOnly(OS string) error {
func DefaultOpts(cfg *mgrconfig.Config) Options {
opts := Options{
- Threaded: true,
- Repeat: true,
- Procs: cfg.Procs,
- Slowdown: cfg.Timeouts.Slowdown,
- Sandbox: cfg.Sandbox,
- UseTmpDir: true,
- HandleSegv: true,
+ Threaded: true,
+ Repeat: true,
+ Procs: cfg.Procs,
+ Slowdown: cfg.Timeouts.Slowdown,
+ Sandbox: cfg.Sandbox,
+ UseTmpDir: true,
+ HandleSegv: true,
+ CallComments: true,
}
if cfg.TargetOS == targets.Linux {
opts.NetInjection = true
diff --git a/pkg/csource/syscall_generation_test.go b/pkg/csource/syscall_generation_test.go
new file mode 100644
index 000000000..c84cb703b
--- /dev/null
+++ b/pkg/csource/syscall_generation_test.go
@@ -0,0 +1,201 @@
+// Copyright 2025 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.
+package csource
+
+import (
+ "bufio"
+ "flag"
+ "fmt"
+ "os"
+ "path"
+ "strings"
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/google/syzkaller/prog"
+ "github.com/google/syzkaller/sys/targets"
+ "github.com/stretchr/testify/assert"
+)
+
+var flagUpdate = flag.Bool("update", false, "update test files accordingly to current results")
+
+type testData struct {
+ filepath string
+ // The input syscall description, e.g. bind$netlink(r0, &(0x7f0000514ff4)={0x10, 0x0, 0x0, 0x2ffffffff}, 0xc).
+ input string
+ calls []annotatedCall
+}
+
+type annotatedCall struct {
+ comment string
+ syscall string
+}
+
+func TestGenerateSyscalls(t *testing.T) {
+ flag.Parse()
+
+ testCases, err := readTestCases("./testdata")
+ assert.NoError(t, err)
+
+ target, err := prog.GetTarget(targets.Linux, targets.AMD64)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for _, tc := range testCases {
+ newData, equal := testGenerationImpl(t, tc, target)
+ if *flagUpdate && !equal {
+ t.Logf("writing updated contents to %s", tc.filepath)
+ err = os.WriteFile(tc.filepath, []byte(newData), 0640)
+ assert.NoError(t, err)
+ }
+ }
+}
+
+func readTestCases(dir string) ([]testData, error) {
+ var testCases []testData
+
+ testFiles, err := os.ReadDir(dir)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, testFile := range testFiles {
+ if testFile.IsDir() {
+ continue
+ }
+
+ testCase, err := readTestData(path.Join(dir, testFile.Name()))
+ if err != nil {
+ return nil, err
+ }
+ testCases = append(testCases, testCase)
+ }
+
+ return testCases, nil
+}
+
+func readTestData(filepath string) (testData, error) {
+ var td testData
+ td.filepath = filepath
+
+ file, err := os.Open(filepath)
+ if err != nil {
+ return testData{}, err
+ }
+
+ scanner := bufio.NewScanner(file)
+
+ var inputBuilder strings.Builder
+ for scanner.Scan() {
+ line := scanner.Text()
+ if line == "" {
+ break
+ }
+ inputBuilder.WriteString(line + "\n")
+ }
+ td.input = inputBuilder.String()
+
+ var commentBuilder strings.Builder
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.HasPrefix(line, commentPrefix) {
+ if commentBuilder.Len() > 0 {
+ commentBuilder.WriteString("\n")
+ }
+ commentBuilder.WriteString(line)
+ } else {
+ td.calls = append(td.calls, annotatedCall{
+ comment: commentBuilder.String(),
+ syscall: line,
+ })
+ commentBuilder.Reset()
+ }
+ }
+
+ if err := scanner.Err(); err != nil {
+ return testData{}, err
+ }
+
+ if commentBuilder.Len() != 0 {
+ return testData{}, fmt.Errorf("expected a syscall expression but got EOF")
+ }
+ return td, nil
+}
+
+// Returns the generated content, and whether or not they were equal.
+func testGenerationImpl(t *testing.T, test testData, target *prog.Target) (string, bool) {
+ p, err := target.Deserialize([]byte(test.input), prog.Strict)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Generate the actual comments.
+ var actualComments []string
+ for _, call := range p.Calls {
+ comment := generateComment(call)
+ // Formatted comments make comparison easier.
+ formatted, err := Format([]byte(comment))
+ if err != nil {
+ t.Fatal(err)
+ }
+ actualComments = append(actualComments, string(formatted))
+ }
+
+ // Minimal options as we are just testing syscall output.
+ opts := Options{
+ Slowdown: 1,
+ }
+ ctx := &context{
+ p: p,
+ opts: opts,
+ target: p.Target,
+ sysTarget: targets.Get(p.Target.OS, p.Target.Arch),
+ calls: make(map[string]uint64),
+ }
+
+ // Partially replicate the flow from csource.go.
+ exec, err := p.SerializeForExec()
+ if err != nil {
+ t.Fatal(err)
+ }
+ decoded, err := ctx.target.DeserializeExec(exec, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var actualSyscalls []string
+ for _, execCall := range decoded.Calls {
+ actualSyscalls = append(actualSyscalls, ctx.fmtCallBody(execCall))
+ }
+
+ if len(actualSyscalls) != len(test.calls) || len(actualSyscalls) != len(actualComments) {
+ t.Fatal("Generated inconsistent syscalls or comments.")
+ }
+
+ areEqual := true
+ for i := range actualSyscalls {
+ if diffSyscalls := cmp.Diff(actualSyscalls[i], test.calls[i].syscall); diffSyscalls != "" {
+ fmt.Print(diffSyscalls)
+ t.Fail()
+ areEqual = false
+ }
+ if diffComments := cmp.Diff(actualComments[i], test.calls[i].comment); diffComments != "" {
+ fmt.Print(diffComments)
+ t.Fail()
+ areEqual = false
+ }
+ }
+
+ var outputBuilder strings.Builder
+ outputBuilder.WriteString(test.input + "\n")
+ for i := range actualSyscalls {
+ outputBuilder.WriteString(actualComments[i] + "\n")
+ outputBuilder.WriteString(actualSyscalls[i])
+ // Avoid trailing newline.
+ if i != len(test.calls)-1 {
+ outputBuilder.WriteString("\n")
+ }
+ }
+
+ return outputBuilder.String(), areEqual
+}
diff --git a/pkg/csource/testdata/0 b/pkg/csource/testdata/0
new file mode 100644
index 000000000..1f8c0f959
--- /dev/null
+++ b/pkg/csource/testdata/0
@@ -0,0 +1,25 @@
+r0 = socket$netlink(0x10, 0x3, 0x2)
+bind$netlink(r0, &(0x7f0000514ff4)={0x10, 0x0, 0x0, 0x2ffffffff}, 0xc)
+
+// socket$netlink arguments: [
+// domain: const = 0x10 (8 bytes)
+// type: const = 0x3 (8 bytes)
+// proto: netlink_proto = 0x2 (4 bytes)
+// ]
+// returns sock_netlink
+syscall(__NR_socket, /*domain=*/0x10ul, /*type=*/3ul, /*proto=NETLINK_USERSOCK*/2)
+// bind$netlink arguments: [
+// fd: sock_netlink (resource)
+// addr: ptr[in, sockaddr_nl_t[AF_NETLINK, netlink_port_id,
+// flags[netlink_group_bitmap, int32]]] {
+// sockaddr_nl_t[AF_NETLINK, netlink_port_id, flags[netlink_group_bitmap,
+// int32]] {
+// nl_family: const = 0x10 (2 bytes)
+// nl_pad: const = 0x0 (2 bytes)
+// nl_pid: int32 = 0x0 (4 bytes)
+// nl_groups: netlink_group_bitmap = 0x2ffffffff (4 bytes)
+// }
+// }
+// addrlen: len = 0xc (8 bytes)
+// ]
+syscall(__NR_bind, /*fd=*/r[0], /*addr=*/0x200000514ff4ul, /*addrlen=*/0xcul) \ No newline at end of file
diff --git a/pkg/csource/testdata/1 b/pkg/csource/testdata/1
new file mode 100644
index 000000000..60af6b708
--- /dev/null
+++ b/pkg/csource/testdata/1
@@ -0,0 +1,80 @@
+r0 = openat$iommufd(0xffffffffffffff9c, &(0x7f0000000000), 0x0, 0x0)
+ioctl$IOMMU_IOAS_ALLOC(r0, 0x3b81, &(0x7f00000003c0)={0xc, 0x0, <r1=>0x0})
+ioctl$IOMMU_IOAS_MAP$PAGES(r0, 0x3b85, &(0x7f0000000040)={0x28, 0x7, r1, 0x0, &(0x7f0000800000/0x800000)=nil, 0x800000, 0x0})
+ioctl$IOMMU_TEST_OP_CREATE_ACCESS(r0, 0x3ba0, &(0x7f0000000340)={0x48, 0x5, r1, 0x0, <r2=>0xffffffffffffffff, 0x1})
+ioctl$IOMMU_TEST_OP_ACCESS_PAGES$syz(r0, 0x3ba0, &(0x7f0000000100)={0x48, 0x7, r2, 0x0, 0x0, 0x0, 0x200000, 0x0, 0x334e8b, 0x200000000000})
+
+// openat$iommufd arguments: [
+// fd: const = 0xffffffffffffff9c (8 bytes)
+// file: ptr[in, buffer] {
+// buffer: {2f 64 65 76 2f 69 6f 6d 6d 75 00} (length 0xb)
+// }
+// flags: open_flags = 0x0 (4 bytes)
+// mode: const = 0x0 (2 bytes)
+// ]
+// returns fd_iommufd
+syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x200000000000ul, /*flags=*/0, /*mode=*/0)
+// ioctl$IOMMU_IOAS_ALLOC arguments: [
+// fd: fd_iommufd (resource)
+// cmd: const = 0x3b81 (4 bytes)
+// arg: ptr[in, iommu_ioas_alloc] {
+// iommu_ioas_alloc {
+// size: len = 0xc (4 bytes)
+// flags: const = 0x0 (4 bytes)
+// out_ioas_id: ioas_handle (resource)
+// }
+// }
+// ]
+syscall(__NR_ioctl, /*fd=*/r[0], /*cmd=*/0x3b81, /*arg=*/0x2000000003c0ul)
+// ioctl$IOMMU_IOAS_MAP$PAGES arguments: [
+// fd: fd_iommufd (resource)
+// cmd: const = 0x3b85 (4 bytes)
+// arg: ptr[in, iommu_ioas_map$PAGES] {
+// iommu_ioas_map$PAGES {
+// size: len = 0x28 (4 bytes)
+// flags: iommufd_ioas_map_flags = 0x7 (4 bytes)
+// ioas_id: ioas_handle (resource)
+// __reserved: const = 0x0 (4 bytes)
+// user_va: VMA[0x800000]
+// length: len = 0x800000 (8 bytes)
+// iova: int64 = 0x0 (8 bytes)
+// }
+// }
+// ]
+syscall(__NR_ioctl, /*fd=*/r[0], /*cmd=*/0x3b85, /*arg=*/0x200000000040ul)
+// ioctl$IOMMU_TEST_OP_CREATE_ACCESS arguments: [
+// fd: fd_iommufd (resource)
+// cmd: const = 0x3ba0 (4 bytes)
+// arg: ptr[in, iommu_test_cmd$create_access] {
+// iommu_test_cmd$create_access {
+// size: len = 0x48 (4 bytes)
+// op: const = 0x5 (4 bytes)
+// id: ioas_handle (resource)
+// __reserved: const = 0x0 (4 bytes)
+// out_access_fd: fd_access (resource)
+// flags: iommu_test_cmd_create_access_flags = 0x1 (4 bytes)
+// pad = 0x0 (48 bytes)
+// }
+// }
+// ]
+syscall(__NR_ioctl, /*fd=*/r[0], /*cmd=*/0x3ba0, /*arg=*/0x200000000340ul)
+// ioctl$IOMMU_TEST_OP_ACCESS_PAGES$syz arguments: [
+// fd: fd_iommufd (resource)
+// cmd: const = 0x3ba0 (4 bytes)
+// arg: ptr[in, iommu_test_cmd$access_pages$syz] {
+// iommu_test_cmd$access_pages$syz {
+// size: len = 0x48 (4 bytes)
+// op: const = 0x7 (4 bytes)
+// id: fd_access (resource)
+// __reserved: const = 0x0 (4 bytes)
+// flags: iommu_test_cmd_acess_pages_flags_syz = 0x0 (4 bytes)
+// out_access_pages_id: access_pages_handle (resource)
+// nth_area: int32 = 0x200000 (4 bytes)
+// offset: int32 = 0x0 (4 bytes)
+// length: int64 = 0x334e8b (8 bytes)
+// uptr: const = 0x200000000000 (8 bytes)
+// pad = 0x0 (24 bytes)
+// }
+// }
+// ]
+syscall(__NR_ioctl, /*fd=*/r[0], /*cmd=*/0x3ba0, /*arg=*/0x200000000100ul) \ No newline at end of file
diff --git a/pkg/csource/testdata/2 b/pkg/csource/testdata/2
new file mode 100644
index 000000000..10d648d59
--- /dev/null
+++ b/pkg/csource/testdata/2
@@ -0,0 +1,144 @@
+#{"repeat":true,"procs":5,"slowdown":1,"sandbox":"none","sandbox_arg":0,"close_fds":true,"swap":true,"tmpdir":true}
+syz_mount_image$f2fs(&(0x7f0000000000), &(0x7f0000000040)='./file0\x00', 0x8, &(0x7f0000005880)=ANY=[@ANYBLOB="6e6f646973636172642c6e6f636865636b706f696e745f6d657267652c616c6c6f635f6d6f64653d64656661756c742c6163746976655f6c6f67733d362c666c7573685f6d657267652c6661756c745f696e6a656374696f6e3d30303030303030303030303030303030303032332c646973636172642c6e6f61636c2c6673796e635f6d6f64653d706f7369782c616c6c6f635f6d6f64653d64656661756c742c6e6f657874656e745f63616368652c6163746976655f6c6f67733d322c6661756c745f747970653d30303030303030303030303031363737373231342c0071b1a3325f83482c0961b0e88944923b0c039b5713440e8bfe9b03cd735839577bdc2206c94f19915532121069d31d5b837bfe566213ca848679685540de5aa794f2bdf4daf374cc29c1f1f12dab5e09560694bda1b83f5d21c821f71fdafb606c829fa1b4d0ab1c7c2dd217dcca946abf1257c4b6cf95ae6b5dcaf73d49491efb2e9918a381568b5a081baddf1cbb01ccbb81b50c7c81028797700195adf5fd02a28c78066133dd0cb0014f44eafea1ab502d2192e8ce9f607d392a23940fc95a5a4867f40ad2335db9a6af219433f7fda740407bf1685b1672a903a2ec8019c0000000000000000000"], 0x1, 0x5505, &(0x7f0000000340)="$eJzs3E1rY9UbAPAn7XTe//Mv4sLdXBiEFiZh0nlBd6PO4At2KKMuXGmapCEzSW5p0rR25cKluPCbiIIrl34GF67diQvFnaDknlud+gJC08ZOfz+4ee45OXnuc8Iw8NxbEsCptZj9/GMlrsSFiJiPiMsRxXmlPAp3U3guIq5GxNwTR6Wc/33ibERcjIgrk+QpZ6V869Pr42u3f3jjp6++OXfm0mdffju7XQOz9nxE9DfT+U4/xbyT4qNyvjHuFrF/a1zG9Eb/cTnOU9xprxcZdhr76xpFvNlJ6/PN7eEkbvQazUnsdDeK+c1BuuBw3NnPU3zgUWOrGLfa60XsDvMidvZSXbt76f+2veEo5WmV+T4o0sdotB/TfHu3nfaz+biIzcGonE9581Z7dxLHZSwvF8281yrqWD/MN/3f9mZ3sL2bjdtbw24+yG7X6i/U6neq9a281R61b1Ub/dadW9lSpzdZVh21G/27nTzv9Nq1Zt5fzpY6zWa1Xs+W7rXXu41BVq/XbtZuVG8vl2fXs1cfvJP1WtnSJL7cHWyPur1htpFvZekTy9lK7eaLy9m1evbW6lq29vD+/dW1t9+79+6Dl1Zff6Vc9JeysqWVGysr1fqN6kp9+RTt/6Oy6CnuHw6lMusCAE4e/T8wC0fX/289jDj6/j/0/1Nxovrf097/H8H+4VD0/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp9Z3C5+/VpwspvGlcv5/5dQz5bgSEXMR8evfmI+zB3LOl3kW/mH9wp9q+LoSRYbJNc6Vx8WIuFsev/z/qL8FAAAAeHp98eHVT1K3nl4WZ10QxyndtJm7/P6U8lUiYmHx+yllm5u8PDulZMW/7zOxO6VsxQ2s81NKlm65nZlWtn9l/kA4/0SopDB3rOUAAADH4mAncLxdCAAAAMfp41kXwGxUYv9R5v6z4OIv7/94IHjhwAgAAAA4gSqzLgAAAAA4ckX/7/f/AAAA4OmWfv8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfmPnfm4TB6I4AD8bvLD/tGi1921lb1DGlrDHPUYUkCYoIAfSQhqgBnJLCRFEeBwCEYdIHttK9H2SMxnL/HiD4DAz0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF26r9aL26vf121zdvt28owGAAAAuGRbrRf1P7PU/9rc/97c+tn0i4goI+LS3H0Un84yR01O9fL8zenz1asa7iLqhMN7TJrrS0T8aa7HH11/CgAAAPBxbZareZqtpz+zoQuiT2nRpvz2N1NeERHV7CFTWnnI+5UprP5+j+N/prR6AWuaKSwtuY1zpb1J/XM/rtpNT5oiNeXFlx2LzDZ2AACgR6Ozpt9ZCAAAAH36N3QBDKOI563M41bgJDXN9t7nsx4AAADwDhVDFwAAAAB0rp7/93T+3975fwAAADCMdP4fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXdpW68VmuZq3zdnt28kzGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHhif95RIATCIAz2ru9M5v6HlQZNTU2qQPj4G4MBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIA3v/vL/4mpcSaZe20sPY8ka6fG1qmxd24c/WF8/RoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgIv9eUmBEAiCKJgz/nfS9z+sJOgZRIiAhkcVtWgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4It+98v/ialxJpk7bSwdjyRrV42tq8beg8bRg/H2bwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgIud+3mNo4oDAP5mZmdrq+IaZQ8RUfCgF7vd1tbexIMSPPgnCCHd1titP9ocbCliLt4k515EjyKCEm/9H3JOIJd4y2EPETwrMzuTnfwA118zm+TzgTfvu8Mw7/tmIeQ77yUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACURm9P4iQ7dMZxXJzb3Hu4lPVbh/rM47Xt+axlcVRn0ifDi9UPUbe5RAAAADg7krK+DyHspOsLWR938vo/La/Jav5vnx7HZT1/uO4v+7L2z9ovP+8+vz9QZzxOdtOby8PBpaOptP6/Wc62Z/7yilb+5PN3L0n+hcTvrT43SvPnGX29sfFOOw/P1ZEtAPBPXCz7Iih/H8r6fpOJAXBmtCqFd1n/J51mcwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQN3+DAAA//962D6S")
+openat(0xffffffffffffff9c, &(0x7f00000000c0)='./file1\x00', 0x8042, 0x0)
+mount$bind(0x0, &(0x7f0000005b00)='./bus\x00', 0x0, 0x0, 0x0)
+openat(0xffffffffffffff9c, &(0x7f0000000080)='./file0\x00', 0x183341, 0x0)
+truncate(&(0x7f0000000280)='./file1\x00', 0x1fefff)
+r0 = openat(0xffffffffffffff9c, &(0x7f0000000040)='./file1\x00', 0x42, 0x0)
+fallocate(r0, 0x0, 0xeffb, 0x9)
+r1 = openat(0xffffffffffffff9c, &(0x7f0000000340)='./file1\x00', 0x44042, 0x1ff)
+r2 = openat$nullb(0xffffffffffffff9c, &(0x7f0000000140), 0x2002, 0x0)
+sendfile(r1, r2, 0x0, 0x20fffe82)
+quotactl$Q_SYNC(0xffffffff80000102, 0x0, 0x0, 0x0)
+
+// syz_mount_image$f2fs arguments: [
+// fs: ptr[in, buffer] {
+// buffer: {66 32 66 73 00} (length 0x5)
+// }
+// dir: ptr[in, buffer] {
+// buffer: {2e 2f 66 69 6c 65 30 00} (length 0x8)
+// }
+// flags: mount_flags = 0x8 (8 bytes)
+// opts: ptr[inout, array[ANYUNION]] {
+// array[ANYUNION] {
+// union ANYUNION {
+// ANYBLOB: buffer: {6e 6f 64 69 73 63 61 72 64 2c 6e 6f 63 68 65 63 6b
+// 70 6f 69 6e 74 5f 6d 65 72 67 65 2c 61 6c 6c 6f 63 5f 6d 6f 64 65 3d
+// 64 65 66 61 75 6c 74 2c 61 63 74 69 76 65 5f 6c 6f 67 73 3d 36 2c 66
+// 6c 75 73 68 5f 6d 65 72 67 65 2c 66 61 75 6c 74 5f 69 6e 6a 65 63 74
+// 69 6f 6e 3d 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 32
+// 33 2c 64 69 73 63 61 72 64 2c 6e 6f 61 63 6c 2c 66 73 79 6e 63 5f 6d
+// 6f 64 65 3d 70 6f 73 69 78 2c 61 6c 6c 6f 63 5f 6d 6f 64 65 3d 64 65
+// 66 61 75 6c 74 2c 6e 6f 65 78 74 65 6e 74 5f 63 61 63 68 65 2c 61 63
+// 74 69 76 65 5f 6c 6f 67 73 3d 32 2c 66 61 75 6c 74 5f 74 79 70 65 3d
+// 30 30 30 30 30 30 30 30 30 30 30 30 31 36 37 37 37 32 31 34 2c 00 71
+// b1 a3 32 5f 83 48 2c 09 61 b0 e8 89 44 92 3b 0c 03 9b 57 13 44 0e 8b
+// fe 9b 03 cd 73 58 39 57 7b dc 22 06 c9 4f 19 91 55 32 12 10 69 d3 1d
+// 5b 83 7b fe 56 62 13 ca 84 86 79 68 55 40 de 5a a7 94 f2 bd f4 da f3
+// 74 cc 29 c1 f1 f1 2d ab 5e 09 56 06 94 bd a1 b8 3f 5d 21 c8 21 f7 1f
+// da fb 60 6c 82 9f a1 b4 d0 ab 1c 7c 2d d2 17 dc ca 94 6a bf 12 57 c4
+// b6 cf 95 ae 6b 5d ca f7 3d 49 49 1e fb 2e 99 18 a3 81 56 8b 5a 08 1b
+// ad df 1c bb 01 cc bb 81 b5 0c 7c 81 02 87 97 70 01 95 ad f5 fd 02 a2
+// 8c 78 06 61 33 dd 0c b0 01 4f 44 ea fe a1 ab 50 2d 21 92 e8 ce 9f 60
+// 7d 39 2a 23 94 0f c9 5a 5a 48 67 f4 0a d2 33 5d b9 a6 af 21 94 33 f7
+// fd a7 40 40 7b f1 68 5b 16 72 a9 03 a2 ec 80 19 c0 00 00 00 00 00 00
+// 00 00 00} (length 0x1c9)
+// }
+// }
+// }
+// chdir: int8 = 0x1 (1 bytes)
+// size: len = 0x5505 (8 bytes)
+// img: ptr[in, buffer] {
+// buffer: (compressed buffer with length 0x5505)
+// }
+// ]
+// returns fd_dir
+syz_mount_image(/*fs=*/0x200000000000, /*dir=*/0x200000000040, /*flags=MS_NOEXEC*/8, /*opts=*/0x200000005880, /*chdir=*/1, /*size=*/0x5505, /*img=*/0x200000000340)
+// openat arguments: [
+// fd: fd_dir (resource)
+// file: ptr[in, buffer] {
+// buffer: {2e 2f 66 69 6c 65 31 00} (length 0x8)
+// }
+// flags: open_flags = 0x8042 (4 bytes)
+// mode: open_mode = 0x0 (2 bytes)
+// ]
+// returns fd
+syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x2000000000c0ul, /*flags=O_LARGEFILE|O_CREAT|O_RDWR*/0x8042, /*mode=*/0)
+// mount$bind arguments: [
+// src: nil
+// dst: ptr[in, buffer] {
+// buffer: {2e 2f 62 75 73 00} (length 0x6)
+// }
+// type: nil
+// flags: mount_flags = 0x0 (8 bytes)
+// data: const = 0x0 (8 bytes)
+// ]
+syscall(__NR_mount, /*src=*/0ul, /*dst=*/0x200000005b00ul, /*type=*/0ul, /*flags=*/0ul, /*data=*/0ul)
+// openat arguments: [
+// fd: fd_dir (resource)
+// file: ptr[in, buffer] {
+// buffer: {2e 2f 66 69 6c 65 30 00} (length 0x8)
+// }
+// flags: open_flags = 0x183341 (4 bytes)
+// mode: open_mode = 0x0 (2 bytes)
+// ]
+// returns fd
+syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x200000000080ul, /*flags=O_TRUNC|O_SYNC|O_NOCTTY|O_CREAT|O_CLOEXEC|FASYNC|0x1*/0x183341, /*mode=*/0)
+// truncate arguments: [
+// file: ptr[in, buffer] {
+// buffer: {2e 2f 66 69 6c 65 31 00} (length 0x8)
+// }
+// len: intptr = 0x1fefff (8 bytes)
+// ]
+syscall(__NR_truncate, /*file=*/0x200000000280ul, /*len=*/0x1feffful)
+// openat arguments: [
+// fd: fd_dir (resource)
+// file: ptr[in, buffer] {
+// buffer: {2e 2f 66 69 6c 65 31 00} (length 0x8)
+// }
+// flags: open_flags = 0x42 (4 bytes)
+// mode: open_mode = 0x0 (2 bytes)
+// ]
+// returns fd
+syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x200000000040ul, /*flags=O_CREAT|O_RDWR*/0x42, /*mode=*/0)
+// fallocate arguments: [
+// fd: fd (resource)
+// mode: fallocate_mode = 0x0 (8 bytes)
+// off: intptr = 0xeffb (8 bytes)
+// len: intptr = 0x9 (8 bytes)
+// ]
+syscall(__NR_fallocate, /*fd=*/r[0], /*mode=*/0ul, /*off=*/0xeffbul, /*len=*/9ul)
+// openat arguments: [
+// fd: fd_dir (resource)
+// file: ptr[in, buffer] {
+// buffer: {2e 2f 66 69 6c 65 31 00} (length 0x8)
+// }
+// flags: open_flags = 0x44042 (4 bytes)
+// mode: open_mode = 0x1ff (2 bytes)
+// ]
+// returns fd
+syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x200000000340ul, /*flags=O_NOATIME|O_DIRECT|O_CREAT|O_RDWR*/0x44042, /*mode=S_IXOTH|S_IWOTH|S_IROTH|S_IXGRP|S_IWGRP|S_IRGRP|S_IXUSR|S_IWUSR|0x100*/0x1ff)
+// openat$nullb arguments: [
+// fd: const = 0xffffffffffffff9c (8 bytes)
+// file: ptr[in, buffer] {
+// buffer: {2f 64 65 76 2f 6e 75 6c 6c 62 30 00} (length 0xc)
+// }
+// flags: open_flags = 0x2002 (4 bytes)
+// mode: const = 0x0 (2 bytes)
+// ]
+// returns fd_block
+syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x200000000140ul, /*flags=FASYNC|O_RDWR*/0x2002, /*mode=*/0)
+// sendfile arguments: [
+// fdout: fd (resource)
+// fdin: fd (resource)
+// off: nil
+// count: intptr = 0x20fffe82 (8 bytes)
+// ]
+syscall(__NR_sendfile, /*fdout=*/r[1], /*fdin=*/r[2], /*off=*/0ul, /*count=*/0x20fffe82ul)
+// quotactl$Q_SYNC arguments: [
+// cmd: quota_cmd_sync = 0xffffffff80000102 (8 bytes)
+// special: const = 0x0 (8 bytes)
+// id: const = 0x0 (8 bytes)
+// addr: const = 0x0 (8 bytes)
+// ]
+syscall(__NR_quotactl, /*cmd=Q_SYNC_PRJ*/0xffffffff80000102ul, /*special=*/0ul, /*id=*/0ul, /*addr=*/0ul) \ No newline at end of file
diff --git a/prog/prog.go b/prog/prog.go
index 89b0e794b..b4c8d692d 100644
--- a/prog/prog.go
+++ b/prog/prog.go
@@ -6,6 +6,7 @@ package prog
import (
"fmt"
"reflect"
+ "strings"
)
type Prog struct {
@@ -494,6 +495,107 @@ func (p *Prog) sanitizeFix() {
}
}
+// FormatArg returns a string slice representation of an argument with one
+// entry per line in the output. The formatting roughly corresponds to syzlang
+// descriptions and is intended to be human readable.
+func FormatArg(arg Arg, name string) []string {
+ const indent string = " " // Two spaces.
+ makeIndent := func(level int) string {
+ return strings.Repeat(indent, level)
+ }
+
+ // Depth-first search starting at initial argument, incrementing the indent
+ // level as we go deeper.
+ var visit func(Arg, string, int) []string
+ visit = func(arg Arg, name string, depth int) []string {
+ var lines []string
+
+ var lineBuilder strings.Builder
+ lineBuilder.WriteString(makeIndent(depth))
+
+ if name != "" {
+ fmt.Fprintf(&lineBuilder, "%s: ", name)
+ }
+
+ switch a := arg.(type) {
+ case *GroupArg:
+ fmt.Fprintf(&lineBuilder, "%s {", a.Type().String())
+ lines = append(lines, lineBuilder.String())
+
+ s, isStruct := a.ArgCommon.Type().(*StructType)
+ for i, inner := range a.Inner {
+ // For GroupArgs, only those of type StructType have named
+ // children.
+ childName := ""
+ if isStruct {
+ childName = s.Fields[i].Name
+ }
+ lines = append(lines, visit(inner, childName, depth+1)...)
+ }
+ lines = append(lines, makeIndent(depth)+"}")
+ case *ConstArg:
+ fmt.Fprintf(&lineBuilder, "%s = 0x%x (%d bytes)", a.Type().Name(), a.Val, a.Size())
+ lines = append(lines, lineBuilder.String())
+ case *DataArg:
+ tpe, ok := a.Type().(*BufferType)
+ if !ok {
+ panic("data args should be a buffer type")
+ }
+
+ fmt.Fprintf(&lineBuilder, "%s: ", a.Type().String())
+
+ // Result buffer - nothing to display.
+ if a.Dir() == DirOut {
+ fmt.Fprint(&lineBuilder, "(DirOut)")
+ } else {
+ // Compressed buffers (e.g., fs images) tend to be very large
+ // and it doesn't make much sense to output their contents.
+ if tpe.Kind == BufferCompressed {
+ fmt.Fprintf(&lineBuilder, "(compressed buffer with length 0x%x)", len(a.Data()))
+ } else {
+ fmt.Fprintf(&lineBuilder, "{% x} (length 0x%x)", a.Data(), len(a.Data()))
+ }
+ }
+ lines = append(lines, lineBuilder.String())
+ case *PointerArg:
+ if a.Res != nil {
+ fmt.Fprintf(&lineBuilder, "%s {", a.Type().String())
+ lines = append(lines, lineBuilder.String())
+ lines = append(lines, visit(a.Res, "", depth+1)...)
+ lines = append(lines, makeIndent(depth)+"}")
+ } else {
+ if a.VmaSize == 0 {
+ lineBuilder.WriteString("nil")
+ } else {
+ fmt.Fprintf(&lineBuilder, "VMA[0x%x]", a.VmaSize)
+ }
+ lines = append(lines, lineBuilder.String())
+ }
+ case *UnionArg:
+ union, ok := a.ArgCommon.Type().(*UnionType)
+ if !ok {
+ panic("a UnionArg should have an ArgCommon of type UnionType")
+ }
+ fmt.Fprintf(&lineBuilder, "union %s {", a.Type().Name())
+ lines = append(lines, lineBuilder.String())
+ if a.Option != nil {
+ lines = append(lines, visit(a.Option, union.Fields[a.Index].Name, depth+1)...)
+ }
+ lines = append(lines, makeIndent(depth)+"}")
+ case *ResultArg:
+ fmt.Fprintf(&lineBuilder, "%s (resource)", a.ArgCommon.Type().String())
+ lines = append(lines, lineBuilder.String())
+ default:
+ // We shouldn't hit this because the switch statements cover every
+ // prog.Arg implementation.
+ panic("Unsupported argument type.")
+ }
+ return lines
+ }
+
+ return visit(arg, name, 0)
+}
+
func (p *Prog) sanitize(fix bool) error {
for _, c := range p.Calls {
if err := p.Target.sanitize(c, fix); err != nil {
diff --git a/tools/syz-prog2c/prog2c.go b/tools/syz-prog2c/prog2c.go
index 6b7394508..27476ffbf 100644
--- a/tools/syz-prog2c/prog2c.go
+++ b/tools/syz-prog2c/prog2c.go
@@ -95,6 +95,7 @@ func main() {
UseTmpDir: *flagUseTmpDir,
HandleSegv: *flagHandleSegv,
Trace: *flagTrace,
+ CallComments: true,
}
src, err := csource.Write(p, opts)
if err != nil {