mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-16 22:35:41 +00:00
Estimated hours taken: 10
Introduce two new directories, trace and browser, containing libraries
holding the C and Mercury code of the debugger respectively. (Although
the browser directory does not have a browser in it yet, the browser
should soon become its biggest component.) Take the opportunity to
rename the existing libraries, for consistency.
After this change, the linking order becomes:
the object of the auto-generated init file
program object files
trace library (libmer_trace.a)
browser library (libmer_browser.a)
standard library (libmer_std.a)
runtime library (libmer_rt.a)
Boehm collector (libgc.a)
To avoid circularities, libraries cannot contain direct calls to
any routines that are defined in libraries (or object files) that
occur earlier in the above list. Any such calls must be made into
indirect calls via function pointers.
In particular, there was a circularity caused by the library calling
MR_trace() which invokes the tracer which in turn invokes the
library. This circularity was broken by having MR_trace(),
which is defined in the runtime, call the tracer indirectly via
a global variable named MR_trace_func_ptr. This global variable
is initialized by the auto-generated *_init.c file.
To avoid linking in the tracer even when it is not being used,
this global variable is only set to point to MR_trace_real()
if you're using a debugging grade or if c2init was invoked
with the `-t' flag. Otherwise it is set to MR_trace_fake()
which just prints an error message telling the user to
rebuild the executable with debugging enabled.
Makefile.DLLs:
Reserve random locations for the two new libraries. Whether they work
will be decided by testing on Windows.
Mmake.common.in:
Add variables naming the new directories, and create variables
naming the libraries.
Mmakefile:
Add targets for the new directories, and modify existing rules
as appropriate.
browser/Mmakefile:
Mmakefile for the new directory, modelled on library/Mmakefile.
browser/browser_library.m:
Umbrella file for the new directory, modelled on library/library.m.
{browser,library}/debugger_interface.m:
Moved this file from library to browser without change.
browser/help.m:
A new module for the help system of the debugger. Not yet used.
compiler/Mmakefile:
Update to refer to the new directories and libraries where
appropriate.
compiler/mercury_compile.m:
If we are doing tracing, then pass -t instead of -i to c2init.
compiler/modules.m:
When generating the .dep file, get the grade flags passed to c2init.
doc/Mmakefile:
Remove the special treatment of library/debugger_interface.m.
library/Mmakefile:
Update to refer to the new directories and libraries where
appropriate, and to conform to the new name of the library.
library/library.m:
Do not import debugger_interface.
profiler/Mmakefile:
Update to refer to the new directories and libraries where
appropriate.
runtime/Mmakefile:
Update to refer to the new directories and libraries where
appropriate, and to conform to the new name of the library.
Remove references to files being moved to the trace directory.
runtime/mercury_init.h:
Refer to the automatically generated dll header file by its new name
(renamed because the runtime library is renamed).
Add declarations to support the new global variable MR_trace_func_ptr.
runtime/mercury_memory_handlers.c:
runtime/mercury_memory_zones.c:
runtime/mercury_misc.c:
Remove inappropriate #includes of "mercury_trace.h", and substitute
a #include of "mercury_trace_base.h" if necessary.
{runtime,trace}/mercury_trace.[ch]:
{runtime,trace}/mercury_trace_external.[ch]:
{runtime,trace}/mercury_trace_internal.[ch]:
Move these files from the runtime to the trace directory.
The only changes are the removal from mercury_trace.h of declarations
added to runtime/mercury_trace_base.h, and the change from MR_trace
to MR_trace_real.
runtime/mercury_trace_base.[ch]:
Define MR_trace(), which does an indirect call through
MR_trace_func_ptr if the event should be traced.
Define MR_trace_fake, which just prints an error message.
Its address will be assigned to MR_trace_func_ptr if tracing
is not enabled.
Define the types needed by the signature of MR_trace.
Fix an old bug: s/MERCURY_TRACE_PERMANENT_H/MERCURY_TRACE_BASE_H/.
runtime/mercury_wrapper.[ch]:
Add the new global variable MR_trace_func_ptr.
scripts/c2init.in:
Add a new option, -t/--trace, which enables tracing by causing the
address of MR_trace_real to be assigned to MR_trace_func_ptr.
Have this option be implied by the grade. Also have the old option
-i (need initialization code) be implied by the grade, as well as by
-t.
scripts/ml.in:
Include the new libraries in the link command.
tests/debugger/Mmakefile:
Include -t instead of -i in the list of c2init options. (-t implies
-i.)
tools/bootcheck:
Copy and build the new directories as appropriate. The trace directory
is treated like the runtime, the browser directory is treated like the
library.
trace/Mmakefile:
Mmakefile for the new directory, modelled on runtime/Mmakefile.
util/mkinit.c:
Add the new option -t, as discussed above.
Mmakefile for the new directory, modelled on runtime/Mmakefile.
util/Mmakefile:
Specify -O0, since with the default optimization level, gcc on
cyclone ignores the assignment of TRUE to need_tracing when -t is
given (!!!).
379 lines
12 KiB
Mathematica
379 lines
12 KiB
Mathematica
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1998 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
% File: debugger_interface.m
|
|
% Authors: fjh, jahier
|
|
% Purpose:
|
|
% This module provide support routines needed by
|
|
% runtime/mercury_trace_external.c for interfacing to an external
|
|
% (in a different process) debugger, in particular an Opium-style
|
|
% debugger.
|
|
%
|
|
% This module corresponds to what is called the "Query Handler" in Opium.
|
|
|
|
:- module debugger_interface.
|
|
:- interface.
|
|
|
|
% This module exports the following C functions:
|
|
% ML_DI_output_current
|
|
% ML_DI_found_match
|
|
% ML_DI_read_request_from_socket
|
|
% These are used by runtime/mercury_trace_external.c.
|
|
|
|
:- pred dummy_pred_to_avoid_warning_about_nothing_exported is det.
|
|
|
|
:- implementation.
|
|
:- import_module io, require.
|
|
:- import_module list, bool, std_util.
|
|
|
|
dummy_pred_to_avoid_warning_about_nothing_exported.
|
|
|
|
% The stuff defined below is also defined in modules prog_data, hlds_data.
|
|
|
|
:- type arity == int.
|
|
|
|
:- type determinism == int.
|
|
% encoded as specified in ../runtime/mercury_stack_layout.h
|
|
% and ../compiler/stack_layout.m.
|
|
|
|
% The stuff defined below is similar to types goal_path and trace_port
|
|
% defined in modules compiler/hlds_goal.m and compiler/trace.m.
|
|
% This enumeration must be EXACTLY the same as the MR_trace_port enum in
|
|
% runtime/mercury_trace.h, and in the same order, since the code assumes
|
|
% the representation is the same.
|
|
|
|
:- type trace_port_type
|
|
---> call
|
|
; exit
|
|
; fail
|
|
; ite_then
|
|
; ite_else
|
|
; disj
|
|
; switch
|
|
; nondet_pragma_first
|
|
; nondet_pragma_later
|
|
.
|
|
|
|
:- type goal_path_string == string.
|
|
|
|
|
|
|
|
% This is known as "debugger_query" in the Opium documentation.
|
|
% The debugger_request type is used for request sent
|
|
% from the debugger process to the Mercury program being debugged.
|
|
% This type would need to be extended to handle spypoints, etc.
|
|
:- type debugger_request
|
|
---> hello_reply % yes, I'm here
|
|
|
|
% A `forward_move' request instructs the debuggee
|
|
% to step forward until we reach a trace event
|
|
% which matches the specified attributes.
|
|
; forward_move(
|
|
match(event_number),
|
|
match(call_number),
|
|
match(depth_number),
|
|
match(trace_port_type),
|
|
match(string), % module name
|
|
match(string), % pred name
|
|
match(arity),
|
|
match(int), % mode number
|
|
match(determinism),
|
|
match(list(univ)), % the arguments
|
|
% XXX we could provide better ways of
|
|
% matching on arguments
|
|
match(goal_path_string)
|
|
)
|
|
|
|
% A `current_slots' request instructs the debuggee to
|
|
% retrieve the attributes of the current trace
|
|
% event (except for argument slot) and report them
|
|
% to the debugger via the socket.
|
|
; current_slots
|
|
% A `current_vars' request instructs the debuggee to
|
|
% retrieve the list of values and the list of internal
|
|
% names of live variables of the current event and
|
|
% report it to the debugger via the socket.
|
|
; current_vars %
|
|
% XXX should provide a way of getting
|
|
% just part of the arguments
|
|
% (to reduce unnecessary socket traffic)
|
|
% A `current_live_var_names' request instructs the debuggee to
|
|
% retrieve the list of internal names of the currently
|
|
% live variables and a list of their corresponding types.
|
|
; current_live_var_names
|
|
% A 'current_nth_var' request instructs the debuggee to
|
|
% retrieve the specified live variable.
|
|
; current_nth_var(int)
|
|
; abort_prog
|
|
% just abort the program
|
|
; no_trace
|
|
% stop tracing, and run the program to completion
|
|
; error(string)
|
|
% something went wrong when trying to get the
|
|
% next request
|
|
.
|
|
|
|
:- type event_number == int.
|
|
:- type call_number == int.
|
|
:- type depth_number == int.
|
|
|
|
|
|
% `match' is called "get status" in the Opium documentation.
|
|
% This type defines a unary predicate which determines whether
|
|
% or not a particular value will be selected.
|
|
:- type match(T)
|
|
---> nop % nop: value = -
|
|
; exact(T) % exact(X): value = X
|
|
; neg(T) % neg(X): value \= X
|
|
; list(list(T)) % list(L): list__member(value, L)
|
|
; interval(T,T) % interval(Low, High): Low =< X, X =< High
|
|
.
|
|
|
|
|
|
% The debugger_response type is used for response sent
|
|
% to the debugger process from the Mercury program being debugged.
|
|
% This type would need to be extended.
|
|
:- type debugger_response
|
|
% sending hello
|
|
---> hello % are you there?
|
|
% start the synchronous communication with the debugger
|
|
; start
|
|
% responses to forward_move
|
|
; forward_move_match_found
|
|
; forward_move_match_not_found
|
|
% responses to current
|
|
% responses to current_slots
|
|
; current_slots(
|
|
event_number,
|
|
call_number,
|
|
depth_number,
|
|
trace_port_type,
|
|
string, % module name
|
|
string, % pred name
|
|
arity,
|
|
int, % mode number
|
|
determinism,
|
|
goal_path_string
|
|
)
|
|
% responses to current_vars
|
|
; current_vars(list(univ), list(string))
|
|
% reponse to current_nth_var
|
|
; current_nth_var(univ)
|
|
% responses to current_live_var_names
|
|
; current_live_var_names(list(string), list(string))
|
|
% response sent when the last event is reached
|
|
; last_event
|
|
% responses to abort_prog or no_trace
|
|
; ok
|
|
% responses to anything
|
|
; error(string)
|
|
.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
% send to the debugger (e.g. Opium) the wanted features.
|
|
|
|
% output_current_slots "ML_DI_output_current_slots":
|
|
% send to the debugger (e.g. Opium) the attributes of the current event
|
|
% except the list of arguments.
|
|
|
|
:- pragma export(output_current_slots(in, in, in, in, in, in, in, in, in,
|
|
in, in, di, uo), "ML_DI_output_current_slots").
|
|
|
|
:- pred output_current_slots(event_number, call_number, depth_number,
|
|
trace_port_type, /* module name */ string, /* pred name */ string,
|
|
arity, /* mode num */ int, determinism, goal_path_string,
|
|
io__output_stream, io__state, io__state).
|
|
:- mode output_current_slots(in, in, in, in, in, in, in, in, in, in, in,
|
|
di, uo) is det.
|
|
|
|
|
|
output_current_slots(EventNumber, CallNumber, DepthNumber, Port,
|
|
ModuleName, PredName, Arity, ModeNum, Determinism,
|
|
Path, OutputStream) -->
|
|
|
|
{ CurrentTraceInfo = current_slots(EventNumber, CallNumber,
|
|
DepthNumber, Port, ModuleName, PredName, Arity,
|
|
ModeNum, Determinism, Path) },
|
|
io__write(OutputStream, CurrentTraceInfo),
|
|
io__print(OutputStream, ".\n"),
|
|
io__flush_output(OutputStream).
|
|
|
|
% output_current_vars "ML_DI_output_current_vars":
|
|
% send to the debugger the list of the live variables of the current event.
|
|
|
|
:- pragma export(output_current_vars(in, in, in, di, uo), "ML_DI_output_current_vars").
|
|
|
|
:- pred output_current_vars(list(univ), list(string),
|
|
io__output_stream, io__state, io__state).
|
|
:- mode output_current_vars(in, in, in, di, uo) is det.
|
|
|
|
|
|
output_current_vars(VarList, StringList, OutputStream) -->
|
|
|
|
{ CurrentTraceInfo = current_vars(VarList, StringList) },
|
|
io__write(OutputStream, CurrentTraceInfo),
|
|
io__print(OutputStream, ".\n"),
|
|
io__flush_output(OutputStream).
|
|
|
|
% output_current_nth_var "ML_DI_output_current_nth_var":
|
|
% send to the debugger the requested live variable of the current event.
|
|
|
|
:- pragma export(output_current_nth_var(in, in, di, uo), "ML_DI_output_current_nth_var").
|
|
|
|
:- pred output_current_nth_var(univ, io__output_stream, io__state, io__state).
|
|
:- mode output_current_nth_var(in, in, di, uo) is det.
|
|
|
|
|
|
output_current_nth_var(Var, OutputStream) -->
|
|
|
|
{ CurrentTraceInfo = current_nth_var(Var) },
|
|
io__write(OutputStream, CurrentTraceInfo),
|
|
io__print(OutputStream, ".\n"),
|
|
io__flush_output(OutputStream).
|
|
|
|
|
|
:- pragma export(output_current_live_var_names(in, in, in, di, uo),
|
|
"ML_DI_output_current_live_var_names").
|
|
|
|
:- pred output_current_live_var_names(list(string), list(string),
|
|
io__output_stream, io__state, io__state).
|
|
:- mode output_current_live_var_names(in, in, in, di, uo) is det.
|
|
|
|
|
|
output_current_live_var_names(LiveVarNameList, LiveVarTypeList,
|
|
OutputStream) -->
|
|
|
|
{ CurrentTraceInfo = current_live_var_names(
|
|
LiveVarNameList, LiveVarTypeList) },
|
|
io__write(OutputStream, CurrentTraceInfo),
|
|
io__print(OutputStream, ".\n"),
|
|
io__flush_output(OutputStream).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pragma export(get_var_number(in) = out, "ML_DI_get_var_number").
|
|
|
|
:- func get_var_number(debugger_request) = int.
|
|
:- mode get_var_number(in) = out is det.
|
|
% This function is intended to retrieve the integer in
|
|
% "current_nth_var(int)" requests.
|
|
|
|
get_var_number(DebuggerRequest) = VarNumber :-
|
|
(
|
|
DebuggerRequest = current_nth_var(Var)
|
|
->
|
|
Var = VarNumber
|
|
;
|
|
error("get_var_number: not a current_nth_var request")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pragma export(found_match(in, in, in, in, in, in, in, in, in, in,
|
|
in, in), "ML_DI_found_match").
|
|
|
|
:- pred found_match(event_number, call_number, depth_number, trace_port_type,
|
|
/* module name */ string, /* pred name */ string, arity,
|
|
/* mode num */ int, determinism, /* the arguments */ list(univ),
|
|
% XXX we could provide better ways of
|
|
% matching on arguments
|
|
goal_path_string, debugger_request).
|
|
:- mode found_match(in, in, in, in, in, in, in, in, in, in, in, in)
|
|
is semidet.
|
|
|
|
found_match(EventNumber, CallNumber, DepthNumber, Port, ModuleName,
|
|
PredName, Arity, ModeNum, Determinism, Args, Path,
|
|
DebuggerRequest) :-
|
|
(
|
|
DebuggerRequest = forward_move(MatchEventNumber,
|
|
MatchCallNumber, MatchDepthNumber, MatchPort,
|
|
MatchModuleName, MatchPredName, MatchArity,
|
|
MatchModeNum, MatchDeterminism, MatchArgs, MatchPath)
|
|
->
|
|
match(MatchEventNumber, EventNumber),
|
|
match(MatchCallNumber, CallNumber),
|
|
match(MatchDepthNumber, DepthNumber),
|
|
match(MatchPort, Port),
|
|
match(MatchModuleName, ModuleName),
|
|
match(MatchPredName, PredName),
|
|
match(MatchArity, Arity),
|
|
match(MatchModeNum, ModeNum),
|
|
match(MatchDeterminism, Determinism),
|
|
match(MatchArgs, Args),
|
|
match(MatchPath, Path)
|
|
;
|
|
error("found_match: forward_move expected")
|
|
).
|
|
|
|
|
|
% match(MatchPattern, Value) is true iff Value matches the specified pattern.
|
|
:- pred match(match(T), T).
|
|
:- mode match(in, in) is semidet.
|
|
|
|
match(nop, _).
|
|
match(exact(X), X).
|
|
match(neg(X), Y) :- X \= Y.
|
|
match(list(L), X) :- list__member(X, L).
|
|
match(interval(Low, High), X) :-
|
|
% X >= Low, X =< High
|
|
compare(LE, X, High),
|
|
(LE = (<) ; LE = (=)),
|
|
compare(GE, X, Low),
|
|
(GE = (>) ; GE = (=)).
|
|
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred read_request_from_socket(io__input_stream, debugger_request, int,
|
|
io__state, io__state).
|
|
|
|
:- mode read_request_from_socket(in, out, out, di, uo) is det.
|
|
|
|
:- pragma export(read_request_from_socket(in, out, out, di, uo),
|
|
"ML_DI_read_request_from_socket").
|
|
|
|
read_request_from_socket(SocketStream, Request, RequestType) -->
|
|
io__read(SocketStream, MaybeRequest),
|
|
( { MaybeRequest = ok(Request0) },
|
|
{ Request = Request0 }
|
|
; { MaybeRequest = error(ErrorMsg, _LineNum) },
|
|
{ Request = error(ErrorMsg) }
|
|
; { MaybeRequest = eof },
|
|
{ Request = error("end of file") }
|
|
),
|
|
{ classify_request(Request, RequestType) }.
|
|
|
|
/***********
|
|
% debugging stuff.
|
|
io__stderr_stream(StdErr),
|
|
io__print(StdErr, "debugger_interface: Receive the Request:+"),
|
|
io__print(StdErr, Request),
|
|
io__print(StdErr, "+ from opium\ndebugger_interface: RequestType = "),
|
|
io__print(StdErr, RequestType),
|
|
io__print(StdErr, ".\n").
|
|
***********/
|
|
|
|
|
|
|
|
:- pred classify_request(debugger_request, int).
|
|
:- mode classify_request(in, out) is det.
|
|
|
|
% the numbers here should match the definition of
|
|
% MR_debugger_request_type in runtime/mercury_trace_external.c.
|
|
|
|
classify_request(hello_reply, 0).
|
|
classify_request(forward_move(_, _, _, _, _, _, _, _, _, _, _), 1).
|
|
classify_request(current_vars, 2).
|
|
classify_request(current_slots, 3).
|
|
classify_request(no_trace, 4).
|
|
classify_request(abort_prog, 5).
|
|
classify_request(error(_), 6).
|
|
classify_request(current_live_var_names, 7).
|
|
classify_request(current_nth_var(_), 8).
|
|
|
|
|
|
%-----------------------------------------------------------------------------%
|