[m-dev.] For review: implementation of collect for Opium-M
Erwan Jahier
Erwan.Jahier at irisa.fr
Fri Oct 29 04:43:11 AEST 1999
| > | Also, the use of MR_Trace_Port
| > | and MR_PredFunc looks dangerous; the type here should exactly match
| > | the type with which the function is defined, and I'll bet that it
| > | will be defined using Integer or Word rather than MR_Trace_Port.
| >
| > Well, collect.m is generated with the help of the file collect.in (which is
| > not typed by users) which contains:
| >
| > % 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_base.h, and in the same order, since the code
| > % assumes the representation is the same.
| >
| > :- type trace_port_type
| > ---> call
| > ; exit
| > ; redo
| > ; fail
| > ...
| >
| > In runtime/mercury_trace_base.h, there is the comment:
| >
| > /*
| > ** This enum should EXACTLY match the definition of the `trace_port_type'
| > ** type in browser/debugger_interface, and the port names list in the
| > ** C source file of this module.
| > */
| >
| > typedef enum {
| > MR_PORT_CALL,
| > MR_PORT_EXIT,
| > ...}
|
| Actually I think that code only assumes that the representation of the
| enum VALUES are the same. I don't think it assumes that the representation
| of the TYPES are the same. (If it does, then that assumption is a bug.)
| In particular, although the same numerical values will be used, the C
| compiler may well choose to use a `short' or `unsigned short' or
| even `unsigned char' type to represent the enum. There is no guarantee
| that the type used will have the same representation and calling convention
| as `Word' or `Integer'.
|
| In particular, for the `pred_or_func'/`MR_PredFunc' type, the enum has
| only two values. The numerical values of these two will always be the
| same (pred = MR_PREDICATE = 0, func = MR_FUNCTION = 1). But a clever C
| compiler might recognize that the MR_PredFunc type has only two values
| and thus might try passing values of type MR_PredFunc in a single-bit
| condition register rather than in a full-word register. The calling
| convention might depend on the type.
|
| It might be best to change the definitions of the types so that
| they are typedefs for `Word' rather than being enums. The enumeration
| constants would of course stay. So the declarations would look like
| this
|
| enum { MR_PORT_CALL, MR_PORT_EXIT, ... };
| typedef Word MR_Trace_Port;
|
| or perhaps like this
|
| typedef enum { MR_PORT_CALL, MR_PORT_EXIT, ... } MR_Trace_Port_Enum;
| typedef Word MR_Trace_Port;
I will do that as a separate change.
Here is the relative diff taking into account your review:
--- logmsg.save Thu Oct 28 19:44:09 1999
+++ logmsg Thu Oct 28 19:57:01 1999
@@ -27,14 +27,24 @@
browser/debugger_interface.m:
Add 2 new debugger requests `link_collect' and `collect':
- (1) `link_collect' to dynamically link the module collect.m with the
- current execution; (2) `collect' to start the monitoring process.
+ (1) `link_collect(ObjectFile)' to dynamically link ObjectFile
+ with the current execution; (2) `collect' to start the monitoring
+ process.
+
+ Define a new predicate get_object_file_name/2 that let the
+ MR_trace_event_external() retrieve the name of the object file
+ available from the `link_collect(string)' request.
+
+ Define a new function get_collecting_variable_type/2 that retrieves
+ the type of a variable. This type is needed in MR_trace_event_external()
+ to be able to call MR_make_permanent() on MR_collecting_variable; we
+ need to do that to ensure that the memory allocated for it won't be
+ deallocated on backtracking.
Add the new request `current_grade' which lets the external debugger
know the grade the current execution has been compiled with; it is
necessary to be able to compile collect.m in the same grade as the
the program being monitored.
-
browser/dl.m:
Move the type definition of the type `handle' to be able to use it in
Index: 0.1/debugger_interface.m
--- 0.1/debugger_interface.m Thu, 28 Oct 1999 12:57:51 +0200 jahier (collect/1_debugger_i 1.1 640)
+++ 0.1(w)/debugger_interface.m Thu, 28 Oct 1999 20:19:39 +0200 jahier (collect/1_debugger_i 1.1 640)
@@ -177,7 +177,7 @@
; browse(string)
% dynamically link the collect module with the
% current execution
- ; link_collect
+ ; link_collect(string)
% execute the collect command
; collect
% retrieve the grade the current execution has been
@@ -602,6 +602,22 @@
;
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 to link 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")
+ ).
%-----------------------------------------------------------------------------%
@@ -629,6 +645,18 @@
error("get_variable_name: not a browse request")
).
+%---------------------------------------------------------------------------%
+
+:- pred get_collecting_variable_type(T, type_info).
+:- mode get_collecting_variable_type(in, out) is det.
+
+:- pragma export(get_collecting_variable_type(in, out),
+ "ML_DI_get_collecting_variable_type").
+ % This predicate allows mercury_trace_external.c to retrieve the name
+ % of the type_info a collecting variable.
+get_collecting_variable_type(CollectVar, Type) :-
+ Type = type_of(CollectVar).
+
%------------------------------------------------------------------------------%
:- pred classify_request(debugger_request, int).
@@ -655,7 +683,7 @@
classify_request(io_query(_),15).
classify_request(mmc_options(_),16).
classify_request(browse(_),17).
-classify_request(link_collect,18).
+classify_request(link_collect(_),18).
classify_request(collect,19).
classify_request(current_grade,20).
Index: 0.1/mercury_trace_external.c
--- 0.1/mercury_trace_external.c Thu, 28 Oct 1999 12:57:51 +0200 jahier (collect/3_mercury_tr 1.1 640)
+++ 0.1(w)/mercury_trace_external.c Thu, 28 Oct 1999 20:24:28 +0200 jahier (collect/3_mercury_tr 1.1 640)
@@ -32,6 +32,7 @@
#include "debugger_interface.h"
#include "collect_lib.h"
#include "std_util.h"
+#include "mercury_deep_copy.h"
#include <stdio.h>
#include <errno.h>
@@ -43,8 +44,11 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
-#include <dlfcn.h>
#include <stdlib.h>
+#ifdef HAVE_DLFCN_H
+ #include <dlfcn.h>
+#endif
+
/*
** This type must match the definition of classify_request in
@@ -93,14 +97,39 @@
/*
** Type of a local variable that indicates in which mode the external
** debugger is. When the external debugger is in mode:
-** - `searching', it tries to find an event that matches a forward move request,
-** - `reading_request', it reads a new request on the socket,
-** - `collecting', it is collecting information (after a `collect' request).
+** - `MR_searching', it tries to find an event that matches a forward
+** move request,
+** - `MR_reading_request', it reads a new request on the socket,
+** - `MR_collecting', it is collecting information (after a `collect' request).
*/
typedef enum {
- searching, reading_request, collecting
+ MR_searching, MR_reading_request, MR_collecting
} MR_external_debugger_mode_type;
+static MR_external_debugger_mode_type
+ external_debugger_mode = MR_reading_request;
+
+/*
+** Global variable that is used to store the information collected during
+** a collect request.
+*/
+
+static Word MR_collecting_variable;
+
+/*
+** Function pointer used to sent the collecting variable to the external
+** debugger.
+*/
+
+static void (*send_collect_result_ptr)(Word, Word);
+
+/*
+** Variable generated during the dynamic linking that is needed to close
+** this linking properly.
+*/
+
+static Word *handle = NULL;
+
/*
** Use a GNU C extension to enforce static type checking
** for printf-style functions.
@@ -146,8 +175,15 @@
Integer *modules_list_length_ptr, Word *modules_list_ptr);
static void MR_get_mmc_options(Word debugger_request,
String *mmc_options_ptr);
+static void MR_get_object_file_name(Word debugger_request,
+ String *objet_file_name_ptr);
static void MR_get_variable_name(Word debugger_request, String *var_name_ptr);
static void MR_trace_browse_one_external(MR_Var_Spec which_var);
+static void MR_COLLECT_filter(Word (*filter_ptr)(Integer, Integer, Integer,
+ Word, Word, String, String, String, Integer, Integer,
+ Integer, String, Word, Word *), Unsigned seqno,
+ Unsigned depth, MR_Trace_Port port,
+ const MR_Stack_Layout_Label *layout, const char *path);
#if 0
This pseudocode should go in the debugger process:
@@ -379,12 +415,29 @@
MR_trace_final_external(void)
{
/*
- ** This can only happen during a forward_move(),
- ** in which case we want to tell the debugger that
- ** no match was found.
+ ** This can only happen during a forward_move or a
+ ** collect request. In the first case, we want to tell
+ ** the debugger that no match was found; in the second
+ ** one we send the result of the collect activity.
*/
- MR_send_message_to_socket("forward_move_match_not_found");
+ switch(external_debugger_mode) {
+ case MR_searching:
+ MR_send_message_to_socket("forward_move_match_not_found");
+ break;
+
+ case MR_collecting:
+ (*send_collect_result_ptr)(
+ (Word) MR_collecting_variable,
+ (Word) &MR_debugger_socket_out);
+ #if defined(HAVE_DLFCN_H)&&defined(HAVE_DLCLOSE)
+ dlclose((void *)handle);
+ #endif
+ break;
+
+ default:
+ fatal_error("Error in the external debugger");
+ }
/*
** Maybe we should loop to process requests from the
** debugger socket here? Currently we just return,
@@ -397,16 +450,11 @@
Code *
MR_trace_event_external(MR_Trace_Cmd_Info *cmd, MR_Event_Info *event_info)
{
- static MR_external_debugger_mode_type
- external_debugger_mode = reading_request;
static Word search_data;
- static Word collecting_variable;
- static Word (*initialize_ptr)(Word *) = NULL;
+ static void (*initialize_ptr)(Word *) = NULL;
static Word (*filter_ptr)(Integer, Integer, Integer, MR_Trace_Port,
MR_PredFunc, String, String, String, Integer,
Integer, Integer, String, Word, Word *) = NULL;
- static Word (*send_collect_result_ptr)(Word, Word);
- static Word *handle = NULL;
static bool collect_linked = FALSE;
Integer debugger_request_type;
Integer live_var_number;
@@ -428,6 +476,7 @@
Integer modules_list_length;
Word modules_list;
static String MR_mmc_options;
+ static String MR_object_file_name;
MR_trace_enabled = FALSE;
@@ -445,7 +494,7 @@
/*
** MR_mmc_options contains the options to pass to mmc when compiling
- ** queries. We initialise it to the String "".
+ ** queries. We initialize it to the String "".
*/
MR_TRACE_CALL_MERCURY(ML_DI_init_mercury_string(&MR_mmc_options));
@@ -453,8 +502,8 @@
event_info->MR_saved_regs);
- switch((MR_external_debugger_mode_type) external_debugger_mode) {
- case searching:
+ switch(external_debugger_mode) {
+ case MR_searching:
/*
** XXX should also pass registers here, since they're
** needed for checking for matches with the arguments
@@ -464,56 +513,32 @@
{
MR_send_message_to_socket(
"forward_move_match_found");
- external_debugger_mode = reading_request;
+ external_debugger_mode = MR_reading_request;
} else {
goto done;
}
break;
- case collecting:
- if (seqno == 1 && port == MR_PORT_EXIT) {
- /* The end of the execution is reached */
- (*send_collect_result_ptr)(
- collecting_variable,
- (Word) &MR_debugger_socket_out);
- #if defined(HAVE_DLFCN_H)&&defined(HAVE_DLCLOSE)
- dlclose((void *)handle);
- #endif
- } else {
- /*
- ** XXX Add a another request that takes
- ** arguments into account. We need two kinds
- ** of request in order to not penalize the
- ** performance of collect in the cases where
- ** arguments are not used.
- **
- ** arguments = MR_make_var_list(layout,
- ** saved_regs);
- */
- (*filter_ptr)(
- MR_trace_event_number,
- seqno,
- depth,
- port,
- layout->MR_sll_entry->MR_sle_user.MR_user_pred_or_func,
- (String)
- layout->MR_sll_entry->MR_sle_user.MR_user_decl_module,
- (String)
- layout->MR_sll_entry->MR_sle_user.MR_user_def_module,
- (String)
- layout->MR_sll_entry->MR_sle_user.MR_user_name,
- layout->MR_sll_entry->MR_sle_user.MR_user_arity,
- layout->MR_sll_entry->MR_sle_user.MR_user_mode,
- layout->MR_sll_entry->MR_sle_detism,
- (String) path,
- (Word) collecting_variable,
- &collecting_variable);
- goto done;
- }
-
- break;
+ case MR_collecting:
+ /*
+ ** XXX Add a another request that takes
+ ** arguments into account. We need two kinds
+ ** of request in order to not penalize the
+ ** performance of collect in the cases where
+ ** arguments are not used.
+ **
+ ** arguments = MR_make_var_list(layout, saved_regs);
+ */
+ MR_COLLECT_filter(
+ *filter_ptr,
+ (Unsigned) seqno,
+ (Unsigned) depth,
+ (MR_Trace_Port) port,
+ layout,
+ path);
+ goto done;
- case reading_request:
+ case MR_reading_request:
break;
default:
@@ -534,7 +559,7 @@
"FORWARD_MOVE\n");
}
search_data = debugger_request;
- external_debugger_mode = searching;
+ external_debugger_mode = MR_searching;
goto done;
case MR_REQUEST_CURRENT_LIVE_VAR_NAMES:
@@ -730,23 +755,40 @@
case MR_REQUEST_LINK_COLLECT:
{
Char result;
+ Word MR_collecting_variable_type;
+ Word *MR_collecting_variable_type_info=NULL;
if (MR_debug_socket) {
fprintf(stderr, "\nMercury runtime: "
"REQUEST_LINK_COLLECT\n");
}
+ MR_get_object_file_name(debugger_request,
+ &MR_object_file_name);
MR_TRACE_CALL_MERCURY(
ML_DI_link_collect(
+ MR_object_file_name,
(Word *) &filter_ptr,
(Word *) &initialize_ptr,
(Word *) &send_collect_result_ptr,
(Word *) &handle,
- (Char *) &result
+ &result
));
collect_linked = (result == 'y');
if (collect_linked) {
MR_send_message_to_socket(
"link_collect_succeeded");
+ MR_TRACE_CALL_MERCURY(
+ ML_DI_get_collecting_variable_type(
+ (Word)
+ MR_collecting_variable_type_info,
+ MR_collecting_variable,
+ (Word *)
+ &MR_collecting_variable_type));
+ MR_collecting_variable =
+ MR_make_permanent(
+ MR_collecting_variable,
+ (Word *)
+ MR_collecting_variable_type);
} else {
MR_send_message_to_socket(
"link_collect_failed");
@@ -764,33 +806,23 @@
if (collect_linked) {
MR_send_message_to_socket(
"collect_linked");
- external_debugger_mode = collecting;
+ external_debugger_mode = MR_collecting;
MR_TRACE_CALL_MERCURY(
- (*initialize_ptr)(&collecting_variable));
+ (*initialize_ptr)(&MR_collecting_variable));
/*
** In order to perform the collect from
** the current event, we need to call
** filter once here.
*/
- (*filter_ptr)(
- MR_trace_event_number,
- seqno,
- depth,
- port,
- layout->MR_sll_entry->MR_sle_user.MR_user_pred_or_func,
- (String)
- layout->MR_sll_entry->MR_sle_user.MR_user_decl_module,
- (String)
- layout->MR_sll_entry->MR_sle_user.MR_user_def_module,
- (String)
- layout->MR_sll_entry->MR_sle_user.MR_user_name,
- layout->MR_sll_entry->MR_sle_user.MR_user_arity,
- layout->MR_sll_entry->MR_sle_user.MR_user_mode,
- layout->MR_sll_entry->MR_sle_detism,
- (String) path,
- (Word) collecting_variable,
- &collecting_variable);
+ MR_COLLECT_filter(
+ *filter_ptr,
+ (Unsigned) seqno,
+ (Unsigned) depth,
+ (MR_Trace_Port) port,
+ layout,
+ path);
+
goto done;
} else {
MR_send_message_to_socket(
@@ -1360,6 +1392,16 @@
}
static void
+MR_get_object_file_name(Word debugger_request, String *object_file_name_ptr)
+{
+ MR_TRACE_CALL_MERCURY(
+ ML_DI_get_object_file_name(
+ debugger_request,
+ object_file_name_ptr);
+ );
+}
+
+static void
MR_get_variable_name(Word debugger_request, String *var_name_ptr)
{
MR_TRACE_CALL_MERCURY(
@@ -1387,6 +1429,34 @@
if (problem != NULL) {
MR_send_message_to_socket_format("error(\"%s\").\n", problem);
}
+}
+
+
+/*
+** This function calls the collect filtering predicate defined by the user
+** and dynamically link with the execution.
+*/
+static void
+MR_COLLECT_filter(Word (*filter_ptr)(Integer, Integer, Integer, Word, Word,
+ String, String, String, Integer, Integer, Integer, String, Word, Word *),
+ Unsigned seqno, Unsigned depth, MR_Trace_Port port,
+ const MR_Stack_Layout_Label *layout, const char *path)
+{
+ MR_TRACE_CALL_MERCURY((*filter_ptr)(
+ MR_trace_event_number,
+ seqno,
+ depth,
+ port,
+ layout->MR_sll_entry->MR_sle_user.MR_user_pred_or_func,
+ (String) layout->MR_sll_entry->MR_sle_user.MR_user_decl_module,
+ (String) layout->MR_sll_entry->MR_sle_user.MR_user_def_module,
+ (String) layout->MR_sll_entry->MR_sle_user.MR_user_name,
+ layout->MR_sll_entry->MR_sle_user.MR_user_arity,
+ layout->MR_sll_entry->MR_sle_user.MR_user_mode,
+ layout->MR_sll_entry->MR_sle_detism,
+ (String) path,
+ MR_collecting_variable,
+ &MR_collecting_variable));
}
#endif /* MR_USE_EXTERNAL_DEBUGGER */
--- collect.op Thu Oct 28 20:31:08 1999
+++ projet_en_cours/rmdb/source/collect.op Thu Oct 28 16:24:53 1999
@@ -70,7 +70,7 @@
event until the end of the execution; \n\
*) foldl/4 is the classical fold predicate operating left-to-right. \n\
\n\
-Hence, collect/2 does the same thing as collect_spec/2 except it operates \
+collect/2 does the same thing as collect_spec/2 except it operates \
on the fly without creating any list of events."
).
@@ -107,7 +107,7 @@
).\n\
'\n\
Then the command `collect(count_call, Result)' will unify Result with the \
-number of calls that occurs during the program execution.\
+number of calls that occur during the program execution.\
"
).
@@ -161,16 +161,17 @@
"mmc --grade ",
Grade,
" -O6",
- " -c --pic-reg collect.m"], Command1),
- sh(Command1),
+ " -c --pic-reg collect.m"], Command1),
print(Command1), nl,
+ sh(Command1),
+ exists("collect.o"),
concat_string([
"ml --grade ",
Grade,
" --make-shared-lib ",
"--pic-reg -o collect.so collect.o"], Command2),
- sh(Command2),
print(Command2), nl,
+ sh(Command2),
exists("collect.so"),
!,
opium_write_debug("collect.m has been compiled successfully.\n").
@@ -293,7 +294,7 @@
write("use generate_collect/1 primitive before.\n"),
fail
),
- send_message_to_socket(link_collect),
+ send_message_to_socket(link_collect("\"./collect.so\"")),
read_message_from_socket(Result),
( Result = link_collect_succeeded ->
opium_write_debug("collect.so has been linked successfully.\n")
--- collect.in Thu Oct 28 20:32:15 1999
+++ projet_en_cours/rmdb/source/collect.in Thu Oct 28 19:34:41 1999
@@ -23,13 +23,13 @@
%------------------------------------------------------------------------------%
:- implementation.
-:- pragma export(initialize(out), "Collect_initialize").
+:- pragma export(initialize(out), "ML_COLLECT_initialize").
:- pragma export(filter(in, in, in, in, in, in, in, in, in, in, in, in,
- acc_in, acc_out), "Collect_filter").
+ acc_in, acc_out), "ML_COLLECT_filter").
:- pragma export(send_collect_result(in, in, di, uo),
- "Collect_send_collect_result").
+ "ML_COLLECT_send_collect_result").
:- import_module int, io.
--- collect_lib.m.old Thu Oct 28 20:39:46 1999
+++ collect_lib.m Thu Oct 28 19:33:29 1999
@@ -44,16 +44,16 @@
:- import_module io, char.
% dynamically link the collect module;
-:- pred link_collect(c_pointer, c_pointer, c_pointer, c_pointer, char,
+:- pred link_collect(string, c_pointer, c_pointer, c_pointer, c_pointer, char,
io__state, io__state).
-:- mode link_collect(out, out, out, out, out, di, uo) is det.
+:- mode link_collect(in, out, out, out, out, out, di, uo) is det.
%------------------------------------------------------------------------------%
:- implementation.
:- import_module int, list, std_util, io, char.
-:- import_module name_mangle, dl.
+:- import_module dl.
-:- pragma export(link_collect(out, out, out, out, out, di, uo),
+:- pragma export(link_collect(in, out, out, out, out, out, di, uo),
"ML_DI_link_collect").
% We need Handle to be able to close the shared object (dlclose) later on.
@@ -61,12 +61,12 @@
% for performance reasons; indeed, filter will be called at every events
% so we don't want to pay the price of the maybe variable de-construction
% at each event.
-link_collect(Filter, Initialize, SendResult, HandlePtr, Result) -->
+link_collect(ObjetFile, Filter, Initialize, SendResult, HandlePtr, Result) -->
%
% Link in the object code for the module `collect' from
% the file `collect.so'.
%
- dl__open("./collect.so", lazy, local, MaybeHandle),
+ dl__open(ObjetFile, lazy, local, MaybeHandle),
(
{ MaybeHandle = error(Msg) },
print("dlopen failed: "), print(Msg), nl,
@@ -77,14 +77,13 @@
{ Result = 'n' }
;
{ MaybeHandle = ok(Handle) },
- %
- % Look up the address of the first mode (mode number 0)
- % of the predicates initialize/1 and filter/14 in the
- % module collect.
- %
- dl__sym(Handle, "Collect_initialize", MaybeInitialize),
- dl__sym(Handle, "Collect_filter", MaybeFilter),
- dl__sym(Handle, "Collect_send_collect_result", MaybeSendResult),
+ %
+ % Look up the address of the C functions corresponding to the
+ % initialize/1 and filter/14 predicates in the collect module.
+ %
+ dl__sym(Handle, "ML_COLLECT_initialize", MaybeInitialize),
+ dl__sym(Handle, "ML_COLLECT_filter", MaybeFilter),
+ dl__sym(Handle, "ML_COLLECT_send_collect_result", MaybeSendResult),
(
{ MaybeInitialize = ok(Initialize0) },
{ MaybeFilter = ok(Filter0) },
@@ -108,13 +107,3 @@
[will_not_call_mercury, thread_safe],
"(Pointer = (Word) NULL)").
-
-:- type io_pred == pred(io__state, io__state).
-:- inst io_pred == (pred(di, uo) is det).
-
-:- func inst_cast(io_pred) = io_pred.
-:- mode inst_cast(in) = out(io_pred) is det.
-
-:- pragma c_code(inst_cast(X::in) = (Y::out(io_pred)),
- [will_not_call_mercury, thread_safe], "Y = X").
-
--
R1.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list