nm: use pdp10_elf36 library, use error:format/1 to format error reasons

This commit is contained in:
Mikael Pettersson 2019-08-19 22:19:39 +02:00
parent c150845358
commit c53d8167c9
2 changed files with 13 additions and 411 deletions

View File

@ -16,7 +16,7 @@
%%% along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
{application, nm,
[{description, "'nm' clone for PDP10 Elf36 files"},
[{description, "'nm' clone for pdp10-elf"},
{vsn, "0.1.0"},
{registered, []},
{applications, [kernel, stdlib, lib]},

View File

@ -1,6 +1,6 @@
%%% -*- erlang-indent-level: 2 -*-
%%%
%%% 'nm' clone for PDP10 Elf36 files
%%% 'nm' clone for pdp10-elf
%%% Copyright (C) 2013-2019 Mikael Pettersson
%%%
%%% This file is part of pdp10-tools.
@ -170,152 +170,30 @@ nm1(Opts, PrintFile, File, FP) ->
print_symtab(Opts, PrintFile, File, ShTab, SymTab, StrTab).
read_ehdr(File, FP) ->
case pdp10_elf36_read_ehdr(FP) of
case pdp10_elf36:read_Ehdr(FP) of
{ok, Ehdr} ->
Ehdr;
{error, Reason} ->
escript_runtime:fatal("invalid PDP10 ELF36 file ~s: ~p\n",
[File, Reason])
escript_runtime:fatal("invalid PDP10 ELF36 file ~s: ~s\n",
[File, error:format(Reason)])
end.
read_shtab(File, FP, Ehdr) ->
case read_shtab(FP, Ehdr) of
{ok, ShTab, ShStrTab} -> {ShTab, ShStrTab};
case pdp10_elf36:read_ShTab(FP, Ehdr) of
{ok, {ShTab, ShStrTab}} -> {ShTab, ShStrTab};
{error, Reason} ->
escript_runtime:fatal("failed to read section header table in ~s: ~p\n",
[File, Reason])
end.
read_shtab(FP, Ehdr) ->
#elf36_Ehdr{ e_shoff = ShOff
, e_shnum = ShNum0
, e_shstrndx = ShStrNdx } = Ehdr,
case ShOff of
0 -> {ok, {[], []}};
_ ->
case pdp10_stdio:fseek(FP, {bof, ShOff}) of
ok ->
case pdp10_elf36_read_shdr(FP) of
{ok, Shdr0} ->
ShNum = actual_shnum(ShNum0, Shdr0),
case do_read_shtab(FP, ShNum - 1, [Shdr0]) of
{ok, ShTab} ->
case read_shstrtab(FP, ShTab, ShStrNdx, Shdr0) of
{ok, ShStrTab} -> {ok, ShTab, ShStrTab};
{error, _Reason} = Error -> Error
end;
{error, _Reason} = Error -> Error
end;
{error, _Reason} = Error -> Error
end;
{error, _Reason} = Error -> Error
end
end.
actual_shnum(0, #elf36_Shdr{sh_size = ShNum} = _Shdr0) -> ShNum;
actual_shnum(ShNum, _Shdr0) -> ShNum.
do_read_shtab(_FP, 0, Shdrs) -> {ok, lists:reverse(Shdrs)};
do_read_shtab(FP, ShNum, Shdrs) when ShNum > 0 ->
case pdp10_elf36_read_shdr(FP) of
{ok, Shdr} -> do_read_shtab(FP, ShNum - 1, [Shdr | Shdrs]);
{error, _Reason} = Error -> Error
end.
read_shstrtab(FP, ShTab, ShStrNdx0, Shdr0) ->
case ShStrNdx0 of
?SHN_UNDEF -> {ok, []};
_ ->
ShStrNdx =
case ShStrNdx0 of
?SHN_XINDEX -> Shdr0#elf36_Shdr.sh_link;
_ -> ShStrNdx0
end,
read_strtab(FP, ShTab, ShStrNdx)
end.
read_strtab(FP, ShTab, Index) ->
ShNum = length(ShTab),
case Index > 0 andalso Index < ShNum of
true ->
#elf36_Shdr{ sh_type = Type
, sh_size = Size
, sh_offset = Offset
} = lists:nth(Index + 1, ShTab),
case Type of
?SHT_STRTAB ->
case pdp10_stdio:fseek(FP, {bof, Offset}) of
ok ->
case pdp10_stdio:fread(1, Size, FP) of
{ok, _StrTab} = Result -> Result;
{error, _Reason} = Error -> Error;
eof -> {error, eof}
end;
{error, _Reason} = Error -> Error
end;
_ ->
{error, io_lib:format("invalid type ~p for string table at index ~p",
[Type, Index])}
end;
false ->
{error, io_lib:format("invalid string table section index ~p",
[Index])}
escript_runtime:fatal("failed to read section header table in ~s: ~s\n",
[File, error:format(Reason)])
end.
read_symtab(File, FP, ShTab) ->
case read_symtab(FP, ShTab) of
{ok, SymTab, StrTab} -> {SymTab, StrTab};
case pdp10_elf36:read_SymTab(FP, ShTab) of
{ok, {SymTab, StrTab}} -> {SymTab, StrTab};
{error, Reason} ->
escript_runtime:fatal("failed to read symbol table table in ~s: ~p\n",
[File, Reason])
escript_runtime:fatal("failed to read symbol table table in ~s: ~s\n",
[File, error:format(Reason)])
end.
read_symtab(FP, ShTab) ->
case find_symtab(ShTab) of
false -> {ok, [], []};
{ok, Shdr} ->
#elf36_Shdr{ sh_link = Link
, sh_entsize = EntSize
, sh_size = Size
, sh_offset = Offset
} = Shdr,
case [] of
_ when EntSize =/= ?ELF36_SYM_SIZEOF ->
{error, io_lib:format("wrong sh_entsize ~p in symtab section header", [EntSize])};
_ when (Size rem ?ELF36_SYM_SIZEOF) =/= 0 ->
{error, io_lib:format("wrong sh_size ~p in symtab section header", [Size])};
_ ->
case read_strtab(FP, ShTab, Link) of
{ok, StrTab} ->
SymNum = Size div ?ELF36_SYM_SIZEOF,
case SymNum of
0 -> {ok, [], StrTab};
_ ->
case pdp10_stdio:fseek(FP, {bof, Offset}) of
ok ->
case do_read_symtab(FP, SymNum, []) of
{ok, SymTab} -> {ok, SymTab, StrTab};
{error, _Reason} = Error -> Error
end;
{error, _Reason} = Error -> Error
end
end;
{error, _Reason} = Error -> Error
end
end
end.
do_read_symtab(_FP, _SymNum = 0, Syms) -> {ok, lists:reverse(Syms)};
do_read_symtab(FP, SymNum, Syms) when SymNum > 0 ->
case pdp10_elf36_read_sym(FP) of
{ok, Sym} -> do_read_symtab(FP, SymNum - 1, [Sym | Syms]);
{error, _Reason} = Error -> Error
end.
find_symtab([]) -> false;
find_symtab([#elf36_Shdr{sh_type = ?SHT_SYMTAB} = Shdr | _]) -> {ok, Shdr};
find_symtab([_Shdr | ShTab]) -> find_symtab(ShTab).
print_symtab(Opts, PrintFile, File, ShTab, SymTab, StrTab) ->
case PrintFile of
true -> io:format("\n~s:\n", [File]);
@ -471,279 +349,3 @@ sym_value(ShTab, #elf36_Sym{st_shndx = ShNdx, st_value = Value}) ->
false -> 0
end,
Base + Value.
%% ELF36 =======================================================================
%% (these bits should go into the pdp10_elf36 library module)
pdp10_elf36_read_ehdr(FP) ->
case pdp10_elf36_read_record(FP, pdp10_elf36_ehdr_desc()) of
{ok, Ehdr} ->
case pdp10_elf36_check_ehdr(Ehdr) of
ok -> {ok, Ehdr};
{error, _Reason} = Error -> Error
end;
{error, _Reason} = Error -> Error
end.
pdp10_elf36_check_ehdr(Ehdr) ->
check(Ehdr,
[ fun check_ehdr_ei_mag0/1
, fun check_ehdr_ei_mag1/1
, fun check_ehdr_ei_mag2/1
, fun check_ehdr_ei_mag3/1
, fun check_ehdr_ei_class/1
, fun check_ehdr_ei_data/1
, fun check_ehdr_ei_version/1
, fun check_ehdr_ei_osabi/1
, fun check_ehdr_ei_abiversion/1
, fun check_ehdr_e_type/1
, fun check_ehdr_e_machine/1
, fun check_ehdr_e_version/1
, fun check_ehdr_e_ehsize/1
, fun check_ehdr_e_shentsize/1
]).
pdp10_elf36_read_shdr(FP) ->
pdp10_elf36_read_record(FP, pdp10_elf36_shdr_desc()).
pdp10_elf36_read_sym(FP) ->
pdp10_elf36_read_record(FP, pdp10_elf36_sym_desc()).
check(_X, []) -> ok;
check(X, [Fun | Funs]) ->
case Fun(X) of
ok -> check(X, Funs);
{error, _Reason} = Error -> Error
end.
check_ehdr_ei_mag0(Ehdr) ->
#elf36_Ehdr{ e_ident = Ident } = Ehdr,
Mag0 = lists:nth(?EI_MAG0 + 1, Ident),
case Mag0 of
?ELFMAG0 -> ok;
_ -> {error, io_lib:format("wrong ei_mag0 ~p", [Mag0])}
end.
check_ehdr_ei_mag1(Ehdr) ->
#elf36_Ehdr{ e_ident = Ident } = Ehdr,
Mag1 = lists:nth(?EI_MAG1 + 1, Ident),
case Mag1 of
?ELFMAG1 -> ok;
_ -> {error, io_lib:format("wrong ei_mag1 ~p", [Mag1])}
end.
check_ehdr_ei_mag2(Ehdr) ->
#elf36_Ehdr{ e_ident = Ident } = Ehdr,
Mag2 = lists:nth(?EI_MAG2 + 1, Ident),
case Mag2 of
?ELFMAG2 -> ok;
_ -> {error, io_lib:format("wrong ei_mag2 ~p", [Mag2])}
end.
check_ehdr_ei_mag3(Ehdr) ->
#elf36_Ehdr{ e_ident = Ident } = Ehdr,
Mag3 = lists:nth(?EI_MAG3 + 1, Ident),
case Mag3 of
?ELFMAG3 -> ok;
_ -> {error, io_lib:format("wrong ei_mag3 ~p", [Mag3])}
end.
check_ehdr_ei_class(Ehdr) ->
#elf36_Ehdr{ e_ident = Ident } = Ehdr,
Class = lists:nth(?EI_CLASS + 1, Ident),
case Class of
?ELFCLASS36 -> ok;
_ -> {error, io_lib:format("wrong ei_class ~p", [Class])}
end.
check_ehdr_ei_data(Ehdr) ->
#elf36_Ehdr{ e_ident = Ident } = Ehdr,
Data = lists:nth(?EI_DATA + 1, Ident),
case Data of
?ELFDATA2MSB -> ok;
_ -> {error, io_lib:format("wrong ei_data ~p", [Data])}
end.
check_ehdr_ei_version(Ehdr) ->
#elf36_Ehdr{ e_ident = Ident } = Ehdr,
Version = lists:nth(?EI_VERSION + 1, Ident),
case Version of
?EV_CURRENT -> ok;
_ -> {error, io_lib:format("wrong ei_version ~p", [Version])}
end.
check_ehdr_ei_osabi(Ehdr) ->
#elf36_Ehdr{ e_ident = Ident } = Ehdr,
OSABI = lists:nth(?EI_OSABI + 1, Ident),
case OSABI of
?ELFOSABI_NONE -> ok;
?ELFOSABI_LINUX -> ok;
_ -> {error, io_lib:format("wrong ei_osabi ~p", [OSABI])}
end.
check_ehdr_ei_abiversion(Ehdr) ->
#elf36_Ehdr{ e_ident = Ident } = Ehdr,
ABIVersion = lists:nth(?EI_ABIVERSION + 1, Ident),
case ABIVersion of
0 -> ok;
_ -> {error, io_lib:format("wrong ei_abiversion ~p", [ABIVersion])}
end.
check_ehdr_e_type(Ehdr) ->
#elf36_Ehdr{ e_type = Type } = Ehdr,
case Type of
?ET_REL -> ok;
?ET_EXEC -> ok;
?ET_DYN -> ok;
?ET_CORE -> ok;
_ -> {error, io_lib:format("wrong e_type ~p", [Type])}
end.
check_ehdr_e_machine(Ehdr) ->
#elf36_Ehdr{ e_machine = Machine } = Ehdr,
case Machine of
?EM_PDP10 -> ok;
_ -> {error, io_lib:format("wrong e_machine ~p", [Machine])}
end.
check_ehdr_e_version(Ehdr) ->
#elf36_Ehdr{ e_version = Version } = Ehdr,
case Version of
?EV_CURRENT -> ok;
_ -> {error, io_lib:format("wrong e_version ~p", [Version])}
end.
check_ehdr_e_ehsize(Ehdr) ->
#elf36_Ehdr{ e_ehsize = EhSize } = Ehdr,
case EhSize of
?ELF36_EHDR_SIZEOF -> ok;
_ -> {error, io_lib:format("wrong e_ehsize ~p", [EhSize])}
end.
check_ehdr_e_shentsize(Ehdr) ->
#elf36_Ehdr{ e_shoff = ShOff
, e_shentsize = ShEntSize } = Ehdr,
case {ShOff, ShEntSize} of
{0, _} -> ok;
{_, ?ELF36_SHDR_SIZEOF} -> ok;
_ -> {error, io_lib:format("wrong e_shentsize ~p", [ShEntSize])}
end.
%% Input of records ============================================================
-type reader() :: fun((pdp10_stdio:file()) -> {ok, integer()} | {error, any()}).
-record(record_desc, {
tag :: atom()
, fields :: [reader()]
}).
pdp10_elf36_read_record(FP, #record_desc{tag = Tag, fields = FieldReaders}) ->
pdp10_elf36_read_record(FP, FieldReaders, [Tag]).
pdp10_elf36_read_record(_FP, [], Values) ->
{ok, list_to_tuple(lists:reverse(Values))};
pdp10_elf36_read_record(FP, [FieldReader | FieldReaders], Values) ->
case FieldReader(FP) of
{ok, Value} ->
pdp10_elf36_read_record(FP, FieldReaders, [Value | Values]);
{error, _Reason} = Error ->
Error
end.
pdp10_elf36_ehdr_desc() ->
#record_desc{ tag = elf36_Ehdr
, fields =
[
fun read_e_ident/1 % e_ident
, fun read_Half/1 % e_type
, fun read_Half/1 % e_machine
, fun read_Word/1 % e_version
, fun read_Addr/1 % e_entry
, fun read_Off/1 % e_phoff
, fun read_Off/1 % e_shoff
, fun read_Word/1 % e_flags
, fun read_Half/1 % e_ehsize
, fun read_Half/1 % e_phentsize
, fun read_Half/1 % e_phnum
, fun read_Half/1 % e_shentsize
, fun read_Half/1 % e_shnum
, fun read_Half/1 % e_shstrndx
]
}.
read_e_ident(FP) ->
pdp10_elf36_read(FP, ?EI_NIDENT, fun(L) -> L end).
pdp10_elf36_shdr_desc() ->
#record_desc{ tag = elf36_Shdr
, fields =
[
fun read_Word/1 % sh_name
, fun read_Word/1 % sh_type
, fun read_Word/1 % sh_flags
, fun read_Addr/1 % sh_addr
, fun read_Off/1 % sh_offset
, fun read_Word/1 % sh_size
, fun read_Word/1 % sh_link
, fun read_Word/1 % sh_info
, fun read_Word/1 % sh_addralign
, fun read_Word/1 % sh_entsize
]
}.
pdp10_elf36_sym_desc() ->
#record_desc{ tag = elf36_Sym
, fields =
[
fun read_Word/1 % st_name
, fun read_Addr/1 % st_value
, fun read_Word/1 % st_size
, fun read_Uchar/1 % st_info
, fun read_Uchar/1 % st_other
, fun read_Half/1 % st_shndx
]
}.
%% Input of scalar items =======================================================
read_Uchar(FP) -> pdp10_elf36_read_uint9(FP).
read_Half(FP) -> pdp10_elf36_read_uint18(FP).
read_Word(FP) -> pdp10_elf36_read_uint36(FP).
read_Addr(FP) -> pdp10_elf36_read_uint36(FP).
read_Off(FP) -> pdp10_elf36_read_uint36(FP).
pdp10_elf36_read_uint9(FP) ->
case pdp10_stdio:fgetc(FP) of
{ok, _Nonet} = Res -> Res;
{error, _Reason} = Res -> Res;
eof -> {error, eof}
end.
pdp10_elf36_read_uint18(FP) ->
pdp10_elf36_read(FP, 2, fun make_uint18be/1).
pdp10_elf36_read_uint36(FP) ->
pdp10_elf36_read(FP, 4, fun make_uint36be/1).
pdp10_elf36_read(FP, N, ConvFun) when N >= 0 ->
pdp10_elf36_read(FP, N, ConvFun, []).
pdp10_elf36_read(_FP, 0, ConvFun, Acc) ->
{ok, ConvFun(lists:reverse(Acc))};
pdp10_elf36_read(FP, N, ConvFun, Acc) ->
case pdp10_elf36_read_uint9(FP) of
{ok, Nonet} ->
pdp10_elf36_read(FP, N - 1, ConvFun, [Nonet | Acc]);
{error, _Reason} = Error ->
Error
end.
make_uint18be([B1, B2]) -> % big-endian conversion
((B1 band 16#1FF) bsl 9) bor (B2 band 16#1FF).
make_uint36be([B1, B2, B3, B4]) -> % big-endian conversion
((B1 band 16#1FF) bsl 27) bor
((B2 band 16#1FF) bsl 19) bor
((B3 band 16#1FF) bsl 9) bor
(B4 band 16#1FF).