diff --git a/clients/drcachesim/CMakeLists.txt b/clients/drcachesim/CMakeLists.txt index f8ea8feee24..4097bc0f539 100644 --- a/clients/drcachesim/CMakeLists.txt +++ b/clients/drcachesim/CMakeLists.txt @@ -165,6 +165,7 @@ add_exported_library(drmemtrace_opcode_mix STATIC tools/opcode_mix.cpp) add_exported_library(drmemtrace_syscall_mix STATIC tools/syscall_mix.cpp) add_exported_library(drmemtrace_view STATIC tools/view.cpp) add_exported_library(drmemtrace_func_view STATIC tools/func_view.cpp) +add_exported_library(drmemtrace_internal_record_view STATIC tools/internal_record_view.cpp) add_exported_library(drmemtrace_invariant_checker STATIC tools/invariant_checker.cpp) add_exported_library(drmemtrace_schedule_stats STATIC tools/schedule_stats.cpp) add_exported_library(drmemtrace_schedule_file STATIC common/schedule_file.cpp) @@ -174,6 +175,7 @@ target_link_libraries(drmemtrace_invariant_checker drdecode drmemtrace_schedule_ configure_DynamoRIO_standalone(drmemtrace_opcode_mix) configure_DynamoRIO_standalone(drmemtrace_view) +configure_DynamoRIO_standalone(drmemtrace_internal_record_view) configure_DynamoRIO_standalone(drmemtrace_invariant_checker) # We combine the cache and TLB simulators as they share code already. @@ -286,7 +288,7 @@ configure_DynamoRIO_standalone(drmemtrace_launcher) target_link_libraries(drmemtrace_launcher drmemtrace_simulator drmemtrace_reuse_distance drmemtrace_histogram drmemtrace_reuse_time drmemtrace_basic_counts drmemtrace_opcode_mix drmemtrace_syscall_mix drmemtrace_view drmemtrace_func_view - drmemtrace_raw2trace directory_iterator drmemtrace_invariant_checker + drmemtrace_internal_record_view drmemtrace_raw2trace directory_iterator drmemtrace_invariant_checker drmemtrace_schedule_stats drmemtrace_record_filter drmemtrace_mutex_dbg_owned) if (UNIX) target_link_libraries(drmemtrace_launcher dl) @@ -369,6 +371,7 @@ 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 tools/view_create.h) install_client_nonDR_header(drmemtrace tools/func_view_create.h) +install_client_nonDR_header(drmemtrace tools/internal_record_view_create.h) install_client_nonDR_header(drmemtrace tools/filter/record_filter_create.h) install_client_nonDR_header(drmemtrace tools/filter/record_filter.h) # TODO i#6412: Create a separate directory for non-tracer headers so that @@ -596,6 +599,7 @@ restore_nonclient_flags(drmemtrace_opcode_mix) restore_nonclient_flags(drmemtrace_syscall_mix) restore_nonclient_flags(drmemtrace_view) restore_nonclient_flags(drmemtrace_func_view) +restore_nonclient_flags(drmemtrace_internal_record_view) restore_nonclient_flags(drmemtrace_record_filter) restore_nonclient_flags(drmemtrace_analyzer) restore_nonclient_flags(drmemtrace_invariant_checker) @@ -669,6 +673,7 @@ add_win32_flags(drmemtrace_opcode_mix) add_win32_flags(drmemtrace_syscall_mix) add_win32_flags(drmemtrace_view) add_win32_flags(drmemtrace_func_view) +add_win32_flags(drmemtrace_internal_record_view) add_win32_flags(drmemtrace_record_filter) add_win32_flags(drmemtrace_analyzer) add_win32_flags(drmemtrace_invariant_checker) @@ -861,8 +866,9 @@ if (BUILD_TESTS) drmemtrace_raw2trace drmemtrace_simulator drmemtrace_reuse_distance drmemtrace_histogram drmemtrace_reuse_time drmemtrace_basic_counts drmemtrace_opcode_mix drmemtrace_syscall_mix drmemtrace_view drmemtrace_func_view - drmemtrace_raw2trace directory_iterator drmemtrace_invariant_checker - drmemtrace_schedule_stats drmemtrace_analyzer drmemtrace_record_filter) + drmemtrace_internal_record_view drmemtrace_raw2trace directory_iterator + drmemtrace_invariant_checker drmemtrace_schedule_stats drmemtrace_analyzer + drmemtrace_record_filter) if (UNIX) target_link_libraries(tool.drcachesim.core_sharded dl) endif () diff --git a/clients/drcachesim/analyzer_multi.cpp b/clients/drcachesim/analyzer_multi.cpp index 521ae6bf488..5e62e9d7c17 100644 --- a/clients/drcachesim/analyzer_multi.cpp +++ b/clients/drcachesim/analyzer_multi.cpp @@ -66,6 +66,7 @@ #include "tools/reuse_distance_create.h" #include "tools/reuse_time_create.h" #include "tools/view_create.h" +#include "tools/internal_record_view_create.h" #include "tools/loader/external_config_file.h" #include "tools/loader/external_tool_creator.h" #include "tools/filter/record_filter_create.h" @@ -341,6 +342,9 @@ record_analyzer_multi_t::create_analysis_tool_from_options(const std::string &to op_trim_after_timestamp.get_value(), op_encodings2regdeps.get_value(), op_filter_func_ids.get_value(), op_modify_marker_value.get_value(), op_verbose.get_value()); + } else if (tool == INTERNAL_RECORD_VIEW) { + return internal_record_view_tool_create(op_skip_refs.get_value(), + op_sim_refs.get_value()); } ERRMSG("Usage error: unsupported record analyzer type \"%s\". Only " RECORD_FILTER " is supported.\n", diff --git a/clients/drcachesim/common/options.h b/clients/drcachesim/common/options.h index 9e64dd920b3..1d4ca46bc22 100644 --- a/clients/drcachesim/common/options.h +++ b/clients/drcachesim/common/options.h @@ -50,6 +50,7 @@ #define SYSCALL_MIX "syscall_mix" #define VIEW "view" #define FUNC_VIEW "func_view" +#define INTERNAL_RECORD_VIEW "internal_record_view" #define INVARIANT_CHECKER "invariant_checker" #define SCHEDULE_STATS "schedule_stats" #define RECORD_FILTER "record_filter" diff --git a/clients/drcachesim/common/trace_entry.cpp b/clients/drcachesim/common/trace_entry.cpp index 2cc0036975f..777c00fb9a5 100644 --- a/clients/drcachesim/common/trace_entry.cpp +++ b/clients/drcachesim/common/trace_entry.cpp @@ -35,6 +35,8 @@ namespace dynamorio { namespace drmemtrace { +/* Keep synched with trace_type_t enum in trace_entry.h. + */ const char *const trace_type_names[] = { "read", "write", @@ -88,5 +90,118 @@ const char *const trace_type_names[] = { "untaken_jump", }; +/* Keep synched with trace_version_t enum in trace_entry.h. + */ +const char *const trace_version_names[] = { + "", "", "no_kernel_pc", "kernel_pc", + "encodings", "branch_info", "frequent_timestamps", +}; + +/* Keep synched with trace_marker_type_t enum in trace_entry.h. + */ +const char *const trace_marker_names[] = { + "marker: kernel xfer", /* TRACE_MARKER_TYPE_KERNEL_EVENT */ + "marker: syscall xfer", /* TRACE_MARKER_TYPE_KERNEL_XFER */ + "marker: timestamp", /* TRACE_MARKER_TYPE_TIMESTAMP */ + "marker: cpu id", /* TRACE_MARKER_TYPE_CPU_ID */ + "marker: function", /* TRACE_MARKER_TYPE_FUNC_ID */ + "marker: function return address", /* TRACE_MARKER_TYPE_FUNC_RETADDR */ + "marker: function argument", /* TRACE_MARKER_TYPE_FUNC_ARG */ + "marker: function return value", /* TRACE_MARKER_TYPE_FUNC_RETVAL */ + "marker: split value", /* TRACE_MARKER_TYPE_SPLIT_VALUE */ + "marker: filetype", /* TRACE_MARKER_TYPE_FILETYPE */ + "marker: cache line size", /* TRACE_MARKER_TYPE_CACHE_LINE_SIZE */ + "marker: instruction count", /* TRACE_MARKER_TYPE_INSTRUCTION_COUNT */ + "marker: version", /* TRACE_MARKER_TYPE_VERSION */ + "marker: rseq abort", /* TRACE_MARKER_TYPE_RSEQ_ABORT */ + "marker: window", /* TRACE_MARKER_TYPE_WINDOW_ID */ + "marker: physical address", /* TRACE_MARKER_TYPE_PHYSICAL_ADDRESS */ + "marker: physical address not available", /* TRACE_MARKER_TYPE_PHYSICAL_ADDRESS_NOT_ + AVAILABLE */ + "marker: virtual address", /* TRACE_MARKER_TYPE_VIRTUAL_ADDRESS */ + "marker: page size", /* TRACE_MARKER_TYPE_PAGE_SIZE */ + "marker: system call idx", /* TRACE_MARKER_TYPE_SYSCALL_IDX */ + "marker: chunk instruction count", /* TRACE_MARKER_TYPE_CHUNK_INSTR_COUNT */ + "marker: chunk footer", /* TRACE_MARKER_TYPE_CHUNK_FOOTER */ + "marker: record ordinal", /* TRACE_MARKER_TYPE_RECORD_ORDINAL */ + "marker: filter endpoint", /* TRACE_MARKER_TYPE_FILTER_ENDPOINT */ + "marker: rseq entry", /* TRACE_MARKER_TYPE_RSEQ_ENTRY */ + "marker: system call", /* TRACE_MARKER_TYPE_SYSCALL */ + "marker: maybe-blocking system call", /* TRACE_MARKER_TYPE_MAYBE_BLOCKING_SYSCALL */ + "marker: trace start for system call", /* TRACE_MARKER_TYPE_SYSCALL_TRACE_START */ + "marker: trace end for system call", /* TRACE_MARKER_TYPE_SYSCALL_TRACE_END */ + "marker: indirect branch target", /* TRACE_MARKER_TYPE_BRANCH_TARGET */ + "marker: system call failed", /* TRACE_MARKER_TYPE_SYSCALL_FAILED */ + "marker: direct switch to thread", /* TRACE_MARKER_TYPE_DIRECT_THREAD_SWITCH */ + "marker: wait for another core", /* TRACE_MARKER_TYPE_CORE_WAIT */ + "marker: core is idle", /* TRACE_MARKER_TYPE_CORE_IDLE */ + "marker: trace start for context switch", /* TRACE_MARKER_TYPE_CONTEXT_SWITCH_START */ + "marker: trace end for context switch", /* TRACE_MARKER_TYPE_CONTEXT_SWITCH_END */ + "marker: vector length", /* TRACE_MARKER_TYPE_VECTOR_LENGTH */ + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: unused", + "marker: reserved end", /* TRACE_MARKER_TYPE_RESERVED_END */ +}; + } // namespace drmemtrace } // namespace dynamorio diff --git a/clients/drcachesim/common/trace_entry.h b/clients/drcachesim/common/trace_entry.h index 903374ddd00..197e3194a47 100644 --- a/clients/drcachesim/common/trace_entry.h +++ b/clients/drcachesim/common/trace_entry.h @@ -44,6 +44,8 @@ #define _TRACE_ENTRY_H_ 1 #include +#include +#include #include #include @@ -720,6 +722,8 @@ enum class func_trace_t : uint64_t { // VS2019 won't infer 64-bit with "enum {". }; extern const char *const trace_type_names[]; +extern const char *const trace_version_names[]; +extern const char *const trace_marker_names[]; /** * Returns whether the type represents an instruction fetch. @@ -1077,6 +1081,120 @@ trace_arch_string(offline_file_type_t type) return "unspecified"; } +/* Returns a string representation of marker type and corresponding marker value (if any) + * together. + */ +static inline std::string +trace_marker_type_value_as_string(trace_marker_type_t marker_type, uintptr_t marker_value) +{ + std::stringstream ss; + const char *marker_name = trace_marker_names[marker_type]; + switch (marker_type) { + /* Handle all the cases where marker_value doesn't matter. + */ + case TRACE_MARKER_TYPE_FILTER_ENDPOINT: + case TRACE_MARKER_TYPE_MAYBE_BLOCKING_SYSCALL: + case TRACE_MARKER_TYPE_CORE_WAIT: + case TRACE_MARKER_TYPE_CORE_IDLE: ss << "<" << marker_name << ">\n"; break; + /* Handle all the cases where we simply print . + */ + case TRACE_MARKER_TYPE_TIMESTAMP: + case TRACE_MARKER_TYPE_CPU_ID: + case TRACE_MARKER_TYPE_INSTRUCTION_COUNT: + case TRACE_MARKER_TYPE_CACHE_LINE_SIZE: + case TRACE_MARKER_TYPE_PAGE_SIZE: + case TRACE_MARKER_TYPE_CHUNK_INSTR_COUNT: + case TRACE_MARKER_TYPE_SYSCALL: + case TRACE_MARKER_TYPE_DIRECT_THREAD_SWITCH: + case TRACE_MARKER_TYPE_WINDOW_ID: + case TRACE_MARKER_TYPE_SYSCALL_IDX: + ss << "<" << marker_name << " " << marker_value << ">\n"; + break; + /* Handle all the cases where we simply print . + */ + case TRACE_MARKER_TYPE_FUNC_RETADDR: + case TRACE_MARKER_TYPE_FUNC_ARG: + case TRACE_MARKER_TYPE_FUNC_RETVAL: + case TRACE_MARKER_TYPE_RECORD_ORDINAL: + case TRACE_MARKER_TYPE_SPLIT_VALUE: + case TRACE_MARKER_TYPE_BRANCH_TARGET: + ss << "<" << marker_name << " 0x" << std::hex << marker_value << std::dec + << ">\n"; + break; + /* Handle all remaining cases where we want to print a more informative output. + */ + case TRACE_MARKER_TYPE_SYSCALL_TRACE_START: + case TRACE_MARKER_TYPE_SYSCALL_TRACE_END: + ss << "<" << marker_name << " number " << marker_value << ">\n"; + break; + case TRACE_MARKER_TYPE_CONTEXT_SWITCH_START: + case TRACE_MARKER_TYPE_CONTEXT_SWITCH_END: + ss << "<" << marker_name << " type " << marker_value << ">\n"; + break; + /* We don't have a way to know the trace version here. This might be an offset, + * but we don't make any distinction. + */ + case TRACE_MARKER_TYPE_KERNEL_XFER: + case TRACE_MARKER_TYPE_KERNEL_EVENT: + ss << "<" << marker_name << " from 0x" << std::hex << marker_value << std::dec + << ">\n"; + break; + case TRACE_MARKER_TYPE_VERSION: + ss << "<" << marker_name << " " << static_cast(marker_value) << " " + << trace_version_names[marker_value] << ">\n"; + break; + case TRACE_MARKER_TYPE_FILETYPE: + ss << "<" << marker_name << " 0x" << std::hex + << static_cast(marker_value) << std::dec << " " + << trace_arch_string((offline_file_type_t)marker_value) << ">\n"; + break; + case TRACE_MARKER_TYPE_RSEQ_ABORT: + ss << "<" << marker_name << " from 0x" << std::hex << marker_value << std::dec + << " to handler>\n"; + break; + case TRACE_MARKER_TYPE_RSEQ_ENTRY: + ss << "<" << marker_name << " with end at 0x" << std::hex << marker_value + << std::dec << ">\n"; + break; + case TRACE_MARKER_TYPE_CHUNK_FOOTER: + ss << "<" << marker_name << " #" << marker_value << ">\n"; + break; + case TRACE_MARKER_TYPE_PHYSICAL_ADDRESS: + ss << "<" << marker_name << " for following virtual: 0x" << std::hex + << marker_value << std::dec << ">\n"; + break; + case TRACE_MARKER_TYPE_VIRTUAL_ADDRESS: + ss << "<" << marker_name << " for prior physical: 0x" << std::hex << marker_value + << std::dec << ">\n"; + break; + case TRACE_MARKER_TYPE_PHYSICAL_ADDRESS_NOT_AVAILABLE: + ss << "<" << marker_name << " for 0x" << std::hex << marker_value << std::dec + << ">\n"; + break; + case TRACE_MARKER_TYPE_FUNC_ID: + if (marker_value >= + static_cast(func_trace_t::TRACE_FUNC_ID_SYSCALL_BASE)) { + ss << "<" << marker_name << "==syscall #" + << (marker_value - + static_cast(func_trace_t::TRACE_FUNC_ID_SYSCALL_BASE)) + << ">\n"; + } else { + ss << "<" << marker_name << " #" << marker_value << ">\n"; + } + break; + case TRACE_MARKER_TYPE_SYSCALL_FAILED: + ss << "<" << marker_name << ": " << marker_value << ">\n"; + break; + case TRACE_MARKER_TYPE_VECTOR_LENGTH: + ss << "<" << marker_name << " " << marker_value << " bytes>\n"; + break; + default: + ss << "\n"; + break; + } + return ss.str(); +} + /* We have non-client targets including this header that do not include API * headers defining IF_X86_ELSE, etc. Those don't need this function so we * simply exclude them. diff --git a/clients/drcachesim/launcher.cpp b/clients/drcachesim/launcher.cpp index c28fd22ce0f..18ba23d11c1 100644 --- a/clients/drcachesim/launcher.cpp +++ b/clients/drcachesim/launcher.cpp @@ -323,7 +323,8 @@ _tmain(int argc, const TCHAR *targv[]) FATAL_ERROR("invalid -outdir %s", op_outdir.get_value().c_str()); } } else { - if (op_tool.get_value() == RECORD_FILTER) { + if (op_tool.get_value() == RECORD_FILTER || + op_tool.get_value() == INTERNAL_RECORD_VIEW) { record_analyzer = new record_analyzer_multi_t; if (!*record_analyzer) { std::string error_string_ = record_analyzer->get_error_string(); diff --git a/clients/drcachesim/tools/internal_record_view.cpp b/clients/drcachesim/tools/internal_record_view.cpp new file mode 100644 index 00000000000..306464a2d2c --- /dev/null +++ b/clients/drcachesim/tools/internal_record_view.cpp @@ -0,0 +1,217 @@ +/* ********************************************************** + * Copyright (c) 2024 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. + */ + +#include "internal_record_view.h" + +#include +#include +#include +#include +#include + +#include "memtrace_stream.h" +#include "trace_entry.h" + +namespace dynamorio { +namespace drmemtrace { + +typedef unsigned int uint; + +record_analysis_tool_t * +internal_record_view_tool_create(uint64_t skip_refs, uint64_t sim_refs) +{ + return new dynamorio::drmemtrace::internal_record_view_t(skip_refs, sim_refs); +} + +internal_record_view_t::internal_record_view_t(uint64_t skip_refs, uint64_t sim_refs) + : skip_refs_(skip_refs) + , sim_refs_(sim_refs) +{ +} + +internal_record_view_t::~internal_record_view_t() +{ +} + +bool +internal_record_view_t::should_skip(void) +{ + if (skip_refs_ > 0) { + --skip_refs_; + return true; + } + if (sim_refs_ > 0) { + --sim_refs_; + return false; + } + return true; +} + +bool +internal_record_view_t::parallel_shard_supported() +{ + return false; +} + +std::string +internal_record_view_t::initialize_shard_type(shard_type_t shard_type) +{ + return ""; +} + +std::string +internal_record_view_t::initialize_stream(memtrace_stream_t *serial_stream) +{ + /* Print warning header. + */ + std::cerr << "The internal_record_view tool is a pretty printer for trace_entry_t " + "records.\nThe trace_entry_t internal record format is not a public " + "interface and is subject to change without notice.\nThis tool is meant " + "for debugging only, please do not rely on the details here.\n"; + return ""; +} + +void * +internal_record_view_t::parallel_shard_init_stream(int shard_index, void *worker_data, + memtrace_stream_t *shard_stream) +{ + return shard_stream; +} + +bool +internal_record_view_t::parallel_shard_exit(void *shard_data) +{ + return true; +} + +std::string +internal_record_view_t::parallel_shard_error(void *shard_data) +{ + return ""; +} + +bool +internal_record_view_t::parallel_shard_memref(void *shard_data, + const trace_entry_t &entry) +{ + if (should_skip()) + return true; + + trace_type_t trace_type = (trace_type_t)entry.type; + if (trace_type == TRACE_TYPE_INVALID) { + std::cerr << "ERROR: trace_entry_t invalid.\n"; + return false; + } + + std::string trace_type_name = std::string(trace_type_names[trace_type]); + + /* Large if-else for all TRACE_TYPE_. Prints one line per trace_entry_t. + * In some cases we use some helper functions (e.g., type_is_instr()), which group + * similar TRACE_TYPE_ together, otherwise we compare trace_type against one or two + * specific TRACE_TYPE_ directly. + */ + if (trace_type == TRACE_TYPE_HEADER) { + trace_version_t trace_version = (trace_version_t)entry.addr; + std::string trace_version_name = std::string(trace_version_names[trace_version]); + std::cerr << "<" << trace_type_name << ", trace_version: " << trace_version + << " == " << trace_version_name << ">\n"; + } else if (trace_type == TRACE_TYPE_FOOTER) { + std::cerr << "<" << trace_type_name << ">\n"; + } else if ((trace_type == TRACE_TYPE_THREAD) || + (trace_type == TRACE_TYPE_THREAD_EXIT)) { + uint tid = (uint)entry.addr; + std::cerr << "<" << trace_type_name << ", tid: " << tid << ">\n"; + } else if (trace_type == TRACE_TYPE_PID) { + uint pid = (uint)entry.addr; + std::cerr << "<" << trace_type_name << ", pid: " << pid << ">\n"; + } else if (trace_type == TRACE_TYPE_ENCODING) { + unsigned short num_encoding_bytes = entry.size; + std::cerr << "<" << trace_type_name + << ", num_encoding_bytes: " << num_encoding_bytes + << ", encoding_bytes: 0x" << std::hex; + /* Print encoding byte by byte (little-endian). + */ + for (int i = num_encoding_bytes - 1; i >= 0; --i) { + uint encoding_byte = static_cast(entry.encoding[i]); + std::cerr << encoding_byte; + } + std::cerr << std::dec << ">\n"; + } else if (trace_type == TRACE_TYPE_INSTR_BUNDLE) { + unsigned short num_instructions_in_bundle = entry.size; + std::cerr << "<" << trace_type_name + << ", num_instructions_in_bundle: " << num_instructions_in_bundle + << ", instrs_length:"; + /* Print length of each instr in the bundle. + */ + for (int i = 0; i < num_instructions_in_bundle; ++i) { + unsigned char instr_length = entry.length[i]; + std::cerr << " " << instr_length; + } + std::cerr << ">\n"; + } else if (type_is_instr(trace_type)) { + unsigned short instr_length = entry.size; + addr_t pc = entry.addr; + std::cerr << "<" << trace_type_name << ", length: " << instr_length << ", pc: 0x" + << std::hex << pc << std::dec << ">\n"; + } else if (type_has_address(trace_type)) { // Includes no-fetch, prefetch, and flush. + unsigned short memref_size = entry.size; + addr_t memref_addr = entry.addr; + std::cerr << "<" << trace_type_name << ", memref_size: " << memref_size + << ", memref_addr: 0x" << std::hex << memref_addr << std::dec << ">\n"; + /* trace_entry_t is a marker. Print marker type and value accordingly. + */ + } else if (trace_type == TRACE_TYPE_MARKER) { + trace_marker_type_t trace_marker_type = (trace_marker_type_t)entry.size; + uintptr_t trace_marker_value = static_cast(entry.addr); + std::cerr << trace_marker_type_value_as_string(trace_marker_type, + trace_marker_value); + } else { + std::cerr << "ERROR: unrecognized trace_entry_t: " << trace_type << ".\n"; + return false; + } + return true; +} + +bool +internal_record_view_t::process_memref(const trace_entry_t &entry) +{ + return parallel_shard_memref(NULL, entry); +} + +bool +internal_record_view_t::print_results() +{ + return true; +} + +} // namespace drmemtrace +} // namespace dynamorio diff --git a/clients/drcachesim/tools/internal_record_view.h b/clients/drcachesim/tools/internal_record_view.h new file mode 100644 index 00000000000..b9fb3efdf19 --- /dev/null +++ b/clients/drcachesim/tools/internal_record_view.h @@ -0,0 +1,96 @@ +/* ********************************************************** + * Copyright (c) 2024 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 _INTERNAL_RECORD_VIEW_H_ +#define _INTERNAL_RECORD_VIEW_H_ 1 + +#include + +#include + +#include "analysis_tool.h" +#include "memtrace_stream.h" +#include "trace_entry.h" + +namespace dynamorio { +namespace drmemtrace { + +/* Analysis tool that prints #trace_entry_t records of an offline trace in human readable + * form. Note that this is an internal tool for debugging purposes only. Its output is + * subject to changes. + */ +class internal_record_view_t : public record_analysis_tool_t { +public: + internal_record_view_t(uint64_t skip_refs, uint64_t sim_refs); + + ~internal_record_view_t() override; + + bool + process_memref(const trace_entry_t &entry) override; + + bool + print_results() override; + + bool + parallel_shard_supported() override; + + std::string + initialize_shard_type(shard_type_t shard_type) override; + + std::string + initialize_stream(memtrace_stream_t *serial_stream) override; + + void * + parallel_shard_init_stream(int shard_index, void *worker_data, + memtrace_stream_t *shard_stream) override; + + bool + parallel_shard_exit(void *shard_data) override; + + bool + parallel_shard_memref(void *shard_data, const trace_entry_t &entry) override; + + std::string + parallel_shard_error(void *shard_data) override; + +protected: + bool + should_skip(void); + + uint64_t skip_refs_; + uint64_t sim_refs_; +}; + +} // namespace drmemtrace +} // namespace dynamorio + +#endif /* _INTERNAL_RECORD_VIEW_H_ */ diff --git a/clients/drcachesim/tools/internal_record_view_create.h b/clients/drcachesim/tools/internal_record_view_create.h new file mode 100644 index 00000000000..9370afa6eac --- /dev/null +++ b/clients/drcachesim/tools/internal_record_view_create.h @@ -0,0 +1,55 @@ +/* ********************************************************** + * Copyright (c) 2024 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. + */ + +/* record view tool creation */ + +#ifndef _INTERNAL_RECORD_VIEW_CREATE_H_ +#define _INTERNAL_RECORD_VIEW_CREATE_H_ 1 + +#include "analysis_tool.h" + +#include + +namespace dynamorio { +namespace drmemtrace { + +/* Creates an analysis tool which pretty prints out the #trace_entry_t records in a trace + * file to std::cerr. Note that this is an internal tool for debugging purposes. Its + * output is subject to changes. + */ +record_analysis_tool_t * +internal_record_view_tool_create(uint64_t skip_refs, uint64_t sim_refs); + +} // namespace drmemtrace +} // namespace dynamorio + +#endif /* _INTERNAL_RECORD_VIEW_CREATE_H_ */ diff --git a/clients/drcachesim/tools/view.cpp b/clients/drcachesim/tools/view.cpp index 702667db73c..380ad44cd90 100644 --- a/clients/drcachesim/tools/view.cpp +++ b/clients/drcachesim/tools/view.cpp @@ -276,14 +276,15 @@ view_t::parallel_shard_memref(void *shard_data, const memref_t &memref) if (trace_version_ != -1) { // Old versions may not have a version marker. if (!should_skip(memstream, memref)) { print_prefix(memstream, memref, version_record_ord_); - std::cerr << "\n"; + std::cerr << "<" << trace_marker_names[TRACE_MARKER_TYPE_VERSION] << " " + << trace_version_ << ">\n"; } } if (filetype_ != -1) { // Handle old/malformed versions. if (!should_skip(memstream, memref)) { print_prefix(memstream, memref, filetype_record_ord_); - std::cerr << "\n"; + std::cerr << "<" << trace_marker_names[TRACE_MARKER_TYPE_FILETYPE] + << " 0x" << std::hex << filetype_ << std::dec << ">\n"; } } } @@ -301,16 +302,19 @@ view_t::parallel_shard_memref(void *shard_data, const memref_t &memref) -1); // Already incremented for timestamp above. } if (timestamp_ > 0) { - std::cerr << "\n"; + std::cerr << "<" << trace_marker_names[TRACE_MARKER_TYPE_TIMESTAMP] << " " + << timestamp_ << ">\n"; timestamp_ = 0; print_prefix(memstream, memref); } - std::cerr << "\n"; + std::cerr << "<" << trace_marker_names[TRACE_MARKER_TYPE_WINDOW_ID] << " " + << memref.marker.marker_value << ">\n"; last_window_[memref.marker.tid] = memref.marker.marker_value; } if (timestamp_ > 0) { print_prefix(memstream, memref, timestamp_record_ord_); - std::cerr << "\n"; + std::cerr << "<" << trace_marker_names[TRACE_MARKER_TYPE_TIMESTAMP] << " " + << timestamp_ << ">\n"; timestamp_ = 0; } } @@ -320,6 +324,7 @@ view_t::parallel_shard_memref(void *shard_data, const memref_t &memref) } if (memref.marker.type == TRACE_TYPE_MARKER) { + const char *marker_name = trace_marker_names[memref.marker.marker_type]; switch (memref.marker.marker_type) { case TRACE_MARKER_TYPE_VERSION: // Handled above. @@ -330,6 +335,9 @@ view_t::parallel_shard_memref(void *shard_data, const memref_t &memref) case TRACE_MARKER_TYPE_TIMESTAMP: // Handled above. break; + case TRACE_MARKER_TYPE_WINDOW_ID: + // Handled above. + break; case TRACE_MARKER_TYPE_CPU_ID: // We include the thread ID here under the assumption that we will always // see a cpuid marker on a thread switch. To avoid that assumption @@ -346,156 +354,48 @@ view_t::parallel_shard_memref(void *shard_data, const memref_t &memref) case TRACE_MARKER_TYPE_KERNEL_EVENT: if (trace_version_ <= TRACE_ENTRY_VERSION_NO_KERNEL_PC) { // Legacy traces just have the module offset. - std::cerr << "\n"; } else { - std::cerr << "\n"; } break; + // TODO: handle this case in trace_marker_type_value_as_string(). case TRACE_MARKER_TYPE_SIGNAL_NUMBER: std::cerr << "\n"; break; - case TRACE_MARKER_TYPE_RSEQ_ABORT: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_RSEQ_ENTRY: - std::cerr << "\n"; - break; case TRACE_MARKER_TYPE_KERNEL_XFER: if (trace_version_ <= TRACE_ENTRY_VERSION_NO_KERNEL_PC) { // Legacy traces just have the module offset. - std::cerr << "\n"; } else { - std::cerr << "\n"; } break; - case TRACE_MARKER_TYPE_INSTRUCTION_COUNT: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_CACHE_LINE_SIZE: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_PAGE_SIZE: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_CHUNK_INSTR_COUNT: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_CHUNK_FOOTER: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_FILTER_ENDPOINT: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_PHYSICAL_ADDRESS: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_VIRTUAL_ADDRESS: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_PHYSICAL_ADDRESS_NOT_AVAILABLE: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_FUNC_ID: - if (memref.marker.marker_value >= - static_cast(func_trace_t::TRACE_FUNC_ID_SYSCALL_BASE)) { - std::cerr << "( - func_trace_t::TRACE_FUNC_ID_SYSCALL_BASE)) - << ">\n"; - } else { - std::cerr << "\n"; - } - break; - case TRACE_MARKER_TYPE_FUNC_RETADDR: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_FUNC_ARG: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_FUNC_RETVAL: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_SYSCALL_FAILED: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_RECORD_ORDINAL: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_SYSCALL: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_MAYBE_BLOCKING_SYSCALL: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_DIRECT_THREAD_SWITCH: - std::cerr << "\n"; - break; + // TODO: handle this case in trace_marker_type_value_as_string(). case TRACE_MARKER_TYPE_SYSCALL_UNSCHEDULE: std::cerr << "\n"; break; + // TODO: handle this case in trace_marker_type_value_as_string(). case TRACE_MARKER_TYPE_SYSCALL_SCHEDULE: std::cerr << "\n"; break; + // TODO: handle this case in trace_marker_type_value_as_string(). case TRACE_MARKER_TYPE_SYSCALL_ARG_TIMEOUT: std::cerr << "\n"; break; - case TRACE_MARKER_TYPE_WINDOW_ID: - // Handled above. - break; - case TRACE_MARKER_TYPE_SYSCALL_TRACE_START: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_SYSCALL_TRACE_END: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_CONTEXT_SWITCH_START: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_CONTEXT_SWITCH_END: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_BRANCH_TARGET: - // These are not expected to be visible (since the reader adds them - // to memref.instr.indirect_branch_target) but we handle nonetheless. - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_CORE_WAIT: - std::cerr << "\n"; - break; - case TRACE_MARKER_TYPE_CORE_IDLE: std::cerr << "\n"; break; - case TRACE_MARKER_TYPE_VECTOR_LENGTH: - std::cerr << "\n"; - break; default: - std::cerr << "\n"; + /* The previous cases have state and require extra processing. Here we print + * all the remaining cases that do not need that extra processing and + * bookkeeping. + */ + std::cerr << trace_marker_type_value_as_string(memref.marker.marker_type, + memref.marker.marker_value); break; } return true; diff --git a/suite/tests/api/dis-a64-v82.txt b/suite/tests/api/dis-a64-v82.txt index 928589da1bd..18284ee13b2 100644 --- a/suite/tests/api/dis-a64-v82.txt +++ b/suite/tests/api/dis-a64-v82.txt @@ -503,4 +503,3 @@ badf03fe : subps x30, sp, sp : subps %sp %sp -> %x30 4e9baf59 : usmmla v25.4s, v26.16b, v27.16b : usmmla %q25 %q26 %q27 $0x00 -> %q25 4e9daf9b : usmmla v27.4s, v28.16b, v29.16b : usmmla %q27 %q28 %q29 $0x00 -> %q27 4e9fafff : usmmla v31.4s, v31.16b, v31.16b : usmmla %q31 %q31 %q31 $0x00 -> %q31 - diff --git a/tools/get_vector_length.py b/tools/get_vector_length.py index f57b0fe5aa7..8f5347bf1ec 100755 --- a/tools/get_vector_length.py +++ b/tools/get_vector_length.py @@ -31,4 +31,3 @@ def get_vector_length(): sys.exit(0) get_vector_length() -