Best Syzkaller code snippet using prog.call
proggen.go
Source:proggen.go
...29 var progs []*prog.Prog30 parseTree(tree, tree.RootPid, target, &progs)31 return progs, nil32}33// parseTree groups system calls in the trace by process id.34// The tree preserves process hierarchy i.e. parent->[]child35func parseTree(tree *parser.TraceTree, pid int64, target *prog.Target, progs *[]*prog.Prog) {36 log.Logf(2, "parsing trace pid %v", pid)37 if p := genProg(tree.TraceMap[pid], target); p != nil {38 *progs = append(*progs, p)39 }40 for _, childPid := range tree.Ptree[pid] {41 if tree.TraceMap[childPid] != nil {42 parseTree(tree, childPid, target, progs)43 }44 }45}46// Context stores metadata related to a syzkaller program47type context struct {48 builder *prog.Builder49 target *prog.Target50 selectors []callSelector51 returnCache returnCache52 currentStraceCall *parser.Syscall53 currentSyzCall *prog.Call54}55// genProg converts a trace to one of our programs.56func genProg(trace *parser.Trace, target *prog.Target) *prog.Prog {57 retCache := newRCache()58 ctx := &context{59 builder: prog.MakeProgGen(target),60 target: target,61 selectors: newSelectors(target, retCache),62 returnCache: retCache,63 }64 for _, sCall := range trace.Calls {65 if sCall.Paused {66 // Probably a case where the call was killed by a signal like the following67 // 2179 wait4(2180, <unfinished ...>68 // 2179 <... wait4 resumed> 0x7fff28981bf8, 0, NULL) = ? ERESTARTSYS69 // 2179 --- SIGUSR1 {si_signo=SIGUSR1, si_code=SI_USER, si_pid=2180, si_uid=0} ---70 continue71 }72 if shouldSkip(sCall) {73 log.Logf(2, "skipping call: %s", sCall.CallName)74 continue75 }76 ctx.currentStraceCall = sCall77 call := ctx.genCall()78 if call == nil {79 continue80 }81 if err := ctx.builder.Append(call); err != nil {82 log.Fatalf("%v", err)83 }84 }85 p, err := ctx.builder.Finalize()86 if err != nil {87 log.Fatalf("error validating program: %v", err)88 }89 return p90}91func (ctx *context) genCall() *prog.Call {92 log.Logf(3, "parsing call: %s", ctx.currentStraceCall.CallName)93 straceCall := ctx.currentStraceCall94 ctx.currentSyzCall = new(prog.Call)95 ctx.currentSyzCall.Meta = ctx.Select(straceCall)96 syzCall := ctx.currentSyzCall97 if ctx.currentSyzCall.Meta == nil {98 log.Logf(2, "skipping call: %s which has no matching description", ctx.currentStraceCall.CallName)99 return nil100 }101 syzCall.Ret = prog.MakeReturnArg(syzCall.Meta.Ret)102 for i := range syzCall.Meta.Args {103 var strArg parser.IrType104 if i < len(straceCall.Args) {105 strArg = straceCall.Args[i]106 }107 res := ctx.genArg(syzCall.Meta.Args[i].Type, prog.DirIn, strArg)108 syzCall.Args = append(syzCall.Args, res)109 }110 ctx.genResult(syzCall.Meta.Ret, straceCall.Ret)111 return syzCall112}113func (ctx *context) Select(syscall *parser.Syscall) *prog.Syscall {114 for _, selector := range ctx.selectors {115 if variant := selector.Select(syscall); variant != nil {116 return variant117 }118 }119 return ctx.target.SyscallMap[syscall.CallName]120}121func (ctx *context) genResult(syzType prog.Type, straceRet int64) {122 if straceRet <= 0 {123 return124 }125 straceExpr := parser.Constant(uint64(straceRet))126 switch syzType.(type) {127 case *prog.ResourceType:128 log.Logf(2, "call: %s returned a resource type with val: %s",129 ctx.currentStraceCall.CallName, straceExpr.String())130 ctx.returnCache.cache(syzType, straceExpr, ctx.currentSyzCall.Ret)131 }132}133func (ctx *context) genArg(syzType prog.Type, dir prog.Dir, traceArg parser.IrType) prog.Arg {134 if traceArg == nil {135 log.Logf(3, "parsing syzType: %s, traceArg is nil. generating default arg...", syzType.Name())136 return syzType.DefaultArg(dir)137 }138 log.Logf(3, "parsing arg of syz type: %s, ir type: %#v", syzType.Name(), traceArg)139 if dir == prog.DirOut {140 switch syzType.(type) {141 case *prog.PtrType, *prog.StructType, *prog.ResourceType, *prog.BufferType:142 // Resource Types need special care. Pointers, Structs can have resource fields e.g. pipe, socketpair143 // Buffer may need special care in out direction144 default:145 return syzType.DefaultArg(dir)146 }147 }148 switch a := syzType.(type) {149 case *prog.IntType, *prog.ConstType, *prog.FlagsType, *prog.CsumType:150 return ctx.genConst(a, dir, traceArg)151 case *prog.LenType:152 return syzType.DefaultArg(dir)153 case *prog.ProcType:154 return ctx.parseProc(a, dir, traceArg)155 case *prog.ResourceType:156 return ctx.genResource(a, dir, traceArg)157 case *prog.PtrType:158 return ctx.genPtr(a, dir, traceArg)159 case *prog.BufferType:160 return ctx.genBuffer(a, dir, traceArg)161 case *prog.StructType:162 return ctx.genStruct(a, dir, traceArg)163 case *prog.ArrayType:164 return ctx.genArray(a, dir, traceArg)165 case *prog.UnionType:166 return ctx.genUnionArg(a, dir, traceArg)167 case *prog.VmaType:168 return ctx.genVma(a, dir, traceArg)169 default:170 log.Fatalf("unsupported type: %#v", syzType)171 }172 return nil173}174func (ctx *context) genVma(syzType *prog.VmaType, dir prog.Dir, _ parser.IrType) prog.Arg {175 npages := uint64(1)176 if syzType.RangeBegin != 0 || syzType.RangeEnd != 0 {177 npages = syzType.RangeEnd178 }179 return prog.MakeVmaPointerArg(syzType, dir, ctx.builder.AllocateVMA(npages), npages)180}181func (ctx *context) genArray(syzType *prog.ArrayType, dir prog.Dir, traceType parser.IrType) prog.Arg {182 var args []prog.Arg183 switch a := traceType.(type) {184 case *parser.GroupType:185 for i := 0; i < len(a.Elems); i++ {186 args = append(args, ctx.genArg(syzType.Elem, dir, a.Elems[i]))187 }188 default:189 log.Fatalf("unsupported type for array: %#v", traceType)190 }191 return prog.MakeGroupArg(syzType, dir, args)192}193func (ctx *context) genStruct(syzType *prog.StructType, dir prog.Dir, traceType parser.IrType) prog.Arg {194 var args []prog.Arg195 switch a := traceType.(type) {196 case *parser.GroupType:197 j := 0198 if ret, recursed := ctx.recurseStructs(syzType, dir, a); recursed {199 return ret200 }201 for i := range syzType.Fields {202 if prog.IsPad(syzType.Fields[i].Type) {203 args = append(args, syzType.Fields[i].DefaultArg(dir))204 continue205 }206 // If the last n fields of a struct are zero or NULL, strace will occasionally omit those values207 // this creates a mismatch in the number of elements in the ir type and in208 // our descriptions. We generate default values for omitted fields209 if j >= len(a.Elems) {210 args = append(args, syzType.Fields[i].DefaultArg(dir))211 } else {212 args = append(args, ctx.genArg(syzType.Fields[i].Type, dir, a.Elems[j]))213 }214 j++215 }216 case *parser.BufferType:217 // We could have a case like the following:218 // ioctl(3, 35111, {ifr_name="\x6c\x6f", ifr_hwaddr=00:00:00:00:00:00}) = 0219 // if_hwaddr gets parsed as a BufferType but our syscall descriptions have it as a struct type220 return syzType.DefaultArg(dir)221 default:222 log.Fatalf("unsupported type for struct: %#v", a)223 }224 return prog.MakeGroupArg(syzType, dir, args)225}226// recurseStructs handles cases where syzType corresponds to struct descriptions like227// sockaddr_storage_in6 {228// addr sockaddr_in6229// } [size[SOCKADDR_STORAGE_SIZE], align_ptr]230// which need to be recursively generated. It returns true if we needed to recurse231// along with the generated argument and false otherwise.232func (ctx *context) recurseStructs(syzType *prog.StructType, dir prog.Dir, traceType *parser.GroupType) (prog.Arg, bool) {233 // only consider structs with one non-padded field234 numFields := 0235 for _, field := range syzType.Fields {236 if prog.IsPad(field.Type) {237 continue238 }239 numFields++240 }241 if numFields != 1 {242 return nil, false243 }244 // the strace group type needs to have more one field (a mismatch)245 if len(traceType.Elems) == 1 {246 return nil, false247 }248 // first field needs to be a struct249 switch t := syzType.Fields[0].Type.(type) {250 case *prog.StructType:251 var args []prog.Arg252 // first element and traceType should have the same number of elements253 if len(t.Fields) != len(traceType.Elems) {254 return nil, false255 }256 args = append(args, ctx.genStruct(t, dir, traceType))257 for _, field := range syzType.Fields[1:] {258 args = append(args, field.DefaultArg(dir))259 }260 return prog.MakeGroupArg(syzType, dir, args), true261 }262 return nil, false263}264func (ctx *context) genUnionArg(syzType *prog.UnionType, dir prog.Dir, straceType parser.IrType) prog.Arg {265 if straceType == nil {266 log.Logf(1, "generating union arg. straceType is nil")267 return syzType.DefaultArg(dir)268 }269 log.Logf(4, "generating union arg: %s %#v", syzType.TypeName, straceType)270 // Unions are super annoying because they sometimes need to be handled case by case271 // We might need to lookinto a matching algorithm to identify the union type that most closely272 // matches our strace type.273 switch syzType.TypeName {274 case "sockaddr_storage":275 return ctx.genSockaddrStorage(syzType, dir, straceType)276 case "sockaddr_nl":277 return ctx.genSockaddrNetlink(syzType, dir, straceType)278 case "ifr_ifru":279 return ctx.genIfrIfru(syzType, dir, straceType)280 }281 return prog.MakeUnionArg(syzType, dir, ctx.genArg(syzType.Fields[0].Type, dir, straceType), 0)282}283func (ctx *context) genBuffer(syzType *prog.BufferType, dir prog.Dir, traceType parser.IrType) prog.Arg {284 if dir == prog.DirOut {285 if !syzType.Varlen() {286 return prog.MakeOutDataArg(syzType, dir, syzType.Size())287 }288 switch a := traceType.(type) {289 case *parser.BufferType:290 return prog.MakeOutDataArg(syzType, dir, uint64(len(a.Val)))291 default:292 switch syzType.Kind {293 case prog.BufferBlobRand:294 size := rand.Intn(256)295 return prog.MakeOutDataArg(syzType, dir, uint64(size))296 case prog.BufferBlobRange:297 max := rand.Intn(int(syzType.RangeEnd) - int(syzType.RangeBegin) + 1)298 size := max + int(syzType.RangeBegin)299 return prog.MakeOutDataArg(syzType, dir, uint64(size))300 default:301 log.Fatalf("unexpected buffer type kind: %v. call %v arg %#v", syzType.Kind, ctx.currentSyzCall, traceType)302 }303 }304 }305 var bufVal []byte306 switch a := traceType.(type) {307 case *parser.BufferType:308 bufVal = []byte(a.Val)309 case parser.Constant:310 val := a.Val()311 bArr := make([]byte, 8)312 binary.LittleEndian.PutUint64(bArr, val)313 bufVal = bArr314 default:315 log.Fatalf("unsupported type for buffer: %#v", traceType)316 }317 // strace always drops the null byte for buffer types but we only need to add it back for filenames and strings318 switch syzType.Kind {319 case prog.BufferFilename, prog.BufferString:320 bufVal = append(bufVal, '\x00')321 }322 if !syzType.Varlen() {323 size := syzType.Size()324 for uint64(len(bufVal)) < size {325 bufVal = append(bufVal, 0)326 }327 bufVal = bufVal[:size]328 }329 return prog.MakeDataArg(syzType, dir, bufVal)330}331func (ctx *context) genPtr(syzType *prog.PtrType, dir prog.Dir, traceType parser.IrType) prog.Arg {332 switch a := traceType.(type) {333 case parser.Constant:334 if a.Val() == 0 {335 return prog.MakeSpecialPointerArg(syzType, dir, 0)336 }337 // Likely have a type of the form bind(3, 0xfffffffff, [3]);338 res := syzType.Elem.DefaultArg(syzType.ElemDir)339 return ctx.addr(syzType, dir, res.Size(), res)340 default:341 res := ctx.genArg(syzType.Elem, syzType.ElemDir, a)342 return ctx.addr(syzType, dir, res.Size(), res)343 }344}345func (ctx *context) genConst(syzType prog.Type, dir prog.Dir, traceType parser.IrType) prog.Arg {346 switch a := traceType.(type) {347 case parser.Constant:348 return prog.MakeConstArg(syzType, dir, a.Val())349 case *parser.GroupType:350 // Sometimes strace represents a pointer to int as [0] which gets parsed351 // as Array([0], len=1). A good example is ioctl(3, FIONBIO, [1]). We may also have an union int type that352 // is a represented as a struct in strace e.g.353 // sigev_value={sival_int=-2123636944, sival_ptr=0x7ffd816bdf30}354 // For now we choose the first option355 if len(a.Elems) == 0 {356 log.Logf(2, "parsing const type, got array type with len 0")357 return syzType.DefaultArg(dir)358 }359 return ctx.genConst(syzType, dir, a.Elems[0])360 case *parser.BufferType:361 // strace decodes some arguments as hex strings because those values are network ordered362 // e.g. sin_port or sin_addr fields of sockaddr_in.363 // network order is big endian byte order so if the len of byte array is 1, 2, 4, or 8 then364 // it is a good chance that we are decoding one of those fields. If it isn't, then most likely365 // we have an error i.e. a sockaddr_un struct passed to a connect call with an inet file descriptor366 var val uint64367 toUint64 := binary.LittleEndian.Uint64368 toUint32 := binary.LittleEndian.Uint32369 toUint16 := binary.LittleEndian.Uint16370 if syzType.Format() == prog.FormatBigEndian {371 toUint64 = binary.BigEndian.Uint64372 toUint32 = binary.BigEndian.Uint32373 toUint16 = binary.BigEndian.Uint16374 }375 switch len(a.Val) {376 case 8:377 val = toUint64([]byte(a.Val))378 case 4:379 val = uint64(toUint32([]byte(a.Val)))380 case 2:381 val = uint64(toUint16([]byte(a.Val)))382 case 1:383 val = uint64(a.Val[0])384 default:385 return syzType.DefaultArg(dir)386 }387 return prog.MakeConstArg(syzType, dir, val)388 default:389 log.Fatalf("unsupported type for const: %#v", traceType)390 }391 return nil392}393func (ctx *context) genResource(syzType *prog.ResourceType, dir prog.Dir, traceType parser.IrType) prog.Arg {394 if dir == prog.DirOut {395 log.Logf(2, "resource returned by call argument: %s", traceType.String())396 res := prog.MakeResultArg(syzType, dir, nil, syzType.Default())397 ctx.returnCache.cache(syzType, traceType, res)398 return res399 }400 switch a := traceType.(type) {401 case parser.Constant:402 val := a.Val()403 if arg := ctx.returnCache.get(syzType, traceType); arg != nil {404 res := prog.MakeResultArg(syzType, dir, arg.(*prog.ResultArg), syzType.Default())405 return res406 }407 res := prog.MakeResultArg(syzType, dir, nil, val)408 return res409 case *parser.GroupType:410 if len(a.Elems) == 1 {411 // For example: 5028 ioctl(3, SIOCSPGRP, [0]) = 0412 // last argument is a pointer to a resource. Strace will output a pointer to413 // a number x as [x].414 res := prog.MakeResultArg(syzType, dir, nil, syzType.Default())415 ctx.returnCache.cache(syzType, a.Elems[0], res)416 return res417 }418 log.Fatalf("generating resource type from GroupType with %d elements", len(a.Elems))419 default:420 log.Fatalf("unsupported type for resource: %#v", traceType)421 }422 return nil423}424func (ctx *context) parseProc(syzType *prog.ProcType, dir prog.Dir, traceType parser.IrType) prog.Arg {425 switch a := traceType.(type) {426 case parser.Constant:427 val := a.Val()428 if val >= syzType.ValuesPerProc {429 return prog.MakeConstArg(syzType, dir, syzType.ValuesPerProc-1)430 }431 return prog.MakeConstArg(syzType, dir, val)432 case *parser.BufferType:433 // Again probably an error case434 // Something like the following will trigger this435 // bind(3, {sa_family=AF_INET, sa_data="\xac"}, 3) = -1 EINVAL(Invalid argument)436 return syzType.DefaultArg(dir)437 default:438 log.Fatalf("unsupported type for proc: %#v", traceType)439 }440 return nil441}442func (ctx *context) addr(syzType prog.Type, dir prog.Dir, size uint64, data prog.Arg) prog.Arg {443 return prog.MakePointerArg(syzType, dir, ctx.builder.Allocate(size, data.Type().Alignment()), data)444}445func shouldSkip(c *parser.Syscall) bool {446 switch c.CallName {447 case "write":448 // We skip all writes to stdout and stderr because they can corrupt our crash summary.449 // Also there will be nothing on stdin, so any reads will hang.450 switch a := c.Args[0].(type) {451 case parser.Constant:452 if a.Val() <= 2 {453 return true454 }455 }456 }457 return unsupportedCalls[c.CallName]458}...
wrappers.go
Source:wrappers.go
...9// implicit pointer indirections and embedded field selections.10//11// (2) thunks: funcs that wrap declared methods. Like wrappers,12// thunks perform indirections and field selections. The thunk's13// first parameter is used as the receiver for the method call.14//15// (3) bounds: funcs that wrap declared methods. The bound's sole16// free variable, supplied by a closure, is used as the receiver17// for the method call. No indirections or field selections are18// performed since they can be done before the call.19import (20 "fmt"21 "go/types"22)23// -- wrappers -----------------------------------------------------------24// makeWrapper returns a synthetic method that delegates to the25// declared method denoted by meth.Obj(), first performing any26// necessary pointer indirections or field selections implied by meth.27//28// The resulting method's receiver type is meth.Recv().29//30// This function is versatile but quite subtle! Consider the31// following axes of variation when making changes:32// - optional receiver indirection33// - optional implicit field selections34// - meth.Obj() may denote a concrete or an interface method35// - the result may be a thunk or a wrapper.36//37// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)38//39func makeWrapper(prog *Program, sel *types.Selection) *Function {40 obj := sel.Obj().(*types.Func) // the declared function41 sig := sel.Type().(*types.Signature) // type of this wrapper42 var recv *types.Var // wrapper's receiver or thunk's params[0]43 name := obj.Name()44 var description Synthetic45 var start int // first regular param46 if sel.Kind() == types.MethodExpr {47 name += "$thunk"48 description = SyntheticThunk49 recv = sig.Params().At(0)50 start = 151 } else {52 description = SyntheticWrapper53 recv = sig.Recv()54 }55 if prog.mode&LogSource != 0 {56 defer logStack("make %s to (%s)", description, recv.Type())()57 }58 fn := &Function{59 name: name,60 method: sel,61 object: obj,62 Signature: sig,63 Synthetic: description,64 Prog: prog,65 functionBody: new(functionBody),66 }67 fn.initHTML(prog.PrintFunc)68 fn.startBody()69 fn.addSpilledParam(recv, nil)70 createParams(fn, start)71 indices := sel.Index()72 var v Value = fn.Locals[0] // spilled receiver73 if isPointer(sel.Recv()) {74 v = emitLoad(fn, v, nil)75 // For simple indirection wrappers, perform an informative nil-check:76 // "value method (T).f called using nil *T pointer"77 if len(indices) == 1 && !isPointer(recvType(obj)) {78 var c Call79 c.Call.Value = &Builtin{80 name: "ir:wrapnilchk",81 sig: types.NewSignature(nil,82 types.NewTuple(anonVar(sel.Recv()), anonVar(tString), anonVar(tString)),83 types.NewTuple(anonVar(sel.Recv())), false),84 }85 c.Call.Args = []Value{86 v,87 emitConst(fn, stringConst(deref(sel.Recv()).String())),88 emitConst(fn, stringConst(sel.Obj().Name())),89 }90 c.setType(v.Type())91 v = fn.emit(&c, nil)92 }93 }94 // Invariant: v is a pointer, either95 // value of *A receiver param, or96 // address of A spilled receiver.97 // We use pointer arithmetic (FieldAddr possibly followed by98 // Load) in preference to value extraction (Field possibly99 // preceded by Load).100 v = emitImplicitSelections(fn, v, indices[:len(indices)-1], nil)101 // Invariant: v is a pointer, either102 // value of implicit *C field, or103 // address of implicit C field.104 var c Call105 if r := recvType(obj); !isInterface(r) { // concrete method106 if !isPointer(r) {107 v = emitLoad(fn, v, nil)108 }109 c.Call.Value = prog.declaredFunc(obj)110 c.Call.Args = append(c.Call.Args, v)111 } else {112 c.Call.Method = obj113 c.Call.Value = emitLoad(fn, v, nil)114 }115 for _, arg := range fn.Params[1:] {116 c.Call.Args = append(c.Call.Args, arg)117 }118 emitTailCall(fn, &c, nil)119 fn.finishBody()120 return fn121}122// createParams creates parameters for wrapper method fn based on its123// Signature.Params, which do not include the receiver.124// start is the index of the first regular parameter to use.125//126func createParams(fn *Function, start int) {127 tparams := fn.Signature.Params()128 for i, n := start, tparams.Len(); i < n; i++ {129 fn.addParamObj(tparams.At(i), nil)130 }131}132// -- bounds -----------------------------------------------------------133// makeBound returns a bound method wrapper (or "bound"), a synthetic134// function that delegates to a concrete or interface method denoted135// by obj. The resulting function has no receiver, but has one free136// variable which will be used as the method's receiver in the137// tail-call.138//139// Use MakeClosure with such a wrapper to construct a bound method140// closure. e.g.:141//142// type T int or: type T interface { meth() }143// func (t T) meth()144// var t T145// f := t.meth146// f() // calls t.meth()147//148// f is a closure of a synthetic wrapper defined as if by:149//150// f := func() { return t.meth() }151//152// Unlike makeWrapper, makeBound need perform no indirection or field153// selections because that can be done before the closure is154// constructed.155//156// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu)157//158func makeBound(prog *Program, obj *types.Func) *Function {159 prog.methodsMu.Lock()160 defer prog.methodsMu.Unlock()161 fn, ok := prog.bounds[obj]162 if !ok {163 if prog.mode&LogSource != 0 {164 defer logStack("%s", SyntheticBound)()165 }166 fn = &Function{167 name: obj.Name() + "$bound",168 object: obj,169 Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver170 Synthetic: SyntheticBound,171 Prog: prog,172 functionBody: new(functionBody),173 }174 fn.initHTML(prog.PrintFunc)175 fv := &FreeVar{name: "recv", typ: recvType(obj), parent: fn}176 fn.FreeVars = []*FreeVar{fv}177 fn.startBody()178 createParams(fn, 0)179 var c Call180 if !isInterface(recvType(obj)) { // concrete181 c.Call.Value = prog.declaredFunc(obj)182 c.Call.Args = []Value{fv}183 } else {184 c.Call.Value = fv185 c.Call.Method = obj186 }187 for _, arg := range fn.Params {188 c.Call.Args = append(c.Call.Args, arg)189 }190 emitTailCall(fn, &c, nil)191 fn.finishBody()192 prog.bounds[obj] = fn193 }194 return fn195}196// -- thunks -----------------------------------------------------------197// makeThunk returns a thunk, a synthetic function that delegates to a198// concrete or interface method denoted by sel.Obj(). The resulting199// function has no receiver, but has an additional (first) regular200// parameter.201//202// Precondition: sel.Kind() == types.MethodExpr.203//204// type T int or: type T interface { meth() }205// func (t T) meth()206// f := T.meth207// var t T208// f(t) // calls t.meth()209//210// f is a synthetic wrapper defined as if by:211//212// f := func(t T) { return t.meth() }213//214// TODO(adonovan): opt: currently the stub is created even when used215// directly in a function call: C.f(i, 0). This is less efficient216// than inlining the stub.217//218// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu)219//220func makeThunk(prog *Program, sel *types.Selection) *Function {221 if sel.Kind() != types.MethodExpr {222 panic(sel)223 }224 key := selectionKey{225 kind: sel.Kind(),226 recv: sel.Recv(),227 obj: sel.Obj(),228 index: fmt.Sprint(sel.Index()),229 indirect: sel.Indirect(),...
call
Using AI Code Generation
1import (2func main() {3 prog := new(Prog)4 prog.Call()5}6import (7func main() {8 prog := new(Prog)9 prog.Call()10}11import (12func main() {13 prog := new(Prog)14 prog.Call()15}16import (17func main() {18 prog := new(Prog)19 prog.Call()20}21import (22func main() {23 prog := new(Prog)24 prog.Call()25}26import (27func main() {28 prog := new(Prog)29 prog.Call()30}31import (32func main() {33 prog := new(Prog)34 prog.Call()35}36import (37func main() {38 prog := new(Prog)39 prog.Call()40}41import (42func main() {43 prog := new(Prog)44 prog.Call()45}46import (47func main() {48 prog := new(Prog)49 prog.Call()50}51import (52func main() {53 prog := new(Prog)54 prog.Call()55}56import (57func main() {58 prog := new(Prog)59 prog.Call()60}
call
Using AI Code Generation
1import "fmt"2func main() {3 p.call()4}5import "fmt"6func main() {7 p.call()8}9import "fmt"10func main() {11 p.call()12}13import "fmt"14func main() {15 p.call()16}17import "fmt"18func main() {19 p.call()20}21import "fmt"22func main() {23 p.call()24}25import "fmt"26func main() {27 p.call()28}29import "fmt"30func main() {31 p.call()32}33import "fmt"34func main() {35 p.call()36}37import "fmt"38func main() {39 p.call()40}41import "fmt"42func main() {43 p.call()44}45import "fmt"46func main() {47 p.call()48}49import "fmt"50func main() {51 p.call()52}53import
call
Using AI Code Generation
1import (2func main() {3 fmt.Println("Hello, World!")4 p.call()5}6import (7type prog struct {8}9func (p prog) call() {10 fmt.Println("In call method of prog class")11}
call
Using AI Code Generation
1import "fmt"2import "github.com/PratikSavadiya/GolangTraining/02_package/stringutil"3func main() {4fmt.Println(stringutil.Reverse("!oG ,olleH"))5fmt.Println(stringutil.MyName)6}
call
Using AI Code Generation
1import (2func main() {3 fmt.Println(prog.Call())4}5func Call() string {6}7import (8func main() {9 fmt.Println(package.Call())10}
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!