github.com/aergoio/aergo@v1.3.1/contract/hook_dbg.go (about)

     1  // +build Debug
     2  
     3  package contract
     4  
     5  /*
     6  #include "debug.h"
     7  #include <stdlib.h>
     8  */
     9  import "C"
    10  import (
    11  	"container/list"
    12  	"encoding/hex"
    13  	"errors"
    14  	"fmt"
    15  	"path/filepath"
    16  
    17  	"github.com/aergoio/aergo/types"
    18  )
    19  
    20  type contract_info struct {
    21  	contract_id_base58 string
    22  	src_path           string
    23  	breakpoints        *list.List
    24  }
    25  
    26  var contract_info_map = make(map[string]*contract_info)
    27  var watchpoints = list.New()
    28  
    29  func (ce *Executor) setCountHook(limit C.int) {
    30  	if ce == nil || ce.L == nil {
    31  		return
    32  	}
    33  	if ce.err != nil {
    34  		return
    35  	}
    36  
    37  	if cErrMsg := C.vm_set_debug_hook(ce.L); cErrMsg != nil {
    38  		errMsg := C.GoString(cErrMsg)
    39  
    40  		ctrLog.Fatal().Str("err", errMsg).Msg("Fail to initialize lua contract debugger")
    41  	}
    42  }
    43  
    44  func HexAddrToBase58Addr(contract_id_hex string) (string, error) {
    45  	byteContractID, err := hex.DecodeString(contract_id_hex)
    46  	if err != nil {
    47  		return "", err
    48  	}
    49  
    50  	return types.NewAccount(byteContractID).ToString(), nil
    51  }
    52  
    53  func HexAddrOrPlainStrToHexAddr(d string) string {
    54  	// try to convert to base58 address to test input format
    55  	if encodedAddr, err := HexAddrToBase58Addr(d); err == nil {
    56  		// try to decode the encoded str
    57  		if _, err = types.DecodeAddress(encodedAddr); err == nil {
    58  			// input is hex string. just return
    59  			return d
    60  		}
    61  	}
    62  
    63  	// input is a name to hashing or base58 address
    64  	return PlainStrToHexAddr(d)
    65  }
    66  
    67  func PlainStrToHexAddr(d string) string {
    68  
    69  	return hex.EncodeToString(strHash(d))
    70  }
    71  
    72  func SetBreakPoint(contract_id_hex string, line uint64) error {
    73  
    74  	if HasBreakPoint(contract_id_hex, line) {
    75  		return errors.New("Same breakpoint already exists")
    76  	}
    77  
    78  	addr, err := HexAddrToBase58Addr(contract_id_hex)
    79  	if err != nil {
    80  		return err
    81  	}
    82  
    83  	if _, ok := contract_info_map[contract_id_hex]; !ok {
    84  		// create new one if not exist
    85  		contract_info_map[contract_id_hex] = &contract_info{
    86  			addr,
    87  			"",
    88  			list.New()}
    89  	}
    90  
    91  	insertPoint := contract_info_map[contract_id_hex].breakpoints.Front()
    92  	if insertPoint != nil {
    93  		for {
    94  			nextIter := insertPoint.Next()
    95  			if line < insertPoint.Value.(uint64) {
    96  				insertPoint = nil
    97  				break
    98  			} else if nextIter == nil || line < nextIter.Value.(uint64) {
    99  				break
   100  			}
   101  			insertPoint = nextIter
   102  		}
   103  	}
   104  
   105  	if insertPoint == nil {
   106  		// line is the smallest or list is empty. insert the line to the first of the list
   107  		contract_info_map[contract_id_hex].breakpoints.PushFront(line)
   108  	} else {
   109  		// insert after the most biggest breakpoints among smaller ones
   110  		contract_info_map[contract_id_hex].breakpoints.InsertAfter(line, insertPoint)
   111  	}
   112  
   113  	return nil
   114  }
   115  
   116  func DelBreakPoint(contract_id_hex string, line uint64) error {
   117  	if !HasBreakPoint(contract_id_hex, line) {
   118  		return errors.New("Breakpoint does not exists")
   119  	}
   120  
   121  	if info, ok := contract_info_map[contract_id_hex]; ok {
   122  		for iter := info.breakpoints.Front(); iter != nil; iter = iter.Next() {
   123  			if line == iter.Value.(uint64) {
   124  				info.breakpoints.Remove(iter)
   125  				return nil
   126  			}
   127  		}
   128  	}
   129  
   130  	return nil
   131  }
   132  
   133  func HasBreakPoint(contract_id_hex string, line uint64) bool {
   134  	if info, ok := contract_info_map[contract_id_hex]; ok {
   135  		for iter := info.breakpoints.Front(); iter != nil; iter = iter.Next() {
   136  			if line == iter.Value {
   137  				return true
   138  			}
   139  		}
   140  	}
   141  	return false
   142  }
   143  
   144  //export PrintBreakPoints
   145  func PrintBreakPoints() {
   146  	if len(contract_info_map) == 0 {
   147  		return
   148  	}
   149  	for _, info := range contract_info_map {
   150  		fmt.Printf("%s (%s): ", info.contract_id_base58, info.src_path)
   151  		for iter := info.breakpoints.Front(); iter != nil; iter = iter.Next() {
   152  			fmt.Printf("%d ", iter.Value)
   153  		}
   154  		fmt.Printf("\n")
   155  	}
   156  }
   157  
   158  //export ResetBreakPoints
   159  func ResetBreakPoints() {
   160  	for _, info := range contract_info_map {
   161  		info.breakpoints = list.New()
   162  	}
   163  }
   164  
   165  func SetWatchPoint(code string) error {
   166  	if code == "" {
   167  		return errors.New("Empty string cannot be set")
   168  	}
   169  
   170  	watchpoints.PushBack(code)
   171  
   172  	return nil
   173  }
   174  
   175  func DelWatchPoint(idx uint64) error {
   176  	if uint64(watchpoints.Len()) < idx {
   177  		return errors.New("invalid index")
   178  	}
   179  
   180  	var i uint64 = 0
   181  	for e := watchpoints.Front(); e != nil; e = e.Next() {
   182  		i++
   183  		if i >= idx {
   184  			watchpoints.Remove(e)
   185  			return nil
   186  		}
   187  	}
   188  
   189  	return nil
   190  }
   191  
   192  func ListWatchPoints() *list.List {
   193  	return watchpoints
   194  }
   195  
   196  //export ResetWatchPoints
   197  func ResetWatchPoints() {
   198  	watchpoints = list.New()
   199  }
   200  
   201  func UpdateContractInfo(contract_id_hex string, path string) {
   202  
   203  	if path != "" {
   204  		absPath, err := filepath.Abs(path)
   205  		if err != nil {
   206  			ctrLog.Fatal().Str("path", path).Msg("Try to set a invalid path")
   207  		}
   208  		path = filepath.ToSlash(absPath)
   209  	}
   210  
   211  	if info, ok := contract_info_map[contract_id_hex]; ok {
   212  		info.src_path = path
   213  
   214  	} else {
   215  		addr, err := HexAddrToBase58Addr(contract_id_hex)
   216  		if err != nil {
   217  			ctrLog.Fatal().Str("contract_id_hex", contract_id_hex).Msg("Fail to Decode Hex Address")
   218  		}
   219  		contract_info_map[contract_id_hex] = &contract_info{
   220  			addr,
   221  			path,
   222  			list.New()}
   223  	}
   224  }
   225  
   226  func ResetContractInfo() {
   227  	// just remove src paths. keep others for future use
   228  	for _, info := range contract_info_map {
   229  		info.src_path = ""
   230  	}
   231  
   232  }
   233  
   234  //export CGetContractID
   235  func CGetContractID(contract_id_hex_c *C.char) *C.char {
   236  	contract_id_hex := C.GoString(contract_id_hex_c)
   237  	if info, ok := contract_info_map[contract_id_hex]; ok {
   238  		return C.CString(info.contract_id_base58)
   239  	} else {
   240  		return C.CString("")
   241  	}
   242  }
   243  
   244  //export CGetSrc
   245  func CGetSrc(contract_id_hex_c *C.char) *C.char {
   246  	contract_id_hex := C.GoString(contract_id_hex_c)
   247  	if info, ok := contract_info_map[contract_id_hex]; ok {
   248  		return C.CString(info.src_path)
   249  	} else {
   250  		return C.CString("")
   251  	}
   252  }
   253  
   254  //export CSetBreakPoint
   255  func CSetBreakPoint(contract_name_or_hex_c *C.char, line_c C.double) {
   256  
   257  	contract_name_or_hex := C.GoString(contract_name_or_hex_c)
   258  	line := uint64(line_c)
   259  
   260  	err := SetBreakPoint(HexAddrOrPlainStrToHexAddr(contract_name_or_hex), line)
   261  	if err != nil {
   262  		ctrLog.Error().Err(err).Msg("Fail to add breakpoint")
   263  	}
   264  }
   265  
   266  //export CDelBreakPoint
   267  func CDelBreakPoint(contract_name_or_hex_c *C.char, line_c C.double) {
   268  	contract_name_or_hex := C.GoString(contract_name_or_hex_c)
   269  	line := uint64(line_c)
   270  
   271  	err := DelBreakPoint(HexAddrOrPlainStrToHexAddr(contract_name_or_hex), line)
   272  	if err != nil {
   273  		ctrLog.Error().Err(err).Msg("Fail to delete breakpoint")
   274  	}
   275  }
   276  
   277  //export CHasBreakPoint
   278  func CHasBreakPoint(contract_id_hex_c *C.char, line_c C.double) C.int {
   279  
   280  	contract_id_hex := C.GoString(contract_id_hex_c)
   281  	line := uint64(line_c)
   282  
   283  	if HasBreakPoint(contract_id_hex, line) {
   284  		return C.int(1)
   285  	}
   286  
   287  	return C.int(0)
   288  }
   289  
   290  //export CSetWatchPoint
   291  func CSetWatchPoint(code_c *C.char) {
   292  	code := C.GoString(code_c)
   293  
   294  	err := SetWatchPoint(code)
   295  	if err != nil {
   296  		ctrLog.Error().Err(err).Msg("Fail to set watchpoint")
   297  	}
   298  }
   299  
   300  //export CDelWatchPoint
   301  func CDelWatchPoint(idx_c C.double) {
   302  	idx := uint64(idx_c)
   303  
   304  	err := DelWatchPoint(idx)
   305  	if err != nil {
   306  		ctrLog.Error().Err(err).Msg("Fail to del watchpoint")
   307  	}
   308  }
   309  
   310  //export CGetWatchPoint
   311  func CGetWatchPoint(idx_c C.int) *C.char {
   312  	idx := int(idx_c)
   313  	var i int = 0
   314  	for e := watchpoints.Front(); e != nil; e = e.Next() {
   315  		i++
   316  		if i == idx {
   317  			return C.CString(e.Value.(string))
   318  		}
   319  	}
   320  
   321  	return C.CString("")
   322  }
   323  
   324  //export CLenWatchPoints
   325  func CLenWatchPoints() C.int {
   326  	return C.int(watchpoints.Len())
   327  }
   328  
   329  //export GetDebuggerCode
   330  func GetDebuggerCode() *C.char {
   331  
   332  	return C.CString(`
   333  	package.preload['__debugger'] = function()
   334  
   335  	--{{{  history
   336  
   337  	--15/03/06 DCN Created based on RemDebug
   338  	--28/04/06 DCN Update for Lua 5.1
   339  	--01/06/06 DCN Fix command argument parsing
   340  	--             Add step/over N facility
   341  	--             Add trace lines facility
   342  	--05/06/06 DCN Add trace call/return facility
   343  	--06/06/06 DCN Make it behave when stepping through the creation of a coroutine
   344  	--06/06/06 DCN Integrate the simple debugger into the main one
   345  	--07/06/06 DCN Provide facility to step into coroutines
   346  	--13/06/06 DCN Fix bug that caused the function environment to get corrupted with the global one
   347  	--14/06/06 DCN Allow 'sloppy' file names when setting breakpoints
   348  	--04/08/06 DCN Allow for no space after command name
   349  	--11/08/06 DCN Use io.write not print
   350  	--30/08/06 DCN Allow access to array elements in 'dump'
   351  	--10/10/06 DCN Default to breakfile for all commands that require a filename and give '-'
   352  	--06/12/06 DCN Allow for punctuation characters in DUMP variable names
   353  	--03/01/07 DCN Add pause on/off facility
   354  	--19/06/07 DCN Allow for duff commands being typed in the debugger (thanks to Michael.Bringmann@lsi.com)
   355  	--             Allow for case sensitive file systems               (thanks to Michael.Bringmann@lsi.com)
   356  	--04/08/09 DCN Add optional line count param to pause
   357  	--05/08/09 DCN Reset the debug hook in Pause() even if we think we're started
   358  	--30/09/09 DCN Re-jig to not use co-routines (makes debugging co-routines awkward)
   359  	--01/10/09 DCN Add ability to break on reaching any line in a file
   360  	--24/07/13 TWW Added code for emulating setfenv/getfenv in Lua 5.2 as per
   361  	--             http://lua-users.org/lists/lua-l/2010-06/msg00313.html
   362  	--25/07/13 TWW Copied Alex Parrill's fix for errors when tracing back across a C frame
   363  	--             (https://github.com/ColonelThirtyTwo/clidebugger, 26/01/12)
   364  	--25/07/13 DCN Allow for windows and unix file name conventions in has_breakpoint
   365  	--26/07/13 DCN Allow for \ being interpreted as an escape inside a [] pattern in 5.2
   366  	--29/01/17 RMM Fix lua 5.2 and 5.3 compat, fix crash in error msg, sort help output
   367  	--22/03/19 Modified for Aergo Contracts
   368  
   369  	--}}}
   370  	--{{{  description
   371  
   372  	--A simple command line debug system for Lua written by Dave Nichols of
   373  	--Match-IT Limited. Its public domain software. Do with it as you wish.
   374  
   375  	--This debugger was inspired by:
   376  	-- RemDebug 1.0 Beta
   377  	-- Copyright Kepler Project 2005 (http://www.keplerproject.org/remdebug)
   378  
   379  	--Usage:
   380  	--  require('debugger')        --load the debug library
   381  	--  pause(message)             --start/resume a debug session
   382  
   383  	--An assert() failure will also invoke the debugger.
   384  
   385  	--}}}
   386  
   387  	__debugger = {}
   388  
   389  	local coro_debugger
   390  	local events = { BREAK = 1, WATCH = 2, STEP = 3, SET = 4 }
   391  	local watches = {}
   392  	local step_into   = false
   393  	local step_over   = false
   394  	local step_lines  = 0
   395  	local step_level  = {main=0}
   396  	local stack_level = {main=0}
   397  	local trace_level = {main=0}
   398  	local ret_file, ret_line, ret_name
   399  	local current_thread = 'main'
   400  	local started = false
   401  	local _g      = _G
   402  	local skip_pause_for_init = false
   403  
   404  	--{{{  make Lua 5.2 compatible
   405  
   406  	local unpack = unpack or table.unpack
   407  	local loadstring = loadstring or load
   408  
   409  	--}}}
   410  
   411  	--{{{  local hints -- command help
   412  	--The format in here is name=summary|description
   413  	local hints = {
   414  
   415  		setb =    [[
   416  	setb [line file]    -- set a breakpoint to line/file|, line 0 means 'any'
   417  
   418  	If file is omitted or is '-'' the breakpoint is set at the file for the
   419  	currently set level (see 'set'). Execution pauses when this line is about
   420  	to be executed and the debugger session is re-activated.
   421  
   422  	The file can be given as the fully qualified name, partially qualified or
   423  	just the file name. E.g. if file is set as 'myfile.lua', then whenever
   424  	execution reaches any file that ends with 'myfile.lua' it will pause. If
   425  	no extension is given, any extension will do.
   426  
   427  	If the line is given as 0, then reaching any line in the file will do.
   428  	]],
   429  
   430  	delb =    [[
   431  	delb [line file]    -- removes a breakpoint|
   432  
   433  	If file is omitted or is '-'' the breakpoint is removed for the file of the
   434  	currently set level (see 'set').
   435  	]],
   436  
   437  	resetb = [[
   438  	resetb             -- removes all breakpoints|
   439  	]],
   440  
   441  	setw =    [[
   442  	setw <exp>          -- adds a new watch expression|
   443  
   444  	The expression is evaluated before each line is executed. If the expression
   445  	yields true then execution is paused and the debugger session re-activated.
   446  	The expression is executed in the context of the line about to be executed.
   447  	]],
   448  
   449  	delw =    [[
   450  	delw <index>        -- removes the watch expression at index|
   451  
   452  	The index is that returned when the watch expression was set by setw.
   453  	]],
   454  
   455  	resetw = [[
   456  	resetw             -- removes all watch expressions|
   457  	]],
   458  
   459  	run     = [[
   460  	run                 -- run until next breakpoint or watch expression|
   461  	]],
   462  
   463  	step    = [[
   464  	step [N]            -- run next N lines, stepping into function calls|
   465  
   466  	If N is omitted, use 1.
   467  	]],
   468  
   469  	over    = [[
   470  	over [N]            -- run next N lines, stepping over function calls|
   471  
   472  	If N is omitted, use 1.
   473  	]],
   474  
   475  	out     = [[
   476  	out [N]             -- run lines until stepped out of N functions|
   477  
   478  	If N is omitted, use 1.
   479  	If you are inside a function, using 'out 1' will run until you return
   480  	from that function to the caller.
   481  	]],
   482  
   483  	listb   = [[
   484  	listb               -- lists breakpoints|
   485  	]],
   486  
   487  	listw   = [[
   488  	listw               -- lists watch expressions|
   489  	]],
   490  
   491  	set     = [[
   492  	set [level]         -- set context to stack level, omitted=show|
   493  
   494  	If level is omitted it just prints the current level set.
   495  	This sets the current context to the level given. This affects the
   496  	context used for several other functions (e.g. vars). The possible
   497  	levels are those shown by trace.
   498  	]],
   499  
   500  	vars    = [[
   501  	vars [depth]        -- list context locals to depth, omitted=1|
   502  
   503  	If depth is omitted then uses 1.
   504  	Use a depth of 0 for the maximum.
   505  	Lists all non-nil local variables and all non-nil upvalues in the
   506  	currently set context. For variables that are tables, lists all fields
   507  	to the given depth.
   508  	]],
   509  
   510  	fenv    = [[
   511  	fenv [depth]        -- list context function env to depth, omitted=1|
   512  
   513  	If depth is omitted then uses 1.
   514  	Use a depth of 0 for the maximum.
   515  	Lists all function environment variables in the currently set context.
   516  	For variables that are tables, lists all fields to the given depth.
   517  	]],
   518  
   519  	glob    = [[
   520  	glob [depth]        -- list globals to depth, omitted=1|
   521  
   522  	If depth is omitted then uses 1.
   523  	Use a depth of 0 for the maximum.
   524  	Lists all global variables.
   525  	For variables that are tables, lists all fields to the given depth.
   526  	]],
   527  
   528  	ups     = [[
   529  	ups                 -- list all the upvalue names|
   530  
   531  	These names will also be in the 'vars' list unless their value is nil.
   532  	This provides a means to identify which vars are upvalues and which are
   533  	locals. If a name is both an upvalue and a local, the local value takes
   534  	precedance.
   535  	]],
   536  
   537  	locs    = [[
   538  	locs                -- list all the locals names|
   539  
   540  	These names will also be in the 'vars' list unless their value is nil.
   541  	This provides a means to identify which vars are upvalues and which are
   542  	locals. If a name is both an upvalue and a local, the local value takes
   543  	precedance.
   544  	]],
   545  
   546  	dump    = [[
   547  	dump <var> [depth]  -- dump all fields of variable to depth|
   548  
   549  	If depth is omitted then uses 1.
   550  	Use a depth of 0 for the maximum.
   551  	Prints the value of <var> in the currently set context level. If <var>
   552  	is a table, lists all fields to the given depth. <var> can be just a
   553  	name, or name.field or name.# to any depth, e.g. t.1.f accesses field
   554  	'f' in array element 1 in table 't'.
   555  
   556  	Can also be called from a script as dump(var,depth).
   557  	]],
   558  
   559  	trace   = [[
   560  	trace               -- dumps a stack trace|
   561  
   562  	Format is [level] = file,line,name
   563  	The level is a candidate for use by the 'set' command.
   564  	]],
   565  
   566  	info    = [[
   567  	info                -- dumps the complete debug info captured|
   568  
   569  	Only useful as a diagnostic aid for the debugger itself. This information
   570  	can be HUGE as it dumps all variables to the maximum depth, so be careful.
   571  	]],
   572  
   573  	show    = [[
   574  	show line file X Y  -- show X lines before and Y after line in file|
   575  
   576  	If line is omitted or is '-' then the current set context line is used.
   577  	If file is omitted or is '-' then the current set context file is used.
   578  	If file is not fully qualified and cannot be opened as specified, then
   579  	a search for the file in the package[path] is performed using the usual
   580  	'require' searching rules. If no file extension is given, .lua is used.
   581  	Prints the lines from the source file around the given line.
   582  	]],
   583  
   584  	exit    = [[
   585  	exit                -- exits debugger, re-start it using pause()|
   586  	]],
   587  
   588  	help    = [[
   589  	help [command]      -- show this list or help for command|
   590  	]],
   591  
   592  	['<statement>'] = [[
   593  	<statement>         -- execute a statement in the current context|
   594  
   595  	The statement can be anything that is legal in the context, including
   596  	assignments. Such assignments affect the context and will be in force
   597  	immediately. Any results returned are printed. Use '=' as a short-hand
   598  	for 'return', e.g. '=func(arg)' will call 'func' with 'arg' and print
   599  	the results, and '=var' will just print the value of 'var'.
   600  	]],
   601  
   602  	}
   603  	--}}}
   604  
   605  	--{{{  local function getinfo(level,field)
   606  
   607  	--like debug.getinfo but copes with no activation record at the given level
   608  	--and knows how to get 'field'. 'field' can be the name of any of the
   609  	--activation record fields or any of the 'what' names or nil for everything.
   610  	--only valid when using the stack level to get info, not a function name.
   611  
   612  	local function getinfo(level,field)
   613  		level = level + 1  --to get to the same relative level as the caller
   614  		if not field then return debug.getinfo(level) end
   615  		local what
   616  		if field == 'name' or field == 'namewhat' then
   617  			what = 'n'
   618  		elseif field == 'what' or field == 'source' or field == 'linedefined' or field == 'lastlinedefined' or field == 'short_src' then
   619  			what = 'S'
   620  		elseif field == 'currentline' then
   621  			what = 'l'
   622  		elseif field == 'nups' then
   623  			what = 'u'
   624  		elseif field == 'func' then
   625  			what = 'f'
   626  		else
   627  			return debug.getinfo(level,field)
   628  		end
   629  		local ar = debug.getinfo(level,what)
   630  		if ar then return ar[field] else return nil end
   631  	end
   632  
   633  	--}}}
   634  	--{{{  local function indented( level, ... )
   635  
   636  	local function indented( level, ... )
   637  		io.write( string.rep('  ',level), table.concat({...}), '\n' )
   638  	end
   639  
   640  	--}}}
   641  	--{{{  local function dumpval( level, name, value, limit )
   642  
   643  	local function dumpval( level, name, value, limit )
   644  		local index
   645  		if type(name) == 'number' then
   646  			index = string.format('[%d] = ',name)
   647  		elseif type(name) == 'string'
   648  			and (name == '__VARSLEVEL__' or name == '__ENVIRONMENT__' or name == '__GLOBALS__' or name == '__UPVALUES__' or name == '__LOCALS__') then
   649  		--ignore these, they are debugger generated
   650  			return
   651  		elseif type(name) == 'string' and string.find(name,'^[_%a][_.%w]*$') then
   652  			index = name ..' = '
   653  		else
   654  			index = string.format('[%q] = ',tostring(name))
   655  		end
   656  		if type(value) == 'table' then
   657  			if (limit or 0) > 0 and level+1 >= limit then
   658  				indented( level, index, tostring(value), ';' )
   659  			else
   660  				indented( level, index, '{' )
   661  				for n,v in pairs(value) do
   662  					dumpval( level+1, n, v, limit )
   663  				end
   664  				indented( level, '};' )
   665  			end
   666  		else
   667  			if type(value) == 'string' then
   668  				if string.len(value) > 40 then
   669  					indented( level, index, '[[', value, ']];' )
   670  				else
   671  					indented( level, index, string.format('%q',value), ';' )
   672  				end
   673  			else
   674  				indented( level, index, tostring(value), ';' )
   675  			end
   676  		end
   677  	end
   678  
   679  	--}}}
   680  	--{{{  local function dumpvar( value, limit, name )
   681  
   682  	local function dumpvar( value, limit, name )
   683  		dumpval( 0, name or tostring(value), value, limit )
   684  	end
   685  
   686  	--}}}
   687  
   688  	--{{{  local function show(contract_id_hex,line,before,after)
   689  
   690  	--show +/-N lines of a contract source around line M
   691  
   692  	local function show(contract_id_hex,line,before,after)
   693  
   694  		line   = tonumber(line   or 1)
   695  		before = tonumber(before or 10)
   696  		after  = tonumber(after  or before)
   697  		local file = ''
   698  		local base58_addr = ''
   699  
   700  		-- find matched source from 
   701  		_, file = __get_contract_info(contract_id_hex)
   702  
   703  		if not string.find(file,'%.') then file = file..'.lua' end
   704  
   705  		local f = io.open(file,'r')
   706  		if not f then
   707  			io.write('Cannot find '..file..' for contract '..base58_addr..'\n')
   708  		return
   709  		end
   710  
   711  		local i = 0
   712  		for l in f:lines() do
   713  			i = i + 1
   714  			if i >= (line-before) then
   715  				if i > (line+after) then break end
   716  				if i == line then
   717  					io.write(i..'***\t'..l..'\n')
   718  				else
   719  					io.write(i..'\t'..l..'\n')
   720  				end
   721  			end
   722  		end
   723  
   724  		f:close()
   725  
   726  	end
   727  
   728  	--}}}
   729  	--{{{  local function tracestack(l)
   730  
   731  	local function gi( i )
   732  		return function() i=i+1 return debug.getinfo(i),i end
   733  	end
   734  
   735  	local function gl( level, j )
   736  		return function() j=j+1 return debug.getlocal( level, j ) end
   737  	end
   738  
   739  	local function gu( func, k )
   740  		return function() k=k+1 return debug.getupvalue( func, k ) end
   741  	end
   742  
   743  	local  traceinfo
   744  
   745  	local function tracestack(l)
   746  		local l = l + 1                        --NB: +1 to get level relative to caller
   747  		traceinfo = {}
   748  		--traceinfo.pausemsg = pausemsg
   749  		for ar,i in gi(l) do
   750  			table.insert( traceinfo, ar )
   751  			if ar.what ~= 'C' then
   752  				local names  = {}
   753  				local values = {}
   754  				
   755  				for n,v in gl(i-1,0) do
   756  				--for n,v in gl(i,0) do
   757  				if string.sub(n,1,1) ~= '(' then   --ignore internal control variables
   758  					table.insert( names, n )
   759  					table.insert( values, v )
   760  				end
   761  				end
   762  				if #names > 0 then
   763  					ar.lnames  = names
   764  					ar.lvalues = values
   765  				end
   766  			end
   767  			if ar.func then
   768  				local names  = {}
   769  				local values = {}
   770  				for n,v in gu(ar.func,0) do
   771  				if string.sub(n,1,1) ~= '(' then   --ignore internal control variables
   772  					table.insert( names, n )
   773  					table.insert( values, v )
   774  				end
   775  				end
   776  				if #names > 0 then
   777  					ar.unames  = names
   778  					ar.uvalues = values
   779  				end
   780  			end
   781  		end
   782  	end
   783  
   784  	--}}}
   785  	--{{{  local function trace()
   786  
   787  	local function trace(set)
   788  		local mark
   789  		for level,ar in ipairs(traceinfo) do
   790  			if level == set then
   791  				mark = '***'
   792  			else
   793  				mark = ''
   794  			end
   795  			local contract_id_base58, _ = __get_contract_info(ar.source)
   796  			io.write('['..level..']'..mark..'\t'..(ar.name or ar.what)..' in '..(contract_id_base58 or ar.short_src)..':'..ar.currentline..'\n')
   797  		end
   798  	end
   799  
   800  	--}}}
   801  	--{{{  local function info()
   802  
   803  	local function info() dumpvar( traceinfo, 0, 'traceinfo' ) end
   804  
   805  	--}}}
   806  
   807  	--}}}
   808  	--{{{  local function has_breakpoint(file, line)
   809  
   810  	--allow for 'sloppy' file names
   811  	--search for file and all variations walking up its directory hierachy
   812  	--ditto for the file with no extension
   813  	--a breakpoint can be permenant or once only, if once only its removed
   814  	--after detection here, these are used for temporary breakpoints in the
   815  	--a breakpoint on line 0 of a file means any line in that file
   816  
   817  	local function has_breakpoint(contract_id_hex, line)
   818  		
   819  		return __has_breakpoint(contract_id_hex, line)
   820  	end
   821  
   822  	--}}}
   823  	--{{{  local function capture_vars(ref,level,line)
   824  
   825  	local function capture_vars(ref,level,line)
   826  		--get vars, contract_id_hex, contract_id_base58 and line for the given level relative to debug_hook offset by ref
   827  
   828  		local lvl = ref + level                --NB: This includes an offset of +1 for the call to here
   829  
   830  		--{{{  capture variables
   831  
   832  		local ar = debug.getinfo(lvl, 'f')
   833  		if not ar then return {},'?','?',0 end
   834  
   835  		local vars = {__UPVALUES__={}, __LOCALS__={}}
   836  		local i
   837  
   838  		local func = ar.func
   839  		if func then
   840  			i = 1
   841  			while true do
   842  				local name, value = debug.getupvalue(func, i)
   843  				if not name then break end
   844  				if string.sub(name,1,1) ~= '(' then  --NB: ignoring internal control variables
   845  					vars[name] = value
   846  					vars.__UPVALUES__[i] = name
   847  				end
   848  				i = i + 1
   849  			end
   850  			vars.__ENVIRONMENT__ = getfenv(func)
   851  		end
   852  
   853  		vars.__GLOBALS__ = getfenv(0)
   854  
   855  		i = 1
   856  		while true do
   857  			local name, value = debug.getlocal(lvl, i)
   858  			if not name then break end
   859  			if string.sub(name,1,1) ~= '(' then    --NB: ignoring internal control variables
   860  				vars[name] = value
   861  				vars.__LOCALS__[i] = name
   862  			end
   863  			i = i + 1
   864  		end
   865  
   866  		vars.__VARSLEVEL__ = level
   867  
   868  		if func then
   869  			--NB: Do not do this until finished filling the vars table
   870  			setmetatable(vars, { __index = getfenv(func), __newindex = getfenv(func) })
   871  		end
   872  
   873  		--NB: Do not read or write the vars table anymore else the metatable functions will get invoked!
   874  
   875  		--}}}
   876  
   877  		local contract_id_hex = getinfo(lvl, 'source')
   878  		if string.find(contract_id_hex, '@') == 1 then
   879  			contract_id_hex = string.sub(contract_id_hex, 2)
   880  		end
   881  
   882  		local contract_id_base58, _ = __get_contract_info(contract_id_hex)
   883  		
   884  		if not line then
   885  			line = getinfo(lvl, 'currentline')
   886  		end
   887  
   888  		return vars,contract_id_hex,contract_id_base58,line
   889  
   890  	end
   891  
   892  	--}}}
   893  	--{{{  local function restore_vars(ref,vars)
   894  
   895  	local function restore_vars(ref,vars)
   896  
   897  		if type(vars) ~= 'table' then return end
   898  
   899  		local level = vars.__VARSLEVEL__       --NB: This level is relative to debug_hook offset by ref
   900  		if not level then return end
   901  
   902  		level = level + ref                    --NB: This includes an offset of +1 for the call to here
   903  
   904  		local i
   905  		local written_vars = {}
   906  
   907  		i = 1
   908  		while true do
   909  			local name, value = debug.getlocal(level, i)
   910  			if not name then break end
   911  			if vars[name] and string.sub(name,1,1) ~= '(' then     --NB: ignoring internal control variables
   912  				debug.setlocal(level, i, vars[name])
   913  				written_vars[name] = true
   914  			end
   915  			i = i + 1
   916  		end
   917  
   918  		local ar = debug.getinfo(level, 'f')
   919  		if not ar then return end
   920  
   921  		local func = ar.func
   922  		if func then
   923  
   924  		i = 1
   925  		while true do
   926  			local name, value = debug.getupvalue(func, i)
   927  			if not name then break end
   928  			if vars[name] and string.sub(name,1,1) ~= '(' then   --NB: ignoring internal control variables
   929  				if not written_vars[name] then
   930  					debug.setupvalue(func, i, vars[name])
   931  				end
   932  				written_vars[name] = true
   933  			end
   934  			i = i + 1
   935  		end
   936  
   937  		end
   938  
   939  	end
   940  
   941  	--}}}
   942  	--{{{  local function trace_event(event, line, level)
   943  
   944  		local function trace_event(event, line, level)
   945  
   946  		if event ~= 'line' then return end
   947  
   948  		local slevel = stack_level[current_thread]
   949  		local tlevel = trace_level[current_thread]
   950  
   951  		trace_level[current_thread] = stack_level[current_thread]
   952  
   953  	end
   954  
   955  	--}}}
   956  	--{{{  local function report(ev, vars, file, line, idx_watch)
   957  
   958  	local function report(ev, vars, contract_id_base58, line, idx_watch)
   959  		local vars = vars or {}
   960  		local contract_id_base58 = contract_id_base58 or '?'
   961  		local line = line or 0
   962  		local prefix = ''
   963  		if current_thread ~= 'main' then prefix = '['..tostring(current_thread)..'] ' end
   964  		if ev == events.STEP then
   965  			io.write(prefix..'Paused at contract '..contract_id_base58..' line '..line..' ('..stack_level[current_thread]..')\n')
   966  		elseif ev == events.BREAK then
   967  			io.write(prefix..'Paused at contract '..contract_id_base58..' line '..line..' ('..stack_level[current_thread]..') (breakpoint)\n')
   968  		elseif ev == events.WATCH then
   969  			io.write(prefix..'Paused at contract '..contract_id_base58..' line '..line..' ('..stack_level[current_thread]..')'..' (watch expression '..idx_watch.. ': ['..__get_watchpoint(idx_watch)..'])\n')
   970  		elseif ev == events.SET then
   971  			--do nothing
   972  		else
   973  			io.write(prefix..'Error in application: '..contract_id_base58..' line '..line..'\n')
   974  		end
   975  		return vars, contract_id_base58, line
   976  	end
   977  
   978  	--}}}
   979  
   980  	--{{{  local function debugger_loop(ev, vars, file, line, idx_watch)
   981  
   982  	local function debugger_loop(ev, vars, file, line, idx_watch)
   983  
   984  		local eval_env  = vars or {}
   985  		local breakfile = file or '?'
   986  		local breakline = line or 0
   987  
   988  		local command, args
   989  
   990  		--{{{  local function getargs(spec)
   991  
   992  		--get command arguments according to the given spec from the args string
   993  		--the spec has a single character for each argument, arguments are separated
   994  		--by white space, the spec characters can be one of:
   995  		-- F for a filename    (defaults to breakfile if - given in args)
   996  		-- L for a line number (defaults to breakline if - given in args)
   997  		-- N for a number
   998  		-- V for a variable name
   999  		-- S for a string
  1000  
  1001  		local function getargs(spec)
  1002  			local res={}
  1003  			local char,arg
  1004  			local ptr=1
  1005  			for i=1,string.len(spec) do
  1006  				char = string.sub(spec,i,i)
  1007  				if     char == 'F' then
  1008  					_,ptr,arg = string.find(args..' ','%s*([%w%p]*)%s*',ptr)
  1009  					if not arg or arg == '' then arg = '-' end
  1010  					if arg == '-' then arg = breakfile end
  1011  				elseif char == 'L' then
  1012  					_,ptr,arg = string.find(args..' ','%s*([%w%p]*)%s*',ptr)
  1013  					if not arg or arg == '' then arg = '-' end
  1014  					if arg == '-' then arg = breakline end
  1015  					arg = tonumber(arg) or 0
  1016  				elseif char == 'N' then
  1017  					_,ptr,arg = string.find(args..' ','%s*([%w%p]*)%s*',ptr)
  1018  					if not arg or arg == '' then arg = '0' end
  1019  					arg = tonumber(arg) or 0
  1020  				elseif char == 'V' then
  1021  					_,ptr,arg = string.find(args..' ','%s*([%w%p]*)%s*',ptr)
  1022  					if not arg or arg == '' then arg = '' end
  1023  				elseif char == 'S' then
  1024  					_,ptr,arg = string.find(args..' ','%s*([%w%p]*)%s*',ptr)
  1025  					if not arg or arg == '' then arg = '' end
  1026  				else
  1027  					arg = ''
  1028  				end
  1029  				table.insert(res,arg or '')
  1030  			end
  1031  			return unpack(res)
  1032  		end
  1033  
  1034  		--}}}
  1035  
  1036  		while true do
  1037  			io.write('[DEBUG]> ')
  1038  			local line = io.read('*line')
  1039  			if line == nil then io.write('\n'); line = 'exit' end
  1040  
  1041  			if string.find(line, '^[a-z]+') then
  1042  				command = string.sub(line, string.find(line, '^[a-z]+'))
  1043  				args    = string.gsub(line,'^[a-z]+%s*','',1)            --strip command off line
  1044  			else
  1045  				command = ''
  1046  			end
  1047  
  1048  			if command == 'setb' then
  1049  				--{{{  set breakpoint
  1050  
  1051  				local line, contract_id_hex  = getargs('LF')
  1052  				if contract_id_hex ~= '' and line ~= '' then
  1053  					__set_breakpoint(contract_id_hex,line)
  1054  				else
  1055  					io.write('Bad request\n')
  1056  				end
  1057  
  1058  				--}}}
  1059  
  1060  			elseif command == 'delb' then
  1061  				--{{{  delete breakpoint
  1062  
  1063  				local line, contract_id_hex = getargs('LF')
  1064  				if contract_id_hex ~= '' and line ~= '' then
  1065  					__delete_breakpoint(contract_id_hex, line)
  1066  				else
  1067  					io.write('Bad request\n')
  1068  				end
  1069  
  1070  				--}}}
  1071  
  1072  			elseif command == 'resetb' then
  1073  				--{{{  delete all breakpoints
  1074  				--TODO
  1075  				io.write('All breakpoints deleted\n')
  1076  				--}}}
  1077  
  1078  			elseif command == 'listb' then
  1079  				--{{{  list breakpoints
  1080  				__print_breakpoints()
  1081  				--}}}
  1082  
  1083  			elseif command == 'setw' then
  1084  				--{{{  set watch expression
  1085  
  1086  				if args and args ~= '' then
  1087  					__set_watchpoint(args)
  1088  					io.write('Set watch exp no. ' .. __len_watchpoints() ..'\n')
  1089  				else
  1090  					io.write('Bad request\n')
  1091  				end
  1092  
  1093  				--}}}
  1094  
  1095  			elseif command == 'delw' then
  1096  				--{{{  delete watch expression
  1097  
  1098  				local index = tonumber(args)
  1099  				if index then
  1100  					__delete_watchpoint(index)
  1101  					io.write('Watch expression deleted\n')
  1102  				else
  1103  					io.write('Bad request\n')
  1104  				end
  1105  
  1106  				--}}}
  1107  
  1108  			elseif command == 'resetw' then
  1109  				--{{{  delete all watch expressions
  1110  				__reset_watchpoints()
  1111  				io.write('All watch expressions deleted\n')
  1112  				--}}}
  1113  
  1114  			elseif command == 'listw' then
  1115  				--{{{  list watch expressions
  1116  				for i, v in pairs(__list_watchpoints()) do
  1117  					io.write(i .. ': ' .. v..'\n')
  1118  				end
  1119  				--}}}
  1120  
  1121  			elseif command == 'run' then
  1122  				--{{{  run until breakpoint
  1123  				step_into = false
  1124  				step_over = false
  1125  				return 'cont'
  1126  				--}}}
  1127  
  1128  			elseif command == 'step' then
  1129  				--{{{  step N lines (into functions)
  1130  				local N = tonumber(args) or 1
  1131  				step_over  = false
  1132  				step_into  = true
  1133  				step_lines = tonumber(N or 1)
  1134  				return 'cont'
  1135  				--}}}
  1136  
  1137  			elseif command == 'over' then
  1138  				--{{{  step N lines (over functions)
  1139  				local N = tonumber(args) or 1
  1140  				step_into  = false
  1141  				step_over  = true
  1142  				step_lines = tonumber(N or 1)
  1143  				step_level[current_thread] = stack_level[current_thread]
  1144  				return 'cont'
  1145  				--}}}
  1146  
  1147  			elseif command == 'out' then
  1148  				--{{{  step N lines (out of functions)
  1149  				local N = tonumber(args) or 1
  1150  				step_into  = false
  1151  				step_over  = true
  1152  				step_lines = 1
  1153  				step_level[current_thread] = stack_level[current_thread] - tonumber(N or 1)
  1154  				return 'cont'
  1155  				--}}}
  1156  
  1157  			elseif command == 'set' then
  1158  				--{{{  set/show context level
  1159  				local level = args
  1160  				if level and level == '' then level = nil end
  1161  				if level then return level end
  1162  				--}}}
  1163  
  1164  			elseif command == 'vars' then
  1165  				--{{{  list context variables
  1166  				local depth = args
  1167  				if depth and depth == '' then depth = nil end
  1168  				depth = tonumber(depth) or 1
  1169  				dumpvar(eval_env, depth+1, 'variables')
  1170  				--}}}
  1171  
  1172  			elseif command == 'glob' then
  1173  				--{{{  list global variables
  1174  				local depth = args
  1175  				if depth and depth == '' then depth = nil end
  1176  				depth = tonumber(depth) or 1
  1177  				dumpvar(eval_env.__GLOBALS__,depth+1,'globals')
  1178  				--}}}
  1179  
  1180  			elseif command == 'fenv' then
  1181  				--{{{  list function environment variables
  1182  				local depth = args
  1183  				if depth and depth == '' then depth = nil end
  1184  				depth = tonumber(depth) or 1
  1185  				dumpvar(eval_env.__ENVIRONMENT__,depth+1,'environment')
  1186  				--}}}
  1187  
  1188  			elseif command == 'ups' then
  1189  				--{{{  list upvalue names
  1190  				dumpvar(eval_env.__UPVALUES__,2,'upvalues')
  1191  				--}}}
  1192  
  1193  			elseif command == 'locs' then
  1194  				--{{{  list locals names
  1195  				dumpvar(eval_env.__LOCALS__,2,'upvalues')
  1196  				--}}}
  1197  
  1198  			elseif command == 'dump' then
  1199  				--{{{  dump a variable
  1200  				local name, depth = getargs('VN')
  1201  				if name ~= '' then
  1202  					if depth == '' or depth == 0 then depth = nil end
  1203  					depth = tonumber(depth or 1)
  1204  					local v = eval_env
  1205  					local n = nil
  1206  					for w in string.gmatch(name,'[^%.]+') do     --get everything between dots
  1207  						if tonumber(w) then
  1208  							v = v[tonumber(w)]
  1209  						else
  1210  							v = v[w]
  1211  						end
  1212  						if n then n = n..'.'..w else n = w end
  1213  						if not v then break end
  1214  					end
  1215  					dumpvar(v,depth+1,n)
  1216  				else
  1217  					io.write('Bad request\n')
  1218  				end
  1219  				--}}}
  1220  
  1221  			elseif command == 'show' then
  1222  				--{{{  show contract around a line or the current breakpoint
  1223  				local line, contract_id_hex, before, after = getargs('LFNN')
  1224  				if before == 0 then before = 10     end
  1225  				if after  == 0 then after  = before end
  1226  
  1227  				if contract_id_hex ~= '' and contract_id_hex ~= '=stdin' then
  1228  					show(contract_id_hex,line,before,after)
  1229  				else
  1230  					io.write('Nothing to show\n')
  1231  				end
  1232  				--}}}
  1233  
  1234  			elseif command == 'trace' then
  1235  				--{{{  dump a stack trace
  1236  				trace(eval_env.__VARSLEVEL__)
  1237  				--}}}
  1238  
  1239  			elseif command == 'info' then
  1240  				--{{{  dump all debug info captured
  1241  				info()
  1242  				--}}}
  1243  
  1244  			elseif command == 'pause' then
  1245  				--{{{  not allowed in here
  1246  				io.write('pause() should only be used in the script you are debugging\n')
  1247  				--}}}
  1248  
  1249  			elseif command == 'help' then
  1250  				--{{{  help
  1251  				local command = getargs('S')
  1252  				if command ~= '' and hints[command] then
  1253  					io.write(hints[command]..'\n')
  1254  				else
  1255  					local l = {}
  1256  					for k,v in pairs(hints) do
  1257  						local _,_,h = string.find(v,'(.+)|')
  1258  						l[#l+1] = h..'\n'
  1259  					end
  1260  					table.sort(l)
  1261  					io.write(table.concat(l))
  1262  				end
  1263  				--}}}
  1264  
  1265  			elseif command == 'exit' then
  1266  				--{{{  exit debugger
  1267  				return 'stop'
  1268  				--}}}
  1269  
  1270  			elseif line ~= '' then
  1271  				--{{{  just execute whatever it is in the current context
  1272  
  1273  				--map line starting with '=...' to 'return ...'
  1274  				if string.sub(line,1,1) == '=' then line = string.gsub(line,'=','return ',1) end
  1275  
  1276  				local ok, func = pcall(loadstring,line)
  1277  				if ok and func==nil then -- auto-print variables
  1278  					ok, func = pcall(loadstring,'io.write(tostring(' .. line .. '))')
  1279  				end
  1280  				if func == nil then                             --Michael.Bringmann@lsi.com
  1281  					io.write('Compile error: '..line..'\n')
  1282  				elseif not ok then
  1283  					io.write('Compile error: '..func..'\n')
  1284  				else
  1285  					setfenv(func, eval_env)
  1286  					local res = {pcall(func)}
  1287  					if res[1] then
  1288  						if res[2] then
  1289  						table.remove(res,1)
  1290  						for _,v in ipairs(res) do
  1291  							io.write(tostring(v))
  1292  							io.write('\t')
  1293  						end
  1294  						end
  1295  						--update in the context
  1296  						io.write('\n')
  1297  						return 0
  1298  					else
  1299  						io.write('Run error: '..res[2]..'\n')
  1300  					end
  1301  				end
  1302  
  1303  				--}}}
  1304  			end
  1305  		end
  1306  
  1307  	end
  1308  
  1309  	--}}}
  1310  	--{{{  local function debug_hook(event, line, level, thread)
  1311  	local function debug_hook(event, line, level, thread)
  1312  		if not started then debug.sethook(); coro_debugger = nil; return end
  1313  		current_thread = thread or 'main'
  1314  		local level = level or 2
  1315  		trace_event(event,line,level)
  1316  		if event == 'line' then
  1317  			-- calculate current stack
  1318  			for i=1,99999,1 do 
  1319  				if not debug.getinfo(i) then break end
  1320  				stack_level[current_thread] = i - 1 -- minus one to remove this debug_hook stack
  1321  			end
  1322  			
  1323  			local vars,contract_id_hex,contract_id_base58,line = capture_vars(level,1,line)
  1324  			local stop, ev, idx = false, events.STEP, 0
  1325  			while true do
  1326  				for index, value in pairs(__list_watchpoints()) do
  1327  				local func = loadstring('return(' .. value .. ')')
  1328  				if func ~= nil then
  1329  					setfenv(func, vars)
  1330  					local status, res = pcall(func)
  1331  					if status and res then
  1332  						ev, idx = events.WATCH, index
  1333  						stop = true
  1334  						break
  1335  					end
  1336  				end
  1337  				end
  1338  				if stop then break end
  1339  				if (step_into)
  1340  				or (step_over and (stack_level[current_thread] <= step_level[current_thread] or stack_level[current_thread] == 0)) then
  1341  					step_lines = step_lines - 1
  1342  					if step_lines < 1 then
  1343  						ev, idx = events.STEP, 0
  1344  						break
  1345  					end
  1346  				end
  1347  				if has_breakpoint(contract_id_hex, line) then
  1348  					ev, idx = events.BREAK, 0
  1349  					break
  1350  				end
  1351  				return
  1352  			end
  1353  			if skip_pause_for_init then
  1354  				--DO notthing
  1355  			elseif not coro_debugger then
  1356  				io.write('Lua Debugger\n')
  1357  				vars, contract_id_base58, line = report(ev, vars, contract_id_base58, line, idx)
  1358  				io.write('Type \'help\' for commands\n')
  1359  				coro_debugger = true
  1360  			else
  1361  				vars, contract_id_base58, line = report(ev, vars, contract_id_base58, line, idx)
  1362  			end
  1363  			tracestack(level)
  1364  			local last_next = 1
  1365  			local next = 'ask'
  1366  			local silent = false
  1367  			while true do
  1368  				if next == 'ask' then
  1369  					if skip_pause_for_init then 
  1370  						step_into = false
  1371  						--step_over = false
  1372  						skip_pause_for_init = false -- reset flag
  1373  						return -- for the first time
  1374  					end
  1375  					next = debugger_loop(ev, vars, contract_id_hex, line, idx)
  1376  				elseif next == 'cont' then
  1377  					return
  1378  				elseif next == 'stop' then
  1379  					started = false
  1380  					debug.sethook()
  1381  					coro_debugger = nil
  1382  					return
  1383  				elseif tonumber(next) then --get vars for given level or last level
  1384  					next = tonumber(next)
  1385  					if next == 0 then silent = true; next = last_next else silent = false end
  1386  					last_next = next
  1387  					restore_vars(level,vars)
  1388  					vars, contract_id_hex, contract_id_base58, line = capture_vars(level,next)
  1389  					if not silent then
  1390  						if vars and vars.__VARSLEVEL__ then
  1391  							io.write('Level: '..vars.__VARSLEVEL__..'\n')
  1392  						else
  1393  							io.write('No level set\n')
  1394  						end
  1395  					end
  1396  					ev = events.SET
  1397  					next = 'ask'
  1398  				else
  1399  					io.write('Unknown command from debugger_loop: '..tostring(next)..'\n')
  1400  					io.write('Stopping debugger\n')
  1401  					next = 'stop'
  1402  				end
  1403  			end
  1404  		end
  1405  	end
  1406  
  1407  
  1408  	--{{{  function hook()
  1409  
  1410  	--
  1411  	-- Init and Register Debug Hook
  1412  	--
  1413  	--function hook()
  1414  
  1415  	function __debugger.hook()
  1416  		--set to stop when get out of pause()
  1417  		trace_level[current_thread] = 0
  1418  		step_level [current_thread] = 0
  1419  		stack_level[current_thread] = 1
  1420  		step_lines = 1
  1421  		step_into = true
  1422  		started    = true
  1423  		skip_pause_for_init = true
  1424  
  1425  		debug.sethook(debug_hook, 'l')   
  1426  	end
  1427  
  1428  	--}}}
  1429  	--{{{  function dump(v,depth)
  1430  
  1431  	--shows the value of the given variable, only really useful
  1432  	--when the variable is a table
  1433  	--see dump debug command hints for full semantics
  1434  
  1435  	local function dump(v,depth)
  1436  		dumpvar(v,(depth or 1)+1,tostring(v))
  1437  	end
  1438  
  1439  	--}}}
  1440  
  1441  	return __debugger
  1442  end
  1443  
  1444  require('__debugger').hook()
  1445  `)
  1446  }