* Copyright (c) 2023 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 GOOGLE, 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.
*/
* a "burst" of execution during which SYS_futex is called. The resulting
* trace is analyzed to confirm that futex parameters were included.
*/
#include "dr_api.h"
#include "drmemtrace/drmemtrace.h"
#include "analysis_tool.h"
#include "scheduler.h"
#include "tracer/raw2trace.h"
#include "tracer/raw2trace_directory.h"
#include <assert.h>
#include <linux/futex.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <iostream>
namespace dynamorio {
namespace drmemtrace {
static uint32_t futex_var;
bool
my_setenv(const char *var, const char *value)
{
#ifdef UNIX
return setenv(var, value, 1 ) == 0;
#else
return SetEnvironmentVariable(var, value) == TRUE;
#endif
}
static void
do_some_work()
{
long res = syscall(SYS_futex, &futex_var, FUTEX_WAKE, 1,
nullptr, nullptr, 0);
}
* Maybe we can share some of it through common library.
*/
static std::string
post_process(const std::string &out_subdir)
{
const char *raw_dir;
drmemtrace_status_t mem_res = drmemtrace_get_output_path(&raw_dir);
assert(mem_res == DRMEMTRACE_SUCCESS);
std::string outdir = std::string(raw_dir) + DIRSEP + out_subdir;
void *dr_context = dr_standalone_init();
* run by the outer test harness will find (TRACE_FILENAME).
* Use a new scope to free raw2trace_directory_t before dr_standalone_exit().
* We could alternatively make a scope exit template helper.
*/
{
raw2trace_directory_t dir;
if (!dr_create_dir(outdir.c_str())) {
std::cerr << "Failed to create output dir";
assert(false);
}
std::string dir_err = dir.initialize(raw_dir, outdir);
assert(dir_err.empty());
raw2trace_t raw2trace(dir.modfile_bytes_, dir.in_files_, dir.out_files_,
dir.out_archives_, dir.encoding_file_,
dir.serial_schedule_file_, dir.cpu_schedule_file_,
dr_context,
0
#ifdef WINDOWS
* causes problems. We disable the pool for now.
*/
,
0
#endif
);
std::string error = raw2trace.do_conversion();
if (!error.empty()) {
std::cerr << "raw2trace failed: " << error << "\n";
assert(false);
}
}
dr_standalone_exit();
return outdir;
}
static std::string
gather_trace(const std::string &tracer_ops, const std::string &out_subdir)
{
std::string dr_ops("-stderr_mask 0xc -client_lib ';;-offline " + tracer_ops + "'");
if (!my_setenv("DYNAMORIO_OPTIONS", dr_ops.c_str()))
std::cerr << "failed to set env var!\n";
dr_app_setup();
assert(!dr_app_running_under_dynamorio());
dr_app_start();
assert(dr_app_running_under_dynamorio());
do_some_work();
dr_app_stop_and_cleanup();
assert(!dr_app_running_under_dynamorio());
return post_process(out_subdir);
}
int
test_main(int argc, const char *argv[])
{
std::string tracedir = gather_trace("", "futex");
void *dr_context = dr_standalone_init();
scheduler_t scheduler;
std::vector<scheduler_t::input_workload_t> sched_inputs;
sched_inputs.emplace_back(tracedir);
if (scheduler.init(sched_inputs, 1, scheduler_t::make_scheduler_serial_options()) !=
scheduler_t::STATUS_SUCCESS) {
std::cerr << "Failed to initialize scheduler " << scheduler.get_error_string()
<< "\n";
}
auto *stream = scheduler.get_stream(0);
memref_t memref;
int arg_ord = 0;
bool saw_maybe_blocking = false;
bool saw_futex_marker = false;
for (scheduler_t::stream_status_t status = stream->next_record(memref);
status != scheduler_t::STATUS_EOF; status = stream->next_record(memref)) {
assert(status == scheduler_t::STATUS_OK);
if (memref.marker.type != TRACE_TYPE_MARKER)
continue;
if (memref.marker.marker_type == TRACE_MARKER_TYPE_MAYBE_BLOCKING_SYSCALL) {
saw_maybe_blocking = true;
}
if (memref.marker.marker_type == TRACE_MARKER_TYPE_FUNC_ID) {
saw_futex_marker = true;
assert(memref.marker.marker_value ==
static_cast<uintptr_t>(func_trace_t::TRACE_FUNC_ID_SYSCALL_BASE) +
IF_X64_ELSE(SYS_futex, SYS_futex & 0xffff));
}
if (memref.marker.marker_type == TRACE_MARKER_TYPE_FUNC_ARG) {
switch (arg_ord) {
case 0:
assert(memref.marker.marker_value ==
reinterpret_cast<uintptr_t>(&futex_var));
break;
case 1: assert(memref.marker.marker_value == FUTEX_WAKE); break;
case 2: assert(memref.marker.marker_value == 1); break;
default: assert(memref.marker.marker_value == 0); break;
}
++arg_ord;
}
if (memref.marker.marker_type == TRACE_MARKER_TYPE_FUNC_RETVAL) {
assert(memref.marker.marker_value == 1);
}
}
assert(saw_maybe_blocking);
assert(saw_futex_marker);
static constexpr int FUTEX_ARG_COUNT = 6;
assert(arg_ord == FUTEX_ARG_COUNT);
dr_standalone_exit();
std::cerr << "all done\n";
return 0;
}
}
}