crashdump_viewer.erl

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

ERL
2,144
字号
		crashdump_viewer_html:info_page(What,[TruncText,LastCalls]);	    {_,"StackDump"} ->		crashdump_viewer_html:info_page(What,[TruncText,Expanded]);	    {"false",_} ->		crashdump_viewer_html:pretty_info_page(What,Expanded);	    {"true",_} ->		crashdump_viewer_html:info_page(What,[TruncText,Expanded])	end,    {reply,Reply,State};handle_call({expand_memory,Input},_From,State=#state{file=File,binaries=B}) ->    [{"pid",Pid},{"what",What}] = httpd:parse_query(Input),    Reply = 	case truncated_warning([{"=proc",Pid}]) of	    [] ->		Expanded = expand_memory(File,What,Pid,B),		crashdump_viewer_html:expanded_memory(What,Expanded);	    _TW ->		Info = 		    "The crashdump is truncated in the middle of this "		    "process' memory information, so this information "		    "can not be extracted.",		crashdump_viewer_html:info_page(What,Info)	end,    {reply,Reply,State};handle_call({expand_binary,Input},_From,State=#state{file=File}) ->    [{"pos",Pos0}] = httpd:parse_query(Input),    Pos = list_to_integer(Pos0),    Fd = open(File),    pos_bof(Fd,Pos),    {Bin,_Line} = get_binary(val(Fd)),    close(Fd),    Reply=crashdump_viewer_html:expanded_binary(io_lib:format("~p",[Bin])),    {reply,Reply,State};handle_call({next,Input},_From,State=#state{file=File}) ->    [{"pos",Pos},{"num",N},{"start",Start},{"what",What}] =	httpd:parse_query(Input),    Tags = related_tags(What),    TW = truncated_warning(Tags),    Next = get_next(File,list_to_integer(Pos),list_to_integer(N),		    list_to_integer(Start),What),    Reply = crashdump_viewer_html:next(Next,TW),    {reply,Reply,State};handle_call(general_info,_From,State=#state{file=File}) ->    GenInfo=general_info(File),    Reply = crashdump_viewer_html:general_info(GenInfo),    {reply,Reply,State};handle_call(procs_summary,_From,State=#state{file=File,shared_heap=SH}) ->    ProcsSummary =	case State#state.procs_summary of	    undefined -> procs_summary(File);	    PS -> PS	end,    TW = truncated_warning(["=proc"]),    Reply = crashdump_viewer_html:procs_summary("pid",ProcsSummary,TW,SH),    {reply,Reply,State#state{procs_summary=ProcsSummary,sorted="pid"}};handle_call({sort_procs,Input}, _From, State=#state{shared_heap=SH}) ->    {ok,Sort} = get_value("sort",httpd:parse_query(Input)),    {ProcsSummary,Sorted} = do_sort_procs(Sort,					  State#state.procs_summary,					  State#state.sorted),    TW = truncated_warning(["=proc"]),    Reply = crashdump_viewer_html:procs_summary(Sort,ProcsSummary,TW,SH),    {reply,Reply,State#state{sorted=Sorted}};handle_call({proc_details,Input},_From,State=#state{file=File,shared_heap=SH}) ->    {ok,Pid} = get_value("pid",httpd:parse_query(Input)),    Reply = 	case get_proc_details(File,Pid) of	    {ok,Proc} -> 		TW = truncated_warning([{"=proc",Pid}]),		crashdump_viewer_html:proc_details(Pid,Proc,TW,SH);	    {other_node,Node} -> 		TW = truncated_warning(["=visible_node",					"=hidden_node",					"=not_connected"]),		crashdump_viewer_html:nods(Node,TW);	    not_found -> 		crashdump_viewer_html:info_page(["Could not find process: ",						 Pid],?space)	end,    {reply, Reply, State};handle_call({ports,Input},_From,State=#state{file=File}) ->    Reply = 	case get_value("port",httpd:parse_query(Input)) of	    {ok,P} -> 		Id = [$#|P],		case get_port(File,Id) of		    {ok,PortInfo} ->			TW = truncated_warning([{"=port",Id}]),			crashdump_viewer_html:ports(Id,[PortInfo],TW);		    {other_node,Node} ->			TW = truncated_warning(["=visible_node",						"=hidden_node",						"=not_connected"]),			crashdump_viewer_html:nods(Node,TW);		    not_found -> 			crashdump_viewer_html:info_page(			  ["Could not find port: ",Id],?space)		end;	    error -> % no port identity in Input - get all ports		Ports=get_ports(File),		TW = truncated_warning(["=port"]),		crashdump_viewer_html:ports("Port Information",Ports,TW)	end,    {reply,Reply,State};handle_call({ets_tables,Input},_From,State=#state{file=File,wordsize=WS}) ->    {Pid,Heading,InternalEts} = 	case get_value("pid",httpd:parse_query(Input)) of	    {ok,P} -> 		{P,["ETS Tables for Process ",P],[]};	    error -> 		I = get_internal_ets_tables(File,WS),		{'_',"ETS Table Information",I}	end,    EtsTables = get_ets_tables(File,Pid,WS),    TW = truncated_warning(["=ets"]),    Reply = crashdump_viewer_html:ets_tables(Heading,EtsTables,InternalEts,TW),    {reply,Reply,State};handle_call({timers,Input},_From,State=#state{file=File}) ->    {Pid,Heading} = 	case get_value("pid",httpd:parse_query(Input)) of	    {ok,P} -> {P,["Timers for Process ",P]};	    error -> {'_',"Timer Information"}	end,    Timers=get_timers(File,Pid),    TW = truncated_warning(["=timer"]),    Reply = crashdump_viewer_html:timers(Heading,Timers,TW),    {reply,Reply,State};handle_call(dist_info,_From,State=#state{file=File}) ->    Nods=nods(File),    TW = truncated_warning(["=visible_node","=hidden_node","=not_connected"]),    Reply = crashdump_viewer_html:nods(Nods,TW),    {reply,Reply,State};handle_call(loaded_mods,_From,State=#state{file=File}) ->    LoadedMods=loaded_mods(File),    TW = truncated_warning(["=mod"]),    Reply = crashdump_viewer_html:loaded_mods(LoadedMods,TW),    {reply,Reply,State};handle_call({loaded_mod_details,Input},_From,State=#state{file=File}) ->    {ok,Mod} = get_value("mod",httpd:parse_query(Input)),    ModInfo = get_loaded_mod_details(File,Mod),    TW = truncated_warning([{"=mod",Mod}]),    Reply = crashdump_viewer_html:loaded_mod_details(ModInfo,TW),    {reply,Reply,State};handle_call(funs,_From,State=#state{file=File}) ->    Funs=funs(File),    TW = truncated_warning(["=fun"]),    Reply = crashdump_viewer_html:funs(Funs,TW),    {reply,Reply,State};handle_call(atoms,_From,State=#state{file=File,num_atoms=Num}) ->    Atoms=atoms(File),    TW = truncated_warning(["=atoms","=num_atoms"]),    Reply = crashdump_viewer_html:atoms(Atoms,Num,TW),    {reply,Reply,State};handle_call(memory,_From,State=#state{file=File}) ->    Memory=memory(File),    TW = truncated_warning(["=memory"]),    Reply = crashdump_viewer_html:memory(Memory,TW),    {reply,Reply,State};handle_call(allocated_areas,_From,State=#state{file=File}) ->    AllocatedAreas=allocated_areas(File),    TW = truncated_warning(["=allocated_areas"]),    Reply = crashdump_viewer_html:allocated_areas(AllocatedAreas,TW),    {reply,Reply,State};handle_call(allocator_info,_From,State=#state{file=File}) ->    SlAlloc=allocator_info(File),    TW = truncated_warning(["=allocator"]),    Reply = crashdump_viewer_html:allocator_info(SlAlloc,TW),    {reply,Reply,State};handle_call(hash_tables,_From,State=#state{file=File}) ->    HashTables=hash_tables(File),    TW = truncated_warning(["=hash_table","=index_table"]),    Reply = crashdump_viewer_html:hash_tables(HashTables,TW),    {reply,Reply,State};handle_call(index_tables,_From,State=#state{file=File}) ->    IndexTables=index_tables(File),    TW = truncated_warning(["=hash_table","=index_table"]),    Reply = crashdump_viewer_html:index_tables(IndexTables,TW),    {reply,Reply,State}.%%--------------------------------------------------------------------%% Function: handle_cast/2%% Description: Handling cast messages%% Returns: {noreply, State}          |%%          {noreply, State, Timeout} |%%          {stop, Reason, State}            (terminate/2 is called)%%--------------------------------------------------------------------handle_cast({background_done,{Page,File,Binaries},Dict}, State) ->    lists:foreach(fun({Key,Val}) -> put(Key,Val) end, Dict),    {noreply, State#state{file=File,binaries=Binaries,bg_status={done,Page}}};handle_cast({background_status,Status}, State) ->    {noreply, State#state{bg_status=Status}}.%%--------------------------------------------------------------------%% Function: handle_info/2%% Description: Handling all non call/cast messages%% Returns: {noreply, State}          |%%          {noreply, State, Timeout} |%%          {stop, Reason, State}            (terminate/2 is called)%%--------------------------------------------------------------------handle_info(_Info, State) ->    {noreply, State}.%%--------------------------------------------------------------------%% Function: terminate/2%% Description: Shutdown the server%% Returns: any (ignored by gen_server)%%--------------------------------------------------------------------terminate(_Reason, _State) ->    ok.%%--------------------------------------------------------------------%% Func: code_change/3%% Purpose: Convert process state when code is changed%% Returns: {ok, NewState}%%--------------------------------------------------------------------code_change(_OldVsn, State, _Extra) ->    {ok, State}.%%--------------------------------------------------------------------%%% Internal functions%%--------------------------------------------------------------------    call(Request) ->     gen_server:call(?SERVER,Request,?call_timeout).cast(Msg) ->    gen_server:cast(?SERVER,Msg).unexpected(_Fd,{eof,_LastLine},_Where) ->    ok; % truncated fileunexpected(Fd,{part,What},Where) ->    skip_rest_of_line(Fd),    io:format("WARNING: Found unexpected line in ~s:~n~s ...~n",[Where,What]);unexpected(_Fd,What,Where) ->    io:format("WARNING: Found unexpected line in ~s:~n~s~n",[Where,What]).truncated_warning([]) ->    [];truncated_warning([Tag|Tags]) ->    case truncated_here(Tag) of	true -> truncated_warning();	false -> truncated_warning(Tags)    end.truncated_warning() ->    ["WARNING: The crash dump is truncated here. "     "Some information might be missing."].truncated_here(Tag) ->    case get(truncated) of	true ->	    case get(last_tag) of		Tag -> % Tag == {TagType,Id}		    true;		{Tag,_Id} ->		    true;		_LastTag ->		    truncated_earlier(Tag)	    end;	false ->	    false    end.		    %% Check if the dump was truncated with the same tag, but earlier id.%% Eg if this is {"=proc","<0.30.0>"}, we should warn if the dump was%% truncated in {"=proc","<0.29.0>"} or earliertruncated_earlier({"=proc",Pid}) ->    compare_pid(Pid,get(truncated_proc));truncated_earlier(_Tag) ->    false.compare_pid("<"++Id,"<"++OtherId) ->    Id>=OtherId;compare_pid(_,_) ->    false.background_status(Action,File) ->    SizeInfo = filesizeinfo(File),     background_status(Action,File,SizeInfo).background_status(translating,File,SizeInfo) ->   "Converting "  ++ File ++ SizeInfo ++ " to new crashdump format";background_status(processing,File,SizeInfo) ->    "Processing " ++ File ++ SizeInfo;background_status(reading,File,SizeInfo) ->    "Reading file " ++ File ++ SizeInfo.filesizeinfo(File) ->    case file:read_file_info(File) of	{ok,#file_info{size=Size}} -> 	    " (" ++ integer_to_list(Size) ++ " bytes)";	_X ->	    ""    end.open(File) ->    {ok,Fd} = file:open(File,[read,read_ahead,raw,binary]),    Fd.close(Fd) ->    erase(chunk),    file:close(Fd).pos_bof(Fd,Pos) ->    reset_chunk(),    file:position(Fd,{bof,Pos}). get_chunk(Fd) ->    case erase(chunk) of	undefined ->	    case read(Fd) of		eof -> 		    put_pos(Fd),		    eof;		Other ->		    Other	    end;	Bin ->	    {ok,Bin}    end.read(Fd) ->    file:read(Fd,?chunk_size).put_chunk(Fd,Bin) ->    {ok,Pos0} = file:position(Fd,cur),    Pos = Pos0 - size(Bin),    put(chunk,Bin),    put(pos,Pos).put_pos(Fd) ->    {ok,Pos} = file:position(Fd,cur),    put(pos,Pos).    reset_chunk() ->    erase(chunk),    erase(pos).line_head(Fd) ->    case get_chunk(Fd) of	{ok,Bin} -> line_head(Fd,Bin,[],0);	eof -> {eof,[]}    end.line_head(Fd,Bin,Acc,?max_line_size) ->    put_chunk(Fd,Bin),    {part,lists:reverse(Acc)};line_head(Fd,<<$\n:8,Bin/binary>>,Acc,_N) ->    put_chunk(Fd,Bin),    lists:reverse(Acc);line_head(Fd,<<$::8,$\r:8,$\n:8,Bin/binary>>,Acc,_N) ->    put_chunk(Fd,Bin),    lists:reverse(Acc);line_head(Fd,<<$::8,Space:8,Bin/binary>>,Acc,_N) when Space=:=$ ;Space=:=$\n ->    put_chunk(Fd,Bin),    lists:reverse(Acc);line_head(Fd,Colon,Acc,N) when Colon == <<$::8>>; Colon == <<$::8,$\r:8>>->    case get_chunk(Fd) of	{ok,Bin} -> line_head(Fd,<<$:,Bin/binary>>,Acc,N);	eof -> {eof,lists:reverse(Acc)}    end;line_head(Fd,<<$::8,Bin/binary>>,Acc,_N) ->    put_chunk(Fd,Bin),    lists:reverse(Acc);line_head(Fd,<<$\r:8,Bin/binary>>,Acc,N) ->    line_head(Fd,Bin,Acc,N+1);line_head(Fd,<<Char:8,Bin/binary>>,Acc,N) ->    line_head(Fd,Bin,[Char|Acc],N+1);line_head(Fd,<<>>,Acc,N) ->    case get_chunk(Fd) of	{ok,Bin} -> line_head(Fd,Bin,Acc,N);	eof -> {eof,lists:reverse(Acc)}    end.skip_rest_of_line(Fd) ->    case get_chunk(Fd) of	{ok,Bin} -> skip(Fd,Bin);	eof -> ok    end.skip(Fd,<<$\n:8,Bin/binary>>) ->    put_chunk(Fd,Bin),    ok;skip(Fd,<<_Char:8,Bin/binary>>) ->    skip(Fd,Bin);skip(Fd,<<>>) ->    case get_chunk(Fd) of	{ok,Bin} -> skip(Fd,Bin);	eof -> ok    end.val(Fd) ->    case get_rest_of_line(Fd) of	{eof,[]} -> "-1";	[] -> "-1";	{eof,Val} -> Val;	Val -> Val    end.get_rest_of_line(Fd) ->    case get_chunk(Fd) of	{ok,Bin} -> get_rest_of_line_1(Fd, Bin, 0, []);	eof -> {eof,[]}    end.get_rest_of_line_1(Fd, Bin0, I, Acc) ->    case Bin0 of	<<_:I/binary,$\n:8,Bin/binary>> ->	    put_chunk(Fd, Bin),	    lists:reverse(Acc);	<<_:I/binary,$\r:8,_/binary>> ->	    get_rest_of_line_1(Fd, Bin0, I+1, Acc);	<<_:I/binary,Char:8,_/binary>> ->	    get_rest_of_line_1(Fd, Bin0, I+1, [Char|Acc]);	<<_:I/binary>> ->	    case get_chunk(Fd) of		{ok,Bin} -> get_rest_of_line_1(Fd, Bin, 0, Acc);		eof -> {eof,lists:reverse(Acc)}	    end    end.count_rest_of_line(Fd) ->    case get_chunk(Fd) of	{ok,Bin} -> count_rest_of_line(Fd,Bin,0);	eof -> {eof,0}    end.count_rest_of_line(Fd,<<$\n:8,Bin/binary>>,N) ->    put_chunk(Fd,Bin),    N;count_rest_of_line(Fd,<<$\r:8,Bin/binary>>,N) ->

⌨️ 快捷键说明

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