[m-dev.] for review: new debugger command set, part 2

Fergus Henderson fjh at cs.mu.OZ.AU
Tue Jul 7 05:58:59 AEST 1998


On 06-Jul-1998, Zoltan Somogyi <zs at cs.mu.OZ.AU> wrote:
> 
> Index: runtime/mercury_trace_internal.c
> +#include <unistd.h>

Please document why.
Non-ANSI depencies ought to be minimized.

> +extern	int	optind;

I suggest `#include "mercury_getopt.h"' instead.

> +#define	MR_INIT_SPY_POINTS	10

Please document what that macro is for.

> +/* If you add a usage message, add it to MR_trace_help as well. */
> +static	char	step_usage[] = "step [-NSans] [<number>]";
> +static	char	goto_usage[] = "goto [-NSans] <number>";
> +static	char	finish_usage[] = "finish [-NSans]";
> +static	char	forward_usage[] = "forward [-NSans]";
> +static	char	continue_usage[] = "continue [-NSans]";
> +static	char	restart_usage[] = "restart";
> +static	char	level_usage[] = "level <number>";
> +static	char	up_usage[] = "up <number>";
> +static	char	down_usage[] = "down <number>";
> +static	char	vars_usage[] = "vars";
> +static	char	print_usage[] = "print (<number> | *)";
> +static	char	stack_usage[] = "stack";
> +static	char	stack_regs_usage[] = "stack_regs";
> +static	char	break_usage[] = "break (info | [-PSaei] (<module> <pred> [<arity> [<mode>]] | here))";
> +static	char	enable_usage[] = "enable (<number> | *)";
> +static	char	disable_usage[] = "disable (<number> | *)";
> +static	char	register_usage[] = "register";
> +static	char	module_table_usage[] = "module_table";
> +#ifdef	MR_TRACE_HISTOGRAM
> +static	char	histogram_all_usage[] = "histogram_all";
> +static	char	histogram_exp_usage[] = "histogram_exp";
> +static	char	clear_histogram_usage[] = "clear_histogram";
> +#endif
> +static	char	printlevel_usage[] = "printlevel [none | some | all]";
> +static	char	scroll_usage[] = "scroll [on | off]";
> +static	char	echo_usage[] = "echo [on | off]";
> +static	char	help_usage[] = "help";
> +static	char	quit_usage[] = "quit";

s/char/const char/g

The use of `(', '|' and ')' is confusing, IMHO.
I think it would be better to list the different possibilities
on different lines, e.g.

	Usage:
		enable <number>
		enable *

The complicated syntax for the procedure specifier in the
"break" command is also confusing; I think it would be better
to describe it as taking a <procedure specifier> and then
describe what the syntax for that is, e.g. something like

	Usage:
		break <procedure specifier>
		break here
		break info
	where
		a <procedure specifier> is of the form
			<module> <name> [<arity> [<mode>]]
		<module> is the module name
		<name> is the predicate or function name
		<arity> is the number of arguments
		<mode> is the mode number (0 for the first mode,
			1 for the second mode, etc.)

with the stuff after `where' not appearing in the general summary.

Speaking of which, a `help <command>' command would be helpful! ;-)

> +	/*
> +	** These globals can be overwritten when we call Mercury code,
> +	** such as the term browser. We therefore save and restore them
> +	** across calls to MR_trace_debug_cmd. However, we store the
> +	** saved values in global instead of local variables, to allow them
> +	** to be modified by MR_trace_restart().
> +	*/
> +
> +	MR_trace_saved_call_seqno = MR_trace_call_seqno;
> +	MR_trace_saved_call_depth = MR_trace_call_depth;
> +	MR_trace_saved_event_number = MR_trace_event_number;

These variables (both those on LHS and RHS) should all be thread-local,
in case you're running two copies of the debugger to debug two concurrent
threads.

The way to make them thread-local is to put them in the MercuryEngine
structure.

It may be best to leave worrying about that to a seperate change,
but please at least put an XXX comment for it.

