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 + -
显示快捷键?