// InfoProgramSubcmd implements the debugger command: // info program // This command prints information about the program including: // instruction number // block number // function number // stop event // source-code position func InfoProgramSubcmd(args []string) { if gub.TraceEvent == ssa2.PROGRAM_TERMINATION { gub.Msg("program stop event: %s", ssa2.Event2Name[gub.TraceEvent]) return } fr := gub.CurFrame() pc := fr.PC() gub.Msg("instruction number: %d", pc) block := gub.CurBlock() if block == nil { gub.Msg("unknown block") } else { gub.Msg("basic block: %d", block.Index) if block.Scope != nil { gub.Msg("scope: %d", block.Scope.ScopeId()) } else { gub.Msg("unknown scope") } } gub.Msg("function: %s", fr.FnAndParamString()) gub.Msg("program stop event: %s", ssa2.Event2Name[gub.TraceEvent]) gub.Msg("position: %s", gub.CurFrame().PositionRange()) }
func InfoScopeSubcmd(args []string) { fr := gub.CurFrame() scope := fr.Scope() if scope == nil { gub.Errmsg("No scope recorded here") return } count := 0 if len(args) == 3 { var err error count, err = gub.GetInt(args[2], "count", 0, gub.MAXSTACKSHOW) if err != nil { return } } typescope := scope.Scope for i := 0; i < count; i++ { typescope = typescope.Parent() if typescope == nil { gub.Errmsg("There are only %d nested scopes", i) return } scope = fr.Fn().Pkg.TypeScope2Scope[typescope] if scope == nil { gub.Errmsg("No parent scope; There are only %d nested scopes", i) return } } gub.Section("scope number %d", scope.ScopeId()) gub.Msg("%s", typescope) }
// LocalsCommand implements the debugger command: // locals [*name*] // which shows local variable info. // // See also "globals", "whatis", and "eval". func LocalsCommand(args []string) { argc := len(args) - 1 fr := gub.CurFrame() if argc == 0 { for i, _ := range fr.Locals() { gub.PrintLocal(fr, uint(i), false) } for reg, v := range fr.Reg2Var { gub.Msg("reg %s, var %s", reg, v) } } else { varname := args[1] if gub.PrintIfLocal(fr, varname, false) { return } // FIXME: This really shouldn't be needed. for i, v := range fr.Locals() { ssaVal := fr.Fn().Locals[i] if varname == ssaVal.Name() { gub.Msg("fixme %s %s: %s", varname, fr.Fn().Locals[i], interp.ToInspect(v, nil)) break } } } }
// AstCommand implements the debugger command: ast // // ast // // Prints AST for current function. func AstCommand(args []string) { var syntax ast.Node var err error fr := gub.CurFrame() fn := fr.Fn() if len(args) > 1 { name := args[1] fn, err = gub.FuncLookup(name) if err != nil { gub.Errmsg(err.Error()) return } else if fn == nil { gub.Errmsg("function '%s' not found", name) return } else { syntax = fn.Syntax() } } else { syntax = fn.Syntax() switch s := (*gub.Instr).(type) { case *ssa2.Trace: syntax = s.Syntax() } } if syntax != nil { ast.Print(fn.Prog.Fset, syntax) fmt.Println("") } else { gub.Msg("Sorry, we don't have an AST for this") } }
func EnvironmentCommand(args []string) { if len(args) == 2 { name := args[1] nameVal, interpVal, scopeVal := gub.EnvLookup(gub.CurFrame(), name, gub.CurScope()) if nameVal != nil { gub.PrintInEnvironment(gub.CurFrame(), name, nameVal, interpVal, scopeVal) } else { gub.Errmsg("%s is in not the environment", name) } return } for nameVal, interpVal := range gub.CurFrame().Env() { gub.PrintInEnvironment(gub.CurFrame(), nameVal.Name(), nameVal, interpVal, gub.CurScope()) } }
// FormatCommand implements the debugger command: format // // format // // Formats AST and produces source text for function. // FIXME: allow one to specify a function or package func FormatCommand(args []string) { var syntax ast.Node var err error fr := gub.CurFrame() fn := fr.Fn() if len(args) > 1 { name := args[1] if name != "." { fn, err = gub.FuncLookup(name) if err != nil { gub.Errmsg(err.Error()) return } else if fn == nil { gub.Errmsg("function '%s' not found", name) return } } syntax = fn.Syntax() } else { syntax = fn.Syntax() switch s := (*gub.Instr).(type) { case *ssa2.Trace: syntax = s.Syntax() } } // FIXME: Put this as a routine in parent gub and // use when showing locations if syntax != nil { gub.PrintSyntax(syntax, fn.Prog.Fset) } else { gub.Msg("Sorry, we don't have an AST for this") } }
func LocationsCommand(args []string) { fn := gub.CurFrame().Fn() pkg := fn.Pkg for _, l := range pkg.Locs() { gub.Msg("\t%s", ssa2.FmtRange(fn, l.Pos(), l.EndP())) } }
func InstructionCommand(args []string) { fr := gub.CurFrame() ic := uint64(fr.PC()) if len(args) >= 2 { new_ic, ok := gub.GetUInt(args[1], "instruction number", 0, uint64(len(gub.CurFrame().Block().Instrs))) if ok == nil { ic = new_ic } else { gub.Errmsg("Expecting integer; got %s.", args[1]) return } // if len(args) == 3 { // new_num, ok = strconv.Atoi(args[2]) // if ok != nil { // gub.Errmsg("Expecting integer; got %s", args[2]) // return // } } gub.DisasmInst(fr.Fn(), fr.Block().Index, ic) genericInstr := fr.Block().Instrs[ic] switch instr := genericInstr.(type) { case *ssa2.ChangeType: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.Convert: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.MakeInterface: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.ChangeInterface: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.Range: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.UnOp: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.Field: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) case *ssa2.BinOp: gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.X), nil)) gub.Msg("%s: %s", instr.X.Name(), gub.Deref2Str(fr.Get(instr.Y), nil)) case *ssa2.Trace: default: gub.Msg("Don't know how to deal with %s yet", instr) } }
// GlobalsCommand implements the debugger command: // globals [*name*] // which shows global variable info. // // See also "locals", "whatis", and "eval". func GlobalsCommand(args []string) { argc := len(args) - 1 if argc == 0 { for k, v := range gub.CurFrame().I().Globals() { if v == nil { fmt.Printf("%s: nil\n") } else { // FIXME: figure out why reflect.lookupCache causes // an panic on a nil pointer or invalid address if fmt.Sprintf("%s", k) == "reflect.lookupCache" { continue } gub.Msg("%s: %s", k, interp.ToInspect(*v, &k)) } } } else { // This doesn't work and I don't know how to fix it. for i := 1; i <= argc; i++ { vv := ssa2.NewConst(exact.MakeString(args[i]), types.Typ[types.String], token.NoPos, token.NoPos) // fmt.Println(vv, "vs", interp.ToInspect(vv)) v, ok := gub.CurFrame().I().Globals()[vv] if ok { gub.Msg("%s: %s", vv, interp.ToInspect(*v, nil)) } } // This is ugly, but I don't know how to turn a string into // a ssa2.Value. globals := make(map[string]*interp.Value) for k, v := range gub.CurFrame().I().Globals() { globals[fmt.Sprintf("%s", k)] = v } for i := 1; i <= argc; i++ { vv := args[i] v, ok := globals[vv] if ok { gub.Msg("%s: %s", vv, interp.ToInspect(*v, nil)) } } } }
func InfoNodeSubcmd(args []string) { fr := gub.CurFrame() scope := fr.Scope() if scope == nil { gub.Errmsg("No scope recorded here") return } if scope.Node() != nil { ast.Print(fr.Fset(), scope.Node()) } }
func JumpCommand(args []string) { fr := gub.CurFrame() b := gub.CurBlock() ic, err := gub.GetInt(args[1], "instruction number", 0, len(b.Instrs)-1) if err != nil { return } // compensate for interpreter loop which does ic++ at end of loop body fr.SetPC(ic - 1) gub.InCmdLoop = false }
func InfoPCSubcmd(args []string) { fr := gub.CurFrame() pc := fr.PC() fn := fr.FnAndParamString() if block := gub.CurBlock(); block != nil { gub.Msg("instruction number: %d of block %d, function %s", pc, block.Index, fn) } else if pc == -2 { gub.Msg("instruction number: %d (at return), function %s", pc, fn) } else { gub.Msg("instruction number: %d, function %s", pc, fn) } }
func DisassembleCommand(args []string) { fr := gub.CurFrame() myfn := fr.Fn() if len(args) > 1 { what := args[1] if what == "." { if block := gub.CurBlock(); block != nil { gub.DisasmBlock(myfn, block.Index, fr.PC()) } else { gub.Errmsg("Can't get block info here") } return } else if what != "+" { if fn, err := gub.FuncLookup(what); err == nil && fn != nil { myfn = fn } else { bnum, err := gub.GetInt(args[1], "block number of function name", 0, len(myfn.Blocks)-1) if err == nil { lastBlock := len(myfn.Blocks) - 1 if bnum <= lastBlock { b := myfn.Blocks[bnum] if len(args) == 3 { ic, err := gub.GetUInt(args[2], "instruction number", 0, uint64(len(b.Instrs)-1)) if err == nil { gub.DisasmInst(myfn, bnum, ic) } } else { gub.DisasmBlock(myfn, bnum, -1) } } else { gub.Errmsg("Block number should be between 0 and %d; got %d", lastBlock, bnum) } } return } } } else { gub.DisasmCurrentInst() return } myfn.WriteTo(os.Stderr) }
// InfoArgsSubcmd implements the debugger command: // info args [arg-name] // which shows argument variables of the current stack frame. func InfoArgsSubcmd(args []string) { fr := gub.CurFrame() fn := fr.Fn() if len(args) == 2 { if len(fn.Params) == 0 { gub.Msg("Function `%s()' has no parameters", fn.Name()) return } for i, p := range fn.Params { gub.Msg("%s %s", fn.Params[i], interp.ToInspect(fr.Env()[p], nil)) } } else { varname := args[2] for i, p := range fn.Params { if varname == fn.Params[i].Name() { gub.Msg("%s %s", fn.Params[i], interp.ToInspect(fr.Env()[p], nil)) break } } } }
// StepCommand implements the debugger command: step // // This executes the current statement, stopping at the next event. // Sometimes this is called 'step into'. // // See also: stepi, continue, finish, and next. func StepCommand(args []string) { gub.Msg("Stepping...") interp.SetStepIn(gub.CurFrame()) gub.LastCommand = "step " + gub.CmdArgstr gub.InCmdLoop = false }
// InfoFrameSubcmd implements the debugger command: // info frame // which prints frame information including: // goroutine number // location // function and parameter names func InfoFrameSubcmd(args []string) { fr := gub.CurFrame() gub.Msg("goroutine number: %d", fr.GoNum()) gub.Msg("location: %s", fr.PositionRange()) gub.Msg("frame: %s", fr.FnAndParamString()) }
// StepInstructionCommand implements the debugger command: // stepi // which executes one SSA instrcution and stop. // // See also "step", "next", "continue" and "finish". func StepInstructionCommand(args []string) { gub.Msg("Stepping Instruction...") interp.SetStepInstruction(gub.CurFrame()) gub.InCmdLoop = false }
// BreakpointCommand implements the debugger command: // breakpoint [*fn* | line [column] // which sets a breakpoint. // // The target can either be a function name as fn pkg.fn // or a line and and optional column number. Specifying a column number // may be useful if there is more than one statement on a line or if you // want to distinguish parts of a compound statement. // // See also "info break", "enable", and "disable" and "delete". func BreakpointCommand(args []string) { if len(args) == 1 { InfoBreakpointSubcmd(args) return } name := args[1] fn := gub.GetFunction(name) if fn != nil { if ext := interp.Externals()[name]; ext != nil { gub.Msg("Sorry, %s is a built-in external function.", name) return } interp.SetFnBreakpoint(fn) bp := &gub.Breakpoint { Hits: 0, Id: gub.BreakpointNext(), Pos: fn.Pos(), EndP: fn.EndP(), Ignore: 0, Kind: "Function", Temp: false, Enabled: true, } bpnum := gub.BreakpointAdd(bp) gub.Msg(" Breakpoint %d set in function %s at %s", bpnum, name, ssa2.FmtRange(fn, fn.Pos(), fn.EndP())) return } line, ok := strconv.Atoi(args[1]) if ok != nil { gub.Errmsg("Don't know yet how to deal with a break that doesn't start with a function or integer") return } column := -1 if len(args) == 3 { foo, ok := strconv.Atoi(args[2]) if ok != nil { gub.Errmsg("Don't know how to deal a non-int argument as 2nd parameter yet") return } column = foo } fn = gub.CurFrame().Fn() fset := gub.CurFrame().Fset() position := gub.CurFrame().Position() if position.IsValid() { filename := position.Filename for _, l := range fn.Pkg.Locs() { try := fset.Position(l.Pos()) if try.Filename == filename && line == try.Line { if column == -1 || column == try.Column { bp := &gub.Breakpoint { Hits: 0, Id: gub.BreakpointNext(), Pos: l.Pos(), EndP: l.Pos(), Ignore: 0, Kind: "Statement", Temp: false, Enabled: true, } bpnum := gub.BreakpointAdd(bp) if l.Trace != nil { l.Trace.Breakpoint = true } else if l.Fn != nil { l.Fn.Breakpoint = true bp.Kind = "Function" } else { gub.Errmsg("Internal error setting in file %s line %d, column %d", bpnum, filename, line, try.Column) return } gub.Msg("Breakpoint %d set in file %s line %d, column %d", bpnum, filename, line, try.Column) return } } } suffix := "" if column != -1 { suffix = ", column " + args[2] } gub.Errmsg("Can't find statement in file %s at line %d%s", filename, line, suffix) } }