github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/compiler/gen.go (about) 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 4 package compiler 5 6 import ( 7 "bytes" 8 "fmt" 9 "reflect" 10 "sort" 11 12 "github.com/google/syzkaller/pkg/ast" 13 "github.com/google/syzkaller/pkg/serializer" 14 "github.com/google/syzkaller/prog" 15 ) 16 17 const sizeUnassigned = ^uint64(0) 18 19 func (comp *compiler) genResources() []*prog.ResourceDesc { 20 var resources []*prog.ResourceDesc 21 for name, n := range comp.resources { 22 if !comp.used[name] { 23 continue 24 } 25 resources = append(resources, comp.genResource(n)) 26 } 27 sort.Slice(resources, func(i, j int) bool { 28 return resources[i].Name < resources[j].Name 29 }) 30 return resources 31 } 32 33 func (comp *compiler) genResource(n *ast.Resource) *prog.ResourceDesc { 34 res := &prog.ResourceDesc{ 35 Name: n.Name.Name, 36 } 37 for n != nil { 38 res.Values = append(genIntArray(n.Values), res.Values...) 39 res.Kind = append([]string{n.Name.Name}, res.Kind...) 40 n = comp.resources[n.Base.Ident] 41 } 42 if len(res.Values) == 0 { 43 res.Values = []uint64{0} 44 } 45 return res 46 } 47 48 func (comp *compiler) collectCallArgSizes() map[string][]uint64 { 49 argPos := make(map[string]ast.Pos) 50 callArgSizes := make(map[string][]uint64) 51 for _, decl := range comp.desc.Nodes { 52 n, ok := decl.(*ast.Call) 53 if !ok { 54 continue 55 } 56 // Figure out number of arguments and their sizes for each syscall. 57 // For example, we may have: 58 // ioctl(fd fd, cmd int32, arg intptr) 59 // ioctl$FOO(fd fd, cmd const[FOO]) 60 // Here we will figure out that ioctl$FOO have 3 args, even that 61 // only 2 are specified and that size of cmd is 4 even that 62 // normally we would assume it's 8 (intptr). 63 argSizes := callArgSizes[n.CallName] 64 for i, arg := range n.Args { 65 if len(argSizes) <= i { 66 argSizes = append(argSizes, comp.ptrSize) 67 } 68 desc, _, _ := comp.getArgsBase(arg.Type, true) 69 typ := comp.genField(arg, comp.ptrSize, prog.DirInOut) 70 // Ignore all types with base (const, flags). We don't have base in syscall args. 71 // Also ignore resources and pointers because fd can be 32-bits and pointer 64-bits, 72 // and then there is no way to fix this. 73 // The only relevant types left is plain int types. 74 if desc != typeInt { 75 continue 76 } 77 if !comp.target.Int64SyscallArgs && typ.Size() > comp.ptrSize { 78 comp.error(arg.Pos, "%v arg %v is larger than pointer size", n.Name.Name, arg.Name.Name) 79 continue 80 } 81 argID := fmt.Sprintf("%v|%v", comp.getCallName(n), i) 82 if _, ok := argPos[argID]; !ok { 83 argSizes[i] = typ.Size() 84 argPos[argID] = arg.Pos 85 continue 86 } 87 if argSizes[i] != typ.Size() { 88 comp.error(arg.Pos, "%v arg %v is redeclared with size %v, previously declared with size %v at %v", 89 n.Name.Name, arg.Name.Name, typ.Size(), argSizes[i], argPos[argID]) 90 continue 91 } 92 } 93 callArgSizes[comp.getCallName(n)] = argSizes 94 } 95 return callArgSizes 96 } 97 98 func (comp *compiler) getCallName(n *ast.Call) string { 99 // getCallName is used for checking that all variants of the same syscall have same argument sizes 100 // for matching arguments. Automatically-generated syscalls may violate that condition, 101 // so for them we use full syscall name. As the result manual and automatic variants 102 // of the same syscall are not checked against each other. 103 if comp.fileMeta(n.Pos).Automatic { 104 return n.Name.Name 105 } 106 return n.CallName 107 } 108 109 func (comp *compiler) genSyscalls() []*prog.Syscall { 110 callArgSizes := comp.collectCallArgSizes() 111 var calls []*prog.Syscall 112 for _, decl := range comp.desc.Nodes { 113 if n, ok := decl.(*ast.Call); ok && n.NR != ^uint64(0) { 114 calls = append(calls, comp.genSyscall(n, callArgSizes[comp.getCallName(n)])) 115 } 116 } 117 // We assign SquashableElem here rather than during pointer type generation 118 // because during pointer generation recursive struct types may not be fully 119 // generated yet, thus ForeachArgType won't observe all types. 120 prog.ForeachTypePost(calls, func(typ prog.Type, ctx *prog.TypeCtx) { 121 if ptr, ok := typ.(*prog.PtrType); ok { 122 ptr.SquashableElem = isSquashableElem(ptr.Elem, ptr.ElemDir) 123 } 124 }) 125 sort.Slice(calls, func(i, j int) bool { 126 return calls[i].Name < calls[j].Name 127 }) 128 return calls 129 } 130 131 func (comp *compiler) genSyscall(n *ast.Call, argSizes []uint64) *prog.Syscall { 132 var ret prog.Type 133 if n.Ret != nil { 134 ret = comp.genType(n.Ret, comp.ptrSize) 135 } 136 var attrs prog.SyscallAttrs 137 attrs.Automatic = comp.fileMeta(n.Pos).Automatic 138 intAttrs, _, stringAttrs := comp.parseAttrs(callAttrs, n, n.Attrs) 139 for desc, val := range intAttrs { 140 fld := reflect.ValueOf(&attrs).Elem().FieldByName(desc.Name) 141 switch desc.Type { 142 case intAttr: 143 fld.SetUint(val) 144 case flagAttr: 145 fld.SetBool(val != 0) 146 default: 147 panic(fmt.Sprintf("unexpected attrDesc type: %q", desc.Type)) 148 } 149 } 150 for desc, val := range stringAttrs { 151 fld := reflect.ValueOf(&attrs).Elem().FieldByName(desc.Name) 152 switch desc.Type { 153 case stringAttr: 154 fld.SetString(val) 155 default: 156 panic(fmt.Sprintf("unexpected attrDesc type: %q", desc.Type)) 157 } 158 } 159 fields, _ := comp.genFieldArray(n.Args, argSizes) 160 return &prog.Syscall{ 161 Name: n.Name.Name, 162 CallName: n.CallName, 163 NR: n.NR, 164 MissingArgs: len(argSizes) - len(n.Args), 165 Args: fields, 166 Ret: ret, 167 Attrs: attrs, 168 } 169 } 170 171 type typeProxy struct { 172 typ prog.Type 173 id string 174 ref prog.Ref 175 locations []*prog.Type 176 } 177 178 func (comp *compiler) generateTypes(syscalls []*prog.Syscall) []prog.Type { 179 // Replace all Type's in the descriptions with Ref's 180 // and prepare a sorted array of corresponding real types. 181 proxies := make(map[string]*typeProxy) 182 prog.ForeachTypePost(syscalls, func(typ prog.Type, ctx *prog.TypeCtx) { 183 if _, ok := typ.(prog.Ref); ok { 184 return 185 } 186 if !typ.Varlen() && typ.Size() == sizeUnassigned { 187 panic("unassigned size") 188 } 189 id := typ.Name() 190 switch typ.(type) { 191 case *prog.StructType, *prog.UnionType: 192 // There types can be uniquely identified with the name. 193 default: 194 buf := new(bytes.Buffer) 195 serializer.Write(buf, typ) 196 id = buf.String() 197 } 198 proxy := proxies[id] 199 if proxy == nil { 200 proxy = &typeProxy{ 201 typ: typ, 202 id: id, 203 ref: prog.Ref(len(proxies)), 204 } 205 proxies[id] = proxy 206 } 207 *ctx.Ptr = proxy.ref 208 proxy.locations = append(proxy.locations, ctx.Ptr) 209 }) 210 array := make([]*typeProxy, 0, len(proxies)) 211 for _, proxy := range proxies { 212 array = append(array, proxy) 213 } 214 sort.Slice(array, func(i, j int) bool { 215 return array[i].id < array[j].id 216 }) 217 types := make([]prog.Type, len(array)) 218 for i, proxy := range array { 219 types[i] = proxy.typ 220 for _, loc := range proxy.locations { 221 *loc = prog.Ref(i) 222 } 223 } 224 return types 225 } 226 227 func (comp *compiler) layoutTypes(syscalls []*prog.Syscall) { 228 // Calculate struct/union/array sizes, add padding to structs, mark bitfields. 229 padded := make(map[prog.Type]bool) 230 prog.ForeachTypePost(syscalls, func(typ prog.Type, _ *prog.TypeCtx) { 231 comp.layoutType(typ, padded) 232 }) 233 } 234 235 func (comp *compiler) layoutType(typ prog.Type, padded map[prog.Type]bool) { 236 if padded[typ] { 237 return 238 } 239 padded[typ] = true 240 switch t := typ.(type) { 241 case *prog.ArrayType: 242 comp.layoutType(t.Elem, padded) 243 comp.layoutArray(t) 244 case *prog.StructType: 245 for _, f := range t.Fields { 246 comp.layoutType(f.Type, padded) 247 } 248 comp.layoutStruct(t) 249 case *prog.UnionType: 250 for _, f := range t.Fields { 251 comp.layoutType(f.Type, padded) 252 } 253 comp.layoutUnion(t) 254 default: 255 return 256 } 257 if !typ.Varlen() && typ.Size() == sizeUnassigned { 258 panic("size unassigned") 259 } 260 } 261 262 func (comp *compiler) layoutArray(t *prog.ArrayType) { 263 t.TypeSize = 0 264 if t.Kind == prog.ArrayRangeLen && t.RangeBegin == t.RangeEnd && !t.Elem.Varlen() { 265 t.TypeSize = t.RangeBegin * t.Elem.Size() 266 } 267 t.TypeAlign = t.Elem.Alignment() 268 } 269 270 func (comp *compiler) layoutUnion(t *prog.UnionType) { 271 for _, fld := range t.Fields { 272 t.TypeAlign = max(t.TypeAlign, fld.Alignment()) 273 } 274 t.TypeSize = 0 275 structNode := comp.structs[t.TypeName] 276 if structNode == conditionalFieldWrapper { 277 return 278 } 279 attrs := comp.parseIntAttrs(unionAttrs, structNode, structNode.Attrs) 280 if attrs[attrVarlen] != 0 { 281 return 282 } 283 sizeAttr, hasSize := attrs[attrSize] 284 for i, fld := range t.Fields { 285 sz := fld.Size() 286 if hasSize && sz > sizeAttr { 287 comp.error(structNode.Fields[i].Pos, "union %v has size attribute %v"+ 288 " which is less than field %v size %v", 289 structNode.Name.Name, sizeAttr, fld.Type.Name(), sz) 290 } 291 t.TypeSize = max(t.TypeSize, sz) 292 } 293 if hasSize { 294 t.TypeSize = sizeAttr 295 } 296 } 297 298 func (comp *compiler) layoutStruct(t *prog.StructType) { 299 // Add paddings, calculate size, mark bitfields. 300 structNode := comp.structs[t.TypeName] 301 varlen := false 302 for _, f := range t.Fields { 303 if f.Varlen() { 304 varlen = true 305 } 306 } 307 attrs := comp.parseIntAttrs(structAttrs, structNode, structNode.Attrs) 308 t.AlignAttr = attrs[attrAlign] 309 comp.layoutStructFields(t, varlen, attrs[attrPacked] != 0) 310 if align := attrs[attrAlign]; align != 0 { 311 t.TypeAlign = align 312 } else if attrs[attrPacked] != 0 { 313 t.TypeAlign = 1 314 } else { 315 for _, f := range t.Fields { 316 t.TypeAlign = max(t.TypeAlign, f.Alignment()) 317 } 318 } 319 t.TypeSize = 0 320 if !varlen { 321 var size uint64 322 for i, f := range t.Fields { 323 if i == t.OverlayField { 324 size = 0 325 } 326 size += f.Size() 327 t.TypeSize = max(t.TypeSize, size) 328 } 329 sizeAttr, hasSize := attrs[attrSize] 330 if hasSize { 331 if t.TypeSize > sizeAttr { 332 comp.error(structNode.Attrs[0].Pos, "struct %v has size attribute %v"+ 333 " which is less than struct size %v", 334 structNode.Name.Name, sizeAttr, t.TypeSize) 335 } 336 if pad := sizeAttr - t.TypeSize; pad != 0 { 337 t.Fields = append(t.Fields, genPad(pad)) 338 } 339 t.TypeSize = sizeAttr 340 } 341 } 342 } 343 344 func (comp *compiler) layoutStructFields(t *prog.StructType, varlen, packed bool) { 345 var newFields []prog.Field 346 overlayField0 := t.OverlayField 347 var structAlign, byteOffset, bitOffset uint64 348 for i, field := range t.Fields { 349 f := field.Type 350 if i == overlayField0 { 351 // We layout fields before overlay and the overlay fields effectively as 2 independent structs. 352 // So if we starting overlay, add any trailign padding/finalize bitfield layout and reset state. 353 newFields = comp.finalizeStructFields(t, newFields, varlen, structAlign, byteOffset, bitOffset) 354 t.OverlayField = len(newFields) // update overlay field index after we added paddings 355 structAlign, byteOffset, bitOffset = 0, 0, 0 356 } 357 fieldAlign := uint64(1) 358 if !packed { 359 fieldAlign = f.Alignment() 360 structAlign = max(structAlign, fieldAlign) 361 } 362 fullBitOffset := byteOffset*8 + bitOffset 363 var fieldOffset uint64 364 365 if f.IsBitfield() { 366 unitAlign := f.UnitSize() 367 if packed { 368 unitAlign = 1 369 } 370 fieldOffset = rounddown(fullBitOffset/8, unitAlign) 371 unitBits := f.UnitSize() * 8 372 occupiedBits := fullBitOffset - fieldOffset*8 373 remainBits := unitBits - occupiedBits 374 375 if remainBits < f.BitfieldLength() { 376 fieldOffset = roundup(roundup(fullBitOffset, 8)/8, unitAlign) 377 fullBitOffset, bitOffset = 0, 0 378 } else if fieldOffset*8 >= fullBitOffset { 379 fullBitOffset, bitOffset = fieldOffset*8, 0 380 } 381 fieldBitOffset := (fullBitOffset - fieldOffset*8) % unitBits 382 setBitfieldOffset(f, fieldBitOffset) 383 } else { 384 fieldOffset = roundup(roundup(fullBitOffset, 8)/8, fieldAlign) 385 bitOffset = 0 386 } 387 if fieldOffset > byteOffset { 388 pad := fieldOffset - byteOffset 389 byteOffset += pad 390 if i != 0 && t.Fields[i-1].IsBitfield() { 391 setBitfieldTypeSize(t.Fields[i-1].Type, pad) 392 if bitOffset >= 8*pad { 393 // The padding is due to bitfields, so consume the bitOffset. 394 bitOffset -= 8 * pad 395 } else if bitOffset >= 8 { 396 // Unclear is this is a bug or not and what to do in this case. 397 // But since we don't have any descriptions that trigger this, 398 // let's just guard with the panic. 399 panic(fmt.Sprintf("bad bitOffset: %v.%v pad=%v bitOffset=%v", 400 t.Name(), field.Name, pad, bitOffset)) 401 } 402 } else { 403 newFields = append(newFields, genPad(pad)) 404 } 405 } 406 if f.IsBitfield() { 407 if byteOffset > fieldOffset { 408 unitOffset := byteOffset - fieldOffset 409 setBitfieldUnitOffset(f, unitOffset) 410 } 411 } 412 newFields = append(newFields, field) 413 if f.IsBitfield() { 414 bitOffset += f.BitfieldLength() 415 } else if !f.Varlen() { 416 // Increase offset if the current field except when it's 417 // the last field in a struct and has variable length. 418 byteOffset += f.Size() 419 } 420 } 421 t.Fields = comp.finalizeStructFields(t, newFields, varlen, structAlign, byteOffset, bitOffset) 422 } 423 424 func (comp *compiler) finalizeStructFields(t *prog.StructType, fields []prog.Field, varlen bool, 425 structAlign, byteOffset, bitOffset uint64) []prog.Field { 426 if bitOffset != 0 { 427 pad := roundup(bitOffset, 8) / 8 428 byteOffset += pad 429 i := len(fields) 430 if i != 0 && fields[i-1].IsBitfield() { 431 setBitfieldTypeSize(fields[i-1].Type, pad) 432 } else { 433 fields = append(fields, genPad(pad)) 434 } 435 } 436 437 if t.AlignAttr != 0 { 438 structAlign = t.AlignAttr 439 } 440 if !varlen && structAlign != 0 && byteOffset%structAlign != 0 { 441 pad := structAlign - byteOffset%structAlign 442 fields = append(fields, genPad(pad)) 443 } 444 return fields 445 } 446 447 func roundup(v, a uint64) uint64 { 448 return rounddown(v+a-1, a) 449 } 450 451 func rounddown(v, a uint64) uint64 { 452 if (a & (a - 1)) != 0 { 453 panic(fmt.Sprintf("rounddown(%v)", a)) 454 } 455 return v & ^(a - 1) 456 } 457 458 func bitfieldFields(t0 prog.Type) (*uint64, *uint64, *uint64) { 459 switch t := t0.(type) { 460 case *prog.IntType: 461 return &t.TypeSize, &t.BitfieldOff, &t.BitfieldUnitOff 462 case *prog.ConstType: 463 return &t.TypeSize, &t.BitfieldOff, &t.BitfieldUnitOff 464 case *prog.LenType: 465 return &t.TypeSize, &t.BitfieldOff, &t.BitfieldUnitOff 466 case *prog.FlagsType: 467 return &t.TypeSize, &t.BitfieldOff, &t.BitfieldUnitOff 468 case *prog.ProcType: 469 return &t.TypeSize, &t.BitfieldOff, &t.BitfieldUnitOff 470 default: 471 panic(fmt.Sprintf("type %#v can't be a bitfield", t)) 472 } 473 } 474 475 func setBitfieldTypeSize(t prog.Type, v uint64) { 476 p, _, _ := bitfieldFields(t) 477 *p = v 478 } 479 480 func setBitfieldOffset(t prog.Type, v uint64) { 481 _, p, _ := bitfieldFields(t) 482 *p = v 483 } 484 485 func setBitfieldUnitOffset(t prog.Type, v uint64) { 486 _, _, p := bitfieldFields(t) 487 *p = v 488 } 489 490 func genPad(size uint64) prog.Field { 491 return prog.Field{ 492 Type: &prog.ConstType{ 493 IntTypeCommon: genIntCommon(genCommon("pad", size, false), 0, false), 494 IsPad: true, 495 }, 496 } 497 } 498 499 func (comp *compiler) genFieldArray(fields []*ast.Field, argSizes []uint64) ([]prog.Field, int) { 500 outOverlay := -1 501 for i, f := range fields { 502 intAttrs := comp.parseIntAttrs(structFieldAttrs, f, f.Attrs) 503 if intAttrs[attrOutOverlay] > 0 { 504 outOverlay = i 505 } 506 } 507 var res []prog.Field 508 for i, f := range fields { 509 overlayDir := prog.DirInOut 510 if outOverlay != -1 { 511 overlayDir = prog.DirIn 512 if i >= outOverlay { 513 overlayDir = prog.DirOut 514 } 515 } 516 res = append(res, comp.genField(f, argSizes[i], overlayDir)) 517 } 518 return res, outOverlay 519 } 520 521 func (comp *compiler) genFieldDir(attrs map[*attrDesc]uint64) (prog.Dir, bool) { 522 switch { 523 case attrs[attrIn] != 0: 524 return prog.DirIn, true 525 case attrs[attrOut] != 0: 526 return prog.DirOut, true 527 case attrs[attrInOut] != 0: 528 return prog.DirInOut, true 529 default: 530 return prog.DirIn, false 531 } 532 } 533 534 func (comp *compiler) genField(f *ast.Field, argSize uint64, overlayDir prog.Dir) prog.Field { 535 intAttrs, exprAttrs, _ := comp.parseAttrs(structFieldAttrs, f, f.Attrs) 536 dir, hasDir := overlayDir, true 537 if overlayDir == prog.DirInOut { 538 dir, hasDir = comp.genFieldDir(intAttrs) 539 } 540 return prog.Field{ 541 Name: f.Name.Name, 542 Type: comp.genType(f.Type, argSize), 543 HasDirection: hasDir, 544 Direction: dir, 545 Condition: exprAttrs[attrIf], 546 } 547 } 548 549 var conditionalFieldWrapper = &ast.Struct{} 550 551 // For structs, we wrap conditional fields in anonymous unions with a @void field. 552 func (comp *compiler) wrapConditionalField(name string, field prog.Field) prog.Field { 553 common := genCommon(fmt.Sprintf("_%s_%s_wrapper", name, field.Name), sizeUnassigned, false) 554 common.IsVarlen = true 555 common.TypeAlign = field.Type.Alignment() 556 557 // Fake the corresponding ast.Struct. 558 comp.structs[common.TypeName] = conditionalFieldWrapper 559 560 voidBase := genIntCommon(genCommon("void", sizeUnassigned, false), 0, false) 561 voidType := typeVoid.Gen(comp, nil, nil, voidBase) 562 563 var newCondition prog.Expression 564 if field.Condition != nil { 565 newCondition = field.Condition.Clone() 566 // Prepend "parent:". 567 newCondition.ForEachValue(func(val *prog.Value) { 568 if len(val.Path) == 0 { 569 return 570 } 571 if val.Path[0] == prog.ParentRef { 572 val.Path = append([]string{prog.ParentRef}, val.Path...) 573 } else { 574 // Single "parent:" would not change anything. 575 val.Path = append([]string{prog.ParentRef, prog.ParentRef}, val.Path...) 576 } 577 }) 578 } 579 580 return prog.Field{ 581 Name: field.Name, 582 Type: &prog.UnionType{ 583 TypeCommon: common, 584 Fields: []prog.Field{ 585 { 586 Name: "value", 587 Type: field.Type, 588 HasDirection: field.HasDirection, 589 Direction: field.Direction, 590 Condition: newCondition, 591 }, 592 { 593 Name: "void", 594 Type: voidType, 595 Condition: &prog.BinaryExpression{ 596 Operator: prog.OperatorCompareEq, 597 Left: newCondition, 598 Right: &prog.Value{Value: 0x0, Path: nil}, 599 }, 600 }, 601 }, 602 }, 603 } 604 } 605 606 func (comp *compiler) genType(t *ast.Type, argSize uint64) prog.Type { 607 desc, args, base := comp.getArgsBase(t, argSize != 0) 608 if desc.Gen == nil { 609 panic(fmt.Sprintf("no gen for %v %#v", t.Ident, t)) 610 } 611 if argSize != 0 { 612 // Now that we know a more precise size, patch the type. 613 // This is somewhat hacky. Ideally we figure out the size earlier, 614 // store it somewhere and use during generation of the arg base type. 615 base.TypeSize = argSize 616 if desc.CheckConsts != nil { 617 desc.CheckConsts(comp, t, args, base) 618 } 619 } 620 base.IsVarlen = desc.Varlen != nil && desc.Varlen(comp, t, args) 621 return desc.Gen(comp, t, args, base) 622 } 623 624 const valueIdent = "value" 625 626 var binaryOperatorMap = map[ast.Operator]prog.BinaryOperator{ 627 ast.OperatorCompareEq: prog.OperatorCompareEq, 628 ast.OperatorCompareNeq: prog.OperatorCompareNeq, 629 ast.OperatorBinaryAnd: prog.OperatorBinaryAnd, 630 ast.OperatorOr: prog.OperatorOr, 631 } 632 633 func (comp *compiler) genExpression(t *ast.Type) prog.Expression { 634 if binary := t.Expression; binary != nil { 635 operator, ok := binaryOperatorMap[binary.Operator] 636 if !ok { 637 comp.error(binary.Pos, "unknown binary operator") 638 return nil 639 } 640 return &prog.BinaryExpression{ 641 Operator: operator, 642 Left: comp.genExpression(binary.Left), 643 Right: comp.genExpression(binary.Right), 644 } 645 } else { 646 return comp.genValue(t) 647 } 648 } 649 650 func (comp *compiler) genValue(val *ast.Type) *prog.Value { 651 if val.Ident == valueIdent { 652 if len(val.Args) != 1 { 653 comp.error(val.Pos, "value reference must have only one argument") 654 return nil 655 } 656 arg := val.Args[0] 657 if arg.Args != nil { 658 comp.error(val.Pos, "value aguments must not have any further arguments") 659 return nil 660 } 661 path := []string{arg.Ident} 662 for _, elem := range arg.Colon { 663 if elem.Args != nil { 664 comp.error(arg.Pos, "value path elements must not have any attributes") 665 return nil 666 } 667 path = append(path, elem.Ident) 668 } 669 return &prog.Value{Path: path} 670 } 671 if val.Expression != nil || val.HasString { 672 comp.error(val.Pos, "the token must be either an integer or an identifier") 673 return nil 674 } 675 if len(val.Args) != 0 { 676 comp.error(val.Pos, "consts in expressions must not have any arguments") 677 return nil 678 } 679 return &prog.Value{ 680 Value: val.Value, 681 } 682 } 683 684 func genCommon(name string, size uint64, opt bool) prog.TypeCommon { 685 return prog.TypeCommon{ 686 TypeName: name, 687 TypeSize: size, 688 IsOptional: opt, 689 } 690 } 691 692 func genIntCommon(com prog.TypeCommon, bitLen uint64, bigEndian bool) prog.IntTypeCommon { 693 bf := prog.FormatNative 694 if bigEndian { 695 bf = prog.FormatBigEndian 696 } 697 bfUnit := uint64(0) 698 if bitLen != 0 { 699 bfUnit = com.TypeSize 700 com.TypeSize = 0 701 } 702 return prog.IntTypeCommon{ 703 TypeCommon: com, 704 ArgFormat: bf, 705 BitfieldLen: bitLen, 706 BitfieldUnit: bfUnit, 707 } 708 } 709 710 func genIntArray(a []*ast.Int) []uint64 { 711 r := make([]uint64, len(a)) 712 for i, v := range a { 713 r[i] = v.Value 714 } 715 return r 716 } 717 718 func genStrArray(a []*ast.String) []string { 719 r := make([]string, len(a)) 720 for i, v := range a { 721 r[i] = v.Value 722 } 723 return r 724 }