Author Topic: Debug print  (Read 6526 times)

dunkers

  • Senior Community Member
  • Posts: 774
  • Hero Points: 36
Debug print
« on: January 18, 2008, 02:42:11 AM »
When one is debugging some tedious structure-based code one often has the locals window open with some structure spread open as if it were on a disection table, revealing its internals in gory detail. Sometimes one would like a snapshot of the data and an abortive visit to the File|Print menu item is then usually followed by a muffled curse. A flurry of context menu examination and menu poking then tends to result in a printscreen and visit to Paint or similar...

Is there a better way of recording the state of variables during a debugging session? Copy to file, print, anything? Could we have something, please?

Graeme

  • Senior Community Member
  • Posts: 2793
  • Hero Points: 347
Re: Debug print
« Reply #1 on: January 19, 2008, 03:19:29 AM »
When one is debugging some tedious structure-based code one often has the locals window open with some structure spread open as if it were on a disection table, revealing its internals in gory detail. Sometimes one would like a snapshot of the data and an abortive visit to the File|Print menu item is then usually followed by a muffled curse. A flurry of context menu examination and menu poking then tends to result in a printscreen and visit to Paint or similar...

Is there a better way of recording the state of variables during a debugging session? Copy to file, print, anything? Could we have something, please?


You could probably write Slick C code to do this yourself.  Look at debug_gui_update_locals in debuggui.e in slick macros folder - you'll see this code
Code: [Select]
         tree_wid1._TreeBeginUpdate(TREE_ROOT_INDEX);
         status=dbg_update_locals_tree(tree_wid1, TREE_ROOT_INDEX, thread_id, frame_id, null);
         tree_wid1._TreeEndUpdate(TREE_ROOT_INDEX);
         tree_wid1._TreeSortUserInfo(TREE_ROOT_INDEX,'N');
         tree_wid1.debug_gui_reexpand_fields(TREE_ROOT_INDEX);
         tree_wid1.debug_warn_if_empty();
         tree_wid1._TreeSortCol();
         tree_wid1._TreeRefresh();

and see this in debug.sh
Code: [Select]
/**
 * Update the list of local variables for the specified
 * stack frame within the given thread.
 * Each local has three columns:
 * <UL>
 * <LI>variable bitmap (variable or parameter)
 * <LI>local variable name
 * <LI>value of variable
 * </UL>
 *
 * @param tree_wid        window ID of tree control
 * @param tree_index      Index to insert under (TREE_ROOT_INDEX)
 * @param thread_id       Thread ID to look at stack for
 * @param frame_id        ID of Stack frame to inspect
 * @param local_path      (optional) position to start updating tree at
 *
 * @return 0 on success, <0 on error.
 *
 * @categories Debugger_Functions
 */
int dbg_update_locals_tree(int tree_wid,int tree_index,
                           int thread_id,int frame_id,_str local_path=null);

