crashdump_viewer.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 2,144 行 · 第 1/5 页

ERL
2,144
字号
    parse_dictionary(Line0, D) ->    {Entry,Line,_} = parse_term(Line0, D),    [] = skip_blanks(Line),    Entry.    %%%%%% Read heap data.%%%read_heap(Fd,Pid,Dict0) ->    case ets:match(cdv_dump_index_table,{"=proc_heap",Pid,'$2'}) of	[[Pos]] ->	    pos_bof(Fd,Pos),	    read_heap(Dict0);	[] ->	    Dict0    end.read_heap(Dict0) ->    %% This function is never called if the dump is truncated in "=proc_heap:Pid"    case get(fd) of	end_of_heap ->	    Dict0;	Fd ->	    case val(Fd) of		"=" ++ _next_tag ->		    put(fd, end_of_heap),		    Dict0;		Line ->		    Dict = parse(Line,Dict0),		    read_heap(Dict)	    end    end.parse(Line0, Dict0) ->    {Addr,":"++Line1} = get_hex(Line0),    {_Term,Line,Dict} = parse_heap_term(Line1, Addr, Dict0),    [] = skip_blanks(Line),    Dict.do_sort_procs("state",Procs,"state") ->    {lists:reverse(lists:keysort(#proc.state,Procs)),"rstate"};do_sort_procs("state",Procs,_) ->    {lists:keysort(#proc.state,Procs),"state"};do_sort_procs("pid",Procs,"pid") ->    {lists:reverse(Procs),"rpid"};do_sort_procs("pid",Procs,_) ->    {Procs,"pid"};do_sort_procs("msg_q_len",Procs,"msg_q_len") ->    {lists:keysort(#proc.msg_q_len,Procs),"rmsg_q_len"};do_sort_procs("msg_q_len",Procs,_) ->    {lists:reverse(lists:keysort(#proc.msg_q_len,Procs)),"msg_q_len"};do_sort_procs("reds",Procs,"reds") ->    {lists:keysort(#proc.reds,Procs),"rreds"};do_sort_procs("reds",Procs,_) ->    {lists:reverse(lists:keysort(#proc.reds,Procs)),"reds"};do_sort_procs("mem",Procs,"mem") ->    {lists:keysort(#proc.stack_heap,Procs),"rmem"};do_sort_procs("mem",Procs,_) ->    {lists:reverse(lists:keysort(#proc.stack_heap,Procs)),"mem"};do_sort_procs("init_func",Procs,"init_func") ->    {lists:reverse(lists:keysort(#proc.init_func,Procs)),"rinit_func"};do_sort_procs("init_func",Procs,_) ->    {lists:keysort(#proc.init_func,Procs),"init_func"};do_sort_procs("name_func",Procs,"name_func") ->    {lists:reverse(lists:keysort(#proc.name,Procs)),"rname_func"};do_sort_procs("name_func",Procs,_) ->    {lists:keysort(#proc.name,Procs),"name_func"};do_sort_procs("name",Procs,Sorted) ->    {No,Yes} = 	lists:foldl(fun(P,{N,Y}) ->			    case P#proc.name of				?space -> {[P|N],Y};				_other -> {N,[P|Y]}			    end		    end,		    {[],[]},		    Procs),    Result = lists:keysort(#proc.name,Yes) ++ No,    case Sorted of	"name" -> {lists:reverse(Result),"rname"};	_ -> {Result,"name"}    end.    get_port(File,Port) ->    case ets:match(cdv_dump_index_table,{"=port",Port,'$1'}) of	[[Start]] ->	    Fd = open(File),	    R = get_portinfo(Fd,Port,Start),	    close(Fd),	    {ok,R};	[] ->	    case maybe_other_node(File,Port) of		{other_node,Type,Node} -> 		    Info = "The port you are searching for was residing on "			"a remote node. No port information is available. "			"Information about the remote node is show below.",		    {other_node,{Type,Info,Node}};		not_found ->		    not_found	    end    end.get_ports(File) ->    Ports = ets:lookup(cdv_dump_index_table,"=port"),    Fd = open(File),    R = lists:map(fun({"=port",Id,Start}) -> get_portinfo(Fd,Id,Start) end, 		  Ports),    close(Fd),    R.get_portinfo(Fd,Id,Start) ->    pos_bof(Fd,Start),    get_portinfo(Fd,#port{id=Id,_=?space}).get_portinfo(Fd,Port) ->    case line_head(Fd) of	"Slot" ->	    get_portinfo(Fd,Port#port{slot=val(Fd)});	"Connected" ->	    get_portinfo(Fd,Port#port{connected=val(Fd)});	"Links" ->	    get_portinfo(Fd,Port#port{links=val(Fd)});	"Port controls linked-in driver" ->	    get_portinfo(Fd,Port#port{controls=["Linked in driver: " |						val(Fd)]});	"Port controls external process" ->	    get_portinfo(Fd,Port#port{controls=["External proc: " | val(Fd)]});	"Port is a file" ->	    get_portinfo(Fd,Port#port{controls=["File: "| val(Fd)]});	"Port is UNIX fd not opened by emulator" ->	    get_portinfo(Fd,Port#port{			      controls=["UNIX fd not opened by emulator: "| 					val(Fd)]});	"=" ++ _next_tag ->	    Port;	Other ->	    unexpected(Fd,Other,"port info"),	    Port    end.get_ets_tables(File,Pid,WS) ->    EtsTables = ets:match_object(cdv_dump_index_table,{"=ets",Pid,'_'}),    Fd = open(File),    R = lists:map(fun({"=ets",P,Start}) -> 			  get_etsinfo(Fd,P,Start,WS) 		  end, 		  EtsTables),    close(Fd),    R.get_internal_ets_tables(File,WS) ->    InternalEts = ets:match_object(cdv_dump_index_table,				   {"=internal_ets",'_','_'}),    Fd = open(File),    R = lists:map(fun({"=internal_ets",Descr,Start}) ->			  {Descr,get_etsinfo(Fd,undefined,Start,WS)}		  end,		  InternalEts),    close(Fd),    R.    get_etsinfo(Fd,Pid,Start,WS) ->    pos_bof(Fd,Start),    get_etsinfo(Fd,#ets_table{pid=Pid,type="hash",_=?space},WS).get_etsinfo(Fd,EtsTable,WS) ->    case line_head(Fd) of	"Slot" ->	    get_etsinfo(Fd,EtsTable#ets_table{slot=val(Fd)},WS);	"Table" ->	    get_etsinfo(Fd,EtsTable#ets_table{id=val(Fd)},WS);	"Name" ->	    get_etsinfo(Fd,EtsTable#ets_table{name=val(Fd)},WS);	"Ordered set (AVL tree), Elements" ->	    skip_rest_of_line(Fd),	    get_etsinfo(Fd,EtsTable#ets_table{type="tree",buckets="-"},WS);	"Buckets" ->	    get_etsinfo(Fd,EtsTable#ets_table{buckets=val(Fd)},WS);	"Objects" ->	    get_etsinfo(Fd,EtsTable#ets_table{size=val(Fd)},WS);	"Words" ->	    Words = list_to_integer(val(Fd)),	    Bytes = 		case Words of		    -1 -> "-1"; % probably truncated		    _ -> integer_to_list(Words * WS)		end,	    get_etsinfo(Fd,EtsTable#ets_table{memory=Bytes},WS);	"=" ++ _next_tag ->	    EtsTable;	Other ->	    unexpected(Fd,Other,"ETS info"),	    EtsTable    end.get_timers(File,Pid) ->    Timers = ets:match_object(cdv_dump_index_table,{"=timer",Pid,'$1'}),    Fd = open(File),    R = lists:map(fun({"=timer",P,Start}) -> 			  get_timerinfo(Fd,P,Start) 		  end, 		  Timers),    close(Fd),    R.get_timerinfo(Fd,Pid,Start) ->    pos_bof(Fd,Start),    get_timerinfo(Fd,#timer{pid=Pid,_=?space}).get_timerinfo(Fd,Timer) ->    case line_head(Fd) of	"Message" ->	    get_timerinfo(Fd,Timer#timer{msg=val(Fd)});	"Time left" ->	    get_timerinfo(Fd,Timer#timer{time=val(Fd)});	"=" ++ _next_tag ->	    Timer;	Other ->	    unexpected(Fd,Other,"timer info"),	    Timer    end.nods(File) ->    case ets:lookup(cdv_dump_index_table,"=no_distribution") of	[] ->	    V = ets:lookup(cdv_dump_index_table,"=visible_node"),	    H = ets:lookup(cdv_dump_index_table,"=hidden_node"),	    N = ets:lookup(cdv_dump_index_table,"=not_connected"),	    Fd = open(File),	    Visible = lists:map(			fun({"=visible_node",Channel,Start}) -> 				get_nodeinfo(Fd,Channel,Start)			end, 			V),	    Hidden = lists:map(		       fun({"=hidden_node",Channel,Start}) -> 			       get_nodeinfo(Fd,Channel,Start)		       end, 		       H),	    NotConnected = lists:map(			     fun({"=not_connected",Channel,Start}) -> 				     get_nodeinfo(Fd,Channel,Start)			     end, 			     N),	    close(Fd),	    {Visible,Hidden,NotConnected};	[_] ->	    no_distribution    end.get_nodeinfo(Fd,Channel,Start) ->    pos_bof(Fd,Start),    get_nodeinfo(Fd,#nod{channel=Channel,_=?space}).get_nodeinfo(Fd,Nod) ->    case line_head(Fd) of	"Name" ->	    get_nodeinfo(Fd,Nod#nod{name=val(Fd)});	"Controller" ->	    get_nodeinfo(Fd,Nod#nod{controller=val(Fd)});	"Creation" ->	    get_nodeinfo(Fd,Nod#nod{creation=val(Fd)});	"Remote link" ->	    Procs = val(Fd), % e.g. "<0.31.0> <4322.54.0>"	    RemoteLinks = Nod#nod.remote_links,	    get_nodeinfo(Fd,Nod#nod{remote_links=[split(Procs)|RemoteLinks]});	"Remote monitoring" ->	    Procs = val(Fd), % e.g. "<0.31.0> <4322.54.0>"	    RemoteMon = Nod#nod.remote_mon,	    get_nodeinfo(Fd,Nod#nod{remote_mon=[split(Procs)|RemoteMon]});	"Remotely monitored by" ->	    Procs = val(Fd), % e.g. "<0.31.0> <4322.54.0>"	    RemoteMonBy = Nod#nod.remote_mon_by,	    get_nodeinfo(Fd,Nod#nod{remote_mon_by=[split(Procs)|RemoteMonBy]});	"Error" ->	    get_nodeinfo(Fd,Nod#nod{error=val(Fd)});	    	"=" ++ _next_tag ->	    Nod;	Other ->	    unexpected(Fd,Other,"node info"),	    Nod    end.loaded_mods(File) ->    case ets:lookup(cdv_dump_index_table,"=loaded_modules") of	[{"=loaded_modules",_,StartTotal}] ->	    Fd = open(File),	    pos_bof(Fd,StartTotal),	    {CC,OC} = get_loaded_mod_totals(Fd,{"unknown","unknown"}),	    	    Mods = ets:lookup(cdv_dump_index_table,"=mod"),	    LM = lists:map(fun({"=mod",M,Start}) -> 				   pos_bof(Fd,Start),				   InitLM = #loaded_mod{mod=M,_=?space},				   get_loaded_mod_info(Fd,InitLM,						       fun main_modinfo/3)			   end, 			   Mods),	    close(Fd),	    {CC,OC,LM};	[] ->	    {"unknown","unknown",[]}    end.get_loaded_mod_totals(Fd,{CC,OC}) ->    case line_head(Fd) of	"Current code" ->	    get_loaded_mod_totals(Fd,{val(Fd),OC});	"Old code" ->	    get_loaded_mod_totals(Fd,{CC,val(Fd)});	"=" ++ _next_tag ->	    {CC,OC};	Other ->	    unexpected(Fd,Other,"loaded modules info"),	    {CC,OC} % truncated file    end.get_loaded_mod_details(File,Mod) ->    [[Start]] = ets:match(cdv_dump_index_table,{"=mod",Mod,'$1'}),    Fd = open(File),    pos_bof(Fd,Start),    InitLM = #loaded_mod{mod=Mod,old_size="No old code exists",			 _="No information available"},    ModInfo = get_loaded_mod_info(Fd,InitLM,fun all_modinfo/3),    close(Fd),    ModInfo.get_loaded_mod_info(Fd,LM,Fun) ->    case line_head(Fd) of	"Current size" ->	    get_loaded_mod_info(Fd,LM#loaded_mod{current_size=val(Fd)},Fun);	"Old size" ->	    get_loaded_mod_info(Fd,LM#loaded_mod{old_size=val(Fd)},Fun);	"=" ++ _next_tag ->	    LM;	{eof,_} ->	    LM; % truncated file	Other ->	    LM1 = Fun(Fd,LM,Other),	    get_loaded_mod_info(Fd,LM1,Fun)    end.main_modinfo(_Fd,LM,_LineHead) ->    LM.all_modinfo(Fd,LM,LineHead) ->    case LineHead of	"Current attributes" ->	    Str = hex_to_str(val(Fd)),	    LM#loaded_mod{current_attrib=Str};	"Current compilation info" ->	    Str = hex_to_str(val(Fd)),	    LM#loaded_mod{current_comp_info=Str};	"Old attributes" ->	    Str = hex_to_str(val(Fd)),	    LM#loaded_mod{old_attrib=Str};	"Old compilation info" ->	    Str = hex_to_str(val(Fd)),	    LM#loaded_mod{old_comp_info=Str};	Other ->	    unexpected(Fd,Other,"loaded modules info"),	    LM    end.    hex_to_str(Hex) ->    Term = hex_to_term(Hex,[]),    io_lib:format("~p~n",[Term]).hex_to_term([X,Y|Hex],Acc) ->    MS = hex_to_dec([X]),    LS = hex_to_dec([Y]),    Z = 16*MS+LS,    hex_to_term(Hex,[Z|Acc]);hex_to_term([],Acc) ->    Bin = list_to_binary(lists:reverse(Acc)),    case catch binary_to_term(Bin) of	{'EXIT',_Reason} ->	    {"WARNING: The term is probably truncated!",	     "I can not do binary_to_term.",	     Bin};	Term ->	    Term    end.hex_to_dec("F") -> 15;hex_to_dec("E") -> 14;hex_to_dec("D") -> 13;hex_to_dec("C") -> 12;hex_to_dec("B") -> 11;hex_to_dec("A") -> 10;hex_to_dec(N) -> list_to_integer(N).    funs(File) ->    case ets:lookup(cdv_dump_index_table,"=fun") of	[] ->	    [];	AllFuns ->	    Fd = open(File),	    R = lists:map(fun({"=fun",_,Start}) -> 				  get_funinfo(Fd,Start) 			  end, 			  AllFuns),	    close(Fd),	    R    end.get_funinfo(Fd,Start) ->    pos_bof(Fd,Start),    get_funinfo1(Fd,#fu{_=?space}).get_funinfo1(Fd,Fu) ->    case line_head(Fd) of	"Module" ->	    get_funinfo1(Fd,Fu#fu{module=val(Fd)});	"Uniq" ->	    get_funinfo1(Fd,Fu#fu{uniq=val(Fd)});	"Index" ->	    get_funinfo1(Fd,Fu#fu{index=val(Fd)});	"Address" ->	    get_funinfo1(Fd,Fu#fu{address=val(Fd)});	"Na

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?