mirror of
https://github.com/mikpe/pdp10-tools.git
synced 2026-01-23 10:59:42 +00:00
readelf: rewrite in Erlang
This commit is contained in:
parent
a255160ff7
commit
e410aa86da
@ -21,7 +21,7 @@ REBAR3=$(shell type -p rebar3 || echo ./rebar3)
|
||||
REBAR3_GIT=https://github.com/erlang/rebar3.git
|
||||
REBAR3_VSN=3.7.5
|
||||
|
||||
PROGRAMS=8to9 ar as nm od
|
||||
PROGRAMS=8to9 ar as nm od readelf
|
||||
|
||||
default: compile link
|
||||
|
||||
|
||||
25
erlang/apps/readelf/src/readelf.app.src
Normal file
25
erlang/apps/readelf/src/readelf.app.src
Normal file
@ -0,0 +1,25 @@
|
||||
%%% Copyright (C) 2019 Mikael Pettersson
|
||||
%%%
|
||||
%%% This file is part of pdp10-tools.
|
||||
%%%
|
||||
%%% pdp10-tools is free software: you can redistribute it and/or modify
|
||||
%%% it under the terms of the GNU General Public License as published by
|
||||
%%% the Free Software Foundation, either version 3 of the License, or
|
||||
%%% (at your option) any later version.
|
||||
%%%
|
||||
%%% pdp10-tools is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
%%% GNU General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
{application, readelf,
|
||||
[{description, "'readelf' clone for pdp10-elf"},
|
||||
{vsn, "0.1.0"},
|
||||
{registered, []},
|
||||
{applications, [kernel, stdlib, lib]},
|
||||
{env, []},
|
||||
{modules, []}
|
||||
]}.
|
||||
598
erlang/apps/readelf/src/readelf.erl
Normal file
598
erlang/apps/readelf/src/readelf.erl
Normal file
@ -0,0 +1,598 @@
|
||||
%%% -*- erlang-indent-level: 2 -*-
|
||||
%%%
|
||||
%%% 'readelf' clone for pdp10-elf
|
||||
%%% Copyright (C) 2013-2019 Mikael Pettersson
|
||||
%%%
|
||||
%%% This file is part of pdp10-tools.
|
||||
%%%
|
||||
%%% pdp10-tools is free software: you can redistribute it and/or modify
|
||||
%%% it under the terms of the GNU General Public License as published by
|
||||
%%% the Free Software Foundation, either version 3 of the License, or
|
||||
%%% (at your option) any later version.
|
||||
%%%
|
||||
%%% pdp10-tools is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
%%% GNU General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
-module(readelf).
|
||||
-export([main/1]).
|
||||
|
||||
-include_lib("lib/include/pdp10_elf36.hrl").
|
||||
-include_lib("lib/include/pdp10_opcodes.hrl").
|
||||
|
||||
-record(options,
|
||||
{ file_header = false
|
||||
, segments = false
|
||||
, sections = false
|
||||
, section_groups = false
|
||||
, section_details = false
|
||||
, symbols = false
|
||||
, dyn_syms = false
|
||||
, notes = false
|
||||
, relocs = false
|
||||
, unwind = false
|
||||
, dynamic = false
|
||||
, version_info = false
|
||||
, arch_specific = false
|
||||
, use_dynamic = false
|
||||
, archive_index = false
|
||||
, histogram = false
|
||||
, disassemble = false % extension
|
||||
}).
|
||||
|
||||
%% Command-line interface ======================================================
|
||||
|
||||
main(Argv) ->
|
||||
escript_runtime:start(fun main_/1, Argv).
|
||||
|
||||
main_(Argv) ->
|
||||
case getopt:parse(Argv, "ahlSgtesnrudVADcIvW",
|
||||
[
|
||||
%% long-only options
|
||||
{ "dyn-syms", no, dyn_syms }
|
||||
, { "disassemble", no, disassemble } % extension
|
||||
%% long aliases for short options
|
||||
, { "all", no, $a }
|
||||
, { "file-header", no, $h }
|
||||
, { "program-headers", no, $l }
|
||||
, { "segments", no, $l }
|
||||
, { "section-groups", no, $g }
|
||||
, { "section-details", no, $t }
|
||||
, { "headers", no, $e }
|
||||
, { "symbols", no, $s }
|
||||
, { "syms", no, $s }
|
||||
, { "notes", no, $n }
|
||||
, { "relocs", no, $r }
|
||||
, { "unwind", no, $u }
|
||||
, { "version-info", no, $V }
|
||||
, { "arch-specific", no, $A }
|
||||
, { "use-dynamic", no, $D }
|
||||
, { "archive-index", no, $c }
|
||||
, { "histogram", no, $I }
|
||||
, { "version", no, $v }
|
||||
, { "wide", no, $W }
|
||||
%% --{hex,string,relocated}-dump: NYI
|
||||
%% --debug-dump: NYI
|
||||
%% --dwarf-{depth,start}: NYI
|
||||
%% --decompress: NYI
|
||||
%% --help: NYI
|
||||
%% @file: NYI
|
||||
]) of
|
||||
{ok, {Options, Files}} ->
|
||||
Opts = scan_options(Options),
|
||||
case Files of
|
||||
[] -> usage();
|
||||
_ ->
|
||||
case readelf(Opts, Files) of
|
||||
ok -> halt(0);
|
||||
{error, Reason} ->
|
||||
escript_runtime:fatal("~s\n", [error:format(Reason)])
|
||||
end
|
||||
end;
|
||||
{error, Reason} ->
|
||||
escript_runtime:errmsg("~s\n", [error:format(Reason)]),
|
||||
usage()
|
||||
end.
|
||||
|
||||
usage() ->
|
||||
escript_runtime:fmterr(
|
||||
"Usage: ~s -[ahlSgtesnrudVADcIvW] elffile..\n",
|
||||
[escript_runtime:progname()]),
|
||||
halt(1).
|
||||
|
||||
scan_options(Options) ->
|
||||
lists:foldl(fun scan_option/2, #options{}, Options).
|
||||
|
||||
scan_option(Option, Opts) ->
|
||||
case Option of
|
||||
$a ->
|
||||
Opts#options{ file_header = true
|
||||
, segments = true
|
||||
, sections = true
|
||||
, symbols = true
|
||||
, relocs = true
|
||||
, dynamic = true
|
||||
, notes = true
|
||||
, version_info = true
|
||||
, arch_specific = true
|
||||
, unwind = true
|
||||
, section_groups = true
|
||||
, histogram = true };
|
||||
$h ->
|
||||
Opts#options{ file_header = true };
|
||||
$l ->
|
||||
Opts#options{ segments = true };
|
||||
$S ->
|
||||
Opts#options{ sections = true };
|
||||
$g ->
|
||||
Opts#options{ section_groups = true };
|
||||
$t ->
|
||||
Opts#options{ section_details = true
|
||||
, sections = true };
|
||||
$s ->
|
||||
Opts#options{ symbols = true };
|
||||
dyn_syms ->
|
||||
Opts#options{ dyn_syms = true };
|
||||
$e ->
|
||||
Opts#options{ file_header = true
|
||||
, segments = true
|
||||
, sections = true };
|
||||
$n ->
|
||||
Opts#options{ notes = true };
|
||||
$r ->
|
||||
Opts#options{ relocs = true };
|
||||
$u ->
|
||||
Opts#options{ unwind = true };
|
||||
$d ->
|
||||
Opts#options{ dynamic = true };
|
||||
$V ->
|
||||
Opts#options{ version_info = true };
|
||||
$A ->
|
||||
Opts#options{ arch_specific = true };
|
||||
$D ->
|
||||
Opts#options{ use_dynamic = true };
|
||||
$c ->
|
||||
Opts#options{ archive_index = true };
|
||||
$I ->
|
||||
Opts#options{ histogram = true };
|
||||
$v ->
|
||||
version();
|
||||
$W ->
|
||||
Opts; % --wide is default in this readelf
|
||||
disassemble -> % extension
|
||||
Opts#options{ disassemble = true }
|
||||
end.
|
||||
|
||||
version() ->
|
||||
io:format(standard_io, "pdp10-tools readelf version 0.1\n", []),
|
||||
halt(0).
|
||||
|
||||
%% readelf =====================================================================
|
||||
|
||||
readelf(_Opts, []) -> ok;
|
||||
readelf(Opts, [File | Files]) ->
|
||||
case readelf_file(Opts, File) of
|
||||
ok -> readelf(Opts, Files);
|
||||
{error, _Reason} = Error -> Error
|
||||
end.
|
||||
|
||||
readelf_file(Opts, File) ->
|
||||
case pdp10_stdio:fopen(File, [raw, read]) of
|
||||
{ok, FP} ->
|
||||
try readelf_ehdr(Opts, FP)
|
||||
after pdp10_stdio:fclose(FP) end;
|
||||
{error, _Reason} = Error -> Error
|
||||
end.
|
||||
|
||||
readelf_ehdr(Opts, FP) ->
|
||||
case pdp10_elf36:read_Ehdr(FP) of
|
||||
{ok, Ehdr} ->
|
||||
case print_ehdr(Opts, Ehdr) of
|
||||
ok -> readelf_shtab(Opts, FP, Ehdr);
|
||||
{error, _Reason} = Error -> Error
|
||||
end;
|
||||
{error, _Reason} = Error -> Error
|
||||
end.
|
||||
|
||||
readelf_shtab(Opts, FP, Ehdr) ->
|
||||
case pdp10_elf36:read_ShTab(FP, Ehdr) of
|
||||
{ok, ShTab} ->
|
||||
case print_shtab(Opts, ShTab) of
|
||||
ok -> readelf_symtab(Opts, FP, ShTab);
|
||||
{error, _Reason} = Error -> Error
|
||||
end;
|
||||
{error, _Reason} = Error -> Error
|
||||
end.
|
||||
|
||||
readelf_symtab(Opts, FP, ShTab) ->
|
||||
case pdp10_elf36:read_SymTab(FP, ShTab) of
|
||||
{ok, {SymTab, ShNdx}} ->
|
||||
case print_symtab(Opts, SymTab, ShNdx, ShTab) of
|
||||
ok -> disassemble(Opts, FP, ShTab, SymTab);
|
||||
{error, _Reason} = Error -> Error
|
||||
end;
|
||||
{error, _Reason} = Error -> Error
|
||||
end.
|
||||
|
||||
%% print_ehdr ==================================================================
|
||||
|
||||
print_ehdr(#options{file_header = false}, _Ehdr) -> ok;
|
||||
print_ehdr(_Opts, Ehdr = #elf36_Ehdr{}) ->
|
||||
EIdent = Ehdr#elf36_Ehdr.e_ident,
|
||||
io:format("ELF Header:\n"),
|
||||
print_e_ident(EIdent),
|
||||
print_ei_class(lists:nth(1 + ?EI_CLASS, EIdent)),
|
||||
print_ei_data(lists:nth(1 + ?EI_DATA, EIdent)),
|
||||
print_ei_version(lists:nth(1 + ?EI_VERSION, EIdent)),
|
||||
print_ei_osabi(lists:nth(1 + ?EI_OSABI, EIdent)),
|
||||
print_ei_abiversion(lists:nth(1 + ?EI_ABIVERSION, EIdent)),
|
||||
print_e_type(Ehdr#elf36_Ehdr.e_type),
|
||||
print_e_machine(Ehdr#elf36_Ehdr.e_machine),
|
||||
print_e_version(Ehdr#elf36_Ehdr.e_version),
|
||||
print_e_entry(Ehdr#elf36_Ehdr.e_entry),
|
||||
print_e_phoff(Ehdr#elf36_Ehdr.e_phoff),
|
||||
print_e_shoff(Ehdr#elf36_Ehdr.e_shoff),
|
||||
print_e_flags(Ehdr#elf36_Ehdr.e_flags),
|
||||
print_e_ehsize(Ehdr#elf36_Ehdr.e_ehsize),
|
||||
print_e_phentsize(Ehdr#elf36_Ehdr.e_phentsize),
|
||||
print_e_phnum(Ehdr#elf36_Ehdr.e_phnum),
|
||||
print_e_shentsize(Ehdr#elf36_Ehdr.e_shentsize),
|
||||
print_e_shnum(Ehdr#elf36_Ehdr.e_shnum),
|
||||
print_e_shstrndx(Ehdr#elf36_Ehdr.e_shstrndx),
|
||||
io:format("\n").
|
||||
|
||||
print_e_ident(EIdent) ->
|
||||
io:format(" Magic:\t\t\t\t"),
|
||||
print_e_ident("", EIdent),
|
||||
io:format("\n").
|
||||
|
||||
print_e_ident(_Pfx, []) -> ok;
|
||||
print_e_ident(Pfx, [Byte | Bytes]) ->
|
||||
io:format("~s", [Pfx]),
|
||||
%% bytes in [256,512[ are unlikely, but handle them correctly anyway
|
||||
if Byte > 255 -> io:format("~3.16.0b", [Byte]);
|
||||
true -> io:format("~2.16.0b", [Byte])
|
||||
end,
|
||||
print_e_ident(" ", Bytes).
|
||||
|
||||
print_ei_class(EIClass) ->
|
||||
io:format(" Class:\t\t\t\t~.10b (~s)\n",
|
||||
[EIClass,
|
||||
case EIClass of
|
||||
?ELFCLASS32 -> "ELF32";
|
||||
?ELFCLASS64 -> "ELF64";
|
||||
?ELFCLASS36 -> "ELF36";
|
||||
_ -> "?"
|
||||
end]).
|
||||
|
||||
print_ei_data(EIData) ->
|
||||
io:format(" Data:\t\t\t\t\t~.10b (~s)\n",
|
||||
[EIData,
|
||||
case EIData of
|
||||
?ELFDATA2LSB -> "2's complement, little endian";
|
||||
?ELFDATA2MSB -> "2's complement, big endian";
|
||||
_ -> "?"
|
||||
end]).
|
||||
|
||||
print_ei_version(EIVersion) ->
|
||||
io:format(" Version:\t\t\t\t~.10b (~s)\n",
|
||||
[EIVersion, version_string(EIVersion)]).
|
||||
|
||||
print_ei_osabi(EIOSABI) ->
|
||||
io:format(" OS/ABI:\t\t\t\t~.10b (~s)\n",
|
||||
[EIOSABI,
|
||||
case EIOSABI of
|
||||
?ELFOSABI_NONE -> "Generic";
|
||||
?ELFOSABI_LINUX -> "Linux";
|
||||
_ -> "?"
|
||||
end]).
|
||||
|
||||
print_ei_abiversion(EIABIVersion) ->
|
||||
io:format(" ABI Version:\t\t\t\t~.10b\n", [EIABIVersion]).
|
||||
|
||||
print_e_type(EType) ->
|
||||
io:format(" Type:\t\t\t\t\t~.10b (~s)\n",
|
||||
[EType,
|
||||
case EType of
|
||||
?ET_REL -> "Relocatable file";
|
||||
?ET_EXEC -> "Executable file";
|
||||
?ET_DYN -> "Shared object file";
|
||||
?ET_CORE -> "Core file";
|
||||
_ -> "?"
|
||||
end]).
|
||||
|
||||
print_e_machine(EMachine) ->
|
||||
io:format(" Machine:\t\t\t\t~.10b (~s)\n",
|
||||
[EMachine,
|
||||
case EMachine of
|
||||
?EM_PDP10 -> "Digital Equipment Corp. PDP-10";
|
||||
_ -> "?"
|
||||
end]).
|
||||
|
||||
print_e_version(EVersion) ->
|
||||
io:format(" Version:\t\t\t\t~.10b (~s)\n",
|
||||
[EVersion, version_string(EVersion)]).
|
||||
|
||||
version_string(?EV_CURRENT) -> "current";
|
||||
version_string(_) -> "?".
|
||||
|
||||
print_e_entry(EEntry) ->
|
||||
io:format(" Entry point address:\t\t\t0x~.16b\n", [EEntry]).
|
||||
|
||||
print_e_phoff(EPhOff) ->
|
||||
io:format(" Start of program headers:\t\t~.10b\n", [EPhOff]).
|
||||
|
||||
print_e_shoff(EShOff) ->
|
||||
io:format(" Start of section headers:\t\t~.10b\n", [EShOff]).
|
||||
|
||||
print_e_flags(EFLags) ->
|
||||
io:format(" Flags:\t\t\t\t0x~.16b\n", [EFLags]).
|
||||
|
||||
print_e_ehsize(EEhSize) ->
|
||||
io:format(" Size of this header:\t\t\t~.10b\n", [EEhSize]).
|
||||
|
||||
print_e_phentsize(EPhEntSize) ->
|
||||
io:format(" Size of program headers:\t\t~.10b\n", [EPhEntSize]).
|
||||
|
||||
print_e_phnum(EPhNum) ->
|
||||
io:format(" Number of program headers:\t\t~.10b\n", [EPhNum]).
|
||||
|
||||
print_e_shentsize(EShEntSize) ->
|
||||
io:format(" Size of section headers:\t\t~.10b\n", [EShEntSize]).
|
||||
|
||||
print_e_shnum(EShNum) ->
|
||||
io:format(" Number of section headers:\t\t~.10b\n", [EShNum]).
|
||||
|
||||
print_e_shstrndx(EShStrNdx) ->
|
||||
io:format(" Section header string table index:\t~.10b\n", [EShStrNdx]).
|
||||
|
||||
%% print_shtab =================================================================
|
||||
|
||||
print_shtab(#options{sections = false}, _ShTab) -> ok;
|
||||
print_shtab(_Opts, ShTab) ->
|
||||
io:format("Section Headers:\n"),
|
||||
io:format(" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n"),
|
||||
print_shdrs(ShTab, 0).
|
||||
|
||||
print_shdrs([Shdr | Shdrs], I) ->
|
||||
io:format(" [~.10b] ~s ~s 0x~.16b ~.10b ~.10b ~.10b ~s ~.10b ~.10b ~.10b\n",
|
||||
[ I
|
||||
, sh_name(Shdr)
|
||||
, sh_type(Shdr)
|
||||
, Shdr#elf36_Shdr.sh_addr
|
||||
, Shdr#elf36_Shdr.sh_offset
|
||||
, Shdr#elf36_Shdr.sh_size
|
||||
, Shdr#elf36_Shdr.sh_entsize
|
||||
, sh_flags(Shdr)
|
||||
, Shdr#elf36_Shdr.sh_link
|
||||
, Shdr#elf36_Shdr.sh_info
|
||||
, Shdr#elf36_Shdr.sh_addralign
|
||||
]),
|
||||
print_shdrs(Shdrs, I + 1);
|
||||
print_shdrs([], _I) ->
|
||||
io:format("Key to Flags:\n"),
|
||||
io:format(" W (write), A (alloc), X (execute), M (merge), S (strings), Z (compressed)\n"),
|
||||
io:format(" I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)\n"),
|
||||
io:format(" O (extra OS processing required), o (OS specific), p (processor specific)\n"),
|
||||
io:format("\n").
|
||||
|
||||
sh_name(#elf36_Shdr{sh_name = ShName}) ->
|
||||
case ShName of
|
||||
"" -> "(empty)";
|
||||
_ -> ShName
|
||||
end.
|
||||
|
||||
sh_type(#elf36_Shdr{sh_type = ShType}) ->
|
||||
case ShType of
|
||||
?SHT_NULL -> "NULL";
|
||||
?SHT_PROGBITS -> "PROGBITS";
|
||||
?SHT_SYMTAB -> "SYMTAB";
|
||||
?SHT_STRTAB -> "STRTAB";
|
||||
?SHT_RELA -> "RELA";
|
||||
?SHT_HASH -> "HASH";
|
||||
?SHT_DYNAMIC -> "DYNAMIC";
|
||||
?SHT_NOTE -> "NOTE";
|
||||
?SHT_NOBITS -> "NOBITS";
|
||||
?SHT_REL -> "REL";
|
||||
?SHT_SHLIB -> "SHLIB";
|
||||
?SHT_DYNSYM -> "DYNSYM";
|
||||
?SHT_INIT_ARRAY -> "INIT_ARRAY";
|
||||
?SHT_FINI_ARRAY -> "FINI_ARRAY";
|
||||
?SHT_PREINIT_ARRAY -> "PREINIT_ARRAY";
|
||||
?SHT_GROUP -> "GROUP";
|
||||
?SHT_SYMTAB_SHNDX -> "SYMTAB_SHNDX";
|
||||
?SHT_GNU_INCREMENTAL_INPUTS -> "GNU_INCREMENTAL_INPUTS";
|
||||
?SHT_GNU_ATTRIBUTES -> "GNU_ATTRIBUTES";
|
||||
?SHT_GNU_HASH -> "GNU_HASH";
|
||||
?SHT_GNU_LIBLIST -> "GNU_LIBLIST";
|
||||
?SHT_GNU_verdef -> "GNU_verdef";
|
||||
?SHT_GNU_verneed -> "GNU_verneed";
|
||||
?SHT_GNU_versym -> "GNU_versym";
|
||||
_ -> io_lib:format("~.10b", [ShType])
|
||||
end.
|
||||
|
||||
sh_flags(#elf36_Shdr{sh_flags = ShFlags}) ->
|
||||
sh_flags("WAXxMSILOGTZ", 0, ShFlags, 0, []).
|
||||
|
||||
sh_flags([C | Flags], I, ShFlags, Mask, Acc) ->
|
||||
{NewMask, NewAcc} =
|
||||
case I =/= 3 andalso (ShFlags band (1 bsl I)) =/= 0 of
|
||||
true -> {Mask bor (1 bsl I), [C | Acc]};
|
||||
false -> {Mask, Acc}
|
||||
end,
|
||||
sh_flags(Flags, I + 1, ShFlags, NewMask, NewAcc);
|
||||
sh_flags([], _I, ShFlags, Mask, Acc) ->
|
||||
{NewMask, NewAcc} =
|
||||
case ShFlags band ?SHF_EXCLUDE =/= 0 of
|
||||
true -> {Mask bor ?SHF_EXCLUDE, [$E | Acc]};
|
||||
false -> {Mask, Acc}
|
||||
end,
|
||||
case ShFlags of
|
||||
0 -> "-";
|
||||
NewMask -> lists:reverse(NewAcc);
|
||||
_ -> io_lib:format("0x~.16b", [ShFlags])
|
||||
end.
|
||||
|
||||
%% print_symtab ================================================================
|
||||
|
||||
print_symtab(#options{symbols = false}, _SymTab, _ShNdx, _ShTab) -> ok;
|
||||
print_symtab(_Opts, SymTab, ShNdx, ShTab) ->
|
||||
Shdr = lists:nth(1 + ShNdx, ShTab),
|
||||
io:format("Symbol table '~s' in section ~.10b contains ~.10b entries:\n",
|
||||
[Shdr#elf36_Shdr.sh_name, ShNdx, length(SymTab)]),
|
||||
io:format(" Num Value Size Type Bind Vis Ndx Name\n"),
|
||||
print_syms(SymTab, 0).
|
||||
|
||||
print_syms([Sym | Syms], I) ->
|
||||
io:format(" ~.10b 0x~.16b ~.10b ~s ~s ~s ~.10b ~s\n",
|
||||
[ I
|
||||
, Sym#elf36_Sym.st_value
|
||||
, Sym#elf36_Sym.st_size
|
||||
, st_type(Sym)
|
||||
, st_bind(Sym)
|
||||
, st_vis(Sym)
|
||||
, Sym#elf36_Sym.st_shndx
|
||||
, st_name(Sym)
|
||||
]),
|
||||
print_syms(Syms, I + 1);
|
||||
print_syms([], _I) ->
|
||||
io:format("\n").
|
||||
|
||||
st_type(#elf36_Sym{st_info = StInfo}) ->
|
||||
case ?ELF36_ST_TYPE(StInfo) of
|
||||
?STT_NOTYPE -> "NOTYPE";
|
||||
?STT_OBJECT -> "OBJECT";
|
||||
?STT_FUNC -> "FUNC";
|
||||
?STT_SECTION -> "SECTION";
|
||||
?STT_FILE -> "FILE";
|
||||
?STT_COMMON -> "COMMON";
|
||||
?STT_TLS -> "TLS";
|
||||
?STT_RELC -> "RELC";
|
||||
?STT_SRELC -> "SRELC";
|
||||
?STT_GNU_IFUNC -> "GNU_IFUNC";
|
||||
StType -> io_lib:format("~.10b", [StType])
|
||||
end.
|
||||
|
||||
st_bind(#elf36_Sym{st_info = StInfo}) ->
|
||||
case ?ELF36_ST_BIND(StInfo) of
|
||||
?STB_LOCAL -> "LOCAL";
|
||||
?STB_GLOBAL -> "GLOBAL";
|
||||
?STB_WEAK -> "WEAK";
|
||||
?STB_GNU_UNIQUE -> "GNU_UNIQUE";
|
||||
StBind -> io_lib:format("~.10b", [StBind])
|
||||
end.
|
||||
|
||||
st_vis(#elf36_Sym{st_other = StOther}) ->
|
||||
case ?ELF36_ST_VISIBILITY(StOther) of
|
||||
?STV_DEFAULT -> "DEFAULT";
|
||||
?STV_INTERNAL -> "INTERNAL";
|
||||
?STV_HIDDEN -> "HIDDEN";
|
||||
?STV_PROTECTED -> "PROTECTED";
|
||||
StVis -> io_lib:format("~.10b", [StVis])
|
||||
end.
|
||||
|
||||
st_name(#elf36_Sym{st_name = StName}) ->
|
||||
case StName of
|
||||
"" -> "(empty)";
|
||||
_ -> StName
|
||||
end.
|
||||
|
||||
%% disassemble =================================================================
|
||||
|
||||
disassemble(#options{disassemble = false}, _FP, _ShTab, _SymTab) -> ok;
|
||||
disassemble(_Opts, FP, ShTab, SymTab) ->
|
||||
disassemble_sections(ShTab, 0, FP, SymTab).
|
||||
|
||||
disassemble_sections([], _ShNdx, _FP, _SymTab) -> ok;
|
||||
disassemble_sections([Shdr | ShTab], ShNdx, FP, SymTab) ->
|
||||
case disassemble_section(Shdr, ShNdx, FP, SymTab) of
|
||||
ok -> disassemble_sections(ShTab, ShNdx + 1, FP, SymTab);
|
||||
{error, _Reason} = Error -> Error
|
||||
end.
|
||||
|
||||
disassemble_section(Shdr, ShNdx, FP, SymTab) ->
|
||||
case Shdr of
|
||||
#elf36_Shdr{ sh_type = ?SHT_PROGBITS
|
||||
, sh_flags = ?SHF_ALLOC bor ?SHF_EXECINSTR
|
||||
, sh_offset = ShOffset
|
||||
, sh_size = ShSize
|
||||
} ->
|
||||
io:format("Disassembly of section nr ~.10b ~s:\n\n",
|
||||
[ShNdx, sh_name(Shdr)]),
|
||||
case pdp10_stdio:fseek(FP, {bof, ShOffset}) of
|
||||
ok -> disassemble_insns(0, ShSize, FP, labels(SymTab, ShNdx));
|
||||
{error, _Reason} = Error -> Error
|
||||
end;
|
||||
#elf36_Shdr{} ->
|
||||
ok
|
||||
end.
|
||||
|
||||
disassemble_insns(Offset, Size, FP, Labels) when Offset < Size ->
|
||||
case pdp10_elf36:read_uint36(FP) of
|
||||
{ok, InsnWord} ->
|
||||
RestLabels = print_labels(Labels, Offset),
|
||||
io:format(" 0x~.16b:\t0~12.8.0b\t", [Offset, InsnWord]),
|
||||
disassemble_insn(InsnWord),
|
||||
disassemble_insns(Offset + 4, Size, FP, RestLabels);
|
||||
{error, _Reason} = Error -> Error
|
||||
end;
|
||||
disassemble_insns(_ShOffset, _ShSize, _FP, _Labels) -> ok.
|
||||
|
||||
disassemble_insn(InsnWord) ->
|
||||
Models = ?PDP10_KL10_271up,
|
||||
High13 = InsnWord bsr (36 - 13),
|
||||
Extended = false,
|
||||
Section0 = false,
|
||||
case pdp10_opcodes:insn_from_high13(Models, High13, Extended, Section0) of
|
||||
#pdp10_insn_desc{name = Name, format = Format} ->
|
||||
io:format("~s ", [Name]),
|
||||
case Format of
|
||||
?PDP10_INSN_A_OPCODE -> ok;
|
||||
_ -> io:format("~.10b,", [(InsnWord bsr 23) band 16#F])
|
||||
end,
|
||||
case InsnWord band (1 bsl 22) of
|
||||
0 -> ok;
|
||||
_ -> io:format("@")
|
||||
end,
|
||||
io:format("~.10b", [InsnWord band ((1 bsl 18) - 1)]),
|
||||
case (InsnWord bsr 18) band 16#F of
|
||||
0 -> ok;
|
||||
IxReg -> io:format("(~.10b)", [IxReg])
|
||||
end,
|
||||
io:format("\n");
|
||||
false ->
|
||||
io:format("(bad)\n")
|
||||
end.
|
||||
|
||||
print_labels([], _Offset) -> [];
|
||||
print_labels(Labels = [Label | RestLabels], Offset) ->
|
||||
#elf36_Sym{st_value = StValue} = Label,
|
||||
if StValue < Offset -> print_labels(RestLabels, Offset);
|
||||
StValue =:= Offset ->
|
||||
io:format("0x~9.16.0b <~s>:\n", [Offset, st_name(Label)]),
|
||||
print_labels(RestLabels, Offset);
|
||||
true -> Labels
|
||||
end.
|
||||
|
||||
labels(SymTab, TextShNdx) ->
|
||||
lists:sort(fun sym_cmp_by_value/2,
|
||||
lists:filter(fun(Sym) -> sym_is_label(Sym, TextShNdx) end,
|
||||
SymTab)).
|
||||
|
||||
sym_is_label(Sym, TextShNdx) ->
|
||||
#elf36_Sym{st_shndx = StShNdx, st_info = StInfo} = Sym,
|
||||
StShNdx =:= TextShNdx andalso
|
||||
?ELF36_ST_TYPE(StInfo) =:= ?STT_FUNC andalso % TODO: type of a label?
|
||||
(case ?ELF36_ST_BIND(StInfo) of
|
||||
?STB_GLOBAL -> true;
|
||||
?STB_LOCAL -> true;
|
||||
?STB_WEAK -> true;
|
||||
_ -> false
|
||||
end).
|
||||
|
||||
sym_cmp_by_value(Sym1, Sym2) ->
|
||||
Sym1#elf36_Sym.st_value =< Sym2#elf36_Sym.st_value.
|
||||
@ -32,10 +32,10 @@
|
||||
{escript_emu_args, "%%! +sbtu +A1 +Bd -noshell -smp auto\n"}.
|
||||
|
||||
{profiles,
|
||||
[
|
||||
{'8to9', [{escript_main_app, '8to9'}]}
|
||||
, {ar, [{escript_main_app, ar}]}
|
||||
, {as, [{escript_main_app, as}]}
|
||||
, {nm, [{escript_main_app, nm}]}
|
||||
, {od, [{escript_main_app, od}]}
|
||||
[ {'8to9', [{escript_main_app, '8to9'}]}
|
||||
, {ar, [{escript_main_app, ar}]}
|
||||
, {as, [{escript_main_app, as}]}
|
||||
, {nm, [{escript_main_app, nm}]}
|
||||
, {od, [{escript_main_app, od}]}
|
||||
, {readelf, [{escript_main_app, readelf}]}
|
||||
]}.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user