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

extends the demanglers library to the new targets infrastructure #1504

Merged
merged 2 commits into from
Jun 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/bap_core_theory/bap_core_theory.mli
Original file line number Diff line number Diff line change
Expand Up @@ -1383,7 +1383,7 @@ module Theory : sig
This type is a unique identifier of the target,
represented as [KB.Name.t] underneath the hood.
*)
type t = target
type t = target [@@deriving bin_io, compare, sexp]
include Base.Comparable.S with type t := t
include Binable.S with type t := t
include Stringable.S with type t := t
Expand Down Expand Up @@ -1699,6 +1699,12 @@ module Theory : sig
(** the persistence type class, derived from [KB.Name.persistent] *)
val persistent : t KB.persistent


(** [hash t] returns the target's hash.

@since 2.5.0 *)
val hash : t -> int

(** An extensible set of the target options.

The set is represented with the {!KB.Value.t},
Expand Down
2 changes: 2 additions & 0 deletions lib/bap_core_theory/bap_core_theory_target.ml
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,8 @@ let matches t name =

let nicknames t = (info t).names

let hash = Self.hash

type alias = Alias.t

include (Self : Base.Comparable.S with type t := t)
Expand Down
1 change: 1 addition & 0 deletions lib/bap_core_theory/bap_core_theory_target.mli
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ include Binable.S with type t := t
include Stringable.S with type t := t
include Pretty_printer.S with type t := t
val name : t -> KB.Name.t
val hash : t -> int
val unknown : t
val domain : t KB.domain
val persistent : t KB.persistent
118 changes: 63 additions & 55 deletions lib/bap_demangle/bap_demangle.ml
Original file line number Diff line number Diff line change
@@ -1,72 +1,80 @@
open Core_kernel[@@warning "-D"]

let maybe_mangled name =
String.length name > 2 &&
Char.(name.[0] = '_') &&
Char.is_uppercase name.[1] &&
Char.is_alpha name.[1]

let demangle_internal str =
let open String in
let open Option.Monad_infix in
let extract_number pos_ref =
lfindi str ~pos:!pos_ref ~f:(fun _ c -> Char.is_digit c)
>>= fun s1_p0 ->
lfindi str ~pos:s1_p0 ~f:(fun _ c -> not (Char.is_digit c))
>>= fun s1_p1 ->
let len = (s1_p1 - s1_p0) in
let str = Bytes.of_string str in
let n = Substring.create ~pos:s1_p0 ~len str |>
Substring.to_string |> Int.of_string in
pos_ref := s1_p0 + len;
Some n in
let extract_name pos_ref =
let str = Bytes.of_string str in
extract_number pos_ref >>= fun len ->
let name = Substring.create ~pos:!pos_ref ~len str |>
Substring.to_string in
pos_ref := !pos_ref + len;
Some name in
let pos = ref 0 in
let rec extract_names acc =
match extract_name pos with
| None | Some "" -> List.rev acc
| Some name -> extract_names (name::acc) in
match extract_names [] |> String.concat ~sep:"::" with
| "" -> str
| s -> s

let demangle_internal name =
if maybe_mangled name then
Option.try_with (fun () -> demangle_internal name)
else None

let run_internal name =
Option.value_map ~default:name ~f:Fn.id (demangle_internal name)
open Bap_core_theory

module Std = struct
type demangler = {
name : string;
name : KB.Name.t;
run : string -> string
}

let registry = Hashtbl.create (module KB.Name)
let selected = Hashtbl.create (module Theory.Target)

module Demangler = struct
type t = demangler
let create name run = {name; run}
let create ?package name run =
let name = KB.Name.create ?package name in
if Hashtbl.mem registry name
then failwithf "The demangler %s is already registered, \
please pick a unique name" (KB.Name.show name) ();
Hashtbl.add_exn registry name run;
{name; run}

let declare ?package name run = ignore (create ?package name run)

let run d = d.run
let name d = d.name
let fullname d = d.name
let name d = KB.Name.unqualified d.name

let id = create ~package:"bap" "id" Fn.id
let strip_leading_underscore =
create ~package:"bap" "strip-leading-underscore" @@ fun s ->
match String.chop_prefix s ~prefix:"_" with
| None -> s
| Some s -> s
end

module Demanglers = struct
let demanglers = ref []
let register d = demanglers := d :: !demanglers
let available () = !demanglers
let register = ignore
let available () =
Hashtbl.to_alist registry |>
List.map ~f:(fun (name,run) -> {name; run})

let install target demangler =
match Hashtbl.add selected target demangler with
| `Ok -> ()
| `Duplicate ->
let used = Hashtbl.find_exn selected target in
failwithf "Failed to install demangler %s to the \
target %s, which already has the demangler %s."
(KB.Name.show used.name)
(KB.Name.show (Theory.Target.name target))
(KB.Name.show demangler.name)
()

let bad_name name =
let names =
available () |>
List.map ~f:(fun d -> KB.Name.show (Demangler.fullname d)) |>
String.concat ~sep:", " in
invalid_argf "Failed to find a demangler named %s, \
the list of available demanglers: %s"
(KB.Name.show name) names ()


let get ?package name =
let name = KB.Name.create ?package name in
match Hashtbl.find registry name with
| Some run -> {name; run}
| None -> bad_name name

let select target = match Hashtbl.find selected target with
| None -> Demangler.id
| Some d -> d

let lookup ?package name =
try Some (get ?package name) with _ -> None
end

let internal = {
name = "internal";
run = run_internal;
}

let () = Demanglers.register internal
end
117 changes: 108 additions & 9 deletions lib/bap_demangle/bap_demangle.mli
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
(** Name demangling.

This library provides an interface for creating and registering
demanglers, that can be used on demand by fronends and plugins.

Name demanglers perfrom ABI-specific name translations that
restore the original source-language names of symbols, like
removing leading underscores, or decoding C++ function names.
*)
open Core_kernel[@@warning "-D"]
open Bap_core_theory


module Std : sig
type demangler
Expand All @@ -14,26 +16,123 @@ module Std : sig
module Demangler : sig
type t = demangler

(** [create name demangler] creates and registers a new named demangler.

(** [create name demangler] *)
val create : string -> (string -> string) -> t
A simple demangler is a total function that either demangles a
symbol name or leaves it untouched if it can't or if the name
is not mangled.

@since 2.5.0 accepts the optional (but recommended) [package]
parameter.

@since 2.5.0 fails demangler with the given [package:name]
already exists.

@since 2.5.0 automatically registers the demangler in the
repository.
*)
val create : ?package:string -> string -> (string -> string) -> t


(** [define name run] creates and registers a simple named demangler.

A simple demangler is a total function that either demangles a
symbol name or leaves it untouched if it can't or if the name
is not mangled.

Essentially, [declare name run] is [ignore (create name run)].

@since 2.5.0
*)
val declare : ?package:string -> string -> (string -> string) -> unit

(** [run demangler name] demangle given [name] *)
val run : t -> string -> string

(** [id] the identity demangler that returns names unchanged.

The [name id] is [bap:id]

@since 2.5.0 *)
val id : demangler



(** [strip_leading_underscore] the demangler that strips one
leading underscore.

If a symbol is not underscored then it is returned unchanged.

The [name strip_leading_underscore] is [bap:strip-leading-underscore]

@since 2.5.0
*)
val strip_leading_underscore : demangler

(** [run demangler name] demangle given [name]. *)
val run : t -> string -> string

(** [name demangler] returns a [demangler]'s name. *)
(** [name demangler] returns [demangler]'s unqualified name as a string. *)
val name : t -> string

(** [fullname d] the fully-qualified name of the demangler [d].

@since 2.5.0 *)
val fullname : t -> KB.Name.t
end


(** Registry of demanglers. *)
module Demanglers : sig

(** [register demangler] register new demangler. *)
(** [install t d] installs [d] as the default demangler for the
target [t].

The demangler will be used every time a name is decided from
the set of possible names for a label that belongs to a
program unit that has target [t].

Fails if a demangler for the given target is already
installed.

@since 2.5.0
*)
val install : Theory.target -> demangler -> unit

(** [register demangler] DEPRECATED.

@before 2.5.0 registers new demangler.
@after 2.5.0 no longer needed and does nothing, all demanglers
are automatically registered on creation. *)
val register : demangler -> unit
[@@deprecated "since 2022-07 use [create] and/or [install]"]

(** [lookup ?package name] lookups in the registry for the
demangler with the given [package:name].

@param package defaults to "user"

@since 2.5.0 *)
val lookup : ?package:string -> string -> demangler option


(** [get ?package name] returns the [package:name] demangler.

Fails with [Invalid_arg] if no such demangler exists.

@since 2.5.0 *)
val get : ?package:string -> string -> demangler


(** [select t] returns the demangler installed for the target [t].

If not demangler was installed then returns an identity
demangler that doesn't touch names.

@since 2.5.0 *)
val select : Theory.Target.t -> demangler

(** [available ()] lists currently registered demanglers. *)
val available : unit -> demangler list


end
end
4 changes: 2 additions & 2 deletions oasis/demangle
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ Library "bap-demangle"
Build$: flag(everything) || flag(demangle)
FindlibName: bap-demangle
CompiledObject: best
BuildDepends: core_kernel
BuildDepends: core_kernel, bap-core-theory, bap-knowledge
Modules: Bap_demangle

Library "demangle_plugin"
Path: plugins/demangle
Build$: flag(everything) || flag(demangle)
FindlibName: bap-plugin-demangle
CompiledObject: best
BuildDepends: core_kernel, bap-demangle, bap, bap-future, bap-plugins
BuildDepends: core_kernel, bap-demangle, bap-main, bap-core-theory, bap-knowledge
InternalModules: Demangle_main
XMETADescription: demangle subroutine names
XMETAExtraLines: tags="demangler"
9 changes: 0 additions & 9 deletions plugins/core_theory/core_theory_main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,8 @@ let herbrand_provides = [
"core:val";
"lifter";
"semantics";
"symbolizer";
]

let decide_name_from_possible_name () : unit =
KB.Rule.(declare ~package "name-of-possible-names" |>
require Theory.Label.possible_name |>
provide Theory.Label.name |>
comment "resolves possible name");
KB.promise Theory.Label.name @@
KB.resolve Theory.Label.possible_name


let domain = KB.Domain.optional "cst"
Expand Down Expand Up @@ -526,7 +518,6 @@ let enable_herbrand () =
~name:"syntax" (KB.return (module Herbrand : Theory.Core))

let () = Extension.declare @@ fun ctxt ->
decide_name_from_possible_name ();
if Extension.Configuration.get ctxt herbrand_enabled
then enable_herbrand ();
Ok ()
3 changes: 2 additions & 1 deletion plugins/demangle/.merlin
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
REC
B ../../_build/lib/bap_demangle
B ../../_build/lib/bap_demangle
B ../../lib/bap_demangle
Loading