Re: BREAKing into Euphoria
- Posted by abuaf Jan 24, 2022
- 1883 views
Quoted code was ok, but you can't invoke trace in a callback. You can queue a trace by patching TraceOn=1 in eu client app (i got the virtual address from gnu disasm - sorry just cut and paste the asm into euphoria - anyone rewrite this in euphoria?); so this works for official eu 4.1.0 download (https://github.com/EuphoriaLanguages/Friendly_Flexible_Fast/raw/OpenEuphoria/euphoria-4.1.0-x86.exe). Update allow_break() machine call should be enhanced to take &2= set TraceOn, &4= color_trace=1, but i'm too lazy to recompile the sources. Anyway my code below correctly pops up the debugger at the next trace'able code whenever the user presses the break keys. It also demonstrates iup timeslicing some heavy foreground processing while updating the iup (windows) gui message pipe to minimize iup callback 'involvement'. If you press 'q' when entering text into the control, you'll break out to the debugger which allows you focused debugging of gui elements; see the 'tr()' conditional trace func. If press break in the console, you'll popup the debugger at the next iup client callback event handler. Now only if the debugger had pageup/down???
-- test.ex IupText Example in C --Creates a IupText that shows asterisks instead of characters (password-like)./ include euphoria/debug/debug.e include std/os.e --include dll.e --include machine.e include gui/iup/iup.e include gui/iup/iup_config.e include std/console.e sequence add_code = { --do trace(1) in "without trace" code, so the debugger pops up in the next "with trace" code. -- Eu trace(1) in "without trace" code is optimized away, and debugger never pops up. #c7, #05, #20, #1a, #5b, #00, -- movl $0x1,0x5b1a20 ie TraceOn=1 #01, #00, #00, #00, #c7, #05, #40, #14, #5b, #00, -- movl $0x1,0x5b1440 ie color_trace = TRUE; --ie ensures the debugger pops up in color (not static uninit value of 0 ie B/W) #01, #00, #00, #00, --#C2, #00, #08 * (platform() = WINDOWS) -- ret 8 #c3 -- ret } atom code_space = allocate_code(add_code) integer code_space_rid = define_c_proc("", code_space, {}) global procedure tr(object condition={}, sequence errorMessage={}) --atom condition <> 0, then print errorMessage, else ignore. Eg tr(1>0, {"%s %d", "five=", 5}) --string 'condition' for simple error message if atom(condition) and condition = 0 then return end if --failed condition if its numeric if length(errorMessage) >= 2 and sequence(errorMessage[1]) then --formatting string, args ... errorMessage=sprintf(errorMessage[1], errorMessage[2..$]) end if if atom(condition) then condition=sprintf("%d", condition) elsif length(condition) then errorMessage=sprintf("%s %s", {condition, errorMessage}) condition="" end if if length(errorMessage) or length(condition) then --non-empty string, so elaborate error printf(1, "\ntr(%s): %s\n", {condition, errorMessage}) end if c_func(xSetForegroundWindow, {hCon} ) --switch to (debugger) console window c_proc(code_space_rid, {}) --trace out to the debugger at next "with trace" code. end procedure function breakProc(integer event) c_proc(code_space_rid, {}) --trace out to the debugger at next "with trace" code. return 1 --handled the control signal so return TRUE for no further action. end function type Ihandle( object x ) return 1 end type with trace Ihandle text, dlg, pwd sequence password function k_any( Ihandle self, atom c ) tr(c='q', {"Debugging IUP client callback, c=%d", c}) switch (c) do case K_BS then integer size = length(password) if equal(size , 0) then return IUP_IGNORE end if password[size-1] = 0 IupSetAttribute(pwd, "VALUE", password) return IUP_DEFAULT case K_CR then case K_SP then case K_ESC then case K_INS then case K_DEL then case K_TAB then case K_HOME then case K_UP then case K_PGUP then case K_LEFT then case K_MIDDLE then case K_RIGHT then case K_END then case K_DOWN then case K_PGDN then return IUP_IGNORE case else return IUP_DEFAULT end switch return 1 end function function action( Ihandle self, integer c, atom after ) if (c) then integer size = length(password) password[size-1] = c password[size] = 0 IupSetAttribute(pwd, "VALUE", password) end if return K_asterisk end function --atom kernel32, xSetConsoleCtrlHandler, cbHR atom xSetConsoleCtrlHandler, cbHR procedure noIup() while 1 do puts(1,"sleeping press q to quit, break to debug\n") sleep(2) puts(1,"awake\n") if get_key() = 'q' then exit end if end while end procedure without trace function main( object argc, object argv ) IupOpen( argc, argv ) password = repeat(0,100) xSetConsoleCtrlHandler = define_c_func(kernel32,"SetConsoleCtrlHandler", {C_POINTER, -- PHANDLER_ROUTINE pHandlerRoutine, // address of handler function C_INT}, -- BOOL fAdd // handler to add or remove C_INT) -- BOOL cbHR = call_back(routine_id("breakProc")) --{’+’, id} for cdecl if not c_func(xSetConsoleCtrlHandler,{cbHR,1}) then ?9/0 end if noIup() text = IupText(NULL) IupSetAttribute(text, "SIZE", "200x") IupSetCallback(text, "ACTION", Icallback("action")) IupSetCallback(text, "K_ANY", Icallback("k_any")) pwd = IupText(NULL) IupSetAttribute(pwd, "READONLY", "YES") IupSetAttribute(pwd, "SIZE", "200x") dlg = IupDialog(IupVbox({text, pwd, NULL})) IupSetAttribute(dlg, "TITLE", "IupText") IupShowXY(dlg, IUP_CENTER, IUP_CENTER) -- IupMainLoop() --blocks this foreground process until user closes GUI loop do ? hCon & date() printf(1, "Press break to debug ") sleep(.01) --do a short (10mSec) bit of forground timeslicing here until IupLoopStep() = IUP_CLOSE --docs say this should be called within a callback end loop IupClose() return EXIT_SUCCESS end function constant kernel32 = open_dll( "kernel32.dll" ) constant xGetConsoleWindow = define_c_func( kernel32, "GetConsoleWindow", {}, C_ULONG ) atom hCon = c_func( xGetConsoleWindow, {} ) constant user32 = open_dll( "user32" ) --constant xSetForegroundWindow = define_c_func( user32, "SetForegroundWindow", {C_ULONG}, C_ULONG ) constant xSetForegroundWindow = define_c_func( user32, "SetForegroundWindow", {C_ULONG}, C_UINT ) -- BOOL SetForegroundWindow(HWND) sequence cmd = command_line() sequence argv = cmd[3..$] integer argc = length( argv ) main( argc, argv )
Pete Lomax wrote: > > I got some "interesting" results (random crashes mainly) from this, however > enough of it works to show that something is possible (comments, Rob?): > Maybe there is a generic problem with trace in call_back routines?? > > }}} <eucode> > -- NOTE: this is probably incompatible with allow_break/check_break(). > with trace > > include misc.e > > constant CTRL_C_EVENT = 0, > CTRL_BREAK_EVENT = 1 > > function HandlerRoutine(integer event) > if event = CTRL_C_EVENT > or event = CTRL_BREAK_EVENT then > trace(1) > sleep(2) > return 1 -- handled > end if > return 0 -- not handled > end function > > atom kernel32, xSetConsoleCtrlHandler, cbHR > include dll.e > > kernel32 = open_dll("kernel32.dll") > > xSetConsoleCtrlHandler = define_c_func(kernel32,"SetConsoleCtrlHandler", > {C_POINTER, -- PHANDLER_ROUTINE pHandlerRoutine, // address of handler > function > C_INT}, -- BOOL fAdd // handler to add or remove > C_INT) -- BOOL > > cbHR = call_back(routine_id("HandlerRoutine")) > if not c_func(xSetConsoleCtrlHandler,{cbHR,1}) then ?9/0 end if > > with trace > > while 1 do > puts(1,"sleeping\n") > sleep(2) > puts(1,"awake\n") > end while > </eucode> {{{ > > I suspect that if you could somehow call the trace(1) in HandlerRoutine but > not then trace any lines in that code, it might actually work. > > When not interpreting source, or under an allow_break(False), then Ctrl Break > should not attempt to fire up the trace window, otherwise it should. > I don't think changing Ctrl C is a good idea, too easy to accidentally hit, > plus eg Edita happily uses it for Copy w/out problems as is. > > Regards, > Pete Pete, That look pretty much what I was after. I understand that it might well not be possible to trace once the break has been executed, but if I can tell where I am in the program then I can start the safer but more laborious technique of putting in trace(1) - or even trace(3) - calls. At present I have no idea where I am executing when everything dies on me. I just need to go Click! and find out which line of the program was executing at the time. We will see... Andy