and this
Code: [Select]
void _tbdebug_locals_form.on_create()
{
   dbg_invalidate_views();

   int editable_flag=(debug_session_is_implemented("modify_local")==0)? 0:TREE_BUTTON_EDITABLE;
   ctl_locals_tree._TreeSetColButtonInfo(0,1500,TREE_BUTTON_PUSHBUTTON|TREE_BUTTON_SORT,0,"Name");
   ctl_locals_tree._TreeSetColButtonInfo(1,10000,TREE_BUTTON_PUSHBUTTON|TREE_BUTTON_WRAP|TREE_BUTTON_AUTOSIZE|editable_flag,0,"Value");

   ctl_locals_tree._TreeRetrieveColButtonInfo();
   ctl_locals_tree.p_user=0;

   ...

You can also see in debug_gui_locals_tree() that the locals tree control is a _tree_view named ctl_locals_tree.  In sysobjs.e you'll see it's a control on the _tbdebug_locals_form form.

In debug_gui_update_locals(), after the call to  _TreeRefresh(), you could iterate through the tree yourself and output the variables and values somewhere (e.g. add an extra parameter to the function that defaults to off and when on, it outputs the tree data  - or make a new function similar to debug_gui_update_locals().  For info on iterating through a treeview control, see "Macro functions by category"  -> tree view methods.  You'll see functions like _TreeGetNextSiblingIndex, _TreeGetFirstChildIndex etc.  An itemindex of zero specifies the root of the tree but you use the supplied TREE_ROOT_INDEX macro for this.


Update : Oops, I forgot to check if there is a way to get the info back from the tree control  - if you look at this function in treeview.e

Code: [Select]
void _TreeSaveNodes(TREENODESTATE &state, int index=TREE_ROOT_INDEX)
{
   _TreeGetInfo(index, state.show_children, state.bm1, state.bm2, state.flags);
   state.caption = _TreeGetCaption(index);
   state.current = (index == _TreeCurIndex());
   state.children._makeempty();
   state.user_info = _TreeGetUserInfo(index);

   int numChildren=0;
   if (state.show_children >= 0) {
      int child = _TreeGetFirstChildIndex(index);
      while (child > 0) {
         _TreeSaveNodes(state.children[numChildren++], child);
         child = _TreeGetNextSiblingIndex(child);
      }
   }
}

struct TREENODESTATE {
   _str caption;              // node caption
   int bm1, bm2;              // current and other bitmaps
   int show_children;         // show children (-1, 0, or 1)
   int flags;                 // TREENODE_* flags
   typeless user_info;        // user info for node
   boolean current;           // is this the current item in the tree?
   TREENODESTATE children[];  // list of children under this node
};


you can see it iterating through a tree control.  I'm guessing that "caption" has the variable name and/or value that you want  - you'll have to experiment to find out.  user_info might also be interesting because you can see the call to _TreeSortUserInfo further above.  Hence you could call tree_wid1._TreeSaveNodes in debug_gui_update_locals() to get the info into a slick c data structure, then output it.

Note - it's probably best not to modify debug_gui_update_locals() itself since it's called from event handlers like _tbdebug_locals_form.on_change - slick treeview code is not re-entrant in my experience and also you could destroy things like the "active window/form" which are still needed by the caller, but you can easily make your own function similar to debug_gui_update_locals() and it probably doesn't need to actually update the treeview info.  Hmm, except that the code you add won't be executed unless you call the function yourself so forget the re-entrant problem  - but it's best not to modify slick source if you don't have to so making your own function is best anyway.

Without actually doing it I can't tell if this would be successful but feel free to ask if you want any more help.


Also, you might be able to get the screen co-ordinates and width/height of the locals window (or any window) and find a way to "print" the screen content of that area.  Off the top of my head I don't know how to do this - see functions like AutoCompleteShowList(),  _GetScreen and _adjust_above_below().  If you're using Windows you might find an API call for printing a region of the screen - or ask on a Windows forum.

Graeme
« Last Edit: January 19, 2008, 05:23:34 AM by Graeme »

dunkers

  • Senior Community Member
  • Posts: 774
  • Hero Points: 36
Re: Debug print
« Reply #2 on: January 19, 2008, 02:43:44 PM »
Wow! Thanks for the comprehensive reply, Graeme  :-*

That all looks like it's not a simple thing to implement, and I'm rather tied up in real work to have a go at this right now. Nevertheless, I appreciate the effort you put into looking at this and will get on it when I have  moment (or several!) free.

Thanks very much++ :)

Graeme

  • Senior Community Member
  • Posts: 2793
  • Hero Points: 347
Re: Debug print
« Reply #3 on: January 20, 2008, 06:34:12 AM »
You can try this code if you feel like it  - there wasn't a lot of code involved so I had a go at it.  It compiles in Slick V12 but it's completely untested because I don't use a debugger with slickedit.  It should output something to a debug window.  I'm guessing that "caption" has the text you're interested in and that UserInfo is just for tree sorting purposes.  In case you didn't already know, Ctrl Alt Shift F2 can be used to break out of a loop in Slick C so if this code hangs you can get out of it.  If you decide to try it, and it works, you could replace the call to the "say" debug function with something else.  You can put this code in vusrmacs.e or anywhere you want.

Graeme

Code: [Select]
/*
struct TREENODESTATE {
   _str caption;              // node caption
   int bm1, bm2;              // current and other bitmaps
   int show_children;         // show children (-1, 0, or 1)
   int flags;                 // TREENODE_* flags
   typeless user_info;        // user info for node
   boolean current;           // is this the current item in the tree?
   TREENODESTATE children[];  // list of children under this node
};
*/

static void output_tree_node(TREENODESTATE & node, int indent)
{
   //int this_indent = indent+1;
   //_str sp = '';
   //while(--this_indent) {
   //   sp = sp :+ '  ';
   //}

   _str sp = indent_string(indent * 2);

   sp = sp :+ node.caption;
   say(sp);
   int child_index = 0;
   while (child_index < node.children._length()) {
      output_tree_node(node.children[child_index++], indent+1);
   }
}


_command void debug_gui_output_locals()
{
   TREENODESTATE locals_tree_nodes;
   _control ctl_locals_tree;

   // the locals treeview content isn't meaningful if the current thread
   // is still executing
   if (!debug_is_suspended()) {
      return;
   }

   CTL_FORM form_wid = debug_gui_locals_wid();
   CTL_TREE tree_wid1=(form_wid ? form_wid.ctl_locals_tree:0)

   // don't care if it's active or not ?
   // if (tree_wid1 && _tbIsWidActive(form_wid)) {

   if (tree_wid1){
      locals_tree_nodes.show_children = 12345678;
      locals_tree_nodes.caption == '12345678';
      tree_wid1._TreeSaveNodes(locals_tree_nodes);

      if (locals_tree_nodes.show_children != 12345678 && locals_tree_nodes.caption != '12345678') {
         // output the content of locals_tree_nodes
         output_tree_node(locals_tree_nodes, 0);
      }
   }
}

dunkers

  • Senior Community Member
  • Posts: 774
  • Hero Points: 36
Re: Debug print
« Reply #4 on: January 20, 2008, 01:38:02 PM »
Ah! Brilliant, thanks :)

