diff --git a/api/docs/release.dox b/api/docs/release.dox index 498e162497e0f3d1482e82f4102510567e82fc01..ffb7821513022e3d01fe62d7b035c52d800c0d0e 100644 --- a/api/docs/release.dox +++ b/api/docs/release.dox @@ -183,7 +183,11 @@ Further non-compatibility-affecting changes include: drmemtrace_get_modlist_path(), and a separate rawtrace library for post-processing customization with raw2trace_t::handle_custom_data(), raw2trace_t::do_module_parsing(), raw2trace_t::do_conversion(), and - raw2trace_directory_t. A corresponding CMake function for finding the + raw2trace_directory_t. The raw2trace library also includes an interface + for obtaining further instruction information than is stored in the + trace via raw2trace_t::do_module_parsing_and_mapping() and + raw2trace_t::find_mapped_trace_address(). + A corresponding CMake function for finding the tracer customization header is use_DynamoRIO_drmemtrace_tracer(). - Added a set_value() function to the \ref page_droption. - Added instrlist_get_auto_predicate() and instrlist_set_auto_predicate(). diff --git a/clients/drcachesim/CMakeLists.txt b/clients/drcachesim/CMakeLists.txt index 2e1d26eea38fa2ab24f650f187e9252b7060da62..fb2a461706c523688d3d66c5273b20ebbd428a6f 100644 --- a/clients/drcachesim/CMakeLists.txt +++ b/clients/drcachesim/CMakeLists.txt @@ -1,5 +1,5 @@ # ********************************************************** -# Copyright (c) 2015-2017 Google, Inc. All rights reserved. +# Copyright (c) 2015-2018 Google, Inc. All rights reserved. # ********************************************************** # Redistribution and use in source and binary forms, with or without @@ -71,6 +71,8 @@ add_exported_library(drmemtrace_reuse_distance STATIC tools/reuse_distance.cpp) add_exported_library(drmemtrace_histogram STATIC tools/histogram.cpp) add_exported_library(drmemtrace_reuse_time STATIC tools/reuse_time.cpp) add_exported_library(drmemtrace_basic_counts STATIC tools/basic_counts.cpp) +add_exported_library(drmemtrace_opcode_mix STATIC tools/opcode_mix.cpp) +configure_DynamoRIO_standalone(drmemtrace_opcode_mix) # We combine the cache and TLB simulators as they share code already. add_exported_library(drmemtrace_simulator STATIC @@ -116,7 +118,8 @@ add_executable(drcachesim ${drcachesim_srcs}) configure_DynamoRIO_standalone(drcachesim) # Link in our tools: target_link_libraries(drcachesim drmemtrace_simulator drmemtrace_reuse_distance - drmemtrace_histogram drmemtrace_reuse_time drmemtrace_basic_counts drmemtrace_raw2trace) + drmemtrace_histogram drmemtrace_reuse_time drmemtrace_basic_counts + drmemtrace_opcode_mix drmemtrace_raw2trace) # To avoid dup symbol errors between drinjectlib and the drdecode brought in # by drfrontendlib we have to explicitly list drdecode up front: target_link_libraries(drcachesim drdecode drinjectlib drconfiglib drfrontendlib) @@ -150,6 +153,7 @@ install_client_nonDR_header(drmemtrace tools/reuse_distance_create.h) install_client_nonDR_header(drmemtrace tools/histogram_create.h) install_client_nonDR_header(drmemtrace tools/reuse_time_create.h) install_client_nonDR_header(drmemtrace tools/basic_counts_create.h) +install_client_nonDR_header(drmemtrace tools/opcode_mix_create.h) install_client_nonDR_header(drmemtrace simulator/cache_simulator_create.h) install_client_nonDR_header(drmemtrace simulator/tlb_simulator_create.h) install_client_nonDR_header(drmemtrace tracer/raw2trace.h) @@ -250,6 +254,7 @@ restore_nonclient_flags(drmemtrace_reuse_distance) restore_nonclient_flags(drmemtrace_histogram) restore_nonclient_flags(drmemtrace_reuse_time) restore_nonclient_flags(drmemtrace_basic_counts) +restore_nonclient_flags(drmemtrace_opcode_mix) restore_nonclient_flags(drmemtrace_analyzer) # We need to pass /EHsc and we pull in libcmtd into drcachesim from a dep lib. @@ -283,13 +288,14 @@ add_win32_flags(drmemtrace_reuse_distance) add_win32_flags(drmemtrace_histogram) add_win32_flags(drmemtrace_reuse_time) add_win32_flags(drmemtrace_basic_counts) +add_win32_flags(drmemtrace_opcode_mix) add_win32_flags(drmemtrace_analyzer) if (WIN32 AND DEBUG) get_target_property(sim_srcs drcachesim SOURCES) get_target_property(raw2trace_srcs drraw2trace SOURCES) # The client, and our standalone DR users, had /MT added so we need to override. # XXX: solve this by avoiding the /MT in the first place! - foreach (src ${client_and_sim_srcs} ${sim_srcs} ${raw2trace_srcs}) + foreach (src ${client_and_sim_srcs} ${sim_srcs} ${raw2trace_srcs} tools/opcode_mix.cpp) get_property(cur SOURCE ${src} PROPERTY COMPILE_FLAGS) string(REPLACE "/MT " "" cur ${cur}) # Avoid override warning. set_source_files_properties(${src} COMPILE_FLAGS "${cur} /MTd") diff --git a/clients/drcachesim/analysis_tool.h b/clients/drcachesim/analysis_tool.h index 5425bf3649a5d735ea4e0375ca6336b8498b60a3..f2371d01c245898ae0d49a505d9c1f76c4893598 100644 --- a/clients/drcachesim/analysis_tool.h +++ b/clients/drcachesim/analysis_tool.h @@ -1,5 +1,5 @@ /* ********************************************************** - * Copyright (c) 2016-2017 Google, Inc. All rights reserved. + * Copyright (c) 2016-2018 Google, Inc. All rights reserved. * **********************************************************/ /* @@ -69,9 +69,13 @@ class analysis_tool_t /** * The heart of an analysis tool, this routine operates on a single trace entry and * takes whatever actions the tool needs to perform its analysis. + * The return value indicates whether it was successful or there was an error. */ virtual bool process_memref(const memref_t &memref) = 0; - /** This routine reports the results of the trace analysis. */ + /** + * This routine reports the results of the trace analysis. + * The return value indicates whether it was successful or there was an error. + */ virtual bool print_results() = 0; protected: bool success; diff --git a/clients/drcachesim/common/options.cpp b/clients/drcachesim/common/options.cpp index f49167dee790fcaf8e7101b489acbe2d3e978f3a..c17249d9a15586a852e8196f6e931e0317257a78 100644 --- a/clients/drcachesim/common/options.cpp +++ b/clients/drcachesim/common/options.cpp @@ -65,7 +65,14 @@ droption_t<std::string> op_indir droption_t<std::string> op_infile (DROPTION_SCOPE_ALL, "infile", "", "Offline trace file for input to the simulator", "Directs the simulator to use a trace file (not a raw data file from -offline: " - "such a file neeeds to be converted via drposttrace or -indir first)."); + "such a file neeeds to be converted via drraw2trace or -indir first)."); + +droption_t<std::string> op_module_file +(DROPTION_SCOPE_ALL, "module_file", "", "Path to modules.log for opcode_mix tool", + "The opcode_mix tool needs the modules.log file (generated by the offline " + "post-processing step in the raw/ subdirectory) in addition to the trace file. " + "If the file is named modules.log and is in the same directory as the trace file, " + "or a raw/ subdirectory below the trace file, this parameter can be omitted."); droption_t<unsigned int> op_num_cores (DROPTION_SCOPE_FRONTEND, "cores", 4, "Number of cores", diff --git a/clients/drcachesim/common/options.h b/clients/drcachesim/common/options.h index 9aa0dedf783ec09ec1258b1472af6d9f1f4edec2..054fde20a133b3b59ceaa25147c689c9ba1fdd8d 100644 --- a/clients/drcachesim/common/options.h +++ b/clients/drcachesim/common/options.h @@ -1,5 +1,5 @@ /* ********************************************************** - * Copyright (c) 2015-2017 Google, Inc. All rights reserved. + * Copyright (c) 2015-2018 Google, Inc. All rights reserved. * **********************************************************/ /* @@ -47,6 +47,7 @@ #define REUSE_DIST "reuse_distance" #define REUSE_TIME "reuse_time" #define BASIC_COUNTS "basic_counts" +#define OPCODE_MIX "opcode_mix" #include <string> #include "droption.h" @@ -56,6 +57,7 @@ extern droption_t<std::string> op_ipc_name; extern droption_t<std::string> op_outdir; extern droption_t<std::string> op_infile; extern droption_t<std::string> op_indir; +extern droption_t<std::string> op_module_file; extern droption_t<unsigned int> op_num_cores; extern droption_t<unsigned int> op_line_size; extern droption_t<bytesize_t> op_L1I_size; diff --git a/clients/drcachesim/common/utils.h b/clients/drcachesim/common/utils.h index 668dd175906c2e51cb16e148d20eee0252461df1..274e0be0e054d5a4f8f4dd91928599082c3116e3 100644 --- a/clients/drcachesim/common/utils.h +++ b/clients/drcachesim/common/utils.h @@ -1,5 +1,5 @@ /* ********************************************************** - * Copyright (c) 2015-2017 Google, Inc. All rights reserved. + * Copyright (c) 2015-2018 Google, Inc. All rights reserved. * **********************************************************/ /* @@ -86,10 +86,12 @@ #ifdef WINDOWS # define DIRSEP "\\" +# define ALT_DIRSEP "/" # define IF_WINDOWS(x) x # define IF_UNIX(x) #else # define DIRSEP "/" +# define ALT_DIRSEP "" # define IF_WINDOWS(x) # define IF_UNIX(x) x #endif diff --git a/clients/drcachesim/drcachesim.dox.in b/clients/drcachesim/drcachesim.dox.in index 65209dff6d4fb5456807f80067d3f09053944cfa..c6c14889027e26af7f6789d587453c4fa1073801 100644 --- a/clients/drcachesim/drcachesim.dox.in +++ b/clients/drcachesim/drcachesim.dox.in @@ -338,7 +338,49 @@ subsequent iterations do not incur a fetch. They are included in the trace as a different type of trace entry to support core simulators in addition to cache simulators. -The top referenced lines are displayed by the \p histogram tool: +The opcode_mix tool uses the non-fetched instruction information along with +the preserved libraries and binaries from the traced execution to gather +more information on each executed instruction than was stored in the trace. +It only supports offline traces, and the \p modules.log file created during +post-processing of the trace must be preserved. The results are broken +down by the opcodes used in DR's IR, where \p mov is split into a separate +opcode for load and store but both have the same public string "mov": + +\code +$ bin64/drrun -t drcachesim -offline -- suite/tests/bin/pi_estimator +Estimation of pi is 3.142425985001098 +$ bin64/drrun -t drcachesim -simulator_type opcode_mix -indir drmemtrace.*.dir +Opcode mix tool results: + 267271 : total executed instructions + 36432 : mov + 31075 : mov + 24715 : add + 22579 : test + 22539 : cmp + 12137 : lea + 11136 : jnz + 10568 : movzx + 10243 : jz + 9056 : and + 8064 : jnz + 7279 : jz + 5659 : push + 4528 : sub + 4357 : pop + 4001 : shr + 3427 : jnbe + 2634 : mov + 2469 : shl + 2344 : jb + 2291 : ret + 2178 : xor + 2164 : call + 2111 : pcmpeqb + 1472 : movdqa +... +\endcode + +The top referenced cache lines are displayed by the \p histogram tool: \code $ bin64/drrun -t drcachesim -simulator_type histogram -- suite/tests/bin/pi_estimator @@ -578,9 +620,9 @@ use_DynamoRIO_drmemtrace(mytool) The \p drmemtrace_analyzer library exported by the DynamoRIO package is the main library to link when building a new tool. The tools described above are also exported as the libraries \p drmemtrace_basic_counts, \p -drmemtrace_histogram, \p drmemtrace_reuse_distance, \p +drmemtrace_opcode_mix, \p drmemtrace_histogram, \p drmemtrace_reuse_distance, \p drmemtrace_reuse_time, and \p drmemtrace_simulator and can be created using -the basic_counts_tool_create(), histogram_tool_create(), +the basic_counts_tool_create(), opcode_mix_tool_create(), histogram_tool_create(), reuse_distance_tool_create(), reuse_time_tool_create(), cache_simulator_create(), and tlb_simulator_create() functions. diff --git a/clients/drcachesim/simulator/analyzer_interface.cpp b/clients/drcachesim/simulator/analyzer_interface.cpp index def958072f3dda8d8f111a3e9545c83fc13dbf0b..f8ba958cccd8653cdb19133f5a452d4bce20d437 100644 --- a/clients/drcachesim/simulator/analyzer_interface.cpp +++ b/clients/drcachesim/simulator/analyzer_interface.cpp @@ -1,5 +1,5 @@ /* ********************************************************** - * Copyright (c) 2017 Google, Inc. All rights reserved. + * Copyright (c) 2017-2018 Google, Inc. All rights reserved. * **********************************************************/ /* @@ -44,6 +44,9 @@ #include "../tools/reuse_distance_create.h" #include "../tools/reuse_time_create.h" #include "../tools/basic_counts_create.h" +#include "../tools/opcode_mix_create.h" +#include "../tracer/raw2trace.h" +#include <fstream> analysis_tool_t * drmemtrace_analysis_tool_create() @@ -97,10 +100,38 @@ drmemtrace_analysis_tool_create() op_verbose.get_value()); } else if (op_simulator_type.get_value() == BASIC_COUNTS) { return basic_counts_tool_create(op_verbose.get_value()); + } else if (op_simulator_type.get_value() == OPCODE_MIX) { + // This tool needs the modules.log, which we assume is next to the trace file or + // in the raw/ subdir from raw2trace. + std::string module_file_path; + if (!op_module_file.get_value().empty()) + module_file_path = op_module_file.get_value(); + else { + std::string trace_dir; + if (!op_indir.get_value().empty()) + trace_dir = op_indir.get_value(); + else { + if (op_infile.get_value().empty()) { + ERRMSG("Usage error: the opcode mix tool requires offline traces.\n"); + return nullptr; + } + size_t sep_index = op_infile.get_value().find_last_of(DIRSEP ALT_DIRSEP); + if (sep_index != std::string::npos) + trace_dir = std::string(op_infile.get_value(), 0, sep_index); + } + module_file_path = trace_dir + std::string(DIRSEP) + + DRMEMTRACE_MODULE_LIST_FILENAME; + if (!std::ifstream(module_file_path.c_str()).good()) { + trace_dir += std::string(DIRSEP) + OUTFILE_SUBDIR; + module_file_path = trace_dir + std::string(DIRSEP) + + DRMEMTRACE_MODULE_LIST_FILENAME; + } + } + return opcode_mix_tool_create(module_file_path, op_verbose.get_value()); } else { ERRMSG("Usage error: unsupported analyzer type. " "Please choose " CPU_CACHE ", " TLB ", " HISTOGRAM ", " REUSE_DIST ", or " BASIC_COUNTS ".\n"); - return NULL; + return nullptr; } } diff --git a/clients/drcachesim/tests/offline-opcode_mix.templatex b/clients/drcachesim/tests/offline-opcode_mix.templatex new file mode 100644 index 0000000000000000000000000000000000000000..676004cc6c0533b36eda9af3718f7d8fc5fc4cdb --- /dev/null +++ b/clients/drcachesim/tests/offline-opcode_mix.templatex @@ -0,0 +1,8 @@ +Hello, world! +Opcode mix tool results: + *[0-9]* : total executed instructions + *[0-9]* : [a-z ]* + *[0-9]* : [a-z ]* + *[0-9]* : [a-z ]* + *[0-9]* : [a-z ]* +.* diff --git a/clients/drcachesim/tools/opcode_mix.cpp b/clients/drcachesim/tools/opcode_mix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cfd2a8a2bc938d27cd66714df2fb898e0f1b7a60 --- /dev/null +++ b/clients/drcachesim/tools/opcode_mix.cpp @@ -0,0 +1,130 @@ +/* ********************************************************** + * Copyright (c) 2017-2018 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +/* This trace analyzer requires access to the modules.log file and the + * libraries and binary from the traced execution in order to obtain further + * information about each instruction than was stored in the trace. + * It does not support online use, only offline. + */ + +#include "dr_api.h" +#include "opcode_mix.h" +#include "common/utils.h" +#include "tracer/raw2trace.h" +#include "tracer/raw2trace_directory.h" +#include <algorithm> +#include <iomanip> +#include <iostream> +#include <vector> + +const std::string opcode_mix_t::TOOL_NAME = "Opcode mix tool"; + +analysis_tool_t * +opcode_mix_tool_create(const std::string& module_file_path, unsigned int verbose) +{ + return new opcode_mix_t(module_file_path, verbose); +} + +opcode_mix_t::opcode_mix_t(const std::string& module_file_path, unsigned int verbose) : + dcontext(nullptr), raw2trace(nullptr), knob_verbose(verbose), instr_count(0) +{ + if (module_file_path.empty()) { + success = false; + return; + } + dcontext = dr_standalone_init(); + raw2trace_directory_t dir(module_file_path); + raw2trace = new raw2trace_t(dir.modfile_bytes, std::vector<std::istream*>(), + nullptr, dcontext, verbose); + std::string error = raw2trace->do_module_parsing_and_mapping(); + if (!error.empty()) { + success = false; + return; + } +} + +opcode_mix_t::~opcode_mix_t() +{ + delete raw2trace; +} + +bool +opcode_mix_t::process_memref(const memref_t &memref) +{ + if (!type_is_instr(memref.instr.type) && + memref.data.type != TRACE_TYPE_INSTR_NO_FETCH) + return true; + ++instr_count; + app_pc mapped_pc; + std::string err = + raw2trace->find_mapped_trace_address((app_pc)memref.instr.addr, &mapped_pc); + if (!err.empty()) + return false; + int opcode; + auto cached_opcode = opcode_cache.find(mapped_pc); + if (cached_opcode != opcode_cache.end()) { + opcode = cached_opcode->second; + } else { + instr_t instr; + instr_init(dcontext, &instr); + app_pc next_pc = decode(dcontext, mapped_pc, &instr); + if (next_pc == NULL || !instr_valid(&instr)) + return false; + opcode = instr_get_opcode(&instr); + opcode_cache[mapped_pc] = opcode; + instr_free(dcontext, &instr); + } + ++opcode_counts[opcode]; + return true; +} + +static bool +cmp_val(const std::pair<int, int_least64_t> &l, + const std::pair<int, int_least64_t> &r) +{ + return (l.second > r.second); +} + +bool +opcode_mix_t::print_results() +{ + std::cerr << TOOL_NAME << " results:\n"; + std::cerr << std::setw(15) << instr_count << " : total executed instructions\n"; + std::vector<std::pair<int, int_least64_t>> sorted(opcode_counts.begin(), + opcode_counts.end()); + std::sort(sorted.begin(), sorted.end(), cmp_val); + for (const auto &keyvals : sorted) { + std::cerr << std::setw(15) << keyvals.second << " : " + << std::setw(9) << decode_opcode_name(keyvals.first) << "\n"; + } + return true; +} diff --git a/clients/drcachesim/tools/opcode_mix.h b/clients/drcachesim/tools/opcode_mix.h new file mode 100644 index 0000000000000000000000000000000000000000..a569e957e9d739830c2db1fc039a0306fab26feb --- /dev/null +++ b/clients/drcachesim/tools/opcode_mix.h @@ -0,0 +1,60 @@ +/* ********************************************************** + * Copyright (c) 2018 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _OPCODE_MIX_H_ +#define _OPCODE_MIX_H_ 1 + +#include <string> +#include <unordered_map> + +#include "analysis_tool.h" +#include "tracer/raw2trace.h" + +class opcode_mix_t : public analysis_tool_t +{ + public: + opcode_mix_t(const std::string& module_file_path, unsigned int verbose); + virtual ~opcode_mix_t(); + virtual bool process_memref(const memref_t &memref); + virtual bool print_results(); + + protected: + void *dcontext; + raw2trace_t *raw2trace; + unsigned int knob_verbose; + int_least64_t instr_count; + std::unordered_map<int, int_least64_t> opcode_counts; + std::unordered_map<app_pc, int> opcode_cache; + static const std::string TOOL_NAME; +}; + +#endif /* _OPCODE_MIX_H_ */ diff --git a/clients/drcachesim/tools/opcode_mix_create.h b/clients/drcachesim/tools/opcode_mix_create.h new file mode 100644 index 0000000000000000000000000000000000000000..d1085590b30cbcbbd28b3677668329bb22c111d9 --- /dev/null +++ b/clients/drcachesim/tools/opcode_mix_create.h @@ -0,0 +1,53 @@ +/* ********************************************************** + * Copyright (c) 2018 Google, Inc. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Google, Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +/* basic-counts tool creation */ + +#ifndef _OPCODE_MIX_CREATE_H_ +#define _OPCODE_MIX_CREATE_H_ 1 + +#include "analysis_tool.h" + +/** + * @file drmemtrace/opcode_mix_create.h + * @brief DrMemtrace opcode mixture trace analysis tool creation. + */ + +/** + * Creates an analysis tool which counts the number of instances of each opcode + * in the trace. This tool needs access to the modules.log and original libraries + * and binaries from the traced execution. It does not support online analysis. + */ +analysis_tool_t * +opcode_mix_tool_create(const std::string& module_file_path, unsigned int verbose = 0); + +#endif /* _OPCODE_MIX_CREATE_H_ */ diff --git a/clients/drcachesim/tracer/raw2trace.cpp b/clients/drcachesim/tracer/raw2trace.cpp index 064340d52f065fea3a26534bb56c0b24ce51b602..e9978063b800bece395f64deeb26e598f0a3ea0d 100644 --- a/clients/drcachesim/tracer/raw2trace.cpp +++ b/clients/drcachesim/tracer/raw2trace.cpp @@ -259,7 +259,7 @@ raw2trace_t::unmap_modules(void) { // drmodtrack_offline_exit requires the parameter to be non-null, but we // may not have even initialized the modhandle yet. - if (modhandle != NULL && + if (modhandle != nullptr && drmodtrack_offline_exit(modhandle) != DRCOVLIB_SUCCESS) { return "Failed to clean up module table data"; } @@ -274,6 +274,42 @@ raw2trace_t::unmap_modules(void) return ""; } +std::string +raw2trace_t::do_module_parsing_and_mapping() +{ + std::string error = read_and_map_modules(); + if (!error.empty()) + return error; + return ""; +} + +std::string +raw2trace_t::find_mapped_trace_address(app_pc trace_address, OUT app_pc *mapped_address) +{ + if (modhandle == nullptr || modlist.empty()) + return "Failed to call do_module_parsing_and_mapping() first"; + if (mapped_address == nullptr) + return "Invalid parameter"; + // For simplicity we do a linear search, caching the prior hit. + if (trace_address >= last_orig_base && + trace_address < last_orig_base + last_map_size) { + *mapped_address = trace_address - last_orig_base + last_map_base; + return ""; + } + for (std::vector<module_t>::iterator mvi = modvec.begin(); + mvi != modvec.end(); ++mvi) { + if (trace_address >= mvi->orig_base && + trace_address < mvi->orig_base + mvi->map_size) { + *mapped_address = trace_address - mvi->orig_base + mvi->map_base; + last_orig_base = mvi->orig_base; + last_map_size = mvi->map_size; + last_map_base = mvi->map_base; + return ""; + } + } + return "Trace address not found"; +} + /*************************************************************************** * Disassembly to fill in instr and memref entries */ @@ -771,7 +807,8 @@ raw2trace_t::raw2trace_t(const char *module_map_in, : modmap(module_map_in), modhandle(NULL), thread_files(thread_files_in), out_file(out_file_in), dcontext(dcontext_in), prev_instr_was_rep_string(false), instrs_are_separate(false), - verbosity(verbosity_in), user_process(nullptr), user_process_data(nullptr) + verbosity(verbosity_in), user_process(nullptr), user_process_data(nullptr), + last_orig_base(nullptr), last_map_size(0), last_map_base(nullptr) { if (dcontext == NULL) { dcontext = dr_standalone_init(); diff --git a/clients/drcachesim/tracer/raw2trace.h b/clients/drcachesim/tracer/raw2trace.h index cb2342e6c8a634ed14103262ff5c3671eca74cc2..ee9812111982f265fa9b934b0a76c2f042d533d8 100644 --- a/clients/drcachesim/tracer/raw2trace.h +++ b/clients/drcachesim/tracer/raw2trace.h @@ -1,5 +1,5 @@ /* ********************************************************** - * Copyright (c) 2016-2017 Google, Inc. All rights reserved. + * Copyright (c) 2016-2018 Google, Inc. All rights reserved. * **********************************************************/ /* @@ -119,6 +119,31 @@ public: */ std::string do_module_parsing(); + /** + * This interface is meant to be used with a final trace rather than a raw + * trace, using the module log file saved from the raw2trace conversion. + * This routine first calls do_module_parsing() and then maps each module into + * the current address space, allowing the user to augment the instruction + * information in the trace with additional information by decoding the + * instruction bytes. The routine find_mapped_trace_address() should be used + * to convert from memref_t.instr.addr to the corresponding mapped address in + * the current process. + * Returns a non-empty error message on failure. + */ + std::string do_module_parsing_and_mapping(); + + /** + * This interface is meant to be used with a final trace rather than a raw + * trace, using the module log file saved from the raw2trace conversion. + * When do_module_parsing_and_mapping() has been called, this routine can be used + * to convert an instruction program counter in a trace into an address in the + * current process where the instruction bytes for that instruction are mapped, + * allowing decoding for obtaining further information than is stored in the trace. + * Returns a non-empty error message on failure. + */ + std::string find_mapped_trace_address(app_pc trace_address, + OUT app_pc *mapped_address); + /** * Performs the conversion from raw data to finished trace files. * Returns a non-empty error message on failure. @@ -178,6 +203,9 @@ private: std::vector<drmodtrack_info_t> modlist; std::string (*user_process)(drmodtrack_info_t *info, void *data, void *user_data); void *user_process_data; + app_pc last_orig_base; + size_t last_map_size; + byte *last_map_base; // Custom module fields that use drmodtrack are global. static const char * (*user_parse)(const char *src, OUT void **data); diff --git a/clients/drcachesim/tracer/raw2trace_directory.cpp b/clients/drcachesim/tracer/raw2trace_directory.cpp index ee6c1bc8f2cdb4b12564f8778d713cc755b9e6d0..8581a7e5a382cd7b122675c5aaf4f7c07b33a41b 100644 --- a/clients/drcachesim/tracer/raw2trace_directory.cpp +++ b/clients/drcachesim/tracer/raw2trace_directory.cpp @@ -1,5 +1,5 @@ /* ********************************************************** - * Copyright (c) 2017 Google, Inc. All rights reserved. + * Copyright (c) 2017-2018 Google, Inc. All rights reserved. * **********************************************************/ /* @@ -144,16 +144,9 @@ raw2trace_directory_t::open_thread_log_file(const char *basename) VPRINT(1, "Opened thread log file %s\n", path); } -raw2trace_directory_t::raw2trace_directory_t(const std::string &indir_in, - const std::string &outname_in, - unsigned int verbosity_in) - : indir(indir_in), outname(outname_in), verbosity(verbosity_in) +void +raw2trace_directory_t::read_module_file(const std::string &modfilename) { - // Support passing both base dir and raw/ subdir. - if (indir.find(OUTFILE_SUBDIR) == std::string::npos) - indir += std::string(DIRSEP) + OUTFILE_SUBDIR; - std::string modfilename = indir + std::string(DIRSEP) + - DRMEMTRACE_MODULE_LIST_FILENAME; modfile = dr_open_file(modfilename.c_str(), DR_FILE_READ); if (modfile == INVALID_FILE) FATAL_ERROR("Failed to open module file %s", modfilename.c_str()); @@ -164,6 +157,20 @@ raw2trace_directory_t::raw2trace_directory_t(const std::string &indir_in, modfile_bytes = new char[modfile_size_]; if (dr_read_file(modfile, modfile_bytes, modfile_size_) < (ssize_t)modfile_size_) FATAL_ERROR("Didn't read whole module file %s", modfilename.c_str()); +} + +raw2trace_directory_t::raw2trace_directory_t(const std::string &indir_in, + const std::string &outname_in, + unsigned int verbosity_in) + : indir(indir_in), outname(outname_in), verbosity(verbosity_in) +{ + // Support passing both base dir and raw/ subdir. + if (indir.find(OUTFILE_SUBDIR) == std::string::npos) { + indir += std::string(DIRSEP) + OUTFILE_SUBDIR; + } + std::string modfilename = indir + std::string(DIRSEP) + + DRMEMTRACE_MODULE_LIST_FILENAME; + read_module_file(modfilename); out_file.open(outname.c_str(), std::ofstream::binary); if (!out_file) @@ -173,6 +180,13 @@ raw2trace_directory_t::raw2trace_directory_t(const std::string &indir_in, open_thread_files(); } +raw2trace_directory_t::raw2trace_directory_t(const std::string &module_file_path, + unsigned int verbosity_in) + : indir(""), outname(""), verbosity(verbosity_in) +{ + read_module_file(module_file_path); +} + raw2trace_directory_t::~raw2trace_directory_t() { delete[] modfile_bytes; diff --git a/clients/drcachesim/tracer/raw2trace_directory.h b/clients/drcachesim/tracer/raw2trace_directory.h index 76e47e14faeb2ec2268a34f730fa6a9552def3b3..f1b0bba57f82bea1cbf78bad62620bf3c77d93af 100644 --- a/clients/drcachesim/tracer/raw2trace_directory.h +++ b/clients/drcachesim/tracer/raw2trace_directory.h @@ -1,5 +1,5 @@ /* ********************************************************** - * Copyright (c) 2017 Google, Inc. All rights reserved. + * Copyright (c) 2017-2018 Google, Inc. All rights reserved. * **********************************************************/ /* @@ -43,6 +43,10 @@ class raw2trace_directory_t { public: raw2trace_directory_t(const std::string &indir, const std::string &outname, unsigned int verbosity = 0); + // This version is for raw2trace_t::do_module_parsing() or + // raw2trace_t::do_module_parsing_and_mapping(). + raw2trace_directory_t(const std::string &module_file_path, + unsigned int verbosity = 0); ~raw2trace_directory_t(); char *modfile_bytes; @@ -50,6 +54,7 @@ public: std::ofstream out_file; private: + void read_module_file(const std::string &modfilename); void open_thread_files(); void open_thread_log_file(const char *basename); file_t modfile; diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 8948d3bfa9336e1d67aecdf3b653a55acbe738bc..52a04d0ca2801bedb9929729beb5cabd20604168 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -2590,6 +2590,12 @@ if (CLIENT_INTERFACE) unset(tool.drcacheoff.basic_counts_rawtemp) endif () + torunonly_drcacheoff(opcode_mix ${ci_shared_app} "" + "@-simulator_type@opcode_mix" "") + # We're using the same app so we serialize to avoid racing trace dirs: + set(tool.drcacheoff.opcode_mix_depends tool.drcacheoff.simple) + set(tool.drcacheoff.opcode_mix_depends tool.drcacheoff.filter) + # FIXME i#2007: fails to link on A64 # XXX i#1551: startstop API is NYI on ARM # XXX i#1997: dynamorio_static is not supported on Mac yet