func ShowOnOff(subcmdName string, on bool) { if on { gub.Msg("%s is on.", subcmdName) } else { gub.Msg("%s is off.", subcmdName) } }
// InfoPackageCommand implements the command: // info package [*name* ] // which show information about a package or lists all packages. func InfoPackageSubcmd(args []string) { if len(args) > 2 { for _, pkg_name := range args[2:len(args)] { if pkg := gub.Program().PackagesByName[pkg_name]; pkg != nil { gub.Msg("Package %s: \"%s\"", pkg_name, pkg.Object.Path()) gub.Section("Package members:") var names []string for k, _ := range pkg.Members { names = append(names, k) } sort.Strings(names) opts := columnize.DefaultOptions() opts.DisplayWidth = gub.Maxwidth opts.LinePrefix = " " mems := strings.TrimRight(columnize.Columnize(names, opts), "\n") gub.Msg(mems) } else { gub.Errmsg("Package %s not imported", pkg_name) } } } else { pkgNames := []string{} for pkg := range gub.Program().PackagesByName { pkgNames = append(pkgNames, pkg) } gub.PrintSorted("All imported packages", pkgNames) } }
// InfoBreakpointSubcmd implements the debugger command: // info breakpoint // // This command shows status of user-settable breakpoints. If no // breakpoint numbers are given, the show all breakpoints. Otherwise // only those breakpoints listed are shown and the order given. // // The "Disp" column contains one of "keep", "del", the disposition of // the breakpoint after it gets hit. // // The "enb" column indicates whether the breakpoint is enabled. // // The "Where" column indicates where the breakpoint is located. // Status of user-settable breakpoints. func InfoBreakpointSubcmd(args []string) { if gub.IsBreakpointEmpty() { gub.Msg("No breakpoints set") return } bpLen := len(gub.Breakpoints) if bpLen-gub.BrkptsDeleted == 0 { gub.Msg("No breakpoints.") } if len(args) > 2 { headerShown := false for _, num := range args[2:] { if bpNum, err := gub.GetInt(num, "breakpoint number", 0, bpLen-1); err == nil { if bp := gub.BreakpointFindById(bpNum); bp != nil { if !headerShown { gub.Section("Num Type Disp Enb Where") headerShown = true } gub.Bpprint(*bp) } else { gub.Errmsg("Breakpoint %d not found.", bpNum) } } } } else { gub.Section("Num Type Disp Enb Where") for _, bp := range gub.Breakpoints { if bp.Deleted { continue } gub.Bpprint(*bp) } } }
func AliasCommand(args []string) { if len(args) == 1 { var names []string for k, _ := range gub.Aliases { names = append(names, k) } gub.Section("All aliases:") sort.Strings(names) opts := columnize.DefaultOptions() opts.DisplayWidth = gub.Maxwidth opts.LinePrefix = " " mems := strings.TrimRight(columnize.Columnize(names, opts), "\n") gub.Msg(mems) } else { cmd := args[1] if info := gub.Cmds[cmd]; info != nil { if len(info.Aliases) > 0 { gub.Msg("Aliases for %s: %s", cmd, strings.Join(info.Aliases, ", ")) } else { gub.Msg("No aliases for %s", cmd) } } else if realCmd := gub.Aliases[cmd]; realCmd != "" { gub.Msg("Alias %s is an alias for command %s", cmd, realCmd) } else { gub.Errmsg("Can't find command or alias %s", cmd) } } }
// 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 } } } }
// 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 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 InfoBlockSubcmd(args []string) { block := gub.CurBlock() // if block == nil && gub.Instr.Block() != nil { // block = gub.Instr.Block() // } 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()) } } }
// 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") } }
// 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 ContinueCommand(args []string) { for fr := gub.TopFrame(); fr != nil; fr = fr.Caller(0) { interp.SetStepOff(fr) } gub.InCmdLoop = false gub.Msg("Continuing...") }
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 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) }
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)) } } } }
// 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 } } } }
// DisableCommand implements the debugger command: // disable [bpnum1 ...] // which disables a breakpoint by its breakpoint number. // // See also "enable", "delete", and "info break". func DisableCommand(args []string) { for i := 1; i < len(args); i++ { msg := fmt.Sprintf("breakpoint number for argument %d", i) bpnum, err := gub.GetInt(args[i], msg, 0, len(gub.Breakpoints)-1) if err != nil { continue } if gub.BreakpointExists(bpnum) { if !gub.BreakpointIsEnabled(bpnum) { gub.Msg("Breakpoint %d is already disabled", bpnum) continue } if gub.BreakpointDisable(bpnum) { gub.Msg("Breakpoint %d disabled", bpnum) } else { gub.Errmsg("Trouble disabling breakpoint %d", bpnum) } } else { gub.Errmsg("Breakpoint %d doesn't exist", bpnum) } } }
func SetHighlightSubcmd(args []string) { onoff := "on" if len(args) == 3 { onoff = args[2] } switch ParseOnOff(onoff) { case ONOFF_ON: if *gub.Highlight { gub.Errmsg("Highlight is already on") } else { gub.Msg("Setting highlight on") *gub.Highlight = true } case ONOFF_OFF: if !*gub.Highlight { gub.Errmsg("highight is already off") } else { gub.Msg("Setting highlight off") *gub.Highlight = false } case ONOFF_UNKNOWN: gub.Msg("Expecting 'on' or 'off', got '%s'; nothing done", onoff) } }
func SetTraceSubcmd(args []string) { onoff := "on" if len(args) == 3 { onoff = args[2] } switch ParseOnOff(onoff) { case ONOFF_ON: if interp.InstTracing() { gub.Errmsg("Instruction tracing already on") } else { gub.Msg("Setting Instruction trace on") interp.SetInstTracing() } case ONOFF_OFF: if !interp.InstTracing() { gub.Errmsg("Instruction tracing already off") } else { gub.Msg("Setting Instruction trace off") interp.ClearInstTracing() } case ONOFF_UNKNOWN: gub.Errmsg("Expecting 'on' or 'off', got '%s'; nothing done", onoff) } }
// QuitCommand implements the debugger command: quit // // quit [exit-code] // // Terminates program. If an exit code is given, that is the exit code // for the program. Zero (normal termination) is used if no // termintation code. func QuitCommand(args []string) { rc := 0 if len(args) == 2 { new_rc, ok := strconv.Atoi(args[1]) if ok == nil { rc = new_rc } else { gub.Errmsg("Expecting integer return code; got %s. Ignoring", args[1]) } } gub.Msg("gub: That's all folks...") // FIXME: determine under which conditions we've used term gnureadline.Rl_reset_terminal(gub.Term) os.Exit(rc) }
func HelpCommand(args []string) { if len(args) == 1 { gub.Msg(gub.Cmds["help"].Help) } else { what := args[1] cmd := gub.LookupCmd(what) if what == "*" { var names []string for k, _ := range gub.Cmds { names = append(names, k) } gub.Section("All command names:") sort.Strings(names) opts := columnize.DefaultOptions() opts.DisplayWidth = gub.Maxwidth opts.LinePrefix = " " mems := strings.TrimRight(columnize.Columnize(names, opts), "\n") gub.Msg(mems) } else if what == "categories" { gub.Section("Categories") for k, _ := range gub.Categories { gub.Msg("\t %s", k) } } else if info := gub.Cmds[cmd]; info != nil { if len(args) > 2 { if info.SubcmdMgr != nil { gub.HelpSubCommand(info.SubcmdMgr, args) return } } gub.Msg(info.Help) if len(info.Aliases) > 0 { gub.Msg("Aliases: %s", strings.Join(info.Aliases, ", ")) } } else if cmds := gub.Categories[what]; len(cmds) > 0 { gub.Section("Commands in class: %s", what) sort.Strings(cmds) opts := columnize.DefaultOptions() opts.DisplayWidth = gub.Maxwidth mems := strings.TrimRight(columnize.Columnize(cmds, opts), "\n") gub.Msg(mems) } else { gub.Errmsg("Can't find help for %s", what) } } }
// 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) } }
func NextCommand(args []string) { interp.SetStepOver(gub.TopFrame()) gub.Msg("Step over...") gub.LastCommand = "next " + gub.CmdArgstr gub.InCmdLoop = false }
func ShowArgsSubcmd(args []string) { gub.Msg(gub.RESTART_ARGS[0]) for i := 1; i < len(gub.RESTART_ARGS); i++ { gub.Msg("\t" + gub.RESTART_ARGS[i]) } }
// 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()) }
func RunCommand(args []string) { ShowArgsSubcmd(args) gub.Msg("gub: restarting...") syscall.Exec(gub.RESTART_ARGS[0], gub.RESTART_ARGS[0:], os.Environ()) }
// 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 }
// 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 }
func FinishCommand(args []string) { interp.SetStepOut(gub.TopFrame()) gub.Msg("Continuing until return...") gub.InCmdLoop = false }