aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/observer/src/cdv_bin_wx.erl5
-rw-r--r--lib/observer/src/cdv_html_page.erl19
-rw-r--r--lib/observer/src/cdv_term_wx.erl45
-rw-r--r--lib/observer/src/crashdump_viewer_html.erl97
-rw-r--r--lib/observer/src/observer_procinfo.erl49
-rw-r--r--lib/observer/src/observer_term_wx.erl113
6 files changed, 142 insertions, 186 deletions
diff --git a/lib/observer/src/cdv_bin_wx.erl b/lib/observer/src/cdv_bin_wx.erl
index d2cbcfb747..6cf344f945 100644
--- a/lib/observer/src/cdv_bin_wx.erl
+++ b/lib/observer/src/cdv_bin_wx.erl
@@ -21,7 +21,10 @@
detail_pages/0]).
%% Callbacks for cdv_detail_win
-get_details(Id) ->
+get_details({_, {T,Key}}) ->
+ [{Key,Term}] = ets:lookup(T,Key),
+ {ok,{"Expanded Binary", Term, []}};
+get_details({cdv, Id}) ->
{ok,Bin} = crashdump_viewer:expand_binary(Id),
{ok,{"Expanded Binary", Bin, []}}.
diff --git a/lib/observer/src/cdv_html_page.erl b/lib/observer/src/cdv_html_page.erl
index b2d059f7f8..d77238c6cf 100644
--- a/lib/observer/src/cdv_html_page.erl
+++ b/lib/observer/src/cdv_html_page.erl
@@ -84,16 +84,23 @@ handle_event(#wx{event=#wxHtmlLink{type=command_html_link_clicked,
"#Binary?" ++ BinSpec ->
[{"offset",Off},{"size",Size},{"pos",Pos}] =
httpd:parse_query(BinSpec),
- Id = {list_to_integer(Off),
- list_to_integer(Size),
- list_to_integer(Pos)},
+ Id = {cdv, {list_to_integer(Off),
+ list_to_integer(Size),
+ list_to_integer(Pos)}},
+ expand(Id,cdv_bin_wx,State);
+ "#OBSBinary?" ++ BinSpec ->
+ [{"offset",Off},{"size",Size},{"pos",Pos}] =
+ httpd:parse_query(BinSpec),
+ Id = {obs, {Tab, {list_to_integer(Off),
+ list_to_integer(Size),
+ list_to_integer(Pos)}}},
expand(Id,cdv_bin_wx,State);
"#Term?" ++ TermKeys ->
[{"key1",Key1},{"key2",Key2},{"key3",Key3}] =
httpd:parse_query(TermKeys),
- Id = {Tab,{list_to_integer(Key1),
- list_to_integer(Key2),
- list_to_integer(Key3)}},
+ Id = {cdv, {Tab,{list_to_integer(Key1),
+ list_to_integer(Key2),
+ list_to_integer(Key3)}}},
expand(Id,cdv_term_wx,State);
_ ->
cdv_virtual_list:start_detail_win(Target),
diff --git a/lib/observer/src/cdv_term_wx.erl b/lib/observer/src/cdv_term_wx.erl
index e029a75b29..9b83249eae 100644
--- a/lib/observer/src/cdv_term_wx.erl
+++ b/lib/observer/src/cdv_term_wx.erl
@@ -21,26 +21,28 @@
detail_pages/0]).
%% Callbacks for cdv_detail_win
-get_details({T,Key}) ->
+get_details({_, {T,Key}}) ->
[{Key,Term}] = ets:lookup(T,Key),
- {ok,{"Expanded Term", Term, []}}.
+ {ok,{"Expanded Term", [Term, T], []}}.
detail_pages() ->
[{"Term", fun init_term_page/2}].
-init_term_page(ParentWin, Term) ->
+init_term_page(ParentWin, [Term, Tab]) ->
+ Expanded = expand(Term, true),
+ BinSaved = expand(Term, Tab),
cdv_multi_panel:start_link(
ParentWin,
- [{"Format \~p",cdv_html_page,format_term_fun("~p",Term)},
- {"Format \~tp",cdv_html_page,format_term_fun("~tp",Term)},
- {"Format \~w",cdv_html_page,format_term_fun("~w",Term)},
- {"Format \~s",cdv_html_page,format_term_fun("~s",expand(Term))},
- {"Format \~ts",cdv_html_page,format_term_fun("~ts",expand(Term))}]).
+ [{"Format \~p",cdv_html_page,format_term_fun("~p",BinSaved,Tab)},
+ {"Format \~tp",cdv_html_page,format_term_fun("~tp",BinSaved,Tab)},
+ {"Format \~w",cdv_html_page,format_term_fun("~w",BinSaved,Tab)},
+ {"Format \~s",cdv_html_page,format_term_fun("~s",Expanded,Tab)},
+ {"Format \~ts",cdv_html_page,format_term_fun("~ts",Expanded,Tab)}]).
-format_term_fun(Format,Term) ->
+format_term_fun(Format,Term,Tab) ->
fun() ->
try io_lib:format(Format,[Term]) of
- Str -> plain_html(Str)
+ Str -> {expand, plain_html(Str), Tab}
catch error:badarg ->
Warning = "This term can not be formatted with " ++ Format,
crashdump_viewer_html:warning(Warning)
@@ -50,17 +52,24 @@ format_term_fun(Format,Term) ->
plain_html(Text) ->
crashdump_viewer_html:plain_page(Text).
-expand(['#CDVBin',Offset,Size,Pos]) ->
+expand(['#CDVBin',Offset,Size,Pos], true) ->
{ok,Bin} = crashdump_viewer:expand_binary({Offset,Size,Pos}),
Bin;
-expand([H|T]) ->
- case expand(T) of
+expand(Bin, Tab) when is_binary(Bin), not is_boolean(Tab) ->
+ <<Preview:80, _/binary>> = Bin,
+ Size = byte_size(Bin),
+ Hash = erlang:phash2(Bin),
+ Key = {Preview, Size, Hash},
+ ets:insert(Tab, {Key,Bin}),
+ ['#OBSBin',Preview,Size,Hash];
+expand([H|T], Expand) ->
+ case expand(T, Expand) of
ET when is_list(ET) ->
- [expand(H)|ET];
+ [expand(H, Expand)|ET];
ET -> % The tail is an expanded binary - cannot append with |
- [expand(H),ET]
+ [expand(H, Expand),ET]
end;
-expand(Tuple) when is_tuple(Tuple) ->
- list_to_tuple(expand(tuple_to_list(Tuple)));
-expand(Term) ->
+expand(Tuple, Expand) when is_tuple(Tuple) ->
+ list_to_tuple(expand(tuple_to_list(Tuple), Expand));
+expand(Term, _) ->
Term.
diff --git a/lib/observer/src/crashdump_viewer_html.erl b/lib/observer/src/crashdump_viewer_html.erl
index 9cd4d6748a..2cc28d04be 100644
--- a/lib/observer/src/crashdump_viewer_html.erl
+++ b/lib/observer/src/crashdump_viewer_html.erl
@@ -590,15 +590,31 @@ all_or_expand(Tab,Term) ->
all_or_expand(Tab,Term,Preview,Exp).
all_or_expand(_Tab,_Term,Str,false) ->
href_proc_port(lists:flatten(Str));
-all_or_expand(Tab,Term,Preview,true) ->
+all_or_expand(Tab,Term,Preview,true)
+ when not is_binary(Term) ->
Key = {Key1,Key2,Key3} = now(),
ets:insert(Tab,{Key,Term}),
- [href_proc_port(lists:flatten(Preview),false), $\n,
- href("TARGET=\"expanded\"",["#Term?key1="++integer_to_list(Key1)++
- "&key2="++integer_to_list(Key2)++
- "&key3="++integer_to_list(Key3)],
+ [href_proc_port(lists:flatten(Preview), false), $\n,
+ href("TARGET=\"expanded\"",
+ ["#Term?key1="++integer_to_list(Key1)++
+ "&key2="++integer_to_list(Key2)++
+ "&key3="++integer_to_list(Key3)],
+ "Click to expand above term")];
+all_or_expand(Tab,Bin,PreviewStr,true) when is_binary(Bin) ->
+ <<Preview:80, _/binary>> = Bin,
+ Size = byte_size(Bin),
+ Hash = erlang:phash2(Bin),
+ Key = {Preview, Size, Hash},
+ ets:insert(Tab,{Key,Bin}),
+ [href_proc_port(lists:flatten(PreviewStr), false), $\n,
+ href("TARGET=\"expanded\"",
+ ["#OBSBinary?key1="++integer_to_list(Preview)++
+ "&key2="++integer_to_list(Size)++
+ "&key3="++integer_to_list(Hash)],
"Click to expand above term")].
+
+
color(true) -> io_lib:format("BGCOLOR=\"#~2.16.0B~2.16.0B~2.16.0B\"", tuple_to_list(?BG_EVEN));
color(false) -> io_lib:format("BGCOLOR=\"#~2.16.0B~2.16.0B~2.16.0B\"", tuple_to_list(?BG_ODD)).
@@ -1131,31 +1147,10 @@ href_proc_port("<"++([C|_]=T),Acc,LTB) when $0 =< C, C =< $9 ->
href_proc_port(Rest,[href(Pid,Pid)|Acc],LTB);
href_proc_port("['#CDVBin'"++T,Acc,LTB) ->
%% Binary written by crashdump_viewer:parse_heap_term(...)
- {OffsetSizePos,Rest} = split($],T),
- BinStr =
- case string:tokens(OffsetSizePos,",.|") of
- [Offset,Size,Pos] ->
- Id = {list_to_integer(Offset),10,list_to_integer(Pos)},
- {ok,PreviewBin} = crashdump_viewer:expand_binary(Id),
- PreviewBytes = binary_to_list(PreviewBin),
- PreviewStr = ["&lt;&lt;",
- [integer_to_list(X)++"," || X <- PreviewBytes],
- "...(",
- observer_lib:to_str({bytes,Size}),
- ")&gt;&gt;"],
- if LTB ->
- href("TARGET=\"expanded\"",
- ["#Binary?offset="++Offset++
- "&size="++Size++
- "&pos="++Pos],
- PreviewStr);
- true ->
- PreviewStr
- end;
- _ ->
- "&lt;&lt; ... &gt;&gt;"
- end,
- href_proc_port(Rest,[BinStr|Acc],LTB);
+ href_proc_bin(cdv, T, Acc, LTB);
+href_proc_port("['#OBSBin'"++T,Acc,LTB) ->
+ %% Binary written by crashdump_viewer:parse_heap_term(...)
+ href_proc_bin(obs, T, Acc, LTB);
href_proc_port("['#CDVPort'"++T,Acc,LTB) ->
%% Port written by crashdump_viewer:parse_term(...)
{Port0,Rest} = split($],T),
@@ -1211,6 +1206,48 @@ href_proc_port([H|T],Acc,LTB) ->
href_proc_port([],Acc,_) ->
lists:reverse(Acc).
+href_proc_bin(From, T, Acc, LTB) ->
+ {OffsetSizePos,Rest} = split($],T),
+ BinStr =
+ case string:tokens(OffsetSizePos,",.| \n") of
+ [Offset,Size,Pos] when From =:= cdv ->
+ Id = {list_to_integer(Offset),10,list_to_integer(Pos)},
+ {ok,PreviewBin} = crashdump_viewer:expand_binary(Id),
+ PreviewStr = ["&lt;&lt;",
+ [integer_to_list(X)++"," || <<X:8>> <= PreviewBin],
+ "...(",
+ observer_lib:to_str({bytes,Size}),
+ ")&gt;&gt;"],
+ if LTB ->
+ href("TARGET=\"expanded\"",
+ ["#Binary?offset="++Offset++
+ "&size="++Size++
+ "&pos="++Pos],
+ PreviewStr);
+ true ->
+ PreviewStr
+ end;
+ [Preview,Size,Md5] when From =:= obs ->
+ PreviewBin = <<(list_to_integer(Preview)):80>>,
+ PreviewStr = ["&lt;&lt;",
+ [integer_to_list(X)++"," || <<X:8>> <= PreviewBin],
+ "...(",
+ observer_lib:to_str({bytes,list_to_integer(Size)}),
+ ")&gt;&gt;"],
+ if LTB ->
+ href("TARGET=\"expanded\"",
+ ["#OBSBinary?offset="++Preview++
+ "&size="++Size++
+ "&pos="++Md5],
+ PreviewStr);
+ true ->
+ PreviewStr
+ end;
+ _ ->
+ "&lt;&lt; ... &gt;&gt;"
+ end,
+ href_proc_port(Rest,[BinStr|Acc],LTB).
+
split(Char,Str) ->
split(Char,Str,[]).
split(Char,[Char|Str],Acc) -> % match Char
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index cfc22e7093..af2b8dda2e 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -49,7 +49,7 @@ start(Process, ParentFrame, Parent) ->
init([Pid, ParentFrame, Parent]) ->
try
- Table = ets:new(observer_expand,[set,protected]),
+ Table = ets:new(observer_expand,[set,public]),
Title=case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, registered_name]) of
[] -> io_lib:format("~p",[Pid]);
{registered_name, Registered} -> io_lib:format("~p (~p)",[Registered, Pid]);
@@ -123,20 +123,33 @@ handle_event(#wx{obj=Obj, event=#wxMouse{type=leave_window}}, State) ->
wxTextCtrl:setForegroundColour(Obj,?wxBLUE),
{noreply, State};
-handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href="#Term?"++Keys}}},
+handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Href}}},
#state{frame=Frame,expand_table=T,expand_wins=Opened0}=State) ->
- [{"key1",Key1},{"key2",Key2},{"key3",Key3}] = httpd:parse_query(Keys),
- Id = {T,{list_to_integer(Key1),list_to_integer(Key2),list_to_integer(Key3)}},
- Opened =
- case lists:keyfind(Id,1,Opened0) of
- false ->
- Win = observer_term_wx:start(Id,Frame),
- [{Id,Win}|Opened0];
- {_,Win} ->
- wxFrame:raise(Win),
- Opened0
- end,
- {noreply,State#state{expand_wins=Opened}};
+ {Type, Rest} = case Href of
+ "#Term?"++Keys -> {cdv_term_wx, Keys};
+ "#OBSBinary?"++Keys -> {cdv_bin_wx, Keys};
+ _ -> {other, Href}
+ end,
+ case Type of
+ other ->
+ observer ! {open_link, Href},
+ {noreply, State};
+ Callback ->
+ [{"key1",Key1},{"key2",Key2},{"key3",Key3}] = httpd:parse_query(Rest),
+ Id = {observer, {T,{list_to_integer(Key1),
+ list_to_integer(Key2),
+ list_to_integer(Key3)}}},
+ Opened =
+ case lists:keyfind(Id,1,Opened0) of
+ false ->
+ Win = cdv_detail_win:start_link(Id,Frame,Callback),
+ [{Id,Win}|Opened0];
+ {_,Win} ->
+ wxFrame:raise(Win),
+ Opened0
+ end,
+ {noreply,State#state{expand_wins=Opened}}
+ end;
handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Info}}}, State) ->
observer ! {open_link, Info},
@@ -145,10 +158,6 @@ handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Info}}}, State)
handle_event(Event, _State) ->
error({unhandled_event, Event}).
-handle_info({expand_win_closed,Id}, #state{expand_wins=Opened0}=State) ->
- Opened = lists:keydelete(Id,1,Opened0),
- {noreply,State#state{expand_wins=Opened}};
-
handle_info(_Info, State) ->
%% io:format("~p: ~p, Handle info: ~p~n", [?MODULE, ?LINE, Info]),
{noreply, State}.
@@ -156,6 +165,10 @@ handle_info(_Info, State) ->
handle_call(Call, From, _State) ->
error({unhandled_call, Call, From}).
+handle_cast({detail_win_closed,Id}, #state{expand_wins=Opened0}=State) ->
+ Opened = lists:keydelete(Id,1,Opened0),
+ {noreply,State#state{expand_wins=Opened}};
+
handle_cast(Cast, _State) ->
error({unhandled_cast, Cast}).
diff --git a/lib/observer/src/observer_term_wx.erl b/lib/observer/src/observer_term_wx.erl
deleted file mode 100644
index 58cb650bef..0000000000
--- a/lib/observer/src/observer_term_wx.erl
+++ /dev/null
@@ -1,113 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-
--module(observer_term_wx).
-
--behaviour(wx_object).
-
--export([start/2]).
-
--export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3,
- handle_call/3, handle_info/2]).
-
--include_lib("wx/include/wx.hrl").
--include("observer_defs.hrl").
-
--define(REFRESH, 601).
-
--record(state, {parent,
- frame,
- id
- }).
-
-start(Id, ParentFrame) ->
- wx_object:start_link(?MODULE, [Id, ParentFrame, self()], []).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-init([{T,Key}=Id, ParentFrame, Parent]) ->
- case ets:lookup(T,Key) of
- [{Key,Term}] ->
- init(Id, ParentFrame, Parent, Term);
- [] ->
- observer_lib:display_info_dialog(
- "The term does no longer exist.\n"
- "Please refresh the process window!"),
- {stop, normal}
- end.
-
-
-
-init(Id, ParentFrame, Parent, Term) ->
- Frame=wxFrame:new(ParentFrame, ?wxID_ANY, ["Expanded Term"],
- [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {850,600}}]),
- MenuBar = wxMenuBar:new(),
- Menus = [{"File", [#create_menu{id=?wxID_CLOSE, text="Close"}]}],
- observer_lib:create_menus(Menus, MenuBar, new_window),
- wxFrame:setMenuBar(Frame, MenuBar),
- Panel = wxPanel:new(Frame),
- Sizer = wxBoxSizer:new(?wxHORIZONTAL),
-
- Window = observer_lib:html_window(Panel),
- Html = crashdump_viewer_html:plain_page(io_lib:format("~p~n",[Term])),
- wxHtmlWindow:setPage(Window, Html),
-
- wxSizer:add(Sizer, Window, [{flag, ?wxEXPAND bor ?wxALL},
- {proportion, 1},
- {border, 5}]),
- wxPanel:setSizer(Panel, Sizer),
- wxFrame:show(Frame),
- {Frame, #state{parent=Parent,
- frame=Frame,
- id=Id
- }}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Callbacks%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-handle_event(#wx{event=#wxClose{type=close_window}}, State) ->
- {stop, normal, State};
-
-handle_event(#wx{id=?wxID_CLOSE, event=#wxCommand{type=command_menu_selected}}, State) ->
- {stop, normal, State};
-
-handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Info}}}, State) ->
- observer ! {open_link, Info},
- {noreply, State};
-
-handle_event(Event, _State) ->
- error({unhandled_event, Event}).
-
-handle_info(_Info, State) ->
- %% io:format("~p: ~p, Handle info: ~p~n", [?MODULE, ?LINE, Info]),
- {noreply, State}.
-
-handle_call(Call, From, _State) ->
- error({unhandled_call, Call, From}).
-
-handle_cast(Cast, _State) ->
- error({unhandled_cast, Cast}).
-
-terminate(_Reason, #state{parent=Parent,id=Id,frame=Frame}) ->
- Parent ! {expand_win_closed, Id},
- case Frame of
- undefined -> ok;
- _ -> wxFrame:destroy(Frame)
- end,
- ok.
-
-code_change(_, _, State) ->
- {ok, State}.