Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduces bap dependencies command #1294

Merged
merged 12 commits into from
Apr 15, 2021
7 changes: 7 additions & 0 deletions lib/bap/bap.mli
Original file line number Diff line number Diff line change
Expand Up @@ -5792,6 +5792,13 @@ module Std : sig
val format : (string, (string -> 'a) -> 'a) Ogre.attribute


(** [(require library)] defines that the unit requires
[library].

@since 2.3.0 *)
val require : (string, (string -> 'a) -> 'a) Ogre.attribute


(** (is-little-endian FLAG)] is set for files with words encoded in the
little-endian order.

Expand Down
1 change: 1 addition & 0 deletions lib/bap_image/bap_image.ml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ module Scheme = struct
let vendor () = declare "vendor" (scheme name) ident
let system () = declare "system" (scheme name) ident
let format () = declare "format" (scheme name) ident
let require () = declare "require" (scheme name) ident
let abi () = declare "abi" (scheme name) ident
let bits () = declare "bits" (scheme size) ident
let is_little_endian () = declare "is-little-endian" (scheme flag) ident
Expand Down
1 change: 1 addition & 0 deletions lib/bap_image/bap_image.mli
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ module Scheme : sig
val format : (string, (string -> 'a) -> 'a) Ogre.attribute
val vendor : (string, (string -> 'a) -> 'a) Ogre.attribute
val system : (string, (string -> 'a) -> 'a) Ogre.attribute
val require : (string, (string -> 'a) -> 'a) Ogre.attribute
val abi : (string, (string -> 'a) -> 'a) Ogre.attribute
val bits : (size, (size -> 'a) -> 'a) Ogre.attribute
val is_little_endian : (bool, (bool -> 'a) -> 'a) Ogre.attribute
Expand Down
88 changes: 81 additions & 7 deletions lib/bap_llvm/bap_llvm_loader.ml
Original file line number Diff line number Diff line change
Expand Up @@ -301,15 +301,89 @@ let overload file_type info =
Ogre.sequence @@
provide_if (String.equal file file_type) info

module ElfDyn = struct
type dyn = {
tag : word;
off : word;
}

type img = {
data : Bigstring.t;
endian : Word.endian;
width : int;
}

let required attr k =
Ogre.request attr >>= function
| None -> Ogre.return ()
| Some x -> k x

let section_by_name {data; endian; width} sec_name =
Ogre.collect Ogre.Query.(begin
select (from (LLVM.section_entry))
~where:(LLVM.section_entry.(name) = str sec_name)
end) >>| Seq.hd >>| function
| None -> None
| Some (_,addr,len,pos) ->
let len = Int64.to_int_trunc len
and pos = Int64.to_int_trunc pos in
let addr = Addr.of_int64 ~width addr in
match Memory.create ~pos ~len endian addr data with
| Ok mem -> Some mem
| _ -> None

let word_size img = Size.of_int_exn img.width

let dynamic_contents img =
section_by_name img ".dynamic" >>| function
| None -> []
| Some mem ->
Memory.fold ~word_size:(word_size img) mem ~f:(fun data (acc,dyn) ->
match dyn with
| None -> acc,Some data
| Some tag -> {tag;off=data}::acc,None)
~init:([],None) |> function
| acc,_ -> List.rev acc

let read ~strtab pos =
let strtab = Memory.to_buffer strtab in
let rec loop off =
if Char.equal (Bigsubstring.get strtab off) '\x00'
then Bigsubstring.sub strtab ~pos ~len:(off-pos)
else loop (off+1) in
Bigsubstring.to_string @@ loop pos


let libraries data =
required is_little_endian @@ fun is_little ->
required bits @@ fun bits ->
let endian = if is_little then LittleEndian else BigEndian in
let img = {endian; data; width = Int64.to_int_exn bits} in
section_by_name img ".dynstr" >>= function
| None -> Ogre.return ()
| Some strtab ->
dynamic_contents img >>|
Seq.of_list >>=
Ogre.Seq.iter ~f:(fun {tag; off} ->
match Word.to_int tag, Word.to_int off with
| Ok 1, Ok off ->
Ogre.provide require (read ~strtab off)
| _ -> Ogre.return ())

end

let provide_elf_segmentation_and_libraries data =
provide_elf_segmentation @ [ElfDyn.libraries data;]

(** translates llvm-specific specification into the image specification *)
let translate user_base =
let translate data user_base =
Ogre.sequence [
provide_base_and_bias user_base;
provide_entry;
Ogre.sequence [
overload "elf" provide_elf_segmentation;
overload "coff" provide_coff_segmentation;
overload "macho" provide_macho_segmentation;
overload "elf" @@ provide_elf_segmentation_and_libraries data;
overload "coff" @@ provide_coff_segmentation;
overload "macho" @@ provide_macho_segmentation;
];
provide_symbols;
provide_relocations;
Expand All @@ -325,8 +399,8 @@ let pdb_path ~pdb filename =
else pdb
else ""

let translate_to_image_spec base doc =
match Ogre.exec (translate base) doc with
let translate_to_image_spec data base doc =
match Ogre.exec (translate data base) doc with
| Ok doc -> Ok (Some doc)
| Error er -> Error er

Expand All @@ -341,7 +415,7 @@ let from_data ~base ~pdb filename data =
let open Or_error.Monad_infix in
load_doc ~pdb filename data >>=
Ogre.Doc.from_string >>=
translate_to_image_spec base
translate_to_image_spec data base

let map_file path =
let fd = Unix.(openfile path [O_RDONLY] 0o400) in
Expand Down
10 changes: 10 additions & 0 deletions lib/bap_llvm/llvm_coff_loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,15 @@ error_or<uint64_t> symbol_file_offset(const coff_obj &obj, const SymbolRef &sym)
return failure("failed to get the section");
}
}

void emit_import_directories(const coff_obj &obj, ogre_doc &s) {
for (auto dir : obj.import_directories()) {
StringRef name;
if (!dir.getName(name))
s.entry("require") << name.str();
}
}

} // namespace coff_loader

error_or<std::string> load(ogre_doc &s, const llvm::object::COFFObjectFile &obj, const char* pdb_path) {
Expand All @@ -356,6 +365,7 @@ error_or<std::string> load(ogre_doc &s, const llvm::object::COFFObjectFile &obj,
emit_symbols(obj, s);
emit_relocations(obj, s);
emit_exported_symbols(obj, s);
emit_import_directories(obj, s);
if (pdb_path)
pdb_loader::load(obj, pdb_path, s);
return s.str();
Expand Down
4 changes: 3 additions & 1 deletion lib/bap_llvm/llvm_loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ static std::string scheme =
"(declare subarch (name str))\n"
"(declare system (name str))\n"
"(declare vendor (name str))\n"
"(declare require (name str))\n"
"(declare llvm:code-entry (name str) (off int) (size int))\n"
"(declare llvm:base-address (addr int))\n"
"(declare llvm:entry-point (addr int))\n"
Expand All @@ -33,7 +34,8 @@ static std::string scheme =
"(declare llvm:symbol-entry (name str) (addr int) (size int) (off int) (value int))\n"
"(declare llvm:elf-virtual-program-header (name str) (addr int) (size int))\n"
"(declare llvm:coff-virtual-section-header (name str) (addr int) (size int))\n"
"(declare llvm:virtual-segment-command (name str) (addr int) (size int))\n";
"(declare llvm:virtual-segment-command (name str) (addr int) (size int))\n"
"(declare llvm:coff-import-library (name str))\n";


namespace loader {
Expand Down
18 changes: 18 additions & 0 deletions lib/bap_llvm/llvm_macho_loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,23 @@ void emit_relocation(const macho &obj, const RelocationRef &rel, section_iterato
emit_relocation(obj, prim::relocation_offset(rel), rel.getSymbol(), sec, s);
}

void emit_libraries(const macho &obj, ogre_doc &s) {
for (const auto &entry : obj.load_commands()) {
if (entry.C.cmd == MachO::LC_LOAD_DYLIB ||
entry.C.cmd == MachO::LC_ID_DYLIB ||
entry.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
entry.C.cmd == MachO::LC_REEXPORT_DYLIB ||
entry.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
entry.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
MachO::dylib_command cmd = obj.getDylibIDLoadCommand(entry);
if (cmd.dylib.name < cmd.cmdsize) {
auto *name = static_cast<const char*>(entry.Ptr) + cmd.dylib.name;
s.entry("require") << name;
}
}
}
}

symbol_iterator get_symbol(const macho &obj, std::size_t index);

void emit_dyn_relocation(const macho &obj, uint32_t sym_num, uint64_t off, ogre_doc &s) {
Expand Down Expand Up @@ -470,6 +487,7 @@ error_or<std::string> load(ogre_doc &s, const llvm::object::MachOObjectFile &obj
emit_sections(obj, s);
emit_symbols(obj, s);
emit_relocations(obj, s);
emit_libraries(obj, s);
return s.str();
}

Expand Down
13 changes: 13 additions & 0 deletions oasis/dependencies
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Flag dependencies
Description: Enable the dependencies command
Default: false

Library dependencies_plugin
Build$: flag(everything) || flag(dependencies)
XMETADescription: analyses the binary dependencies
Path: plugins/dependencies
FindlibName: bap-plugin-dependencies
CompiledObject: best
BuildDepends: bap, core_kernel, bap-main, ogre, regular, ppx_bap
InternalModules: Dependencies_main
XMETAExtraLines: tags="command, dependencies"
4 changes: 2 additions & 2 deletions oasis/specification
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Flag specification

Library specification_plugin
Build$: flag(everything) || flag(specification)
XMETADescription: implements the specification command
XMETADescription: prints the specification of the binary (like readelf)
Path: plugins/specification
FindlibName: bap-plugin-specification
CompiledObject: best
BuildDepends: bap, core_kernel, bap-main, ogre
BuildDepends: bap, core_kernel, bap-main, ogre, regular
InternalModules: Specification_main
XMETAExtraLines: tags="command, specification"
Loading