Library debug
Thursday, April 17th, 2008When I worked on the PhotoFiltre Plugins Pack, I imported a library, the PureHTTP one, in order to download files from the Internet without using any API (this made work easier to port to Linux!). Problem was: that’s a library, that sometimes needs to debug stuff. It was using the classical way, I mean : Debug Var.l. In my case, that was really useless. Because that way, it uses the PureBasic debugger. A debugger that’s not included in final application. Moreover, the PhotoFiltre Plugins Pack has his own included debugger that can be launched with command line (-debug), that was that one I wanted to debug. First, I replaced all the appropriate calls by a PPPDebug(Str(Var)) (PPPDebug is the debug function of the PPP, it writes to stdout the strings it receive before it checked debug mode is activated). But doing that way, I was obliged to declare PPPDebug because libs are included before program functions. So, PureHTTP wasn’t a library any longer (it wasn’t independent because of the function used to debug).
I finally found a quite nice solution to get rid of this problem. I implemented a special debug function in the lib, and each debug call was done with that function. The concept of this function is easy to understand. If it’s called without any initialization, it just debug using the old way. Otherwise, it can be initialized to use a specific debug function (that can be outside the lib, of course!). in that case, it just calls the specified function with the string to debug. Let’s see the code:
#DEBUG_RESET = -1
; That’s the function that will be included in Library
; Each time a library function will have to debug something,
; it will have to call it that way LibraryDebug(”Something to debug”)
; The function can be initialized to use program debug function
; passing null string to Text.s and a pointer to the debug function
; In order to reset, just use the constant. When no debug function
; has been defined, it uses debugger.
; This system allows keeping a dependent library using program debugging systems
Procedure LibraryDebug(Text.s, Flag.l = 0)
Static DebugFunction
If Not Text And Flag ; We are defining Debug method
If Flag = #DEBUG_RESET
DebugFunction = 0
Else
DebugFunction = Flag
EndIf
Else ; We are debugging
If DebugFunction
CallFunctionFast(DebugFunction, Text.s) ; Use defined Debug method
Else
Debug “Default: “+Text.s ; Else use debugger
EndIf
EndIf
EndProcedure
The comments are (I think) explicit. To define the function to use, simply call LibraryDebug with null text, and in flag, the address of the function to call. When passing the constant defined upper, the function do a reset, next call will be done as if the function had not been initialized (that feature isn’t in the PureHTTP implementation for PPP, because I don’t need it…). Just a small example to see how it works (even if that’s not hard to understand ;)):
; One way to debug, using console
Procedure DebugConsole(Text.s)
PrintN(”Console: “+Text.s)
EndProcedure
; One way to debug, using message boxes
Procedure DebugRequester(Text.s)
MessageRequester(”Debug”, “Requester: “+Text.s)
EndProcedure
; On way to debug (the easiest), using PB debugger (if activated)
Procedure DebugDebug(Text.s)
Debug “Debug: “+Text.s
EndProcedure
; Sample code
!
OpenConsole()
LibraryDebug(”Something to debug”)
LibraryDebug(”", @DebugConsole())
LibraryDebug(”Something to debug”)
LibraryDebug(”", @DebugRequester())
LibraryDebug(”Something to debug”)
LibraryDebug(”", @DebugDebug())
LibraryDebug(”Something to debug”)
LibraryDebug(”", #DEBUG_RESET)
LibraryDebug(”Something to debug”)
; Wait until user press enter to quit
Input()
Just run it with, or without debugger.
It also exists an easier (a bit only) way to code LibraryDebug, using ASM to avoid the call to CallFunction (and so including the Library lib from PureBasic) whereas we have the function pointer. That way:
Procedure LibraryDebug(Text.s, Flag.l = 0)
Static DebugFunction
If Not Text And Flag ; We are defining Debug method
If Flag = #DEBUG_RESET
DebugFunction = 0
Else
DebugFunction = Flag
EndIf
Else ; We are debugging
! MOV ebx, dword [s_LibraryDebug.v_DebugFunction]
! TEST ebx, ebx
! JZ l_librarydebug_stddbg
! PUSH dword [p.v_Text]
! CALL ebx ; Use defined Debug method
! JMP l_librarydebug_end
LibraryDebug_StdDbg:
Debug Text.s ; Else use debugger
LibraryDebug_End:
! XOR ebx, ebx
EndIf
EndProcedure


