349
382
%% -> {NFD, binary()} | throw(Error)
350
383
get_chunk(Id, Pos, Size, FD) ->
351
384
case pread(FD, Pos, Size) of
352
{NFD, eof} when Size == 0 -> % cannot happen
385
{NFD, eof} when Size =:= 0 -> % cannot happen
354
387
{_NFD, eof} when Size > 0 ->
355
388
error({chunk_too_big, filename(FD), Id, Size, 0});
356
389
{_NFD, {ok, Chunk}} when Size > size(Chunk) ->
357
390
error({chunk_too_big, filename(FD), Id, Size, size(Chunk)});
358
{NFD, {ok, Chunk}} -> % when Size == size(Chunk)
391
{NFD, {ok, Chunk}} -> % when Size =:= size(Chunk)
362
395
chunks_to_data([{Id, Name} | CNs], Chunks, File, Cs, Module, Atoms, L) ->
363
396
{value, {_Id, Chunk}} = keysearch(Id, 1, Chunks),
364
{NewAtoms, Ret} = chunk_to_data(Name, Chunk, File, Cs, Atoms),
397
{NewAtoms, Ret} = chunk_to_data(Name, Chunk, File, Cs, Atoms, Module),
365
398
chunks_to_data(CNs, Chunks, File, Cs, Module, NewAtoms, [Ret | L]);
366
399
chunks_to_data([], _Chunks, _File, _Cs, Module, _Atoms, L) ->
367
400
{ok, {Module, reverse(L)}}.
369
chunk_to_data(Id, Chunk, File, _Cs, AtomTable) when Id == attributes ->
370
case catch binary_to_term(Chunk) of
372
error({invalid_chunk, File, chunk_name_to_id(Id, File)});
374
{AtomTable, {Id, attributes(Term)}}
376
chunk_to_data(Id, Chunk, File, _Cs, AtomTable) when Id == abstract_code ->
377
case catch binary_to_term(Chunk) of
378
{'EXIT', _} when <<>> == Chunk ->
402
chunk_to_data(Id, Chunk, File, _Cs, AtomTable, _Mod) when Id =:= attributes ->
404
Term = binary_to_term(Chunk),
405
{AtomTable, {Id, attributes(Term)}}
408
error({invalid_chunk, File, chunk_name_to_id(Id, File)})
410
chunk_to_data(Id, Chunk, File, _Cs, AtomTable, _Mod) when Id =:= compile_info ->
412
{AtomTable, {Id, binary_to_term(Chunk)}}
415
error({invalid_chunk, File, chunk_name_to_id(Id, File)})
417
chunk_to_data(Id, Chunk, File, _Cs, AtomTable, Mod) when Id =:= abstract_code ->
379
420
{AtomTable, {Id, no_abstract_code}};
381
error({invalid_chunk, File, chunk_name_to_id(Id, File)});
383
{AtomTable, {Id, Term}}
421
<<0:8,N:8,Mode0:N/binary,Rest/binary>> ->
422
Mode = list_to_atom(binary_to_list(Mode0)),
423
decrypt_abst(Mode, Mod, File, Id, AtomTable, Rest);
425
case catch binary_to_term(Chunk) of
427
error({invalid_chunk, File, chunk_name_to_id(Id, File)});
429
{AtomTable, {Id, Term}}
385
chunk_to_data(Id, _Chunk, _File, Cs, AtomTable0) when Id == atoms ->
432
chunk_to_data(Id, _Chunk, _File, Cs, AtomTable0, _Mod) when Id =:= atoms ->
386
433
AtomTable = ensure_atoms(AtomTable0, Cs),
387
434
Atoms = ets:tab2list(AtomTable),
388
435
{AtomTable, {Id, lists:sort(Atoms)}};
389
chunk_to_data(ChunkName, Chunk, File, Cs, AtomTable) when atom(ChunkName) ->
436
chunk_to_data(ChunkName, Chunk, File,
437
Cs, AtomTable, _Mod) when atom(ChunkName) ->
390
438
case catch symbols(Chunk, AtomTable, Cs, ChunkName) of
391
439
{ok, NewAtomTable, S} ->
392
440
{NewAtomTable, {ChunkName, S}};
394
442
error({invalid_chunk, File, chunk_name_to_id(ChunkName, File)})
396
chunk_to_data(ChunkId, Chunk, _File, _Cs, AtomTable) -> % when list(ChunkId)
444
chunk_to_data(ChunkId, Chunk, _File,
445
_Cs, AtomTable, _Module) -> % when list(ChunkId)
397
446
{AtomTable, {ChunkId, Chunk}}. % Chunk is a binary
399
448
chunk_name_to_id(atoms, _) -> "Atom";
449
chunk_name_to_id(indexed_imports, _) -> "ImpT";
400
450
chunk_name_to_id(imports, _) -> "ImpT";
401
451
chunk_name_to_id(exports, _) -> "ExpT";
402
452
chunk_name_to_id(labeled_exports, _) -> "ExpT";
425
476
symbols(<<_Num:32, B/binary>>, AT0, Cs, Name) ->
426
477
AT = ensure_atoms(AT0, Cs),
427
symbols1(B, AT, Name, []).
478
symbols1(B, AT, Name, [], 1).
429
symbols1(<<I1:32, I2:32, I3:32, B/binary>>, AT, Name, S) ->
430
Symbol = symbol(Name, AT, I1, I2, I3),
431
symbols1(B, AT, Name, [Symbol|S]);
432
symbols1(<<>>, AT, _Name, S) ->
480
symbols1(<<I1:32, I2:32, I3:32, B/binary>>, AT, Name, S, Cnt) ->
481
Symbol = symbol(Name, AT, I1, I2, I3, Cnt),
482
symbols1(B, AT, Name, [Symbol|S], Cnt+1);
483
symbols1(<<>>, AT, _Name, S, _Cnt) ->
433
484
{ok, AT, sort(S)}.
435
symbol(imports, AT, I1, I2, I3) ->
486
symbol(indexed_imports, AT, I1, I2, I3, Cnt) ->
487
{Cnt, atm(AT, I1), atm(AT, I2), I3};
488
symbol(imports, AT, I1, I2, I3, _Cnt) ->
436
489
{atm(AT, I1), atm(AT, I2), I3};
437
symbol(Name, AT, I1, I2, I3) when Name == labeled_exports;
438
Name == labeled_locals ->
490
symbol(Name, AT, I1, I2, I3, _Cnt) when Name =:= labeled_exports;
491
Name =:= labeled_locals ->
439
492
{atm(AT, I1), I2, I3};
440
symbol(_, AT, I1, I2, _I3) ->
493
symbol(_, AT, I1, I2, _I3, _Cnt) ->
441
494
{atm(AT, I1), I2}.
549
603
throw({error, ?MODULE, Reason}).
605
%%% ====================================================================
606
%%% The rest of the file handles encrypted debug info.
608
%%% Encrypting the debug info is only useful if you want to
609
%%% have the debug info available all the time (maybe even in a live
610
%%% system), but don't want to risk that anyone else but yourself
612
%%% ====================================================================
614
-record(state, {crypto_key_f}).
615
-define(CRYPTO_KEY_SERVER, beam_lib__crypto_key_server).
617
decrypt_abst(Mode, Module, File, Id, AtomTable, Bin) ->
619
KeyString = get_crypto_key({debug_info, Mode, Module, File}),
620
Key = make_crypto_key(des3_cbc, KeyString),
621
Term = decrypt_abst_1(Mode, Key, Bin),
622
{AtomTable, {Id, Term}}
625
error({key_missing_or_invalid, File, Id})
628
decrypt_abst_1(des3_cbc, {K1, K2, K3, IVec}, Bin) ->
630
NewBin = crypto:des3_cbc_decrypt(K1, K2, K3, IVec, Bin),
631
binary_to_term(NewBin).
634
case crypto:start() of
635
{error, {already_started, _}} ->
641
get_crypto_key(What) ->
642
call_crypto_server({get_crypto_key, What}).
644
call_crypto_server(Req) ->
646
gen_server:call(?CRYPTO_KEY_SERVER, Req, infinity)
649
start_crypto_server(),
651
call_crypto_server(Req)
654
start_crypto_server() ->
655
gen_server:start({local,?CRYPTO_KEY_SERVER}, ?MODULE, [], []).
660
handle_call({get_crypto_key, _}=R, From, #state{crypto_key_f=undefined}=S) ->
661
case crypto_key_fun_from_file() of
664
F when is_function(F) ->
665
%% The init function for the fun has already been called.
666
handle_call(R, From, S#state{crypto_key_f=F})
668
handle_call({get_crypto_key, What}, From, #state{crypto_key_f=F}=S) ->
671
%% The result may hold information that we don't want
672
%% lying around. Reply first, then GC, then noreply.
673
gen_server:reply(From, Result),
674
erlang:garbage_collect(),
680
handle_call({crypto_key_fun, F}, {_,_} = From, S) ->
681
case S#state.crypto_key_f of
683
%% Don't allow tuple funs here. (They weren't allowed before,
684
%% so there is no reason to allow them now.)
685
if is_function(F), is_function(F, 1) ->
686
{Result, Fun, Reply} =
687
case catch F(init) of
690
{ok, F1} when is_function(F1) ->
692
is_function(F1, 1) ->
699
{false, undefined, {error, Reason}};
701
{false, undefined, {error, Reason}}
703
gen_server:reply(From, Reply),
704
erlang:garbage_collect(),
705
NewS = case Result of
707
S#state{crypto_key_f = Fun};
713
{reply, {error, badfun}, S}
715
OtherF when is_function(OtherF) ->
716
{reply, {error, exists}, S}
718
handle_call(clear_crypto_key_fun, _From, S) ->
719
case S#state.crypto_key_f of
721
{stop,normal,undefined,S};
723
Result = (catch F(clear)),
724
{stop,normal,{ok,Result},S}
727
handle_cast(_, State) ->
730
handle_info(_, State) ->
733
code_change(_OldVsn, State, _Extra) ->
736
terminate(_Reason, _State) ->
739
crypto_key_fun_from_file() ->
740
case init:get_argument(home) of
742
crypto_key_fun_from_file_1([".",Home]);
744
crypto_key_fun_from_file_1(["."])
747
crypto_key_fun_from_file_1(Path) ->
748
case f_p_s(Path, ".erlang.crypt") of
750
try_load_crypto_fun(KeyInfo);
756
case file:path_script(P, F) of
759
{error, {Line, _Mod, _Term}=E} ->
760
error("file:path_script(~p,~p): error on line ~p: ~s~n",
761
[P, F, Line, file:format_error(E)]),
763
{error, E} when is_atom(E) ->
764
error("file:path_script(~p,~p): ~s~n",
765
[P, F, file:format_error(E)]),
771
try_load_crypto_fun(KeyInfo) when is_list(KeyInfo) ->
772
T = ets:new(keys, [private, set]),
774
fun({debug_info, Mode, M, Key}) when is_atom(M) ->
775
ets:insert(T, {{debug_info,Mode,M,[]}, Key});
776
({debug_info, Mode, [], Key}) ->
777
ets:insert(T, {{debug_info, Mode, [], []}, Key});
779
error("unknown key: ~p~n", [Other])
781
fun({debug_info, Mode, M, F}) ->
783
[{debug_info,Mode,M,F},
784
{debug_info,Mode,M,[]},
785
{debug_info,Mode,[],[]}], T);
791
try_load_crypto_fun(KeyInfo) ->
792
error("unrecognized crypto key info: ~p\n", [KeyInfo]).
794
alt_lookup_key([H|T], Tab) ->
795
case ets:lookup(Tab, H) of
797
alt_lookup_key(T, Tab);
801
alt_lookup_key([], _) ->
805
error_logger:error_msg(Fmt, Args),