crashdump_viewer.erl

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

ERL
2,144
字号
    InstrInfo =	case ets:member(cdv_dump_index_table,"=old_instr_data") of	    true ->		old_instr_data;	    false ->		case ets:member(cdv_dump_index_table,"=instr_data") of		    true ->			instr_data;		    false ->			false		end	end,    GI#general_info{node_name=NodeName,		    num_procs=integer_to_list(NumProcs),		    num_ets=integer_to_list(NumEts),		    num_fun=integer_to_list(NumFuns),		    mem_tot=MemTot,		    mem_max=MemMax,		    instr_info=InstrInfo}.get_general_info(Fd,GenInfo) ->    case line_head(Fd) of	"Slogan" ->	    get_general_info(Fd,GenInfo#general_info{slogan=val(Fd)});	"System version" ->	    get_general_info(Fd,GenInfo#general_info{system_vsn=val(Fd)});	"Compiled" ->	    get_general_info(Fd,GenInfo#general_info{compile_time=val(Fd)});	"Atoms" ->	    get_general_info(Fd,GenInfo#general_info{num_atoms=val(Fd)});	"=" ++ _next_tag ->	    GenInfo;	Other ->	    unexpected(Fd,Other,"general information"),	    GenInfo    end.get_num_atoms(Fd) ->    case ets:match(cdv_dump_index_table,{"=hash_table","atom_tab",'$1'}) of	[[Pos]] -> 	    pos_bof(Fd,Pos),	    skip_rest_of_line(Fd), % size	    skip_rest_of_line(Fd), % used	    case line_head(Fd) of		"objs" ->		    val(Fd);		_1 ->		    get_num_atoms2()	    end;	[] ->	    get_num_atoms2()    end.get_num_atoms2() ->    case ets:lookup(cdv_dump_index_table,"=num_atoms") of	[] -> 	    ?space;	[{"=num_atoms",NA,_Pos}] -> 	    %% If dump is translated this will exist	    case get(truncated) of		true ->		    [NA," (visible in dump)"]; % might be more		false ->		    NA	    end    end.count() ->    {ets:select_count(cdv_dump_index_table,count_ms("=proc")),     ets:select_count(cdv_dump_index_table,count_ms("=ets")),     ets:select_count(cdv_dump_index_table,count_ms("=fun"))}.count_ms(Tag) ->    [{{Tag,'_','_'},[],[true]}].procs_summary(File) ->    AllProcs = ets:lookup(cdv_dump_index_table,"=proc"),    Fd = open(File),    R = lists:map(fun({"=proc",Pid,Start}) -> 			  pos_bof(Fd,Start),			  get_procinfo(Fd,fun main_procinfo/4,				       ?initial_proc_record(Pid))		  end, 		  AllProcs),    close(Fd),    R.get_proc_details(File,Pid) ->    DumpVsn = ets:lookup_element(cdv_dump_index_table,"=erl_crash_dump",2),    case ets:match(cdv_dump_index_table,{"=proc",Pid,'$1'}) of	[[Start]] ->	    Fd = open(File),	    pos_bof(Fd,Start),	    Proc0 = 		case DumpVsn of		    "0.0" -> 			%% Old version (translated)			?initial_proc_record(Pid);		    _ ->			(?initial_proc_record(Pid))#proc{			  stack_dump=if_exist("=proc_stack",Pid),			  msg_q=if_exist("=proc_messages",Pid),			  dict=if_exist("=proc_dictionary",Pid),			  debug_dict=if_exist("=debug_proc_dictionary",Pid)}		end,	    Proc = get_procinfo(Fd,fun all_procinfo/4,Proc0),	    close(Fd),	    {ok,Proc};	_ ->	    case maybe_other_node(File,Pid) of		{other_node,Type,Node} -> 		    Info = "The process you are searching for was residing on "			"a remote node. No process information is available. "			"Information about the remote node is show below.",		    {other_node,{Type,Info,Node}};		not_found ->		    not_found	    end    end.if_exist(Tag,Key) ->    case ets:select_count(cdv_dump_index_table,[{{Tag,Key,'_'},[],[true]}]) of	0 -> 	    Tag1 = 		case is_proc_tag(Tag) of		    true -> "=proc";		    false -> Tag		end,	    case truncated_here({Tag1,Key}) of		true -> truncated;		false -> ?space	    end;	_ -> 	    expand    end.get_procinfo(Fd,Fun,Proc) ->    case line_head(Fd) of	"State" ->	    State = case val(Fd) of			"Garbing" -> "Garbing\n(limited info)";			State0 -> State0		    end,	    get_procinfo(Fd,Fun,Proc#proc{state=State});	"Name" ->	    get_procinfo(Fd,Fun,Proc#proc{name=val(Fd)});	"Spawned as" ->	    IF = val(Fd),	    case Proc#proc.name of		?space ->		    get_procinfo(Fd,Fun,Proc#proc{name=IF,init_func=IF});		_ ->		    get_procinfo(Fd,Fun,Proc#proc{init_func=IF})	    end;	"Spawned by" ->	    case val(Fd) of		"[]" ->		    get_procinfo(Fd,Fun,Proc);		Parent ->		    get_procinfo(Fd,Fun,Proc#proc{parent=Parent})	    end;	"Started" ->	    get_procinfo(Fd,Fun,Proc#proc{start_time=val(Fd)});	"Last scheduled in for" ->	    get_procinfo(Fd,Fun,Proc#proc{current_func=					  {"Last scheduled in for",					   val(Fd)}});	"Current call" ->	    get_procinfo(Fd,Fun,Proc#proc{current_func={"Current call",							val(Fd)}});	"Message queue length" -> 	    %% stored as integer so we can sort on it	    get_procinfo(Fd,Fun,Proc#proc{msg_q_len=list_to_integer(val(Fd))});	"Reductions" ->	    %% stored as integer so we can sort on it	    get_procinfo(Fd,Fun,Proc#proc{reds=list_to_integer(val(Fd))});	"Number of heap fragments" ->	    get_procinfo(Fd,Fun,Proc#proc{num_heap_frag=val(Fd)});	"Heap fragment data" ->	    get_procinfo(Fd,Fun,Proc#proc{heap_frag_data=val(Fd)});	Stack when Stack=:="Stack+heap"; Stack=:="Stack" ->	    %% stored as integer so we can sort on it	    get_procinfo(Fd,Fun,Proc#proc{stack_heap=					  list_to_integer(val(Fd))});	"OldHeap" ->	    get_procinfo(Fd,Fun,Proc#proc{old_heap=val(Fd)});	"Heap unused" ->	    get_procinfo(Fd,Fun,Proc#proc{heap_unused=val(Fd)});	"OldHeap unused" ->	    get_procinfo(Fd,Fun,Proc#proc{old_heap_unused=val(Fd)});	"New heap start" ->	    get_procinfo(Fd,Fun,Proc#proc{new_heap_start=val(Fd)});	"New heap top" ->	    get_procinfo(Fd,Fun,Proc#proc{new_heap_top=val(Fd)});	"Stack top" ->	    get_procinfo(Fd,Fun,Proc#proc{stack_top=val(Fd)});	"Stack end" ->	    get_procinfo(Fd,Fun,Proc#proc{stack_end=val(Fd)});	"Old heap start" ->	    get_procinfo(Fd,Fun,Proc#proc{old_heap_start=val(Fd)});	"Old heap top" ->	    get_procinfo(Fd,Fun,Proc#proc{old_heap_top=val(Fd)});	"Old heap end" ->	    get_procinfo(Fd,Fun,Proc#proc{old_heap_end=val(Fd)});	{eof,_} ->	    Proc; % truncated file	Other ->	    Fun(Fd,Fun,Proc,Other)    end.main_procinfo(Fd,Fun,Proc,LineHead) ->    case LineHead of	"Stack dump" ->	    %% This is the last element in older dumps (DumpVsn=0.0)	    Proc;	"=" ++ _next_tag ->	    %% DumpVsn=0.1 or newer: No stack dump here	    Proc;	"arity = " ++ _ ->	    %%! Temporary workaround	    get_procinfo(Fd,Fun,Proc);		_Other ->	    skip_rest_of_line(Fd),	    get_procinfo(Fd,Fun,Proc)    end.all_procinfo(Fd,Fun,Proc,LineHead) ->    case LineHead of	"Message queue" -> 	    get_procinfo(Fd,Fun,Proc#proc{msg_q=size_or_term(Fd)});	"Last calls" ->	    R = case size_or_term(Fd) of		    SizeThing when is_tuple(SizeThing) ->			Proc#proc{last_calls=SizeThing};		    Term ->			Proc#proc{last_calls=replace_all($ ,$\n,Term,[])}		end,	    get_procinfo(Fd,Fun,R);	"Link list" ->	    get_procinfo(Fd,Fun,Proc#proc{links=val(Fd)});	"Program counter" ->	    get_procinfo(Fd,Fun,Proc#proc{prog_count=val(Fd)});	"CP" ->	    get_procinfo(Fd,Fun,Proc#proc{cp=val(Fd)});	"arity = " ++ Arity ->	    %%! Temporary workaround	    get_procinfo(Fd,Fun,Proc#proc{arity=Arity--"\r\n"});	"Dictionary" ->	    get_procinfo(Fd,Fun,Proc#proc{dict=size_or_term(Fd)});	"$Dictionary" ->	    get_procinfo(Fd,Fun,Proc#proc{debug_dict=size_or_term(Fd)});	"Stack dump" ->	    %% This is the last element in older dumps (DumpVsn=0.0)	    get_stack_dump(Fd,Proc);	"=" ++ _next_tag ->	    %% DumpVsn=0.1 or newer: No stack dump here	    Proc;	Other ->	    unexpected(Fd,Other,"process info"),	    get_procinfo(Fd,Fun,Proc)    end.get_stack_dump(Fd,Proc) ->    %% Always show stackdump as "Expand" link    Pos = get(pos),    Size = count_rest_of_tag(Fd),    Proc#proc{stack_dump={size,true,Size,Pos}}.maybe_other_node(File,Id) ->    Channel = 	case split($.,Id) of	    {"<" ++ N, _Rest} ->		N;	    {"#Port<" ++ N, _Rest} ->		N	end,    Ms = ets:fun2ms(	   fun({Tag,Id,Start}) when Tag=:="=visible_node", Id=:=Channel -> 		   {"Visible Node",Start};	      ({Tag,Id,Start}) when Tag=:="=hidden_node", Id=:=Channel ->		   {"Hidden Node",Start};	      ({Tag,Id,Start}) when Tag=:="=not_connected", Id=:=Channel -> 		   {"Not Connected Node",Start}	   end),    case ets:select(cdv_dump_index_table,Ms) of	[] -> 	    not_found;	[{Type,Pos}] -> 	    Fd = open(File),	    NodeInfo = get_nodeinfo(Fd,Channel,Pos),	    close(Fd),	    {other_node,Type,NodeInfo}    end.expand_memory(File,What,Pid,Binaries) ->    Fd = open(File),    put(fd,Fd),    Dict = read_heap(Fd,Pid,Binaries),    Expanded = 	case What of	    "StackDump" -> read_stack_dump(Fd,Pid,Dict);	    "MsgQueue" -> read_messages(Fd,Pid,Dict);	    "Dictionary" -> read_dictionary(Fd,"=proc_dictionary",Pid,Dict);	    "DebugDictionary" -> read_dictionary(Fd,"=debug_proc_dictionary",Pid,Dict)	end,    erase(fd),    close(Fd),    Expanded.    %%%%%% Read binaries.%%%read_binaries(Fd) ->    AllBinaries = ets:match(cdv_dump_index_table,{"=binary",'$1','$2'}),    read_binaries(Fd,AllBinaries, gb_trees:empty()).read_binaries(Fd,[[Addr0,Pos]|Bins],Dict0) ->    pos_bof(Fd,Pos),    {Addr,_} = get_hex(Addr0),    Dict = 	case line_head(Fd) of	    {eof,_} ->		gb_trees:enter(Addr,'#CDVTruncatedBinary',Dict0);	    Size0 ->		{Size,_} = get_hex(Size0),		if Size > ?max_display_binary_size ->			gb_trees:enter(Addr,{'#CDVTooBig',binary,Pos},Dict0);		   true ->			pos_bof(Fd,Pos),			Line = val(Fd),			parse_binary(Addr,Line,Dict0)		end	end,    read_binaries(Fd,Bins,Dict);read_binaries(_Fd,[],Dict) ->    Dict.parse_binary(Addr, Line0, Dict) ->    case get_hex(Line0) of	{N,":"++Line1} ->	    {Bin,Line} = get_binary(N, Line1, []),	    [] = skip_blanks(Line),	    gb_trees:enter(Addr, Bin, Dict);	{_N,[]} ->	    %% If the dump is truncated before the ':' in this line, then	    %% line_head/1 might not discover it (if a \n has been inserted	    %% somehow???)	    gb_trees:enter(Addr,'#CDVTruncatedBinary',Dict)    end.%%%%%% Read top level section.%%%read_stack_dump(Fd,Pid,Dict) ->    case ets:match(cdv_dump_index_table,{"=proc_stack",Pid,'$1'}) of	[[Start]] ->	    pos_bof(Fd,Start),	    read_stack_dump1(Fd,Dict,[]);	[] ->	    []    end.read_stack_dump1(Fd,Dict,Acc) ->    %% This function is never called if the dump is truncated in "=proc_heap:Pid"    case val(Fd) of	"=" ++ _next_tag ->	    lists:reverse(Acc);	Line ->	    Stack = parse_top(Line,Dict),	    read_stack_dump1(Fd,Dict,[Stack|Acc])    end.parse_top(Line0, D) ->    {Label,Line1} = get_label(Line0),    {Term,Line,D} = parse_term(Line1, D),    [] = skip_blanks(Line),    {Label,Term}.%%%%%% Read message queue.%%%read_messages(Fd,Pid,Dict) ->    case ets:match(cdv_dump_index_table,{"=proc_messages",Pid,'$1'}) of	[[Start]] ->	    pos_bof(Fd,Start),	    read_messages1(Fd,Dict,[]);	[] ->	    []    end.read_messages1(Fd,Dict,Acc) ->    %% This function is never called if the dump is truncated in "=proc_heap:Pid"    case val(Fd) of	"=" ++ _next_tag ->	    lists:reverse(Acc);	Line ->	    Msg = parse_message(Line,Dict),	    read_messages1(Fd,Dict,[Msg|Acc])    end.    parse_message(Line0, D) ->    {Msg,":"++Line1,_} = parse_term(Line0, D),    {Token,Line,_} = parse_term(Line1, D),    [] = skip_blanks(Line),    {Msg,Token}.    %%%%%% Read process dictionary%%%read_dictionary(Fd,Tag,Pid,Dict) ->    case ets:match(cdv_dump_index_table,{Tag,Pid,'$1'}) of	[[Start]] ->	    pos_bof(Fd,Start),	    read_dictionary1(Fd,Dict,[]);	[] ->	    []    end.read_dictionary1(Fd,Dict,Acc) ->    %% This function is never called if the dump is truncated in "=proc_heap:Pid"    case val(Fd) of	"=" ++ _next_tag ->	    lists:reverse(Acc);	Line ->	    Msg = parse_dictionary(Line,Dict),	    read_dictionary1(Fd,Dict,[Msg|Acc])    end.

⌨️ 快捷键说明

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