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