From 2264144dd6e6e67ec16a1dcbc590a7202d9a975a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Gonz=C3=A1lez-Abril?= Date: Mon, 31 May 2021 17:22:39 +0200 Subject: [PATCH 1/5] Fix bug where a trace with a result value without a source code representation would cause a crash when being loaded Now all result values are saved to a file using the "Erlang external term format". --- src/cauder_utils.erl | 8 +++++++- src/tracer.erl | 9 ++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/cauder_utils.erl b/src/cauder_utils.erl index d1893e3..2a8fa96 100644 --- a/src/cauder_utils.erl +++ b/src/cauder_utils.erl @@ -588,7 +588,7 @@ load_trace(Dir) -> pid := InitialPid, call := {Mod, Fun, Args}, tracing := Tracing, - return := ReturnValue, + return := ReturnBinary, comp := CompTime, exec := ExecTime } = maps:from_list(ResultTerms), @@ -608,6 +608,12 @@ load_trace(Dir) -> maps:new() ), + ReturnValue = + case ReturnBinary of + none -> none; + _ -> {value, erlang:binary_to_term(ReturnBinary)} + end, + #trace_result{ node = InitialNode, pid = InitialPid, diff --git a/src/tracer.erl b/src/tracer.erl index 17151e1..ac99adb 100644 --- a/src/tracer.erl +++ b/src/tracer.erl @@ -343,7 +343,7 @@ do_trace(Module, Function, Args, Opts) -> pid = pid_index(TracedPid), call = {Module, Function, Args}, tracing = Tracing, - return = ReturnValue, + return = value_to_binary(ReturnValue), comp = CompTime, exec = ExecTime, traces = Traces @@ -468,14 +468,17 @@ write_trace(Dir, TraceResult) -> end, ResultFile = filename:join(Dir, "trace_result.log"), - ResultContent = lists:join($\n, lists:map(fun(T) -> io_lib:format("~p.", [T]) end, maps:to_list(ResultInfo))), + ResultContent = lists:join($\n, lists:map(fun(T) -> io_lib:format("~w.", [T]) end, maps:to_list(ResultInfo))), ok = file:write_file(ResultFile, ResultContent), lists:foreach( fun({Index, List}) -> File = filename:join(Dir, io_lib:format("trace_~b.log", [Index])), - Content = lists:join($\n, lists:map(fun(T) -> io_lib:format("~p.", [T]) end, List)), + Content = lists:join($\n, lists:map(fun(T) -> io_lib:format("~w.", [T]) end, List)), ok = file:write_file(File, Content) end, maps:to_list(Traces) ). + +value_to_binary(none) -> none; +value_to_binary({value, Value}) -> erlang:term_to_binary(Value, [compressed, {minor_version, 2}]). From a33d3c431ca4f4ec63640a6711771a172c49e66f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Gonz=C3=A1lez-Abril?= Date: Mon, 31 May 2021 17:22:57 +0200 Subject: [PATCH 2/5] Update traces --- case-studies/meViolation/trace/trace_result.log | 2 +- case-studies/purchase/trace/trace_result.log | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/case-studies/meViolation/trace/trace_result.log b/case-studies/meViolation/trace/trace_result.log index a5328fc..4be2801 100644 --- a/case-studies/meViolation/trace/trace_result.log +++ b/case-studies/meViolation/trace/trace_result.log @@ -3,5 +3,5 @@ {exec,10001023}. {node,nonode@nohost}. {pid,81}. -{return,{value,<0.88.0>}}. +{return,<<131,88,119,13,110,111,110,111,100,101,64,110,111,104,111,115,116,0,0,0,88,0,0,0,0,0,0,0,0>>}. {tracing,timeout}. \ No newline at end of file diff --git a/case-studies/purchase/trace/trace_result.log b/case-studies/purchase/trace/trace_result.log index 95b2d13..38bacd2 100755 --- a/case-studies/purchase/trace/trace_result.log +++ b/case-studies/purchase/trace/trace_result.log @@ -3,5 +3,5 @@ {exec,389}. {node,nonode@nohost}. {pid,81}. -{return,{value,true}}. +{return,<<131,119,4,116,114,117,101>>}. {tracing,success}. \ No newline at end of file From a5a96801e3c6ed8260057395a9786ffbe2121fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Gonz=C3=A1lez-Abril?= Date: Fri, 7 Jan 2022 14:27:44 +0100 Subject: [PATCH 3/5] Process traces before writing to file and convert pids from `` to `y` --- src/cauder_trace.erl | 37 ++++++++++++++++++++++++++++++++----- src/cauder_tracer.erl | 39 ++++++++++++++++++++++----------------- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/cauder_trace.erl b/src/cauder_trace.erl index 379f6d0..7170d32 100644 --- a/src/cauder_trace.erl +++ b/src/cauder_trace.erl @@ -6,8 +6,11 @@ push/3, pop/3, get/2, - peek/2, - reverse_actions/1, + peek/2 +]). +-export([ + reverse/1, + map_pids/1, to_log/1 ]). @@ -86,12 +89,36 @@ peek(Pid, Trace) -> error end. --spec reverse_actions(Trace) -> NewTrace when +%%%============================================================================= + +-spec reverse(Trace) -> NewTrace when Trace :: cauder_trace:trace(), NewTrace :: cauder_trace:trace(). -reverse_actions(Trace) -> - maps:map(fun(_, Actions) -> lists:reverse(Actions) end, Trace). +reverse(Trace) -> + maps:map(fun(_, Actions) -> lists:reverse(map_pids(Actions)) end, Trace). + +-spec map_pids(term()) -> term(). + +map_pids(List) when is_list(List) -> + lists:map(fun map_pids/1, List); +map_pids(Tuple) when is_tuple(Tuple) -> + list_to_tuple(lists:map(fun map_pids/1, tuple_to_list(Tuple))); +map_pids(Map) when is_map(Map) -> + maps:fold( + fun(K, V, Acc) -> + K1 = map_pids(K), + V1 = map_pids(V), + false = maps:is_key(K1, Acc), + Acc#{K1 => V1} + end, + #{}, + Map + ); +map_pids(Pid) when is_pid(Pid) -> + cauder_process:from_pid(Pid); +map_pids(Term) -> + Term. -spec to_log(Trace) -> Log when Trace :: cauder_trace:trace(), diff --git a/src/cauder_tracer.erl b/src/cauder_tracer.erl index 67a6df4..0c4ef99 100644 --- a/src/cauder_tracer.erl +++ b/src/cauder_tracer.erl @@ -142,10 +142,10 @@ init({MainPid, TracedPid}) -> NewState :: state(). handle_call(get_traces, _From, #state{trace = Trace0} = State) -> - Trace1 = cauder_trace:reverse_actions(Trace0), + Trace1 = cauder_trace:reverse(Trace0), {reply, {ok, Trace1}, State}; handle_call(get_return_value, _From, #state{return = ReturnValue} = State) -> - {reply, ReturnValue, State}; + {reply, cauder_trace:map_pids(ReturnValue), State}; %% ========== 'call' trace messages ========== %% %% Generate message stamp handle_call({trace, Pid, call, {cauder_tracer_erlang, send_centralized, [_, _]}}, _From, State) -> @@ -367,7 +367,7 @@ do_trace(Module, Function, Args, Opts) -> pid = cauder_process:from_pid(TracedPid), call = {Module, Function, Args}, tracing = Tracing, - return = value_to_binary(ReturnValue), + return = ReturnValue, comp = CompTime, exec = ExecTime, trace = Traces @@ -454,13 +454,13 @@ get_uid(Stamp, #state{ets = Table, stamps = Map} = State) -> -spec write_trace(Dir, TraceInfo) -> ok when Dir :: file:filename(), - TraceInfo :: cauder_tracer:trace_info(). + TraceInfo :: cauder_types:trace_info(). -write_trace(Dir, TraceResult) -> +write_trace(Dir, TraceInfo) -> % This not compile time safe but there is no other way to keep it human-friendly and simple - [trace_info | Values] = tuple_to_list(TraceResult), Fields = record_info(fields, trace_info), - {Traces, ResultInfo} = maps:take(trace, maps:from_list(lists:zip(Fields, Values))), + [trace_info | Values] = tuple_to_list(TraceInfo), + {Trace, ResultInfo} = maps:take(trace, maps:from_list(lists:zip(Fields, Values))), ok = filelib:ensure_dir(Dir), case filelib:is_dir(Dir) of @@ -468,18 +468,23 @@ write_trace(Dir, TraceResult) -> false -> ok = file:make_dir(Dir) end, - ResultFile = filename:join(Dir, "trace_result.log"), - ResultContent = lists:join($\n, lists:map(fun(T) -> io_lib:format("~w.", [T]) end, maps:to_list(ResultInfo))), - ok = file:write_file(ResultFile, ResultContent), + ResultFilename = filename:join(Dir, "trace_result.log"), + write_terms(ResultFilename, maps:to_list(ResultInfo)), lists:foreach( - fun({Index, List}) -> - File = filename:join(Dir, io_lib:format("trace_~b.log", [Index])), - Content = lists:join($\n, lists:map(fun(T) -> io_lib:format("~w.", [T]) end, List)), - ok = file:write_file(File, Content) + fun({Index, Terms}) -> + Filename = filename:join(Dir, io_lib:format("trace_~b.log", [Index])), + write_terms(Filename, Terms) end, - maps:to_list(Traces) + maps:to_list(Trace) ). -value_to_binary(none) -> none; -value_to_binary({value, Value}) -> erlang:term_to_binary(Value, [compressed, {minor_version, 2}]). +-spec write_terms(Filename, Terms) -> ok when + Filename :: file:name_all(), + Terms :: [term()]. + +write_terms(Filename, Terms) -> + Lines = lists:map(fun(Term) -> io_lib:format("~w.", [Term]) end, Terms), + Joined = lists:join($\n, Lines), + Text = unicode:characters_to_binary(Joined), + file:write_file(Filename, Text). From 9bd7cceae96bde91998a0bcc808f57431f7af7dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Gonz=C3=A1lez-Abril?= Date: Fri, 7 Jan 2022 14:33:33 +0100 Subject: [PATCH 4/5] Update `meViolation` trace to match new format --- case-studies/meViolation/trace/trace_result.log | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/case-studies/meViolation/trace/trace_result.log b/case-studies/meViolation/trace/trace_result.log index 282ff4d..0955e34 100644 --- a/case-studies/meViolation/trace/trace_result.log +++ b/case-studies/meViolation/trace/trace_result.log @@ -3,5 +3,5 @@ {exec,10016000}. {node,nonode@nohost}. {pid,209}. -{return,{value,<0.216.0>}}. +{return,{value,216}}. {tracing,timeout}. \ No newline at end of file From 66eea3b28225e7a52da4e1a74744d01e96c7b181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Gonz=C3=A1lez-Abril?= Date: Fri, 7 Jan 2022 14:39:39 +0100 Subject: [PATCH 5/5] Refactor `load_trace/1` to match new format --- src/cauder_utils.erl | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/cauder_utils.erl b/src/cauder_utils.erl index d64ef8c..33ce083 100644 --- a/src/cauder_utils.erl +++ b/src/cauder_utils.erl @@ -203,7 +203,7 @@ load_trace(Dir) -> pid := InitialPid, call := {Mod, Fun, Args}, tracing := Tracing, - return := ReturnBinary, + return := ReturnValue, comp := CompTime, exec := ExecTime } = maps:from_list(ResultTerms), @@ -223,12 +223,6 @@ load_trace(Dir) -> maps:new() ), - ReturnValue = - case ReturnBinary of - none -> none; - _ -> {value, erlang:binary_to_term(ReturnBinary)} - end, - #trace_info{ node = InitialNode, pid = InitialPid,