> +static void
> +MR_trace_internal_ensure_init(void)
> +{
> +	static	bool	done = FALSE;
> +
> +	if (! done) {
> +		printf("Melbourne Mercury Debugger\n");
> +		done = TRUE;
> +	}
> +}

Let me bring your attention to 2(c) in the GPL:

 |     c) If the modified program normally reads commands interactively
 |     when run, you must cause it, when started running for such
 |     interactive use in the most ordinary way, to print or display an
 |     announcement including an appropriate copyright notice and a
 |     notice that there is no warranty (or else, saying that you provide
 |     a warranty) and that users may redistribute the program under
 |     these conditions, and telling the user how to view a copy of this
 |     License.  (Exception: if the Program itself is interactive but
 |     does not normally print such an announcement, your work based on
 |     the Program is not required to print an announcement.)

So if you're going to print any announcement, then you need to
include something similar to that printed by gdb:

 | GDB is free software and you are welcome to distribute copies of it
 |  under certain conditions; type "show copying" to see the conditions.
 | There is absolutely no warranty for GDB; type "show warranty" for details.
 | GDB 4.14 (alpha-dec-osf3.2), Copyright 1995 Free Software Foundation, Inc.

> +	} else if (streq(words[0], "break")) {

This is a very long function; it might be better to
split out the code for each command into seperate
subroutines.  The code for handling "break", at least,
is quite long and complex and should be a seperate
subroutine.  Also, there's a lot of duplicate code in the
handling of that case, which should be avoided.

Instead of having a seperate function for each possibility,
i.e. whether the module, arity, or proc number were specified,
you should have a single function which gets passed a
MR_Proc_Specifier struct, whose fields can have special
values that indicate "any", e.g. a NULL module name means
any module matches.

>  static void
> +MR_trace_restart(const MR_Stack_Layout_Label *this_label, int seqno, int depth)
> +{
> +	args = checked_malloc(arg_max * sizeof(Word));

Storage allocated by checked_malloc() is NOT scanned by the conservative
garbage collector.  Either you should add a comment indicating your
reasoning as to why this should use checked_malloc(), or you should use
make_array() [which calls newmem(), which calls GC_MALLOC(),
which calls GC_malloc()] instead.

You should check all your other calls to checked_malloc() too.

Also it would be useful to define a macro like make_array() which
calls checked_malloc() instead of newmem(), and to use it rather
than calling checked_malloc() directly.

> +static Word
> +MR_trace_find_input_arg(const MR_Stack_Layout_Label *label,
> +	const char *name, bool *succeeded)
> +{
...
> +				TRUE, MR_saved_sp(MR_saved_regs), MR_saved_curfr(MR_saved_regs), succeeded);

Please wrap that line.

> +bool
> +MR_event_matches_spy_point(const MR_Stack_Layout_Label *layout,
> +	MR_Trace_Port port, MR_Spy_Action *action_ptr)
> +{
...
> +	hi = MR_spied_procs_next-1;

s/-/ - /

> +	found = FALSE;
> +	while (lo <= hi) {
> +		mid = (lo + hi) / 2;
> +		if (MR_spied_procs[mid].spy_proc == entry) {
> +			found = TRUE;
> +			break;
> +		} else if (MR_spied_procs[mid].spy_proc < entry) {
> +			lo = mid + 1;
> +		} else {
> +			hi = mid - 1;
> +		}
> +	}
> +
> +	if (! found) {
> +		return FALSE;
> +	}
> +
> +	enabled = FALSE;
> +	action = MR_SPY_PRINT;
> +	for (point = MR_spied_procs[mid].spy_points; point != NULL;
> +			point = point->spy_next) {
> +		if (! point->spy_enabled) {
> +			continue;
> +		}
> +
> +		switch (point->spy_when) {
> +
> +			case MR_SPY_ALL:
> +				enabled = TRUE;
> +				action = max(action, point->spy_action);

You need a `break;' here, I think.

> +			case MR_SPY_ENTRY:
> +				if (MR_port_is_entry(port)) {
> +					enabled = TRUE;
> +					action = max(action, point->spy_action);
> +				} else {
> +					continue;
> +				}

Ditto.

> +			case MR_SPY_INTERFACE:
> +				if (MR_port_is_interface(port)) {
> +					enabled = TRUE;
> +					action = max(action, point->spy_action);
> +				} else {
> +					continue;
> +				}

Ditto.

> +			case MR_SPY_SPECIFIC:
> +				if (layout == point->spy_label) {
> +					enabled = TRUE;
> +					action = max(action, point->spy_action);
> +				} else {
> +					continue;
> +				}

Ditto.

> +MR_Spy_Point *
> +MR_add_spy_point(MR_Spy_When when, MR_Spy_Action action,
> +	const MR_Stack_Layout_Entry *entry, const MR_Stack_Layout_Label *label,
> +	const char *path)
> +{
> +	MR_Spy_Point	*point;
> +	int		lo;
> +	int		hi;
> +	int		mid;
> +	bool		found;
> +
> +	lo = 0;
> +	hi = MR_spied_procs_next-1;
> +	found = FALSE;
> +	while (lo <= hi) {
> +		mid = (lo + hi) / 2;
> +		if (MR_spied_procs[mid].spy_proc == entry) {
> +			found = TRUE;
> +			break;
> +		} else if (MR_spied_procs[mid].spy_proc < entry) {
> +			lo = mid + 1;
> +		} else {
> +			hi = mid - 1;
> +		}
> +	}
> +
> +	if (! found) {

I detect some duplicate code, that ought to be in a subroutine.

> +		/* make sure the MR_spied_procs array is big enough */
> +		if (MR_spied_procs_next >= MR_spied_procs_max) {
> +			if (MR_spied_procs_max == 0) {
> +				MR_spied_procs_max = INIT_SPY_TABLE_SIZE;
> +				MR_spied_procs = checked_malloc(
> +							MR_spied_procs_max *
> +							sizeof(MR_Spied_Proc));
> +			} else {
> +				MR_spied_procs_max *= 2;
> +				MR_spied_procs = checked_realloc(
> +							MR_spied_procs,
> +							MR_spied_procs_max *
> +							sizeof(MR_Spied_Proc));
> +			}
> +		}

That code fragment too is something I have seen many occurrences of
(although the variable names are always different).
You should use a macro.

> +/*
> +** The only reason why MR_need_move is function is that

s/is function/is a function/

> +** gcc gets an internal error ("fixed or forbidden register was spilled")
> +** if it isn't a function.

Please name the version number and architecture for which this occurs.

(Did you send a bug report to the gcc developers?)

> +static MR_Module_Info *
> +MR_search_module_info(const char *name)
> +{
> +	int	lo;
> +	int	hi;
> +	int	mid;
> +	int	diff;
> +
> +	lo = 0;
> +	hi = MR_module_info_next-1;
> +	while (lo <= hi) {
> +		mid = (lo + hi) / 2;
> +		diff = strcmp(MR_module_infos[mid].MR_module_name, name);
> +		if (diff == 0) {
> +			return &MR_module_infos[mid];
> +		} else if (diff < 0) {
> +			lo = mid + 1;
> +		} else {
> +			hi = mid - 1;
> +		}
> +	}

More duplicate code.

> +static MR_Module_Info *
> +MR_insert_module_info(const char *name)
> +{
> +	int	i;
> +
> +	/* make sure the MR_module_infos array is big enough */
> +	if (MR_module_info_next >= MR_module_info_max) {
> +		if (MR_module_info_max == 0) {
> +			MR_module_info_max = INIT_MODULE_TABLE_SIZE;
> +			MR_module_infos = checked_malloc(
> +						MR_module_info_max *
> +						sizeof(MR_Module_Info));
> +		} else {
> +			MR_module_info_max *= 2;
> +			MR_module_infos = checked_realloc(
> +						MR_module_infos,
> +						MR_module_info_max *
> +						sizeof(MR_Module_Info));
> +		}
> +	}

Ditto.

> Index: runtime/mercury_trace_tables.h
> +extern	void		MR_register_all_modules_and_procs(FILE *fp);
> +extern	void		MR_dump_module_tables(FILE *fp);
> +
> +extern	const MR_Stack_Layout_Entry
> +			*MR_search_for_module_proc(const char *module_name,
> +				const char *pred_name, bool *unique);
> +extern	const MR_Stack_Layout_Entry
> +			*MR_search_for_module_proc_arity(const char
> +				*module_name, const char *pred_name,
> +				int arity, bool *unique);
> +extern	const MR_Stack_Layout_Entry
> +			*MR_search_for_module_proc_arity_mode(const char
> +				*module_name, const char *pred_name,
> +				int arity, int mode, bool *unique);
> +extern	const MR_Stack_Layout_Entry
> +			*MR_search_for_module_proc_arity_mode_pf(const char
> +				*module_name, const char *pred_name,
> +				int arity, int mode, MR_PredFunc predfunc,
> +				bool *unique);
> +extern	void		MR_process_all_module_proc(
> +				void f(const MR_Stack_Layout_Entry *),
> +				const char *module_name, const char *pred_name);
> +extern	void		MR_process_all_module_proc_arity(
> +				void f(const MR_Stack_Layout_Entry *),
> +				const char *module_name, const char *pred_name,
> +				int arity);
> +extern	void		MR_process_all_module_proc_arity_mode(
> +				void f(const MR_Stack_Layout_Entry *),
> +				const char *module_name, const char *pred_name,
> +				int arity, int mode);
> +extern	void		MR_process_all_module_proc_arity_mode_pf(
> +				void f(const MR_Stack_Layout_Entry *),
> +				const char *module_name, const char *pred_name,
> +				int arity, int mode, MR_PredFunc predfunc);

Please document these functions.

> Index: runtime/mercury_trace_util.c
...
> +int
> +MR_trace_get_register_number(MR_Live_Lval locn)
> +{
> +	int	locn_num;
> +	Word	value;
> +
> +	if (MR_LIVE_LVAL_TYPE(locn) == MR_LVAL_TYPE_R) {
> +		return MR_LIVE_LVAL_NUMBER(locn);
> +	} else {
> +		return -1;
> +	}
> +}

Unused variables `value' and `locn_num'.

...
> Index: runtime/mercury_trace_util.h
> +extern	int	MR_trace_get_register_number(MR_Live_Lval locn);

Please document that function; make sure you explain the role of the
magic number -1.

(The other functions declared in that header ought to be documented too...
though not necessarily as part of this change.)

> RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
> retrieving revision 1.15
> diff -u -u -r1.15 mercury_wrapper.c
> --- mercury_wrapper.c	1998/07/03 02:35:41	1.15
> +++ mercury_wrapper.c	1998/07/03 12:18:52
> @@ -710,9 +710,11 @@
>    #ifndef CONSERVATIVE_GC
>  	heap_zone->max      = heap_zone->min;
>    #endif
> +#if 0
>  	detstack_zone->max  = detstack_zone->min;
>  	nondetstack_zone->max = nondetstack_zone->min;
> +#endif
>  #endif
>  
>  	time_at_start = MR_get_user_cpu_miliseconds();
>  	time_at_last_stat = time_at_start;
> @@ -747,10 +749,12 @@
>  		printf("max heap used:      %6ld words\n",
>  			(long) (heap_zone->max - heap_zone->min));
>    #endif
> +  #if 0
>  		printf("max detstack used:  %6ld words\n",
>  			(long)(detstack_zone->max - detstack_zone->min));
>  		printf("max nondstack used: %6ld words\n",
>  			(long) (nondetstack_zone->max - nondetstack_zone->min));
> +  #endif
>  	}
>  #endif

This change was not mentioned in the log message.
I don't understand it.

--------------------

I'd like to see a relative diff next time.

Cheers,
	Fergus.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.



More information about the developers mailing list