diff --git a/DwarfSynth/Main.ml b/DwarfSynth/Main.ml index da10d48..0b771c5 100644 --- a/DwarfSynth/Main.ml +++ b/DwarfSynth/Main.ml @@ -1,7 +1,9 @@ open Std let main outfile proj = - let pre_dwarf = Simplest.of_proj proj in + let pre_dwarf = proj + |> Simplest.of_proj + |> Simplest.clean_lost_track_subs in Format.printf "%a" Frontend.pp_pre_dwarf_readelf pre_dwarf; let pre_c_dwarf = PreCBinding.convert_pre_c pre_dwarf in let fd = open_out_bin outfile in diff --git a/DwarfSynth/PreCBinding.ml b/DwarfSynth/PreCBinding.ml index a315536..d14d39e 100644 --- a/DwarfSynth/PreCBinding.ml +++ b/DwarfSynth/PreCBinding.ml @@ -1,6 +1,8 @@ open Simplest open Std +exception InvalidPreDwarf of string + type pre_c_pre_dwarf_entry = { location: int64; cfa_offset: int64; @@ -58,7 +60,9 @@ let convert_pre_c_entry loc entry : pre_c_pre_dwarf_entry = let offset, offset_reg = (match entry with | RspOffset off -> off, 7 | RbpOffset off -> off, 6 - | CfaLostTrack -> assert false (* Should be filtered out beforehand *) + | CfaLostTrack -> + raise (InvalidPreDwarf + ("CfaLostTrack should be filtered out beforehand")) ) in { location = loc; @@ -72,22 +76,33 @@ let convert_pre_c_entries entries : pre_c_pre_dwarf_entry array = (fun loc entry _ -> convert_pre_c_entry loc entry) entries empty_entry -let convert_pre_c_fde name entry id : pre_c_pre_dwarf_fde = - { - num = AddrMap.cardinal entry.cfa_changes_fde; - initial_location = entry.beg_pos; - end_location = entry.end_pos; - name = name; - entries = convert_pre_c_entries entry.cfa_changes_fde - } +let convert_pre_c_fde name entry : pre_c_pre_dwarf_fde option = + try + Some { + num = AddrMap.cardinal entry.cfa_changes_fde; + initial_location = entry.beg_pos; + end_location = entry.end_pos; + name = name; + entries = convert_pre_c_entries entry.cfa_changes_fde + } + with InvalidPreDwarf reason -> ( + Format.eprintf "FAILED subroutine %s: %s@." name reason ; + None + ) + module StrMapTool = MapTool(StrMap) let convert_pre_c (cfa_map: subroutine_cfa_map) : pre_c_pre_dwarf = (** Converts a `subroutine_cfa_map` to a `pre_c_pre_dwarf` type, in preparation for C coversion. *) let num_fde = StrMap.cardinal cfa_map in - let fdes = StrMapTool.fold_map_to_array - convert_pre_c_fde cfa_map empty_fde in + let fdes_list_with_none = StrMap.fold (fun name entry folded -> + (convert_pre_c_fde name entry) :: folded) + cfa_map [] in + let fdes_list = List.fold_left (fun folded elt -> match elt with + | Some x -> x::folded + | None -> folded) [] fdes_list_with_none in + let fdes = Array.of_list fdes_list in { num_fde = num_fde ; fdes = fdes diff --git a/DwarfSynth/Simplest.ml b/DwarfSynth/Simplest.ml index 87248ee..b2cda7b 100644 --- a/DwarfSynth/Simplest.ml +++ b/DwarfSynth/Simplest.ml @@ -458,3 +458,13 @@ let of_proj proj : subroutine_cfa_map = (** Extracts the `cfa_changes` of a project *) let prog = BStd.Project.program proj in of_prog prog + +let clean_lost_track_subs pre_dwarf : subroutine_cfa_map = + (** Removes the subroutines on which we lost track from [pre_dwarf] *) + let sub_lost_track sub_name (sub: subroutine_cfa_data) = + not @@ AddrMap.exists (fun addr pos -> (match pos with + | RspOffset _ | RbpOffset _ -> false + | CfaLostTrack -> true)) + sub.cfa_changes_fde + in + StrMap.filter sub_lost_track pre_dwarf diff --git a/csmith/csmith_test_generated.sh b/csmith/csmith_test_generated.sh new file mode 100755 index 0000000..7d8f75a --- /dev/null +++ b/csmith/csmith_test_generated.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +USAGE="$0 nb_tests kept_directory" + +if [ "$#" -lt 1 ] ; then + >&2 echo -e "Missing argument(s). Usage:\n$USAGE" + exit 1 +fi + +NB_TESTS=$1 +KEPT_DIRECTORY=$2 +RUN_TIMEOUT=2 + +tmpdir="$(mktemp -d)" +error_count=0 + +function statusline { + echo -ne "\r\e[1m[\e[32m$(printf "%03d/%03d" "$1" "$NB_TESTS")\e[39m] >>>\e[0m $2 " +} + +function reporterror { + echo -e "\n\e[1;31m[$(printf "%03d" $1)] Error: \e[0m $2" +} + +function mkpath { + echo "$tmpdir/$1" +} + +function failed_test { + path=$(mkpath $1) + cp "$path."* "$KEPT_DIRECTORY" + reporterror "$1" "$2" + error_count=$((error_count + 1)) +} + +function test_empty_dwarf { + path="$2" + statusline $1 "test DWARF emptyness" + if [ -z "$(readelf -wF "$path.eh.bin")" ]; then + return 1 + else + return 0 + fi +} + +function test_run { + path="$2" + statusline $1 "running binaries" + orig="$(timeout $RUN_TIMEOUT "$path.orig.bin")" + orig_status=$? + synth="$(timeout $RUN_TIMEOUT "$path.eh.bin")" + synth_status=$? + + if [ "$orig_status" -ne "$synth_status" ] || [ "$orig" != "$synth" ] ; then + return 1 + else + return 0 + fi +} + +mkdir -p "$KEPT_DIRECTORY" + +statusline "" "" +for num in $(seq 1 $NB_TESTS); do + ## Generation, compilation, synthesis + statusline $num "csmith" + path=$(mkpath $num) + csmith > "$path.c" + statusline $num "compiling" + gcc -O2 -I/usr/include/csmith-2.3.0/ -w "$path.c" -o "$path.orig.bin" + objcopy --remove-section '.eh_frame' --remove-section '.eh_frame_hdr' \ + "$path.orig.bin" "$path.bin" + statusline $num "generating dwarf" + ../synthesize_dwarf.sh "$path.bin" "$path.eh.bin" + + ## Testing + if ! test_empty_dwarf "$num" "$path"; then + failed_test "$num" "empty generated DWARF" + elif ! test_run "$num" "$path"; then + failed_test "$num" "different execution behaviour" + fi +done + +echo "" +if [ "$error_count" -eq "0" ] ; then + echo -e "\n== ALL TESTS PASSED ==" +else + echo -e "\n== FAILED TESTS: $error_count/$NB_TESTS ==" +fi + +rm -rf "$tmpdir" diff --git a/synthesize_dwarf.sh b/synthesize_dwarf.sh index 9a66881..aa68c7c 100755 --- a/synthesize_dwarf.sh +++ b/synthesize_dwarf.sh @@ -35,7 +35,7 @@ function find_ml_dwarf_write { } function bap_synth { - bap "$INPUT_FILE" -p dwarfsynth --dwarfsynth-output "$TMP_DIR/marshal" \ + bap "$INPUT_FILE" --no-byteweight -p dwarfsynth --dwarfsynth-output "$TMP_DIR/marshal" \ > /dev/null return $? }