Files
mercury/browser/debugger_interface.m
Erwan Jahier 860dd288aa Add line numbers in Morphine.
Estimated hours taken: 3
Branch: main


Add line numbers in Morphine.

trace/mercury_trace_external.c
	Modify MR_output_current_slots() so that it takes a MR_Event_Info *
	rather than a MR_Label_Layout *. The reason is that I need it to
	get the parent of the current event. I need the parent of the current
	goal because I want the line number where the call is made,
	not the one where the procedure is defined.

	Add the line number as an output of ML_DI_output_current_slots_*.


browser/util.m
	Define the line_number type.

browser/debugger_interface.m
	Add the line number as argument of output_current_slots/13.


extras/morphine/source/current_slots.op
	Add the line number as argument of current_attributes/12.

extras/morphine/source/display.op
	Add the line number as argument of attribute_display/12 and
	of the attribute_display parameter.

extras/morphine/source/event_attributes.op
	Define the new event attribute alias.

extras/morphine/non-regression-tests/test_vars.exp:
extras/morphine/non-regression-tests/queens.exp:
	Update the expected output of the non-regression test.

extras/morphine/non-regression-tests/queens.in:
	Disable the testing of the browser as it is currently broken.
2001-06-22 15:20:28 +00:00

669 lines
21 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1998-2001 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 mdb__debugger_interface.
:- interface.
% This module exports the following C functions:
% ML_DI_output_current_slots_user
% ML_DI_output_current_slots_comp
% ML_DI_output_current_vars
% ML_DI_output_current_nth_var
% ML_DI_output_current_live_var_names
% ML_DI_found_match_user
% ML_DI_found_match_comp
% ML_DI_read_request_from_socket
% These are used by trace/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.
:- import_module mdb__interactive_query, mdb__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.
% Depending whether the Opium side is requesting for a user defined procedure
% or a compiler generated one, the event has not exactly the same structure.
% The differences between the two types of event are gathered in a forward_move
% slot of that type.
:- type pred_match --->
% match user-defined preds only
match_user_pred(
match(pred_or_func),
match(string) % declaration module name
)
;
% match compiler-generated preds only
match_compiler_generated_pred(
match(string), % type name
match(string) % type module name
)
;
% match either user-defined or compiler-generated preds
match_any_pred.
% 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),
pred_match,
match(string), % definition 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)
% just abort the program
; abort_prog
% stop tracing, and run the program to completion
; no_trace
% restarts execution at the call port of the call
% corresponding to the current event
; retry
% print the ancestors stack
; stack
% prints the contents of the fixed slots of the
% frames on the nondet stack
; nondet_stack
% print the contents of the virtual machine registers
% that point to the det and nondet stacks
; stack_regs
% something went wrong when trying to get the
% next request
; error(string)
% to type interactive queries
; query(imports)
% to type cc interactive queries
; cc_query(imports)
% to type interactive queries that perform io
; io_query(imports)
% options to compile queries with
; mmc_options(options)
% to call the term browser
; browse(string)
% dynamically link the collect module with the
% current execution
; link_collect(string)
% execute the collect command
; collect
% retrieve the grade the current execution has been
% compiled with
; current_grade
% switch the argument collecting on (for collect request)
; collect_arg_on
% switch the argument collecting off (for collect request)
; collect_arg_off
.
:- 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.
:- 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 for user event
; current_slots_user(
event_number,
call_number,
depth_number,
trace_port_type,
pred_or_func,
string, % declaration module name
string, % definition module name
string, % pred name
arity,
int, % mode number
determinism,
goal_path_string,
line_number
)
% responses to current_slots for compiler generated event
; current_slots_comp(
event_number,
call_number,
depth_number,
trace_port_type,
string, % name type
string, % module type
string, % definition module
string, % pred name
arity,
int, % mode number
determinism,
goal_path_string,
line_number
)
% responses to current_vars
; current_vars(list(univ), list(string))
% responses 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 a successful browse request session
; browser_end
% responses to a successful mmc_option request
; mmc_option_ok
% responses to requests that proceeded successfully
; ok
% responses to requests that went wrong
; error(string)
% responses to stack
% The protocol between the debugger and the debuggee is described is
% trace/mercury_trace_external.c.
; level(int) % stack level
; proc(string, string, string, int, int) % compiler generated proc
; proc(string, string, int, int) % user generated proc
; def_module(string)
; detail(int, int, int)
; (pred)
; (func)
; det(string)
; end_stack
% responses to stack_regs
; stack_regs(int, int, int)
% responses to link_collect
; link_collect_succeeded
; link_collect_failed
% responses to collect
; collect_linked
; collect_not_linked
% responses to current_grade
; grade(string)
% responses to collect
%; collected(collected_type)
% This is commented out because collected_type is unknown at
% compile time since it is defined by users in the dynamically
% linked collect module.
% sent if the execution is not terminated after a collect request
; execution_continuing
% sent if the execution is terminated after a collect request
; execution_terminated
% responses to collect_arg_on
; collect_arg_on_ok
% responses to collect_arg_off
; collect_arg_off_ok
.
%-----------------------------------------------------------------------------%
% send to the debugger (e.g. Opium) the wanted features.
% output_current_slots_user "ML_DI_output_current_slots_user":
% send to the debugger (e.g. Opium) the attributes of the current event
% except the list of arguments.
:- pragma export(output_current_slots_user(in, in, in, in, in, in, in, in,
in, in, in, in, in, in, di, uo), "ML_DI_output_current_slots_user").
:- pred output_current_slots_user(event_number, call_number, depth_number,
trace_port_type, pred_or_func, /* declarated module name */ string,
/* definition module name */ string, /* pred name */ string, arity,
/* mode num */ int, determinism, goal_path_string, line_number,
io__output_stream, io__state, io__state).
:- mode output_current_slots_user(in, in, in, in, in, in, in, in, in, in,
in, in, in, in, di, uo) is det.
output_current_slots_user(EventNumber, CallNumber, DepthNumber, Port,
PredOrFunc, DeclModuleName, DefModuleName, PredName, Arity, ModeNum,
Determinism, Path, LineNo, OutputStream) -->
{ CurrentTraceInfo = current_slots_user(EventNumber, CallNumber,
DepthNumber, Port, PredOrFunc, DeclModuleName, DefModuleName,
PredName, Arity, ModeNum, Determinism, Path, LineNo) },
io__write(OutputStream, CurrentTraceInfo),
io__print(OutputStream, ".\n"),
io__flush_output(OutputStream).
% output_current_slots_comp "ML_DI_output_current_slots_comp":
% send to the debugger (e.g. Opium) the attributes of the current event
% except the list of arguments.
:- pragma export(output_current_slots_comp(in, in, in, in, in, in, in,
in, in, in, in, in, in, in, di, uo), "ML_DI_output_current_slots_comp").
:- pred output_current_slots_comp(event_number, call_number, depth_number,
trace_port_type, /* name type */ string, /* module type */ string,
/* definition module */ string, /* pred name */ string, arity,
/* mode num */ int, determinism, goal_path_string, line_number,
io__output_stream, io__state, io__state).
:- mode output_current_slots_comp(in, in, in, in, in, in, in, in, in, in,
in, in, in, in, di, uo) is det.
output_current_slots_comp(EventNumber, CallNumber, DepthNumber, Port,
NameType, ModuleType, DefModuleName, PredName, Arity,
ModeNum, Determinism, Path, LineNo, OutputStream) -->
{ CurrentTraceInfo = current_slots_comp(EventNumber, CallNumber,
DepthNumber, Port, NameType, ModuleType, DefModuleName,
PredName, Arity, ModeNum, Determinism, Path, LineNo) },
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_user(in, in, in, in, in, in, in, in, in, in, in,
in, in, in), "ML_DI_found_match_user").
:- pred found_match_user(event_number, call_number, depth_number,
trace_port_type, pred_or_func, /* declarated module name */ string,
/* defined 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_user(in, in, in, in, in, in, in, in, in, in, in, in, in, in)
is semidet.
found_match_user(EventNumber, CallNumber, DepthNumber, Port, PredOrFunc,
DeclModuleName, DefModuleName, PredName, Arity, ModeNum,
Determinism, Args, Path, DebuggerRequest) :-
(
DebuggerRequest = forward_move(MatchEventNumber,
MatchCallNumber, MatchDepthNumber, MatchPort,
UserPredMatch, MatchDefModuleName, MatchPredName,
MatchArity, MatchModeNum, MatchDeterminism,
MatchArgs, MatchPath)
->
match(MatchEventNumber, EventNumber),
match(MatchCallNumber, CallNumber),
match(MatchDepthNumber, DepthNumber),
match(MatchPort, Port),
(
if
UserPredMatch = match_user_pred(
MatchPredOrFunc, MatchDeclModuleName)
then
match(MatchPredOrFunc, PredOrFunc),
match(MatchDeclModuleName, DeclModuleName)
else
UserPredMatch = match_any_pred
),
match(MatchDefModuleName, DefModuleName),
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 = (=)).
:- pragma export(found_match_comp(in, in, in, in, in, in, in, in, in, in, in,
in, in, in), "ML_DI_found_match_comp").
:- pred found_match_comp(event_number, call_number, depth_number,
trace_port_type, /* name type */ string, /* module type */ string,
/* definition 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_comp(in, in, in, in, in, in, in, in, in, in, in, in, in, in)
is semidet.
found_match_comp(EventNumber, CallNumber, DepthNumber, Port, NameType,
ModuleType, DefModuleName, PredName, Arity, ModeNum,
Determinism, Args, Path, DebuggerRequest) :-
(
DebuggerRequest = forward_move(MatchEventNumber,
MatchCallNumber, MatchDepthNumber, MatchPort,
CompilerGeneratedPredMatch,
MatchDefModuleName, MatchPredName, MatchArity,
MatchModeNum, MatchDeterminism, MatchArgs, MatchPath)
->
match(MatchEventNumber, EventNumber),
match(MatchCallNumber, CallNumber),
match(MatchDepthNumber, DepthNumber),
match(MatchPort, Port),
(
if
CompilerGeneratedPredMatch =
match_compiler_generated_pred(MatchNameType,
MatchModuleType)
then
match(MatchNameType, NameType),
match(MatchModuleType, ModuleType)
else
CompilerGeneratedPredMatch = match_any_pred
),
match(MatchDefModuleName, DefModuleName),
match(MatchPredName, PredName),
match(MatchArity, Arity),
match(MatchModeNum, ModeNum),
match(MatchDeterminism, Determinism),
match(MatchArgs, Args),
match(MatchPath, Path)
;
error("found_match: forward_move expected")
).
%-----------------------------------------------------------------------------%
:- 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 get_list_modules_to_import(debugger_request, int, imports).
:- mode get_list_modules_to_import(in, out, out) is det.
:- pragma export(get_list_modules_to_import(in, out, out),
"ML_DI_get_list_modules_to_import").
get_list_modules_to_import(DebuggerRequest, ListLength, ModulesList) :-
(
DebuggerRequest = query(List)
->
ModulesList = List
;
DebuggerRequest = cc_query(List)
->
ModulesList = List
;
DebuggerRequest = io_query(List)
->
ModulesList = List
;
error("get_list_modules_to_import: not a query request")
),
length(ModulesList, ListLength).
%-----------------------------------------------------------------------------%
:- pred get_mmc_options(debugger_request, options).
:- mode get_mmc_options(in, out) is det.
:- pragma export(get_mmc_options(in, out), "ML_DI_get_mmc_options").
get_mmc_options(DebuggerRequest, Options) :-
(
DebuggerRequest = mmc_options(Options1)
->
Options = Options1
;
error("get_mmc_options: not a mmc_options request")
).
%-----------------------------------------------------------------------------%
:- pred get_object_file_name(debugger_request, string).
:- mode get_object_file_name(in, out) is det.
:- pragma export(get_object_file_name(in, out), "ML_DI_get_object_file_name").
% This predicate allows mercury_trace_external.c to retrieve the name
% of the object file to link the current execution with from a
% `link_collect(ObjectFileName)' request.
get_object_file_name(DebuggerRequest, ObjectFileName) :-
(
DebuggerRequest = link_collect(ObjectFileName1)
->
ObjectFileName = ObjectFileName1
;
error("get_object_file_name: not a link_collect request")
).
%-----------------------------------------------------------------------------%
:- pred init_mercury_string(string).
:- mode init_mercury_string(out) is det.
:- pragma export(init_mercury_string(out), "ML_DI_init_mercury_string").
init_mercury_string("").
%-----------------------------------------------------------------------------%
:- pred get_variable_name(debugger_request, string).
:- mode get_variable_name(in, out) is det.
:- pragma export(get_variable_name(in, out), "ML_DI_get_variable_name").
% This predicate allows mercury_trace_external.c to retrieve the name
% of the variable to browse from a `browse(var_name)' request.
get_variable_name(DebuggerRequest, Options) :-
(
DebuggerRequest = browse(Options1)
->
Options = Options1
;
error("get_variable_name: not a browse request")
).
%------------------------------------------------------------------------------%
:- 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).
classify_request(retry, 9).
classify_request(stack, 10).
classify_request(nondet_stack, 11).
classify_request(stack_regs, 12).
classify_request(query(_),13).
classify_request(cc_query(_),14).
classify_request(io_query(_),15).
classify_request(mmc_options(_),16).
classify_request(browse(_),17).
classify_request(link_collect(_),18).
classify_request(collect,19).
classify_request(current_grade,20).
classify_request(collect_arg_on,21).
classify_request(collect_arg_off,22).
%-----------------------------------------------------------------------------%