1// Copyright 2017 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 4package compiler 5 6import ( 7 "fmt" 8 "strconv" 9 10 "github.com/google/syzkaller/pkg/ast" 11 "github.com/google/syzkaller/prog" 12) 13 14// typeDesc is arg/field type descriptor. 15type typeDesc struct { 16 Names []string 17 CanBeTypedef bool // can be type alias target? 18 CantBeOpt bool // can't be marked as opt? 19 NeedBase bool // needs base type when used as field? 20 AllowColon bool // allow colon (int8:2) on fields? 21 ResourceBase bool // can be resource base type? 22 OptArgs int // number of optional arguments in Args array 23 Args []namedArg // type arguments 24 // CanBeArgRet returns if this type can be syscall argument/return (false if nil). 25 CanBeArgRet func(comp *compiler, t *ast.Type) (bool, bool) 26 // Check does custom verification of the type (optional, consts are not patched yet). 27 Check func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) 28 // CheckConsts does custom verification of the type (optional, consts are patched). 29 CheckConsts func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) 30 // Varlen returns if the type is variable-length (false if not set). 31 Varlen func(comp *compiler, t *ast.Type, args []*ast.Type) bool 32 // ZeroSize returns if the type has static 0 size (false if not set). 33 ZeroSize func(comp *compiler, t *ast.Type, args []*ast.Type) bool 34 // Gen generates corresponding prog.Type. 35 Gen func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type 36} 37 38// typeArg describes a type argument. 39type typeArg struct { 40 Names []string 41 Kind int // int/ident/string 42 MaxArgs int // maxiumum number of subargs 43 AllowColon bool // allow colon (2:3)? 44 // Check does custom verification of the arg (optional). 45 Check func(comp *compiler, t *ast.Type) 46 CheckConsts func(comp *compiler, t *ast.Type) 47} 48 49type namedArg struct { 50 Name string 51 Type *typeArg 52 IsArg bool // does not need base type 53} 54 55const ( 56 kindAny = iota 57 kindInt 58 kindIdent 59 kindString 60) 61 62func canBeArg(comp *compiler, t *ast.Type) (bool, bool) { return true, false } 63func canBeArgRet(comp *compiler, t *ast.Type) (bool, bool) { return true, true } 64 65var typeInt = &typeDesc{ 66 Names: typeArgBase.Type.Names, 67 CanBeArgRet: canBeArg, 68 CanBeTypedef: true, 69 AllowColon: true, 70 ResourceBase: true, 71 OptArgs: 1, 72 Args: []namedArg{{Name: "range", Type: typeArgIntRange}}, 73 Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { 74 typeArgBase.Type.Check(comp, t) 75 }, 76 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 77 size, be := comp.parseIntType(t.Ident) 78 kind, rangeBegin, rangeEnd := prog.IntPlain, uint64(0), uint64(0) 79 if len(args) > 0 { 80 kind, rangeBegin, rangeEnd = prog.IntRange, args[0].Value, args[0].Value2 81 } 82 base.TypeSize = size 83 return &prog.IntType{ 84 IntTypeCommon: genIntCommon(base.TypeCommon, t.Value2, be), 85 Kind: kind, 86 RangeBegin: rangeBegin, 87 RangeEnd: rangeEnd, 88 } 89 }, 90} 91 92var typePtr = &typeDesc{ 93 Names: []string{"ptr", "ptr64"}, 94 CanBeArgRet: canBeArg, 95 CanBeTypedef: true, 96 Args: []namedArg{{Name: "direction", Type: typeArgDir}, {Name: "type", Type: typeArgType}}, 97 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 98 base.ArgDir = prog.DirIn // pointers are always in 99 base.TypeSize = comp.ptrSize 100 if t.Ident == "ptr64" { 101 base.TypeSize = 8 102 } 103 return &prog.PtrType{ 104 TypeCommon: base.TypeCommon, 105 Type: comp.genType(args[1], "", genDir(args[0]), false), 106 } 107 }, 108} 109 110var typeVoid = &typeDesc{ 111 Names: []string{"void"}, 112 CantBeOpt: true, 113 ZeroSize: func(comp *compiler, t *ast.Type, args []*ast.Type) bool { 114 return true 115 }, 116 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 117 base.TypeSize = 0 // the only type with static size 0 118 return &prog.BufferType{ 119 TypeCommon: base.TypeCommon, 120 Kind: prog.BufferBlobRange, 121 RangeBegin: 0, 122 RangeEnd: 0, 123 } 124 }, 125} 126 127var typeArray = &typeDesc{ 128 Names: []string{"array"}, 129 CanBeTypedef: true, 130 CantBeOpt: true, 131 OptArgs: 1, 132 Args: []namedArg{{Name: "type", Type: typeArgType}, {Name: "size", Type: typeArgSizeRange}}, 133 CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { 134 if len(args) > 1 && args[1].Value == 0 && args[1].Value2 == 0 { 135 comp.error(args[1].Pos, "arrays of size 0 are not supported") 136 } 137 }, 138 Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool { 139 if comp.isZeroSize(args[0]) { 140 return false 141 } 142 if comp.isVarlen(args[0]) { 143 return true 144 } 145 if len(args) > 1 { 146 return args[1].Value != args[1].Value2 147 } 148 return true 149 }, 150 ZeroSize: func(comp *compiler, t *ast.Type, args []*ast.Type) bool { 151 return comp.isZeroSize(args[0]) 152 }, 153 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 154 elemType := comp.genType(args[0], "", base.ArgDir, false) 155 kind, begin, end := prog.ArrayRandLen, uint64(0), uint64(0) 156 if len(args) > 1 { 157 kind, begin, end = prog.ArrayRangeLen, args[1].Value, args[1].Value2 158 } 159 if it, ok := elemType.(*prog.IntType); ok && it.Kind == prog.IntPlain && it.TypeSize == 1 { 160 // Special case: buffer is better mutated. 161 bufKind := prog.BufferBlobRand 162 base.TypeSize = 0 163 if kind == prog.ArrayRangeLen { 164 bufKind = prog.BufferBlobRange 165 if begin == end { 166 base.TypeSize = begin * elemType.Size() 167 } 168 } 169 return &prog.BufferType{ 170 TypeCommon: base.TypeCommon, 171 Kind: bufKind, 172 RangeBegin: begin, 173 RangeEnd: end, 174 } 175 } 176 // TypeSize is assigned later in genStructDescs. 177 return &prog.ArrayType{ 178 TypeCommon: base.TypeCommon, 179 Type: elemType, 180 Kind: kind, 181 RangeBegin: begin, 182 RangeEnd: end, 183 } 184 }, 185} 186 187var typeLen = &typeDesc{ 188 Names: []string{"len", "bytesize", "bytesize2", "bytesize4", "bytesize8", "bitsize"}, 189 CanBeArgRet: canBeArg, 190 CantBeOpt: true, 191 NeedBase: true, 192 Args: []namedArg{{Name: "len target", Type: typeArgLenTarget}}, 193 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 194 var bitSize uint64 195 switch t.Ident { 196 case "bytesize": 197 bitSize = 8 198 case "bytesize2", "bytesize4", "bytesize8": 199 byteSize, _ := strconv.ParseUint(t.Ident[8:], 10, 8) 200 bitSize = byteSize * 8 201 case "bitsize": 202 bitSize = 1 203 } 204 return &prog.LenType{ 205 IntTypeCommon: base, 206 Buf: args[0].Ident, 207 BitSize: bitSize, 208 } 209 }, 210} 211 212var typeConst = &typeDesc{ 213 Names: []string{"const"}, 214 CanBeArgRet: canBeArg, 215 CanBeTypedef: true, 216 CantBeOpt: true, 217 NeedBase: true, 218 Args: []namedArg{{Name: "value", Type: typeArgInt}}, 219 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 220 return &prog.ConstType{ 221 IntTypeCommon: base, 222 Val: args[0].Value, 223 } 224 }, 225} 226 227var typeArgLenTarget = &typeArg{ 228 Kind: kindIdent, 229} 230 231var typeFlags = &typeDesc{ 232 Names: []string{"flags"}, 233 CanBeArgRet: canBeArg, 234 CanBeTypedef: true, 235 CantBeOpt: true, 236 NeedBase: true, 237 Args: []namedArg{{Name: "flags", Type: typeArgFlags}}, 238 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 239 name := args[0].Ident 240 base.TypeName = name 241 f := comp.intFlags[name] 242 if len(f.Values) == 0 { 243 // We can get this if all values are unsupported consts. 244 return &prog.IntType{ 245 IntTypeCommon: base, 246 Kind: prog.IntPlain, 247 } 248 } 249 bitmask := true 250 var combined uint64 251 values := genIntArray(f.Values) 252 for _, v := range values { 253 if v&combined != 0 { 254 bitmask = false 255 break 256 } 257 combined |= v 258 } 259 return &prog.FlagsType{ 260 IntTypeCommon: base, 261 Vals: values, 262 BitMask: bitmask, 263 } 264 }, 265} 266 267var typeArgFlags = &typeArg{ 268 Kind: kindIdent, 269 Check: func(comp *compiler, t *ast.Type) { 270 if comp.intFlags[t.Ident] == nil { 271 comp.error(t.Pos, "unknown flags %v", t.Ident) 272 return 273 } 274 }, 275} 276 277var typeFileoff = &typeDesc{ 278 Names: []string{"fileoff"}, 279 CanBeArgRet: canBeArg, 280 CantBeOpt: true, 281 NeedBase: true, 282 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 283 return &prog.IntType{ 284 IntTypeCommon: base, 285 Kind: prog.IntFileoff, 286 } 287 }, 288} 289 290var typeVMA = &typeDesc{ 291 Names: []string{"vma"}, 292 CanBeArgRet: canBeArg, 293 OptArgs: 1, 294 Args: []namedArg{{Name: "size range", Type: typeArgSizeRange}}, 295 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 296 begin, end := uint64(0), uint64(0) 297 if len(args) > 0 { 298 begin, end = args[0].Value, args[0].Value2 299 } 300 base.TypeSize = comp.ptrSize 301 return &prog.VmaType{ 302 TypeCommon: base.TypeCommon, 303 RangeBegin: begin, 304 RangeEnd: end, 305 } 306 }, 307} 308 309var typeCsum = &typeDesc{ 310 Names: []string{"csum"}, 311 NeedBase: true, 312 CantBeOpt: true, 313 OptArgs: 1, 314 Args: []namedArg{ 315 {Name: "csum target", Type: typeArgLenTarget}, 316 {Name: "kind", Type: typeArgCsumType}, 317 {Name: "proto", Type: typeArgInt}, 318 }, 319 Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { 320 if len(args) > 2 && genCsumKind(args[1]) != prog.CsumPseudo { 321 comp.error(args[2].Pos, "only pseudo csum can have proto") 322 } 323 }, 324 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 325 var proto uint64 326 if len(args) > 2 { 327 proto = args[2].Value 328 } 329 return &prog.CsumType{ 330 IntTypeCommon: base, 331 Buf: args[0].Ident, 332 Kind: genCsumKind(args[1]), 333 Protocol: proto, 334 } 335 }, 336} 337 338var typeArgCsumType = &typeArg{ 339 Kind: kindIdent, 340 Names: []string{"inet", "pseudo"}, 341} 342 343func genCsumKind(t *ast.Type) prog.CsumKind { 344 switch t.Ident { 345 case "inet": 346 return prog.CsumInet 347 case "pseudo": 348 return prog.CsumPseudo 349 default: 350 panic(fmt.Sprintf("unknown csum kind %q", t.Ident)) 351 } 352} 353 354var typeProc = &typeDesc{ 355 Names: []string{"proc"}, 356 CanBeArgRet: canBeArg, 357 CanBeTypedef: true, 358 NeedBase: true, 359 Args: []namedArg{ 360 {Name: "range start", Type: typeArgInt}, 361 {Name: "per-proc values", Type: typeArgInt}, 362 }, 363 CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { 364 start := args[0].Value 365 perProc := args[1].Value 366 if perProc == 0 { 367 comp.error(args[1].Pos, "proc per-process values must not be 0") 368 return 369 } 370 size := base.TypeSize * 8 371 max := uint64(1) << size 372 if size == 64 { 373 max = ^uint64(0) 374 } 375 if start >= max { 376 comp.error(args[0].Pos, "values starting from %v overflow base type", start) 377 } else if perProc > (max-start)/prog.MaxPids { 378 comp.error(args[0].Pos, "values starting from %v with step %v overflow base type for %v procs", 379 start, perProc, prog.MaxPids) 380 } 381 }, 382 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 383 return &prog.ProcType{ 384 IntTypeCommon: base, 385 ValuesStart: args[0].Value, 386 ValuesPerProc: args[1].Value, 387 } 388 }, 389} 390 391var typeText = &typeDesc{ 392 Names: []string{"text"}, 393 CantBeOpt: true, 394 Args: []namedArg{{Name: "kind", Type: typeArgTextType}}, 395 Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool { 396 return true 397 }, 398 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 399 base.TypeSize = 0 400 return &prog.BufferType{ 401 TypeCommon: base.TypeCommon, 402 Kind: prog.BufferText, 403 Text: genTextType(args[0]), 404 } 405 }, 406} 407 408var typeArgTextType = &typeArg{ 409 Kind: kindIdent, 410 Names: []string{"x86_real", "x86_16", "x86_32", "x86_64", "arm64"}, 411} 412 413func genTextType(t *ast.Type) prog.TextKind { 414 switch t.Ident { 415 case "x86_real": 416 return prog.TextX86Real 417 case "x86_16": 418 return prog.TextX86bit16 419 case "x86_32": 420 return prog.TextX86bit32 421 case "x86_64": 422 return prog.TextX86bit64 423 case "arm64": 424 return prog.TextArm64 425 default: 426 panic(fmt.Sprintf("unknown text type %q", t.Ident)) 427 } 428} 429 430var typeBuffer = &typeDesc{ 431 Names: []string{"buffer"}, 432 CanBeArgRet: canBeArg, 433 Args: []namedArg{{Name: "direction", Type: typeArgDir}}, 434 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 435 base.TypeSize = comp.ptrSize 436 common := genCommon("", "", 0, genDir(args[0]), false) 437 // BufferBlobRand is always varlen. 438 common.IsVarlen = true 439 return &prog.PtrType{ 440 TypeCommon: base.TypeCommon, 441 Type: &prog.BufferType{ 442 TypeCommon: common, 443 Kind: prog.BufferBlobRand, 444 }, 445 } 446 }, 447} 448 449const ( 450 stringnoz = "stringnoz" 451) 452 453var typeString = &typeDesc{ 454 Names: []string{"string", stringnoz}, 455 CanBeTypedef: true, 456 OptArgs: 2, 457 Args: []namedArg{ 458 {Name: "literal or flags", Type: typeArgStringFlags}, 459 {Name: "size", Type: typeArgInt}, 460 }, 461 Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { 462 if t.Ident == stringnoz && len(args) > 1 { 463 comp.error(args[0].Pos, "fixed-size string can't be non-zero-terminated") 464 } 465 }, 466 CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { 467 if len(args) > 1 { 468 size := args[1].Value 469 vals := comp.genStrings(t, args) 470 for _, s := range vals { 471 if uint64(len(s)) > size { 472 comp.error(args[0].Pos, "string value %q exceeds buffer length %v", 473 s, size) 474 } 475 } 476 } 477 }, 478 Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool { 479 return comp.stringSize(t, args) == varlenString 480 }, 481 ZeroSize: func(comp *compiler, t *ast.Type, args []*ast.Type) bool { 482 return comp.stringSize(t, args) == 0 483 }, 484 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 485 if len(args) > 0 && args[0].Ident == "filename" { 486 base.TypeName = "filename" 487 base.TypeSize = 0 488 if len(args) >= 2 { 489 base.TypeSize = args[1].Value 490 } 491 return &prog.BufferType{ 492 TypeCommon: base.TypeCommon, 493 Kind: prog.BufferFilename, 494 NoZ: t.Ident == stringnoz, 495 } 496 } 497 subkind := "" 498 if len(args) > 0 && args[0].Ident != "" { 499 subkind = args[0].Ident 500 } 501 vals := comp.genStrings(t, args) 502 base.TypeSize = comp.stringSize(t, args) 503 if base.TypeSize == varlenString { 504 base.TypeSize = 0 505 } 506 return &prog.BufferType{ 507 TypeCommon: base.TypeCommon, 508 Kind: prog.BufferString, 509 SubKind: subkind, 510 Values: vals, 511 NoZ: t.Ident == stringnoz, 512 } 513 }, 514} 515 516func (comp *compiler) genStrings(t *ast.Type, args []*ast.Type) []string { 517 var vals []string 518 if len(args) > 0 { 519 if args[0].HasString { 520 vals = append(vals, args[0].String) 521 } else { 522 vals = genStrArray(comp.strFlags[args[0].Ident].Values) 523 } 524 } 525 if t.Ident == stringnoz { 526 return vals 527 } 528 var size uint64 529 if len(args) > 1 { 530 size = args[1].Value 531 } 532 for i, s := range vals { 533 s += "\x00" 534 for uint64(len(s)) < size { 535 s += "\x00" 536 } 537 vals[i] = s 538 } 539 return vals 540} 541 542const varlenString = ^uint64(0) 543 544// stringSize returns static string size, or varlenString if it is variable length. 545func (comp *compiler) stringSize(t *ast.Type, args []*ast.Type) uint64 { 546 switch len(args) { 547 case 0: 548 return varlenString // a random string 549 case 1: 550 var z uint64 551 if t.Ident == "string" { 552 z = 1 553 } 554 if args[0].HasString { 555 return uint64(len(args[0].String)) + z // string constant 556 } 557 size := varlenString 558 for _, s := range comp.strFlags[args[0].Ident].Values { 559 s1 := uint64(len(s.Value)) + z 560 if size != varlenString && size != s1 { 561 return varlenString // strings of different lengths 562 } 563 size = s1 564 } 565 return size // all strings have the same length 566 case 2: 567 return args[1].Value // have explicit length 568 default: 569 panic("too many string args") 570 } 571} 572 573var typeArgStringFlags = &typeArg{ 574 Check: func(comp *compiler, t *ast.Type) { 575 if !t.HasString && t.Ident == "" { 576 comp.error(t.Pos, "unexpected int %v, string arg must be a string literal or string flags", t.Value) 577 return 578 } 579 if t.Ident != "" && comp.strFlags[t.Ident] == nil { 580 comp.error(t.Pos, "unknown string flags %v", t.Ident) 581 return 582 } 583 }, 584} 585 586var typeFmt = &typeDesc{ 587 Names: []string{"fmt"}, 588 CanBeTypedef: true, 589 CantBeOpt: true, 590 Args: []namedArg{ 591 {Name: "format", Type: typeFmtFormat}, 592 {Name: "value", Type: typeArgType, IsArg: true}, 593 }, 594 Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { 595 desc, _, _ := comp.getArgsBase(args[1], "", base.TypeCommon.ArgDir, true) 596 switch desc { 597 case typeResource, typeInt, typeLen, typeFlags, typeProc: 598 default: 599 comp.error(t.Pos, "bad fmt value %v, expect an integer", args[1].Ident) 600 return 601 } 602 }, 603 Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 604 var format prog.BinaryFormat 605 var size uint64 606 switch args[0].Ident { 607 case "dec": 608 format = prog.FormatStrDec 609 size = 20 610 case "hex": 611 format = prog.FormatStrHex 612 size = 18 613 case "oct": 614 format = prog.FormatStrOct 615 size = 23 616 } 617 typ := comp.genType(args[1], "", base.TypeCommon.ArgDir, true) 618 switch t := typ.(type) { 619 case *prog.ResourceType: 620 t.ArgFormat = format 621 t.TypeSize = size 622 case *prog.IntType: 623 t.ArgFormat = format 624 t.TypeSize = size 625 case *prog.LenType: 626 t.ArgFormat = format 627 t.TypeSize = size 628 case *prog.FlagsType: 629 t.ArgFormat = format 630 t.TypeSize = size 631 case *prog.ProcType: 632 t.ArgFormat = format 633 t.TypeSize = size 634 default: 635 panic(fmt.Sprintf("unexpected type: %#v", typ)) 636 } 637 return typ 638 }, 639} 640 641var typeFmtFormat = &typeArg{ 642 Names: []string{"dec", "hex", "oct"}, 643 Kind: kindIdent, 644} 645 646// typeArgType is used as placeholder for any type (e.g. ptr target type). 647var typeArgType = &typeArg{} 648 649var typeResource = &typeDesc{ 650 // No Names, but getTypeDesc knows how to match it. 651 CanBeArgRet: canBeArgRet, 652 ResourceBase: true, 653 // Gen is assigned below to avoid initialization loop. 654} 655 656func init() { 657 typeResource.Gen = func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 658 // Find and generate base type to get its size. 659 var baseType *ast.Type 660 for r := comp.resources[t.Ident]; r != nil; { 661 baseType = r.Base 662 r = comp.resources[r.Base.Ident] 663 } 664 baseProgType := comp.genType(baseType, "", prog.DirIn, false) 665 base.TypeSize = baseProgType.Size() 666 return &prog.ResourceType{ 667 TypeCommon: base.TypeCommon, 668 ArgFormat: baseProgType.Format(), 669 } 670 } 671} 672 673var typeStruct = &typeDesc{ 674 // No Names, but getTypeDesc knows how to match it. 675 CantBeOpt: true, 676 CanBeTypedef: true, 677 // Varlen/Gen are assigned below due to initialization cycle. 678} 679 680func init() { 681 typeStruct.CanBeArgRet = func(comp *compiler, t *ast.Type) (bool, bool) { 682 // Allow unions to be arg if all options can be arg. 683 s := comp.structs[t.Ident] 684 if !s.IsUnion { 685 return false, false 686 } 687 canBeArg := true 688 for _, fld := range s.Fields { 689 desc := comp.getTypeDesc(fld.Type) 690 if desc == nil || desc.CanBeArgRet == nil { 691 return false, false 692 } 693 canBeArg1, _ := desc.CanBeArgRet(comp, fld.Type) 694 if !canBeArg1 { 695 canBeArg = false 696 } 697 } 698 return canBeArg, false 699 } 700 typeStruct.Varlen = func(comp *compiler, t *ast.Type, args []*ast.Type) bool { 701 return comp.structIsVarlen(t.Ident) 702 } 703 typeStruct.ZeroSize = func(comp *compiler, t *ast.Type, args []*ast.Type) bool { 704 for _, fld := range comp.structs[t.Ident].Fields { 705 if !comp.isZeroSize(fld.Type) { 706 return false 707 } 708 } 709 return true 710 } 711 typeStruct.Gen = func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { 712 s := comp.structs[t.Ident] 713 key := prog.StructKey{ 714 Name: t.Ident, 715 Dir: base.ArgDir, 716 } 717 desc := comp.structDescs[key] 718 if desc == nil { 719 // Need to assign to structDescs before calling genStructDesc to break recursion. 720 desc = new(prog.StructDesc) 721 comp.structDescs[key] = desc 722 comp.genStructDesc(desc, s, base.ArgDir, typeStruct.Varlen(comp, t, args)) 723 } 724 if s.IsUnion { 725 return &prog.UnionType{ 726 Key: key, 727 FldName: base.FldName, 728 StructDesc: desc, 729 } 730 } 731 return &prog.StructType{ 732 Key: key, 733 FldName: base.FldName, 734 StructDesc: desc, 735 } 736 } 737} 738 739var typeTypedef = &typeDesc{ 740 // No Names, but getTypeDesc knows how to match it. 741 Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { 742 panic("must not be called") 743 }, 744} 745 746var typeArgDir = &typeArg{ 747 Kind: kindIdent, 748 Names: []string{"in", "out", "inout"}, 749} 750 751func genDir(t *ast.Type) prog.Dir { 752 switch t.Ident { 753 case "in": 754 return prog.DirIn 755 case "out": 756 return prog.DirOut 757 case "inout": 758 return prog.DirInOut 759 default: 760 panic(fmt.Sprintf("unknown direction %q", t.Ident)) 761 } 762} 763 764var typeArgInt = &typeArg{ 765 Kind: kindInt, 766} 767 768var typeArgIntRange = &typeArg{ 769 Kind: kindInt, 770 AllowColon: true, 771 CheckConsts: func(comp *compiler, t *ast.Type) { 772 if !t.HasColon { 773 t.Value2 = t.Value 774 t.Value2Fmt = t.ValueFmt 775 } 776 if t.Value2-t.Value > 1<<64-1<<32 { 777 comp.error(t.Pos, "bad int range [%v:%v]", t.Value, t.Value2) 778 } 779 }, 780} 781 782// Size of array and vma's. 783var typeArgSizeRange = &typeArg{ 784 Kind: kindInt, 785 AllowColon: true, 786 CheckConsts: func(comp *compiler, t *ast.Type) { 787 if !t.HasColon { 788 t.Value2 = t.Value 789 } 790 const maxVal = 1e6 791 if t.Value > t.Value2 || t.Value > maxVal || t.Value2 > maxVal { 792 comp.error(t.Pos, "bad size range [%v:%v]", t.Value, t.Value2) 793 } 794 }, 795} 796 797// Base type of const/len/etc. Same as typeInt, but can't have range. 798var typeArgBase = namedArg{ 799 Name: "base type", 800 Type: &typeArg{ 801 Names: []string{"int8", "int16", "int32", "int64", "int16be", "int32be", "int64be", "intptr"}, 802 AllowColon: true, 803 Check: func(comp *compiler, t *ast.Type) { 804 if t.HasColon { 805 if t.Ident2 != "" { 806 comp.error(t.Pos2, "literal const bitfield sizes are not supported") 807 return 808 } 809 if t.Value2 == 0 { 810 // This was not supported historically 811 // and does not work the way C bitfields of size 0 work. 812 // We could allow this, but then we need to make 813 // this work the way C bitfields work. 814 comp.error(t.Pos2, "bitfields of size 0 are not supported") 815 } 816 size, _ := comp.parseIntType(t.Ident) 817 if t.Value2 > size*8 { 818 comp.error(t.Pos2, "bitfield of size %v is too large for base type of size %v", 819 t.Value2, size*8) 820 } 821 } 822 }, 823 }, 824} 825 826var ( 827 builtinTypes = make(map[string]*typeDesc) 828 builtinTypedefs = make(map[string]*ast.TypeDef) 829 builtinStrFlags = make(map[string]*ast.StrFlags) 830 831 // To avoid weird cases like ptr[in, in] and ptr[out, opt]. 832 reservedName = map[string]bool{ 833 "opt": true, 834 "in": true, 835 "out": true, 836 "inout": true, 837 } 838) 839 840const builtinDefs = ` 841type bool8 int8[0:1] 842type bool16 int16[0:1] 843type bool32 int32[0:1] 844type bool64 int64[0:1] 845type boolptr intptr[0:1] 846 847type filename string[filename] 848filename = "", "." 849 850type optional[T] [ 851 val T 852 void void 853] [varlen] 854` 855 856func init() { 857 builtins := []*typeDesc{ 858 typeInt, 859 typePtr, 860 typeVoid, 861 typeArray, 862 typeLen, 863 typeConst, 864 typeFlags, 865 typeFileoff, 866 typeVMA, 867 typeCsum, 868 typeProc, 869 typeText, 870 typeBuffer, 871 typeString, 872 typeFmt, 873 } 874 for _, desc := range builtins { 875 for _, name := range desc.Names { 876 if builtinTypes[name] != nil { 877 panic(fmt.Sprintf("duplicate builtin type %q", name)) 878 } 879 builtinTypes[name] = desc 880 } 881 } 882 builtinDesc := ast.Parse([]byte(builtinDefs), "builtins", func(pos ast.Pos, msg string) { 883 panic(fmt.Sprintf("failed to parse builtins: %v: %v", pos, msg)) 884 }) 885 for _, decl := range builtinDesc.Nodes { 886 switch n := decl.(type) { 887 case *ast.TypeDef: 888 builtinTypedefs[n.Name.Name] = n 889 case *ast.StrFlags: 890 builtinStrFlags[n.Name.Name] = n 891 case *ast.NewLine: 892 default: 893 panic(fmt.Sprintf("unexpected node in builtins: %#v", n)) 894 } 895 } 896} 897