The locals window pops up a debug window - I've added a screencap so you can see. That window doesn't allow copying or printing either, but it should be simple to use a new file instead. Thanks very much :)

Dennis

  • Senior Community Member
  • Posts: 3954
  • Hero Points: 515
Re: Debug print
« Reply #5 on: January 23, 2008, 11:27:25 PM »
Good suggestion.  We have a somewhat generic API for copying, saving, and printing the text contents of tree controls (almost all the debugger windows are tree controls). 

Code: [Select]
_TreeCopyContents(index, recursive);
_TreeSaveContents(index, recursive);
_TreePrintContents(index, recursive);

You may have noticed that in the Defs tool window and Classes, you can pull down a "Contents" submenu and do these things for the current item, subtree, or the entire tree.

I am hooking the same menu into the debugger windows and slightly enhancing the functions to improve the columnar formatting.  Attached you can see a preview of what SlickEdit 2008 will do for you. 

Here is a sample of the output:

Code: [Select]
     argv           (char **) 0x6694f0
        [0]         "/cygdrive/e/13.0.0/config/SampleProjects/ucpp/Debug/ucpp"
     c1             struct
        i           2280656
        str         0x0
     llllllllllllll 1

Think that's neat?  You haven't seen nothing yet. 

Suppose you do several Save's over the course of a debugging session, and you consistently save them to the same file.  And, you have backup history enabled.  Well, if you want to compare the previous results you saved, all you have to do is pull up File > Backup history for... on your save file, and you can diff any of the versions and see what is happening.

dunkers

  • Senior Community Member
  • Posts: 774
  • Hero Points: 36
Re: Debug print
« Reply #6 on: January 24, 2008, 12:10:57 AM »
Cor! I'm counting the days to 2008 (checks calendar... hmmmm)  ;D

That sounds absolutely brilliant, and might even convince me to use the defs toolbar (which, I'm ashamed to say, I hardly notice exists).