我使用此代码从编译的beam文件中获取erlang源代码:
-spec source(module()) -> iolist().
source(Module) ->
Path = code:which(Module),
{ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(Path, [abstract_code]),
erl_prettypr:format(erl_syntax:form_list(AC)).
结果如下:
"-file(\"src/recon.erl\", 1).\n\n-module(recon).\n\n-export([info/1, info/2, info/3, info/4, proc_count/2,\n\t proc_window/3, bin_leak/1, node_stats_print/2,\n\t node_stats_list/2, node_stats/4, scheduler_usage/1]).\n\n-export([get_state/1, get_state/2]).\n\n-export([remote_load/1, remote_load/2, source/1]).\n\n-export([tcp/0, udp/0, sctp/0, files/0, port_types/0,\n\t inet_count/2, inet_window/3, port_info/1, port_info/2]).\n\n-export([rpc/1, rpc/2, rpc/3, named_rpc/1, named_rpc/2,\n\t named_rpc/3]).\n\n-type({proc_attrs,\n {type, 98, tuple,\n\t[{type, 98, pid, []},\n\t {ann_type, 99, [{var, 99, 'Attr'}, {var, 99, '_'}]},\n\t {type, 100, nonempty_list,\n\t [{ann_type, 100,\n\t [{var, 100, 'Name'},\n\t {type, 100, union,\n\t [{type, 100, atom, []},\n\t {type, 101, tuple,\n\t\t[{atom, 101, current_function}, {type, 101, mfa, []}]},\n\t {type, 102, tuple,\n\t\t[{atom, 102, initial_call},\n\t\t {type, 102, mfa, []}]}]}]}]}]},\n []}).\n\n-type({inet_attrs,\n {type, 104, tuple,\n\t[{type, 104, port, []},\n\t {ann_type, 105, [{var, 105, 'Attr'}, {var, 105, '_'}]},\n\t {type, 106, list,\n\t [{type, 106, tuple,\n\t [{type, 106, atom, []}, {type, 106, term, []}]}]}]},\n []}).\n\n-type({pid_term,\n {type, 108, union,\n\t[{type, 108, pid, []}, {type, 108, atom, []},\n\t {type, 108, string, []},\n\t {type, 109, tuple,\n\t [{atom, 109, global}, {type, 109, term, []}]},\n\t {type, 109, tuple,\n\t [{atom, 109, via}, {type, 109, module, []},\n\t {type, 109, term, []}]},\n\t {type, 110, tuple,\n\t [{type, 110, non_neg_integer, []},\n\t {type, 110, non_neg_integer, []},\n\t {type, 110, non_neg_integer, []}]}]},\n []}).\n\n-type({info_type,\n {type, 112, union,\n\t[{atom, 112, meta}, {atom, 112, signals},\n\t {atom, 112, location}, {atom, 112, memory_used},\n\t {atom, 112, work}]},\n []}).\n\n-type({info_meta_key,\n {type, 114, union,\n\t[{atom, 114, registered_name}, {atom, 114, dictionary},\n\t {atom, 114, group_leader}, {atom, 114, status}]},\n []}).\n\n-type({info_signals_key,\n {type, 115, union,\n\t[{atom, 115, links}, {atom, 115, monitors},\n\t {atom, 115, monitored_by}, {atom, 115, trap_exit}]},\n []}).\n\n-type({info_location_key,\n {type, 116, union,\n\t[{atom, 116, initial_call},\n\t {atom, 116, current_stacktrace}]},\n []}).\n\n-type({info_memory_key,\n {type, 117, union,\n\t[{atom, 117, memory}, {atom, 117, message_queue_len},\n\t {atom, 117, heap_size}, {atom, 118, total_heap_size},\n\t {atom, 118, garbage_collection}]},\n []}).\n\n-type({info_work_key, {atom, 119, reductions}, []}).\n\n-type({info_key,\n {type, 121, union,\n\t[{user_type, 121, info_meta_key, []},\n\t {user_type, 121, info_signals_key, []},\n\t {user_type, 121, info_location_key, []},\n\t {user_type, 122, info_memory_key, []},\n\t {user_type, 122, info_work_key, []}]},\n []}).\n\n-type({port_term,\n {type, 124, union,\n\t[{type, 124, port, []}, {type, 124, string, []},\n\t {type, 124, atom, []}, {type, 124, pos_integer, []}]},\n []}).\n\n-type({port_info_type,\n {type, 126, union,\n\t[{atom, 126, meta}, {atom, 126, signals},\n\t {atom, 126, io}, {atom, 126, memory_used},\n\t {atom, 126, specific}]},\n []}).\n\n-type({port_info_meta_key,\n {type, 128, union,\n\t[{atom, 128, registered_name}, {atom, 128, id},\n\t {atom, 128, name}, {atom, 128, os_pid}]},\n []}).\n\n-type({port_info_signals_key,\n {type, 129, union,\n\t[{atom, 129, connected}, {atom, 129, links},\n\t {atom, 129, monitors}]},\n []}).\n\n-type({port_info_io_key,\n {type, 130, union,\n\t[{atom, 130, input}, {atom, 130, output}]},\n []}).\n\n-type({port_info_memory_key,\n {type, 131, union,\n\t[{atom, 131, memory}, {atom, 131, queue_size}]},\n []}).\n\n-type({port_info_specific_key, {type, 132, atom, []},\n []}).\n\n-type({port_info_key,\n {type, 134, union,\n\t[{user_type, 134, port_info_meta_key, []},\n\t {user_type, 134, port_info_signals_key, []},\n\t {user_type, 135, port_info_io_key, []},\n\t {user_type, 135, port_info_memory_key, []},\n\t {user_type, 136, port_info_specific_key, []}]},\n []}).\n\n-export_type([{proc_attrs, 0}, {inet_attrs, 0},\n\t {pid_term, 0}, {port_term, 0}]).\n\n-export_type([{info_type, 0}, {info_key, 0},\n\t {info_meta_key, 0}, {info_signals_key, 0},\n\t {info_location_key, 0}, {info_memory_key, 0},\n\t {info_work_key, 0}]).\n\n-export_type([{port_info_type, 0}, {port_info_key, 0},\n\t {port_info_meta_key, 0}, {port_info_signals_key, 0},\n\t {port_info_io_key, 0}, {port_info_memory_key, 0},\n\t {port_info_specific_key, 0}]).\n\n-spec({{info, 3},\n [{type, 154, bounded_fun,\n\t [{type, 154, 'fun',\n\t [{type, 154, product,\n\t [{var, 154, 'N'}, {var, 154, 'N'}, {var, 154, 'N'}]},\n\t {type, 154, nonempty_list,\n\t [{type, 154, tuple,\n\t [{user_type, 154, info_type, []},\n\t\t{type, 154, list,\n\t\t [{type, 154, tuple,\n\t\t [{user_type, 154, info_key, []},\n\t\t {type, 154, term, []}]}]}]}]}]},\n\t [{type, 155, constraint,\n\t [{atom, 155, is_subtype},\n\t [{var, 155, 'N'},\n\t {type, 155, non_neg_integer, []}]]}]]}]}).\n\ninfo(A, B, C) -> info(recon_lib:triple_to_pid(A, B, C)).\n\n-spec({{info, 4},\n [{type, 160, bounded_fun,\n\t [{type, 160, 'fun',\n\t [{type, 160, product,\n\t [{var, 160, 'N'}, {var, 160, 'N'}, {var, 160, 'N'},\n\t {var, 160, 'Key'}]},\n\t {type, 160, term, []}]},\n\t [{type, 161, constraint,\n\t [{atom, 161, is_subtype},\n\t [{var, 161, 'N'}, {type, 161, non_neg_integer, []}]]},\n\t {type, 162, constraint,\n\t [{atom, 162, is_subtype},\n\t [{var, 162, 'Key'},\n\t {type, 162, union,\n\t [{user_type, 162, info_type, []},\n\t\t{type, 162, list, [{type, 162, atom, []}]},\n\t\t{type, 162, atom, []}]}]]}]]}]}).\n\ninfo(A, B, C, Key) ->\n info(recon_lib:triple_to_pid(A, B, C), Key).\n\n-spec({{info, 1},\n [{type, 177, bounded_fun,\n\t [{type, 177, 'fun',\n\t [{type, 177, product, [{user_type, 177, pid_term, []}]},\n\t {type, 177, nonempty_list,\n\t [{type, 177, tuple,\n\t [{user_type, 177, info_type, []},\n\t\t{type, 177, list,\n\t\t [{type, 177, tuple,\n\t\t [{user_type, 177, info_key, []},\n\t\t {var, 177, 'Value'}]}]}]}]}]},\n\t [{type, 178, constraint,\n\t [{atom, 178, is_subtype},\n\t [{var, 178, 'Value'}, {type, 178, term, []}]]}]]}]}).\n\ninfo(PidTerm) ->\n Pid = recon_lib:term_to_pid(PidTerm),\n [info(Pid, Type)\n || Type\n\t <- [meta, signals, location, memory_used, work]].\n\n-spec({{info, 2},\n [{type, 200, 'fun',\n\t [{type, 200, product,\n\t [{user_type, 200, pid_term, []},\n\t {user_type, 200, info_type, []}]},\n\t {type, 200, tuple,\n\t [{user_type, 200, info_type, []},\n\t {type, 200, list,\n\t [{type, 200, tuple,\n\t [{user_type, 200, info_key, []},\n\t\t{type, 200, term, []}]}]}]}]},\n\t{type, 201, 'fun',\n\t [{type, 201, product,\n\t [{user_type, 201, pid_term, []},\n\t {type, 201, list, [{type, 201, atom, []}]}]},\n\t {type, 201, list,\n\t [{type, 201, tuple,\n\t [{type, 201, atom, []}, {type, 201, term, []}]}]}]},\n\t{type, 202, 'fun',\n\t [{type, 202, product,\n\t [{user_type, 202, pid_term, []},\n\t {type, 202, atom, []}]},\n\t {type, 202, tuple,\n\t [{type, 202, atom, []}, {type, 202, term, []}]}]}]}).\n\ninfo(PidTerm, meta) ->\n info_type(PidTerm, meta,\n\t [registered_name, dictionary, group_leader, status]);\ninfo(PidTerm, signals) ->\n info_type(PidTerm, signals,\n\t [links, monitors, monitored_by, trap_exit]);\ninfo(PidTerm, location) ->\n info_type(PidTerm, location,\n\t [initial_call, current_stacktrace]);\ninfo(PidTerm, memory_used) ->\n info_type(PidTerm, memory_used,\n\t [memory, message_queue_len, heap_size, total_heap_size,\n\t garbage_collection]);\ninfo(PidTerm, work) ->\n info_type(PidTerm, work, [reductions]);\ninfo(PidTerm, Keys) ->\n proc_info(recon_lib:term_to_pid(PidTerm), Keys).\n\n-spec({{info_type, 3},\n [{type, 219, 'fun',\n\t [{type, 219, product,\n\t [{user_type, 219, pid_term, []},\n\t {user_type, 219, info_type, []},\n\t {type, 219, list, [{user_type, 219, info_key, []}]}]},\n\t {type, 220, tuple,\n\t [{user_type, 220, info_type, []},\n\t {type, 220, list,\n\t [{type, 220, tuple,\n\t [{user_type, 220, info_key, []},\n\t\t{type, 220, term, []}]}]}]}]}]}).\n\ninfo_type(PidTerm, Type, Keys) ->\n Pid = recon_lib:term_to_pid(PidTerm),\n {Type, proc_info(Pid, Keys)}.\n\nproc_info(Pid, binary_memory) ->\n {binary, Bins} = erlang:process_info(Pid, binary),\n {binary_memory, recon_lib:binary_memory(Bins)};\nproc_info(Pid, Term) when is_atom(Term) ->\n erlang:process_info(Pid, Term);\nproc_info(Pid, List) when is_list(List) ->\n case lists:member(binary_memory, List) of\n false -> erlang:process_info(Pid, List);\n true ->\n\t Res = erlang:process_info(Pid,\n\t\t\t\t replace(binary_memory, binary, List)),\n\t proc_fake(List, Res)\n end.\n\nreplace(_, _, []) -> [];\nreplace(H, Val, [H | T]) -> [Val | replace(H, Val, T)];\nreplace(R, Val, [H | T]) -> [H | replace(R, Val, T)].\n\nproc_fake([], []) -> [];\nproc_fake([binary_memory | T1],\n\t [{binary, Bins} | T2]) ->\n [{binary_memory, recon_lib:binary_memory(Bins)}\n | proc_fake(T1, T2)];\nproc_fake([_ | T1], [H | T2]) ->\n [H | proc_fake(T1, T2)].\n\n-spec({{proc_count, 2},\n [{type, 259, bounded_fun,\n\t [{type, 259, 'fun',\n\t [{type, 259, product,\n\t [{var, 259, 'AttributeName'}, {var, 259, 'Num'}]},\n\t {type, 259, list, [{user_type, 259, proc_attrs, []}]}]},\n\t [{type, 260, constraint,\n\t [{atom, 260, is_subtype},\n\t [{var, 260, 'AttributeName'}, {type, 260, atom, []}]]},\n\t {type, 261, constraint,\n\t [{atom, 261, is_subtype},\n\t [{var, 261, 'Num'},\n\t {type, 261, non_neg_integer, []}]]}]]}]}).\n\nproc_count(AttrName, Num) ->\n lists:sublist(lists:usort(fun ({_, A, _}, {_, B, _}) ->\n\t\t\t\t A > B\n\t\t\t end,\n\t\t\t recon_lib:proc_attrs(AttrName)),\n\t\t Num).\n\n-spec({{proc_window, 3},\n [{type, 293, bounded_fun,\n\t [{type, 293, 'fun',\n\t [{type, 293, product,\n\t [{var, 293, 'AttributeName'}, {var, 293, 'Num'},\n\t {var, 293, 'Milliseconds'}]},\n\t {type, 293, list, [{user_type, 293, proc_attrs, []}]}]},\n\t [{type, 294, constraint,\n\t [{atom, 294, is_subtype},\n\t [{var, 294, 'AttributeName'}, {type, 294, atom, []}]]},\n\t {type, 295, constraint,\n\t [{atom, 295, is_subtype},\n\t [{var, 295, 'Num'}, {type, 295, non_neg_integer, []}]]},\n\t {type, 296, constraint,\n\t [{atom, 296, is_subtype},\n\t [{var, 296, 'Milliseconds'},\n\t {type, 296, pos_integer, []}]]}]]}]}).\n\nproc_window(AttrName, Num, Time) ->\n Sample = fun () -> recon_lib:proc_attrs(AttrName) end,\n {First, Last} = recon_lib:sample(Time, Sample),\n lists:sublist(lists:usort(fun ({_, A, _}, {_, B, _}) ->\n\t\t\t\t A > B\n\t\t\t end,\n\t\t\t recon_lib:sliding_window(First, Last)),\n\t\t Num).\n\n-spec({{bin_leak, 1},\n [{type, 318, 'fun',\n\t [{type, 318, product, [{type, 318, pos_integer, []}]},\n\t {type, 318, list,\n\t [{user_type, 318, proc_attrs, []}]}]}]}).\n\nbin_leak(N) ->\n lists:sublist(lists:usort(fun ({K1, V1, _},\n\t\t\t\t {K2, V2, _}) ->\n\t\t\t\t {V1, K1} =< {V2, K2}\n\t\t\t end,\n\t\t\t [try {ok, {_, Pre, Id}} =\n\t\t\t\t recon_lib:proc_attrs(binary, Pid),\n\t\t\t\t erlang:garbage_collect(Pid),\n\t\t\t\t {ok, {_, Post, _}} =\n\t\t\t\t recon_lib:proc_attrs(binary, Pid),\n\t\t\t\t {Pid, length(Post) - length(Pre), Id}\n\t\t\t catch\n\t\t\t\t _:_ -> {Pid, 0, []}\n\t\t\t end\n\t\t\t || Pid <- processes()]),\n\t\t N).\n\n-spec({{node_stats_print, 2},\n [{type, 334, bounded_fun,\n\t [{type, 334, 'fun',\n\t [{type, 334, product,\n\t [{var, 334, 'Repeat'}, {var, 334, 'Interval'}]},\n\t {type, 334, term, []}]},\n\t [{type, 335, constraint,\n\t [{atom, 335, is_subtype},\n\t [{var, 335, 'Repeat'},\n\t {type, 335, non_neg_integer, []}]]},\n\t {type, 336, constraint,\n\t [{atom, 336, is_subtype},\n\t [{var, 336, 'Interval'},\n\t {type, 336, pos_integer, []}]]}]]}]}).\n\nnode_stats_print(N, Interval) ->\n node_stats(N, Interval,\n\t fun (X, _) -> io:format(\"~p~n\", [X]) end, ok).\n\n-spec({{scheduler_usage, 1},\n [{type, 358, bounded_fun,\n\t [{type, 358, 'fun',\n\t [{type, 358, product, [{var, 358, 'Millisecs'}]},\n\t {type, 358, list,\n\t [{type, 358, tuple,\n\t [{var, 358, 'SchedulerId'}, {var, 358, 'Usage'}]}]}]},\n\t [{type, 359, constraint,\n\t [{atom, 359, is_subtype},\n\t [{var, 359, 'Millisecs'},\n\t {type, 359, non_neg_integer, []}]]},\n\t {type, 360, constraint,\n\t [{atom, 360, is_subtype},\n\t [{var, 360, 'SchedulerId'},\n\t {type, 360, pos_integer, []}]]},\n\t {type, 361, constraint,\n\t [{atom, 361, is_subtype},\n\t [{var, 361, 'Usage'}, {type, 361, number, []}]]}]]}]}).\n\nscheduler_usage(Interval) when is_integer(Interval) ->\n FormerFlag = erlang:system_flag(scheduler_wall_time,\n\t\t\t\t true),\n First = erlang:statistics(scheduler_wall_time),\n timer:sleep(Interval),\n Last = erlang:statistics(scheduler_wall_time),\n erlang:system_flag(scheduler_wall_time, FormerFlag),\n recon_lib:scheduler_usage_diff(First, Last).\n\n-spec({{node_stats_list, 2},\n [{type, 375, bounded_fun,\n\t [{type, 375, 'fun',\n\t [{type, 375, product,\n\t [{var, 375, 'Repeat'}, {var, 375, 'Interval'}]},\n\t {type, 375, list, [{var, 375, 'Stats'}]}]},\n\t [{type, 376, constraint,\n\t [{atom, 376, is_subtype},\n\t [{var, 376, 'Repeat'},\n\t {type, 376, non_neg_integer, []}]]},\n\t {type, 377, constraint,\n\t [{atom, 377, is_subtype},\n\t [{var, 377, 'Interval'},\n\t {type, 377, pos_integer, []}]]},\n\t {type, 378, constraint,\n\t [{atom, 378, is_subtype},\n\t [{var, 378, 'Stats'},\n\t {type, 378, tuple,\n\t [{type, 378, list,\n\t\t [{ann_type, 378,\n\t\t [{var, 378, 'Absolutes'},\n\t\t {type, 378, tuple,\n\t\t [{type, 378, atom, []}, {type, 378, term, []}]}]}]},\n\t\t{type, 379, list,\n\t\t [{ann_type, 379,\n\t\t [{var, 379, 'Increments'},\n\t\t {type, 379, tuple,\n\t\t [{type, 379, atom, []},\n\t\t {type, 379, term, []}]}]}]}]}]]}]]}]}).\n\nnode_stats_list(N, Interval) ->\n lists:reverse(node_stats(N, Interval,\n\t\t\t fun (X, Acc) -> [X | Acc] end, [])).\n\n-spec({{node_stats, 4},\n [{type, 397, bounded_fun,\n\t [{type, 397, 'fun',\n\t [{type, 397, product,\n\t [{var, 397, 'N'}, {var, 397, 'Interval'},\n\t {var, 397, 'FoldFun'}, {var, 397, 'Acc'}]},\n\t {var, 397, 'Acc'}]},\n\t [{type, 398, constraint,\n\t [{atom, 398, is_subtype},\n\t [{var, 398, 'N'}, {type, 398, non_neg_integer, []}]]},\n\t {type, 399, constraint,\n\t [{atom, 399, is_subtype},\n\t [{var, 399, 'Interval'},\n\t {type, 399, pos_integer, []}]]},\n\t {type, 400, constraint,\n\t [{atom, 400, is_subtype},\n\t [{var, 400, 'FoldFun'},\n\t {type, 400, 'fun',\n\t [{type, 400, product,\n\t\t [{var, 400, 'Stats'}, {var, 400, 'Acc'}]},\n\t\t{var, 400, 'Acc'}]}]]},\n\t {type, 401, constraint,\n\t [{atom, 401, is_subtype},\n\t [{var, 401, 'Acc'}, {type, 401, term, []}]]},\n\t {type, 402, constraint,\n\t [{atom, 402, is_subtype},\n\t [{var, 402, 'Stats'},\n\t {type, 402, tuple,\n\t [{type, 402, list,\n\t\t [{ann_type, 402,\n\t\t [{var, 402, 'Absolutes'},\n\t\t {type, 402, tuple,\n\t\t [{type, 402, atom, []}, {type, 402, term, []}]}]}]},\n\t\t{type, 403, list,\n\t\t [{ann_type, 403,\n\t\t [{var, 403, 'Increments'},\n\t\t {type, 403, tuple,\n\t\t [{type, 403, atom, []},\n\t\t {type, 403, term, []}]}]}]}]}]]}]]}]}).\n\nnode_stats(N, Interval, FoldFun, Init) ->\n FormerFlag = erlang:system_flag(scheduler_wall_time,\n\t\t\t\t true),\n Stats = fun ({{OldIn, OldOut}, {OldGCs, OldWords, _},\n\t\t SchedWall}) ->\n\t\t ProcC = erlang:system_info(process_count),\n\t\t RunQ = erlang:statistics(run_queue),\n\t\t {_, LogQ} = process_info(whereis(error_logger),\n\t\t\t\t\t message_queue_len),\n\t\t Mem = erlang:memory(),\n\t\t Tot = proplists:get_value(total, Mem),\n\t\t ProcM = proplists:get_value(processes_used, Mem),\n\t\t Atom = proplists:get_value(atom_used, Mem),\n\t\t Bin = proplists:get_value(binary, Mem),\n\t\t Ets = proplists:get_value(ets, Mem),\n\t\t {{input, In}, {output, Out}} = erlang:statistics(io),\n\t\t GC = {GCs, Words, _} =\n\t\t\t erlang:statistics(garbage_collection),\n\t\t BytesIn = In - OldIn,\n\t\t BytesOut = Out - OldOut,\n\t\t GCCount = GCs - OldGCs,\n\t\t GCWords = Words - OldWords,\n\t\t {_, Reds} = erlang:statistics(reductions),\n\t\t SchedWallNew = erlang:statistics(scheduler_wall_time),\n\t\t SchedUsage = recon_lib:scheduler_usage_diff(SchedWall,\n\t\t\t\t\t\t\t\tSchedWallNew),\n\t\t {{[{process_count, ProcC}, {run_queue, RunQ},\n\t\t {error_logger_queue_len, LogQ}, {memory_total, Tot},\n\t\t {memory_procs, ProcM}, {memory_atoms, Atom},\n\t\t {memory_bin, Bin}, {memory_ets, Ets}],\n\t\t [{bytes_in, BytesIn}, {bytes_out, BytesOut},\n\t\t {gc_count, GCCount}, {gc_words_reclaimed, GCWords},\n\t\t {reductions, Reds}, {scheduler_usage, SchedUsage}]},\n\t\t {{In, Out}, GC, SchedWallNew}}\n\t end,\n {{input, In}, {output, Out}} = erlang:statistics(io),\n Gc = erlang:statistics(garbage_collection),\n SchedWall = erlang:statistics(scheduler_wall_time),\n Result = recon_lib:time_fold(N, Interval, Stats,\n\t\t\t\t {{In, Out}, Gc, SchedWall}, FoldFun, Init),\n erlang:system_flag(scheduler_wall_time, FormerFlag),\n Result.\n\n-spec({{get_state, 1},\n [{type, 456, 'fun',\n\t [{type, 456, product, [{user_type, 456, pid_term, []}]},\n\t {type, 456, term, []}]}]}).\n\nget_state(PidTerm) -> get_state(PidTerm, 5000).\n\n-spec({{get_state, 2},\n [{type, 462, 'fun',\n\t [{type, 462, product,\n\t [{user_type, 462, pid_term, []},\n\t {ann_type, 462,\n\t [{var, 462, 'Ms'},\n\t {type, 462, union,\n\t [{type, 462, non_neg_integer, []},\n\t\t{atom, 462, infinity}]}]}]},\n\t {type, 462, term, []}]}]}).\n\nget_state(PidTerm, Timeout) ->\n Proc = recon_lib:term_to_pid(PidTerm),\n try sys:get_state(Proc, Timeout) catch\n error:undef ->\n\t case sys:get_status(Proc, Timeout) of\n\t {status, _Pid, {module, gen_server}, Data} ->\n\t\t{data, Props} = lists:last(lists:nth(5, Data)),\n\t\tproplists:get_value(\"State\", Props);\n\t {status, _Pod, {module, gen_fsm}, Data} ->\n\t\t{data, Props} = lists:last(lists:nth(5, Data)),\n\t\tproplists:get_value(\"StateData\", Props)\n\t end\n end.\n\n-spec({{remote_load, 1},\n [{type, 482, 'fun',\n\t [{type, 482, product, [{type, 482, module, []}]},\n\t {type, 482, term, []}]}]}).\n\nremote_load(Mod) -> remote_load(nodes(), Mod).\n\n-spec({{remote_load, 2},\n [{type, 487, bounded_fun,\n\t [{type, 487, 'fun',\n\t [{type, 487, product,\n\t [{var, 487, 'Nodes'}, {type, 487, module, []}]},\n\t {type, 487, term, []}]},\n\t [{type, 488, constraint,\n\t [{atom, 488, is_subtype},\n\t [{var, 488, 'Nodes'},\n\t {type, 488, union,\n\t [{type, 488, nonempty_list, [{type, 488, node, []}]},\n\t\t{type, 488, node, []}]}]]}]]}]}).\n\nremote_load(Nodes = [_ | _], Mod) when is_atom(Mod) ->\n {Mod, Bin, File} = code:get_object_code(Mod),\n rpc:multicall(Nodes, code, load_binary,\n\t\t [Mod, File, Bin]);\nremote_load(Nodes = [_ | _], Modules)\n when is_list(Modules) ->\n [remote_load(Nodes, Mod) || Mod <- Modules];\nremote_load(Node, Mod) -> remote_load([Node], Mod).\n\n-spec({{source, 1},\n [{type, 503, 'fun',\n\t [{type, 503, product, [{type, 503, module, []}]},\n\t {type, 503, iolist, []}]}]}).\n\nsource(Module) ->\n Path = code:which(Module),\n {ok, {_, [{abstract_code, {_, AC}}]}} =\n\tbeam_lib:chunks(Path, [abstract_code]),\n erl_prettypr:format(erl_syntax:form_list(AC)).\n\n-spec({{tcp, 0},\n [{type, 512, 'fun',\n\t [{type, 512, product, []},\n\t {type, 512, list, [{type, 512, port, []}]}]}]}).\n\ntcp() -> recon_lib:port_list(name, \"tcp_inet\").\n\n-spec({{udp, 0},\n [{type, 516, 'fun',\n\t [{type, 516, product, []},\n\t {type, 516, list, [{type, 516, port, []}]}]}]}).\n\nudp() -> recon_lib:port_list(name, \"udp_inet\").\n\n-spec({{sctp, 0},\n [{type, 520, 'fun',\n\t [{type, 520, product, []},\n\t {type, 520, list, [{type, 520, port, []}]}]}]}).\n\nsctp() -> recon_lib:port_list(name, \"sctp_inet\").\n\n-spec({{files, 0},\n [{type, 524, 'fun',\n\t [{type, 524, product, []},\n\t {type, 524, list, [{type, 524, port, []}]}]}]}).\n\nfiles() -> recon_lib:port_list(name, \"efile\").\n\n-spec({{port_types, 0},\n [{type, 529, 'fun',\n\t [{type, 529, product, []},\n\t {type, 529, list,\n\t [{type, 529, tuple,\n\t [{ann_type, 529,\n\t [{var, 529, 'Type'}, {type, 529, string, []}]},\n\t {ann_type, 529,\n\t [{var, 529, 'Count'},\n\t\t{type, 529, pos_integer, []}]}]}]}]}]}).\n\nport_types() ->\n lists:usort(fun ({KA, VA}, {KB, VB}) ->\n\t\t\t{VA, KB} > {VB, KA}\n\t\tend,\n\t\trecon_lib:count([Name\n\t\t\t\t || {_, Name} <- recon_lib:port_list(name)])).\n\n-spec({{inet_count, 2},\n [{type, 549, bounded_fun,\n\t [{type, 549, 'fun',\n\t [{type, 549, product,\n\t [{var, 549, 'AttributeName'}, {var, 549, 'Num'}]},\n\t {type, 549, list, [{user_type, 549, inet_attrs, []}]}]},\n\t [{type, 550, constraint,\n\t [{atom, 550, is_subtype},\n\t [{var, 550, 'AttributeName'},\n\t {type, 550, union,\n\t [{atom, 550, recv_cnt}, {atom, 550, recv_oct},\n\t\t{atom, 550, send_cnt}, {atom, 550, send_oct},\n\t\t{atom, 551, cnt}, {atom, 551, oct}]}]]},\n\t {type, 552, constraint,\n\t [{atom, 552, is_subtype},\n\t [{var, 552, 'Num'},\n\t {type, 552, non_neg_integer, []}]]}]]}]}).\n\ninet_count(Attr, Num) ->\n lists:sublist(lists:usort(fun ({_, A, _}, {_, B, _}) ->\n\t\t\t\t A > B\n\t\t\t end,\n\t\t\t recon_lib:inet_attrs(Attr)),\n\t\t Num).\n\n-spec({{inet_window, 3},\n [{type, 571, bounded_fun,\n\t [{type, 571, 'fun',\n\t [{type, 571, product,\n\t [{var, 571, 'AttributeName'}, {var, 571, 'Num'},\n\t {var, 571, 'Milliseconds'}]},\n\t {type, 571, list, [{user_type, 571, inet_attrs, []}]}]},\n\t [{type, 572, constraint,\n\t [{atom, 572, is_subtype},\n\t [{var, 572, 'AttributeName'},\n\t {type, 572, union,\n\t [{atom, 572, recv_cnt}, {atom, 572, recv_oct},\n\t\t{atom, 572, send_cnt}, {atom, 572, send_oct},\n\t\t{atom, 573, cnt}, {atom, 573, oct}]}]]},\n\t {type, 574, constraint,\n\t [{atom, 574, is_subtype},\n\t [{var, 574, 'Num'}, {type, 574, non_neg_integer, []}]]},\n\t {type, 575, constraint,\n\t [{atom, 575, is_subtype},\n\t [{var, 575, 'Milliseconds'},\n\t {type, 575, pos_integer, []}]]}]]}]}).\n\ninet_window(Attr, Num, Time) when is_atom(Attr) ->\n Sample = fun () -> recon_lib:inet_attrs(Attr) end,\n {First, Last} = recon_lib:sample(Time, Sample),\n lists:sublist(lists:usort(fun ({_, A, _}, {_, B, _}) ->\n\t\t\t\t A > B\n\t\t\t end,\n\t\t\t recon_lib:sliding_window(First, Last)),\n\t\t Num).\n\n-spec({{port_info, 1},\n [{type, 597, 'fun',\n\t [{type, 597, product,\n\t [{user_type, 597, port_term, []}]},\n\t {type, 597, nonempty_list,\n\t [{type, 597, tuple,\n\t [{user_type, 597, port_info_type, []},\n\t {type, 598, list,\n\t [{type, 598, tuple,\n\t\t [{user_type, 598, port_info_key, []},\n\t\t {type, 598, term, []}]}]}]}]}]}]}).\n\nport_info(PortTerm) ->\n Port = recon_lib:term_to_port(PortTerm),\n [port_info(Port, Type)\n || Type <- [meta, signals, io, memory_used, specific]].\n\n-spec({{port_info, 2},\n [{type, 614, 'fun',\n\t [{type, 614, product,\n\t [{user_type, 614, port_term, []},\n\t {user_type, 614, port_info_type, []}]},\n\t {type, 614, tuple,\n\t [{user_type, 614, port_info_type, []},\n\t {type, 615, list,\n\t [{type, 615, tuple,\n\t [{user_type, 615, port_info_key, []},\n\t\t{var, 615, '_'}]}]}]}]},\n\t{type, 616, 'fun',\n\t [{type, 616, product,\n\t [{user_type, 616, port_term, []},\n\t {type, 616, list, [{type, 616, atom, []}]}]},\n\t {type, 616, list,\n\t [{type, 616, tuple,\n\t [{type, 616, atom, []}, {type, 616, term, []}]}]}]},\n\t{type, 617, 'fun',\n\t [{type, 617, product,\n\t [{user_type, 617, port_term, []},\n\t {type, 617, atom, []}]},\n\t {type, 617, tuple,\n\t [{type, 617, atom, []}, {type, 617, term, []}]}]}]}).\n\nport_info(PortTerm, meta) ->\n {meta, List} = port_info_type(PortTerm, meta,\n\t\t\t\t [id, name, os_pid]),\n case port_info(PortTerm, registered_name) of\n [] -> {meta, List};\n Name -> {meta, [Name | List]}\n end;\nport_info(PortTerm, signals) ->\n port_info_type(PortTerm, signals,\n\t\t [connected, links, monitors]);\nport_info(PortTerm, io) ->\n port_info_type(PortTerm, io, [input, output]);\nport_info(PortTerm, memory_used) ->\n port_info_type(PortTerm, memory_used,\n\t\t [memory, queue_size]);\nport_info(PortTerm, specific) ->\n Port = recon_lib:term_to_port(PortTerm),\n Props = case erlang:port_info(Port, name) of\n\t {_, Type}\n\t\t when Type =:= \"udp_inet\";\n\t\t Type =:= \"tcp_inet\";\n\t\t Type =:= \"sctp_inet\" ->\n\t\t case inet:getstat(Port) of\n\t\t {ok, Stats} -> [{statistics, Stats}];\n\t\t _ -> []\n\t\t end\n\t\t ++\n\t\t case inet:peername(Port) of\n\t\t {ok, Peer} -> [{peername, Peer}];\n\t\t {error, _} -> []\n\t\t end\n\t\t ++\n\t\t case inet:sockname(Port) of\n\t\t\t{ok, Local} -> [{sockname, Local}];\n\t\t\t{error, _} -> []\n\t\t end\n\t\t\t++\n\t\t\tcase inet:getopts(Port,\n\t\t\t\t\t [active, broadcast, buffer,\n\t\t\t\t\t delay_send, dontroute, exit_on_close,\n\t\t\t\t\t header, high_watermark, ipv6_v6only,\n\t\t\t\t\t keepalive, linger, low_watermark,\n\t\t\t\t\t mode, nodelay, packet, packet_size,\n\t\t\t\t\t priority, read_packets, recbuf,\n\t\t\t\t\t reuseaddr, send_timeout, sndbuf])\n\t\t\t of\n\t\t\t {ok, Opts} -> [{options, Opts}];\n\t\t\t {error, _} -> []\n\t\t\tend;\n\t {_, \"efile\"} -> [];\n\t _ -> []\n\t end,\n {type, Props};\nport_info(PortTerm, Keys) when is_list(Keys) ->\n Port = recon_lib:term_to_port(PortTerm),\n [erlang:port_info(Port, Key) || Key <- Keys];\nport_info(PortTerm, Key) when is_atom(Key) ->\n erlang:port_info(recon_lib:term_to_port(PortTerm), Key).\n\nport_info_type(PortTerm, Type, Keys) ->\n Port = recon_lib:term_to_port(PortTerm),\n {Type, [erlang:port_info(Port, Key) || Key <- Keys]}.\n\n-spec({{rpc, 1},\n [{type, 684, 'fun',\n\t [{type, 684, product,\n\t [{type, 684, 'fun',\n\t [{type, 684, product, []}, {type, 684, term, []}]}]},\n\t {type, 684, tuple,\n\t [{type, 684, list,\n\t [{ann_type, 684,\n\t [{var, 684, 'Success'}, {var, 684, '_'}]}]},\n\t {type, 684, list,\n\t [{ann_type, 684,\n\t [{var, 684, 'Fail'}, {var, 684, '_'}]}]}]}]}]}).\n\nrpc(Fun) -> rpc([node() | nodes()], Fun).\n\n-spec({{rpc, 2},\n [{type, 689, 'fun',\n\t [{type, 689, product,\n\t [{type, 689, union,\n\t [{type, 689, node, []},\n\t {type, 689, nonempty_list, [{type, 689, node, []}]}]},\n\t {type, 689, 'fun',\n\t [{type, 689, product, []}, {type, 689, term, []}]}]},\n\t {type, 689, tuple,\n\t [{type, 689, list,\n\t [{ann_type, 689,\n\t [{var, 689, 'Success'}, {var, 689, '_'}]}]},\n\t {type, 689, list,\n\t [{ann_type, 689,\n\t [{var, 689, 'Fail'}, {var, 689, '_'}]}]}]}]}]}).\n\nrpc(Nodes, Fun) -> rpc(Nodes, Fun, infinity).\n\n-spec({{rpc, 3},\n [{type, 694, 'fun',\n\t [{type, 694, product,\n\t [{type, 694, union,\n\t [{type, 694, node, []},\n\t {type, 694, nonempty_list, [{type, 694, node, []}]}]},\n\t {type, 694, 'fun',\n\t [{type, 694, product, []}, {type, 694, term, []}]},\n\t {type, 694, timeout, []}]},\n\t {type, 694, tuple,\n\t [{type, 694, list,\n\t [{ann_type, 694,\n\t [{var, 694, 'Success'}, {var, 694, '_'}]}]},\n\t {type, 694, list,\n\t [{ann_type, 694,\n\t [{var, 694, 'Fail'}, {var, 694, '_'}]}]}]}]}]}).\n\n"
但结果是难看的,谁有好主意做出漂亮的印刷品?