github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/prog/types.go (about) 1 // Copyright 2015/2016 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package prog 5 6 import ( 7 "fmt" 8 "strings" 9 "unicode" 10 ) 11 12 type Syscall struct { 13 ID int 14 NR uint64 // kernel syscall number 15 Name string 16 CallName string 17 MissingArgs int // number of trailing args that should be zero-filled 18 Args []Field 19 Ret Type 20 Attrs SyscallAttrs 21 22 // Resources that are required for this call to be generated (in/inout). 23 inputResources []*ResourceDesc 24 // Resources that this call can be used to create (out, but excluding no_generate). 25 createsResources []*ResourceDesc 26 // Both inputs and output resources (including no_generate). 27 usesResources []*ResourceDesc 28 } 29 30 // SyscallAttrs represents call attributes in syzlang. 31 // 32 // This structure is the source of truth for the all other parts of the system. 33 // pkg/compiler uses this structure to parse descriptions. 34 // syz-sysgen uses this structure to generate code for executor. 35 // 36 // Only `bool`s, `string`s and `uint64`s are currently supported. 37 // 38 // See docs/syscall_descriptions_syntax.md for description of individual attributes. 39 type SyscallAttrs struct { 40 Disabled bool 41 Timeout uint64 42 ProgTimeout uint64 43 IgnoreReturn bool 44 BreaksReturns bool 45 NoGenerate bool 46 NoMinimize bool 47 NoSquash bool 48 RemoteCover bool 49 Automatic bool 50 AutomaticHelper bool 51 KFuzzTest bool 52 Fsck string 53 // Filesystem is used in tools/syz-imagegen when fs name cannot be deduced from 54 // the part after $. 55 Filesystem string 56 } 57 58 // MaxArgs is maximum number of syscall arguments. 59 // Executor also knows about this value. 60 const MaxArgs = 9 61 62 type Dir uint8 63 64 const ( 65 DirIn Dir = iota 66 DirOut 67 DirInOut 68 ) 69 70 func (dir Dir) String() string { 71 switch dir { 72 case DirIn: 73 return "in" 74 case DirOut: 75 return "out" 76 case DirInOut: 77 return "inout" 78 default: 79 panic("unknown dir") 80 } 81 } 82 83 type Field struct { 84 Name string 85 Type 86 HasDirection bool 87 Direction Dir 88 Condition Expression 89 90 // See Target.initRelatedFields. 91 relatedFields map[Type]struct{} 92 } 93 94 func (f *Field) Dir(def Dir) Dir { 95 if f.HasDirection { 96 return f.Direction 97 } 98 return def 99 } 100 101 type ArgFinder func(path []string) Arg 102 103 // Special case reply of ArgFinder. 104 var SquashedArgFound = &DataArg{} 105 106 type Expression interface { 107 fmt.GoStringer 108 ForEachValue(func(*Value)) 109 Clone() Expression 110 Evaluate(ArgFinder) (uint64, bool) 111 } 112 113 type BinaryOperator int 114 115 const ( 116 OperatorCompareEq BinaryOperator = iota 117 OperatorCompareNeq 118 OperatorBinaryAnd 119 OperatorOr 120 ) 121 122 type BinaryExpression struct { 123 Operator BinaryOperator 124 Left Expression 125 Right Expression 126 } 127 128 func (bo BinaryExpression) GoString() string { 129 return fmt.Sprintf("&prog.BinaryExpression{%#v,%#v,%#v}", bo.Operator, bo.Left, bo.Right) 130 } 131 132 func (bo BinaryExpression) ForEachValue(cb func(*Value)) { 133 bo.Left.ForEachValue(cb) 134 bo.Right.ForEachValue(cb) 135 } 136 137 func (bo BinaryExpression) Clone() Expression { 138 return &BinaryExpression{ 139 Operator: bo.Operator, 140 Left: bo.Left.Clone(), 141 Right: bo.Right.Clone(), 142 } 143 } 144 145 type Value struct { 146 // If Path is empty, Value is to be used. 147 Value uint64 148 // Path to the field. 149 Path []string 150 } 151 152 func (v *Value) GoString() string { 153 return fmt.Sprintf("&prog.Value{%#v,%#v}", v.Value, v.Path) 154 } 155 156 func (v *Value) ForEachValue(cb func(*Value)) { 157 cb(v) 158 } 159 160 func (v *Value) Clone() Expression { 161 return &Value{v.Value, append([]string{}, v.Path...)} 162 } 163 164 type BinaryFormat int 165 166 const ( 167 FormatNative BinaryFormat = iota 168 FormatBigEndian 169 FormatStrDec 170 FormatStrHex 171 FormatStrOct 172 ) 173 174 type Type interface { 175 String() string 176 Name() string 177 TemplateName() string // for template structs name without arguments 178 Optional() bool 179 Varlen() bool 180 Size() uint64 181 TypeBitSize() uint64 182 Alignment() uint64 183 Format() BinaryFormat 184 BitfieldOffset() uint64 185 BitfieldLength() uint64 186 IsBitfield() bool 187 // For most of the types UnitSize is equal to Size. 188 // These are different only for all but last bitfield in the group, 189 // where Size == 0 and UnitSize equals to the underlying bitfield type size. 190 UnitSize() uint64 191 UnitOffset() uint64 192 193 DefaultArg(dir Dir) Arg 194 isDefaultArg(arg Arg) bool 195 generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) 196 mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) 197 getMutationPrio(target *Target, arg Arg, ignoreSpecial, ignoreLengths bool) (prio float64, stopRecursion bool) 198 minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool 199 ref() Ref 200 setRef(ref Ref) 201 } 202 203 type Ref uint32 204 205 func (ti Ref) String() string { panic("prog.Ref method called") } 206 func (ti Ref) Name() string { panic("prog.Ref method called") } 207 func (ti Ref) TemplateName() string { panic("prog.Ref method called") } 208 209 func (ti Ref) Optional() bool { panic("prog.Ref method called") } 210 func (ti Ref) Varlen() bool { panic("prog.Ref method called") } 211 func (ti Ref) Size() uint64 { panic("prog.Ref method called") } 212 func (ti Ref) TypeBitSize() uint64 { panic("prog.Ref method called") } 213 func (ti Ref) Alignment() uint64 { panic("prog.Ref method called") } 214 func (ti Ref) Format() BinaryFormat { panic("prog.Ref method called") } 215 func (ti Ref) BitfieldOffset() uint64 { panic("prog.Ref method called") } 216 func (ti Ref) BitfieldLength() uint64 { panic("prog.Ref method called") } 217 func (ti Ref) IsBitfield() bool { panic("prog.Ref method called") } 218 func (ti Ref) UnitSize() uint64 { panic("prog.Ref method called") } 219 func (ti Ref) UnitOffset() uint64 { panic("prog.Ref method called") } 220 func (ti Ref) DefaultArg(dir Dir) Arg { panic("prog.Ref method called") } 221 func (ti Ref) Clone() Type { panic("prog.Ref method called") } 222 func (ti Ref) isDefaultArg(arg Arg) bool { panic("prog.Ref method called") } 223 func (ti Ref) generate(r *randGen, s *state, dir Dir) (Arg, []*Call) { panic("prog.Ref method called") } 224 func (ti Ref) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) ([]*Call, bool, bool) { 225 panic("prog.Ref method called") 226 } 227 func (ti Ref) getMutationPrio(target *Target, arg Arg, ignoreSpecial, ignoreLengths bool) (float64, bool) { 228 panic("prog.Ref method called") 229 } 230 func (ti Ref) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool { 231 panic("prog.Ref method called") 232 } 233 func (ti Ref) ref() Ref { panic("prog.Ref method called") } 234 func (ti Ref) setRef(ref Ref) { panic("prog.Ref method called") } 235 236 func IsPad(t Type) bool { 237 if ct, ok := t.(*ConstType); ok && ct.IsPad { 238 return true 239 } 240 return false 241 } 242 243 type TypeCommon struct { 244 TypeName string 245 // Static size of the type, or 0 for variable size types and all but last bitfields in the group. 246 TypeSize uint64 247 TypeAlign uint64 248 IsOptional bool 249 IsVarlen bool 250 251 self Ref 252 } 253 254 func (t *TypeCommon) Name() string { 255 return t.TypeName 256 } 257 258 func (t *TypeCommon) TemplateName() string { 259 name := t.TypeName 260 if pos := strings.IndexByte(name, '['); pos != -1 { 261 name = name[:pos] 262 } 263 return name 264 } 265 266 func (t *TypeCommon) Optional() bool { 267 return t.IsOptional 268 } 269 270 func (t *TypeCommon) Size() uint64 { 271 if t.IsVarlen { 272 panic(fmt.Sprintf("static type size is not known: %#v", t)) 273 } 274 return t.TypeSize 275 } 276 277 func (t *TypeCommon) TypeBitSize() uint64 { 278 panic("cannot get the bitsize for a non-integer type") 279 } 280 281 func (t *TypeCommon) Varlen() bool { 282 return t.IsVarlen 283 } 284 285 func (t *TypeCommon) Format() BinaryFormat { 286 return FormatNative 287 } 288 289 func (t *TypeCommon) BitfieldOffset() uint64 { 290 return 0 291 } 292 293 func (t *TypeCommon) BitfieldLength() uint64 { 294 return 0 295 } 296 297 func (t *TypeCommon) UnitSize() uint64 { 298 return t.Size() 299 } 300 301 func (t *TypeCommon) UnitOffset() uint64 { 302 return 0 303 } 304 305 func (t *TypeCommon) IsBitfield() bool { 306 return false 307 } 308 309 func (t *TypeCommon) ref() Ref { 310 if t.self == 0 { 311 panic("ref is not assigned yet") 312 } 313 return t.self 314 } 315 316 func (t *TypeCommon) setRef(ref Ref) { 317 t.self = ref 318 } 319 320 func (t *TypeCommon) Alignment() uint64 { 321 return t.TypeAlign 322 } 323 324 type FlagDesc struct { 325 Name string 326 Values []string 327 } 328 329 type ResourceDesc struct { 330 Name string 331 Kind []string 332 Values []uint64 333 Ctors []ResourceCtor 334 } 335 336 type ResourceCtor struct { 337 Call *Syscall 338 Precise bool 339 } 340 341 type ResourceType struct { 342 TypeCommon 343 ArgFormat BinaryFormat 344 Desc *ResourceDesc 345 } 346 347 func (t *ResourceType) String() string { 348 return t.Name() 349 } 350 351 func (t *ResourceType) DefaultArg(dir Dir) Arg { 352 return MakeResultArg(t, dir, nil, t.Default()) 353 } 354 355 func (t *ResourceType) isDefaultArg(arg Arg) bool { 356 a := arg.(*ResultArg) 357 return a.Res == nil && a.OpDiv == 0 && a.OpAdd == 0 && 358 len(a.uses) == 0 && a.Val == t.Default() 359 } 360 361 func (t *ResourceType) Default() uint64 { 362 return t.Desc.Values[0] 363 } 364 365 func (t *ResourceType) SpecialValues() []uint64 { 366 return t.Desc.Values 367 } 368 369 func (t *ResourceType) Format() BinaryFormat { 370 return t.ArgFormat 371 } 372 373 type IntTypeCommon struct { 374 TypeCommon 375 ArgFormat BinaryFormat 376 BitfieldOff uint64 377 BitfieldLen uint64 378 BitfieldUnit uint64 379 BitfieldUnitOff uint64 380 381 // Hint values that don't make sense to use for this type 382 // b/c they are expected to be easily guessed by generation/mutation. 383 // For example, flags values or combinations of few flags values. 384 uselessHints map[uint64]struct{} 385 } 386 387 func (t *IntTypeCommon) String() string { 388 return t.Name() 389 } 390 391 func (t *IntTypeCommon) Format() BinaryFormat { 392 return t.ArgFormat 393 } 394 395 // Returns the size in bits for integers in binary format or 64 for string-formatted integers. The return 396 // value is used in computing limits and truncating other values. 397 func (t *IntTypeCommon) TypeBitSize() uint64 { 398 if t.ArgFormat != FormatNative && t.ArgFormat != FormatBigEndian { 399 // TODO: add special cases for mutation and generation of string-formatted integers. 400 return 64 401 } 402 if t.BitfieldLen != 0 { 403 return t.BitfieldLen 404 } 405 return t.TypeSize * 8 406 } 407 408 func (t *IntTypeCommon) BitfieldOffset() uint64 { 409 return t.BitfieldOff 410 } 411 412 func (t *IntTypeCommon) BitfieldLength() uint64 { 413 return t.BitfieldLen 414 } 415 416 func (t *IntTypeCommon) UnitSize() uint64 { 417 if t.BitfieldLen != 0 { 418 return t.BitfieldUnit 419 } 420 return t.Size() 421 } 422 423 func (t *IntTypeCommon) UnitOffset() uint64 { 424 return t.BitfieldUnitOff 425 } 426 427 func (t *IntTypeCommon) IsBitfield() bool { 428 return t.BitfieldLen != 0 429 } 430 431 func (t *IntTypeCommon) uselessHint(v uint64) bool { 432 _, ok := t.uselessHints[v] 433 return ok 434 } 435 436 func (t *IntTypeCommon) setUselessHints(m map[uint64]struct{}) { 437 t.uselessHints = m 438 } 439 440 type uselessHinter interface { 441 uselessHint(uint64) bool 442 calcUselessHints() []uint64 443 setUselessHints(map[uint64]struct{}) 444 } 445 446 type ConstType struct { 447 IntTypeCommon 448 Val uint64 449 IsPad bool 450 } 451 452 func (t *ConstType) DefaultArg(dir Dir) Arg { 453 return MakeConstArg(t, dir, t.Val) 454 } 455 456 func (t *ConstType) isDefaultArg(arg Arg) bool { 457 return arg.(*ConstArg).Val == t.Val 458 } 459 460 func (t *ConstType) String() string { 461 if t.IsPad { 462 return fmt.Sprintf("pad[%v]", t.Size()) 463 } 464 return fmt.Sprintf("const[%v, %v]", t.Val, t.IntTypeCommon.String()) 465 } 466 467 func (t *ConstType) calcUselessHints() []uint64 { 468 return []uint64{t.Val} 469 } 470 471 type IntKind int 472 473 const ( 474 IntPlain IntKind = iota 475 IntRange 476 ) 477 478 type IntType struct { 479 IntTypeCommon 480 Kind IntKind 481 RangeBegin uint64 482 RangeEnd uint64 483 Align uint64 484 } 485 486 func (t *IntType) DefaultArg(dir Dir) Arg { 487 return MakeConstArg(t, dir, 0) 488 } 489 490 func (t *IntType) isDefaultArg(arg Arg) bool { 491 return arg.(*ConstArg).Val == 0 492 } 493 494 func (t *IntType) calcUselessHints() []uint64 { 495 res := specialInts[:len(specialInts):len(specialInts)] 496 align := max(1, t.Align) 497 rangeVals := (t.RangeEnd - t.RangeBegin) / align 498 if rangeVals != 0 && rangeVals <= 100 { 499 for v := t.RangeBegin; v <= t.RangeEnd; v += align { 500 res = append(res, v) 501 } 502 } 503 return res 504 } 505 506 type FlagsType struct { 507 IntTypeCommon 508 Vals []uint64 // compiler ensures that it's not empty 509 BitMask bool 510 } 511 512 func (t *FlagsType) DefaultArg(dir Dir) Arg { 513 return MakeConstArg(t, dir, 0) 514 } 515 516 func (t *FlagsType) isDefaultArg(arg Arg) bool { 517 return arg.(*ConstArg).Val == 0 518 } 519 520 func (t *FlagsType) calcUselessHints() []uint64 { 521 // Combinations of up to 3 flag values + 0. 522 res := []uint64{0} 523 vals := t.Vals 524 for i0 := 0; i0 < len(vals); i0++ { 525 v0 := vals[i0] 526 res = append(res, v0) 527 if len(vals) <= 10 { 528 for i1 := i0 + 1; i1 < len(vals); i1++ { 529 v1 := v0 | vals[i1] 530 res = append(res, v1) 531 if len(vals) <= 7 { 532 for i2 := i1 + 1; i2 < len(vals); i2++ { 533 v2 := v1 | vals[i2] 534 res = append(res, v2) 535 } 536 } 537 } 538 } 539 } 540 return res 541 } 542 543 type LenType struct { 544 IntTypeCommon 545 BitSize uint64 // want size in multiple of bits instead of array size 546 Offset bool // offset from the beginning of the parent struct or base object 547 Path []string 548 } 549 550 func (t *LenType) DefaultArg(dir Dir) Arg { 551 return MakeConstArg(t, dir, 0) 552 } 553 554 func (t *LenType) isDefaultArg(arg Arg) bool { 555 return arg.(*ConstArg).Val == 0 556 } 557 558 func (t *LenType) calcUselessHints() []uint64 { 559 return nil 560 } 561 562 func (t *LenType) uselessHint(v uint64) bool { 563 return v <= maxArrayLen || v > 1<<20 564 } 565 566 type ProcType struct { 567 IntTypeCommon 568 ValuesStart uint64 569 ValuesPerProc uint64 570 } 571 572 const ( 573 // Some aspects of the linux kernel configs also know about this const, 574 // e.g. they create that many devices of various types (usually these parameters are in CMDLINE). 575 MaxPids = 32 576 procDefaultValue = 0xffffffffffffffff // special value denoting 0 for all procs 577 ) 578 579 func (t *ProcType) DefaultArg(dir Dir) Arg { 580 return MakeConstArg(t, dir, procDefaultValue) 581 } 582 583 func (t *ProcType) isDefaultArg(arg Arg) bool { 584 return arg.(*ConstArg).Val == procDefaultValue 585 } 586 587 type CsumKind int 588 589 const ( 590 CsumInet CsumKind = iota 591 CsumPseudo 592 ) 593 594 type CsumType struct { 595 IntTypeCommon 596 Kind CsumKind 597 Buf string 598 Protocol uint64 // for CsumPseudo 599 } 600 601 func (t *CsumType) String() string { 602 return "csum" 603 } 604 605 func (t *CsumType) DefaultArg(dir Dir) Arg { 606 return MakeConstArg(t, dir, 0) 607 } 608 609 func (t *CsumType) isDefaultArg(arg Arg) bool { 610 return arg.(*ConstArg).Val == 0 611 } 612 613 type VmaType struct { 614 TypeCommon 615 RangeBegin uint64 // in pages 616 RangeEnd uint64 617 } 618 619 func (t *VmaType) String() string { 620 return "vma" 621 } 622 623 func (t *VmaType) DefaultArg(dir Dir) Arg { 624 return MakeSpecialPointerArg(t, dir, 0) 625 } 626 627 func (t *VmaType) isDefaultArg(arg Arg) bool { 628 a := arg.(*PointerArg) 629 return a.IsSpecial() && a.Address == 0 630 } 631 632 type BufferKind int 633 634 const ( 635 BufferBlobRand BufferKind = iota 636 BufferBlobRange 637 BufferString 638 BufferFilename 639 BufferText 640 BufferGlob 641 BufferCompressed 642 ) 643 644 type TextKind int 645 646 const ( 647 TextTarget TextKind = iota 648 TextX86Real 649 TextX86bit16 650 TextX86bit32 651 TextX86bit64 652 TextArm64 653 TextPpc64 654 ) 655 656 type BufferType struct { 657 TypeCommon 658 Kind BufferKind 659 RangeBegin uint64 // for BufferBlobRange kind 660 RangeEnd uint64 // for BufferBlobRange kind 661 Text TextKind // for BufferText 662 SubKind string 663 Values []string // possible values for BufferString and BufferGlob kind 664 NoZ bool // non-zero terminated BufferString/BufferFilename 665 } 666 667 func (t *BufferType) String() string { 668 return "buffer" 669 } 670 671 func (t *BufferType) DefaultArg(dir Dir) Arg { 672 if dir == DirOut { 673 var sz uint64 674 if !t.Varlen() { 675 sz = t.Size() 676 } 677 return MakeOutDataArg(t, dir, sz) 678 } 679 680 var data []byte 681 if len(t.Values) == 1 { 682 data = []byte(t.Values[0]) 683 } else if !t.Varlen() { 684 data = make([]byte, t.Size()) 685 } 686 return MakeDataArg(t, dir, data) 687 } 688 689 func (t *BufferType) isDefaultArg(arg Arg) bool { 690 a := arg.(*DataArg) 691 sz := uint64(0) 692 if !t.Varlen() { 693 sz = t.Size() 694 } 695 if a.Size() != sz { 696 return false 697 } 698 if a.Dir() == DirOut { 699 return true 700 } 701 if len(t.Values) == 1 { 702 return string(a.Data()) == t.Values[0] 703 } 704 for _, v := range a.Data() { 705 if v != 0 { 706 return false 707 } 708 } 709 return true 710 } 711 712 func (t *BufferType) IsCompressed() bool { 713 return t.Kind == BufferCompressed 714 } 715 716 type ArrayKind int 717 718 const ( 719 ArrayRandLen ArrayKind = iota 720 ArrayRangeLen 721 ) 722 723 type ArrayType struct { 724 TypeCommon 725 Elem Type 726 Kind ArrayKind 727 RangeBegin uint64 728 RangeEnd uint64 729 } 730 731 func (t *ArrayType) String() string { 732 return fmt.Sprintf("array[%v]", t.Elem.String()) 733 } 734 735 func (t *ArrayType) DefaultArg(dir Dir) Arg { 736 var elems []Arg 737 if t.Kind == ArrayRangeLen && t.RangeBegin == t.RangeEnd { 738 for i := uint64(0); i < t.RangeBegin; i++ { 739 elems = append(elems, t.Elem.DefaultArg(dir)) 740 } 741 } 742 return MakeGroupArg(t, dir, elems) 743 } 744 745 func (t *ArrayType) isDefaultArg(arg Arg) bool { 746 a := arg.(*GroupArg) 747 if !a.fixedInnerSize() && len(a.Inner) != 0 { 748 return false 749 } 750 for _, elem := range a.Inner { 751 if !isDefault(elem) { 752 return false 753 } 754 } 755 return true 756 } 757 758 type PtrType struct { 759 TypeCommon 760 Elem Type 761 ElemDir Dir 762 SquashableElem bool 763 } 764 765 func (t *PtrType) String() string { 766 return fmt.Sprintf("ptr[%v, %v]", t.ElemDir, t.Elem.String()) 767 } 768 769 func (t *PtrType) DefaultArg(dir Dir) Arg { 770 if t.Optional() { 771 return MakeSpecialPointerArg(t, dir, 0) 772 } 773 return MakePointerArg(t, dir, 0, t.Elem.DefaultArg(t.ElemDir)) 774 } 775 776 func (t *PtrType) isDefaultArg(arg Arg) bool { 777 a := arg.(*PointerArg) 778 if t.Optional() { 779 return a.IsSpecial() && a.Address == 0 780 } 781 return a.Address == 0 && a.Res != nil && isDefault(a.Res) 782 } 783 784 type StructType struct { 785 TypeCommon 786 Fields []Field 787 AlignAttr uint64 788 OverlayField int // index of the field marked with out_overlay attribute (0 if no attribute) 789 } 790 791 func (t *StructType) String() string { 792 return t.Name() 793 } 794 795 func (t *StructType) DefaultArg(dir Dir) Arg { 796 inner := make([]Arg, len(t.Fields)) 797 for i, field := range t.Fields { 798 inner[i] = field.DefaultArg(field.Dir(dir)) 799 } 800 return MakeGroupArg(t, dir, inner) 801 } 802 803 func (t *StructType) isDefaultArg(arg Arg) bool { 804 a := arg.(*GroupArg) 805 for _, elem := range a.Inner { 806 if !isDefault(elem) { 807 return false 808 } 809 } 810 return true 811 } 812 813 type UnionType struct { 814 TypeCommon 815 Fields []Field 816 } 817 818 func (t *UnionType) String() string { 819 return t.Name() 820 } 821 822 func (t *UnionType) DefaultArg(dir Dir) Arg { 823 idx, _ := t.defaultField() 824 f := t.Fields[idx] 825 arg := MakeUnionArg(t, dir, f.DefaultArg(f.Dir(dir)), idx) 826 arg.transient = t.isConditional() 827 return arg 828 } 829 830 func (t *UnionType) defaultField() (int, bool) { 831 // If it's a conditional union, the last field is usually a safe choice for the default value as 832 // it must have no condition. 833 // Auto-generated wrappers for conditional fields are an exception since both fields will have 834 // conditions, and, moreover, these conditions will be mutually exclusive. 835 if t.isConditional() { 836 if t.Fields[len(t.Fields)-1].Condition != nil { 837 // There's no correct default index. 838 return 0, false 839 } 840 return len(t.Fields) - 1, true 841 } 842 // Otherwise, just take the first. 843 return 0, true 844 } 845 846 func (t *UnionType) isConditional() bool { 847 // Either all fields will have a conditions, or all except the last one, or none. 848 // So checking for the first one is always enough. 849 return t.Fields[0].Condition != nil 850 } 851 852 func (t *UnionType) isDefaultArg(arg Arg) bool { 853 a := arg.(*UnionArg) 854 defIdx, ok := t.defaultField() 855 if !ok { 856 // Any value is the only possible option. 857 return isDefault(a.Option) 858 } 859 return a.Index == defIdx && isDefault(a.Option) 860 } 861 862 type ConstValue struct { 863 Name string 864 Value uint64 865 } 866 867 type TypeCtx struct { 868 Meta *Syscall 869 Dir Dir 870 Ptr *Type 871 Optional bool 872 Stop bool // If set by the callback, subtypes of this type are not visited. 873 } 874 875 func ForeachType(syscalls []*Syscall, f func(t Type, ctx *TypeCtx)) { 876 for _, meta := range syscalls { 877 foreachCallTypeImpl(meta, true, f) 878 } 879 } 880 881 func ForeachTypePost(syscalls []*Syscall, f func(t Type, ctx *TypeCtx)) { 882 for _, meta := range syscalls { 883 foreachCallTypeImpl(meta, false, f) 884 } 885 } 886 887 func ForeachCallType(meta *Syscall, f func(t Type, ctx *TypeCtx)) { 888 foreachCallTypeImpl(meta, true, f) 889 } 890 891 // We need seen to be keyed by the type, the direction, and the optionality 892 // bit. Even if the first time we see a type it is optional or DirOut, it 893 // could be required or DirIn on another path. So to ensure that the 894 // information we report to the caller is correct, we need to visit both 895 // occurrences. 896 type seenKey struct { 897 t Type 898 d Dir 899 o bool 900 } 901 902 func foreachCallTypeImpl(meta *Syscall, preorder bool, f func(t Type, ctx *TypeCtx)) { 903 // Note: we specifically don't create seen in ForeachType. 904 // It would prune recursion more (across syscalls), but lots of users need to 905 // visit each struct per-syscall (e.g. prio, used resources). 906 seen := make(map[seenKey]bool) 907 for i := range meta.Args { 908 foreachTypeRec(f, meta, seen, &meta.Args[i].Type, DirIn, preorder, false) 909 } 910 if meta.Ret != nil { 911 foreachTypeRec(f, meta, seen, &meta.Ret, DirOut, preorder, false) 912 } 913 } 914 915 func ForeachArgType(typ Type, f func(t Type, ctx *TypeCtx)) { 916 foreachTypeRec(f, nil, make(map[seenKey]bool), &typ, DirIn, true, false) 917 } 918 919 func foreachTypeRec(cb func(t Type, ctx *TypeCtx), meta *Syscall, seen map[seenKey]bool, ptr *Type, 920 dir Dir, preorder, optional bool) { 921 if _, ref := (*ptr).(Ref); !ref { 922 optional = optional || (*ptr).Optional() 923 } 924 ctx := &TypeCtx{Meta: meta, Dir: dir, Ptr: ptr, Optional: optional} 925 if preorder { 926 cb(*ptr, ctx) 927 if ctx.Stop { 928 return 929 } 930 } 931 switch a := (*ptr).(type) { 932 case *PtrType: 933 foreachTypeRec(cb, meta, seen, &a.Elem, a.ElemDir, preorder, optional) 934 case *ArrayType: 935 foreachTypeRec(cb, meta, seen, &a.Elem, dir, preorder, optional) 936 case *StructType: 937 key := seenKey{ 938 t: a, 939 d: dir, 940 o: optional, 941 } 942 if seen[key] { 943 break // prune recursion via pointers to structs/unions 944 } 945 seen[key] = true 946 for i, f := range a.Fields { 947 foreachTypeRec(cb, meta, seen, &a.Fields[i].Type, f.Dir(dir), preorder, optional) 948 } 949 case *UnionType: 950 key := seenKey{ 951 t: a, 952 d: dir, 953 o: optional, 954 } 955 if seen[key] { 956 break // prune recursion via pointers to structs/unions 957 } 958 seen[key] = true 959 for i, f := range a.Fields { 960 foreachTypeRec(cb, meta, seen, &a.Fields[i].Type, f.Dir(dir), preorder, optional) 961 } 962 case *ResourceType, *BufferType, *VmaType, *LenType, *FlagsType, 963 *ConstType, *IntType, *ProcType, *CsumType: 964 case Ref: 965 // This is only needed for pkg/compiler. 966 default: 967 panic("unknown type") 968 } 969 if !preorder { 970 cb(*ptr, ctx) 971 if ctx.Stop { 972 panic("Stop is set in post-order iteration") 973 } 974 } 975 } 976 977 // CppName transforms PascalStyleNames to cpp_style_names. 978 func CppName(name string) string { 979 var res []byte 980 for i := range name { 981 c := rune(name[i]) 982 if unicode.IsUpper(c) && i != 0 && !unicode.IsUpper(rune(name[i-1])) { 983 res = append(res, '_') 984 } 985 res = append(res, byte(unicode.ToLower(c))) 986 } 987 return string(res) 988 }