Skip to content

Commit

Permalink
feat: filter races that happen in an excluded module
Browse files Browse the repository at this point in the history
  • Loading branch information
fmoessbauer committed May 6, 2020
1 parent 27636c2 commit 6551431
Show file tree
Hide file tree
Showing 14 changed files with 226 additions and 69 deletions.
29 changes: 29 additions & 0 deletions drace-client/include/module/InstrFlags.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once
/*
* DRace, a dynamic data race detector
*
* Copyright 2018 Siemens AG
*
* Authors:
* Felix Moessbauer <felix.moessbauer@siemens.com>
*
* SPDX-License-Identifier: MIT
*/

namespace drace {
namespace module {

/// Instrumentation Level Flags
enum INSTR_FLAGS : uint8_t {
/// do not instrument this module
NONE = 0,
/// instrument functions (e.g. exclude)
SYMBOLS = 1,
/// instrument memory accesses
MEMORY = 2,
/// add shadow-stack instrumentation
STACK = 4
};

} // namespace module
} // namespace drace
19 changes: 4 additions & 15 deletions drace-client/include/module/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,17 @@

#include <dr_api.h>
#include "../globals.h"
#include "InstrFlags.h"
#include "ModTypeFlags.h"

namespace drace {
namespace module {
/// Encapsulates and enriches a dynamorio module_data_t struct
class Metadata {
public:
/// Flags describing characteristics of a module
enum MOD_TYPE_FLAGS : uint8_t {
/// no information available
UNKNOWN = 0x0,
/// native module
NATIVE = 0x1,
/// managed module
MANAGED = 0x2,
/// this (managed module) contains sync mechanisms
SYNC = 0x4 | MANAGED
};
using INSTR_FLAGS = drace::module::INSTR_FLAGS;
using MOD_TYPE_FLAGS = drace::module::MOD_TYPE_FLAGS;

/// Instrumentation Level Flags
enum INSTR_FLAGS : uint8_t { NONE = 0, SYMBOLS = 1, MEMORY = 2, STACK = 4 };

public:
app_pc base;
app_pc end;
bool loaded;
Expand Down
29 changes: 29 additions & 0 deletions drace-client/include/module/ModTypeFlags.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once
/*
* DRace, a dynamic data race detector
*
* Copyright 2018 Siemens AG
*
* Authors:
* Felix Moessbauer <felix.moessbauer@siemens.com>
*
* SPDX-License-Identifier: MIT
*/

namespace drace {
namespace module {

/// Flags describing characteristics of a module
enum MOD_TYPE_FLAGS : uint8_t {
/// no information available
UNKNOWN = 0x0,
/// native module
NATIVE = 0x1,
/// managed module
MANAGED = 0x2,
/// this (managed module) contains sync mechanisms
SYNC = 0x4 | MANAGED
};

} // namespace module
} // namespace drace
36 changes: 23 additions & 13 deletions drace-client/include/module/Tracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,30 @@ class Tracker {
/**
* \brief Returns a shared_ptr to the module which contains the given program
* counter. If the pc is not in a known module, returns a nullptr
*
* \note threadsafe
*/
PMetadata get_module_containing(const app_pc pc) const;
const PMetadata get_module_containing(const app_pc pc) const;

/**
* \brief Registers a module and sets flags accordingly
*
* \note threadsafe
*/
PMetadata register_module(const module_data_t *mod, bool loaded);

private:
/**
* \brief Creates new module in place
*
* \note not-threadsafe
*/
template <class... Args>
inline PMetadata add_emplace(Args &&... args) {
PMetadata ptr = std::make_shared<Metadata>(std::forward<Args>(args)...);
_modules_idx.emplace(ptr->base, ptr);
return ptr;
}

/// Registers a new module by moving it
inline PMetadata add(Metadata &&mod) {
Expand All @@ -60,18 +82,6 @@ class Tracker {
return std::make_shared<Metadata>(mod);
}

/// Creates new module in place
template <class... Args>
inline PMetadata add_emplace(Args &&... args) {
PMetadata ptr = std::make_shared<Metadata>(std::forward<Args>(args)...);
_modules_idx.emplace(ptr->base, ptr);
return ptr;
}

/// Registers a module and sets flags accordingly
PMetadata register_module(const module_data_t *mod, bool loaded);

private:
/// Request a read-lock for the module dataset
inline void lock_read() const { dr_rwlock_read_lock(mod_lock); }

Expand Down
20 changes: 4 additions & 16 deletions drace-client/include/race-collector.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ class RaceCollector {
std::shared_ptr<RaceFilter> _filter;

public:
RaceCollector(bool delayed_lookup,
const std::shared_ptr<symbol::Symbols>& symbols,
RaceCollector(bool delayed_lookup, std::shared_ptr<symbol::Symbols> symbols,
std::shared_ptr<RaceFilter> filter)
: _delayed_lookup(delayed_lookup),
_syms(symbols),
Expand Down Expand Up @@ -140,31 +139,20 @@ class RaceCollector {
inline MutexT& get_mutex() { return _races_lock; }

private:
/**
* Filter false-positive data-races
* \return true if race is suppressed
*/
bool filter_excluded(const Detector::Race* r);

/**
* suppress this race if similar race is already reported
* \return true if race is suppressed
* \note not-threadsafe
*/
bool filter_duplicates(const Detector::Race* r);

/** Takes a detector Access Entry, resolves symbols and converts it to a
/**
* Takes a detector Access Entry, resolves symbols and converts it to a
* ResolvedAccess */
void resolve_symbols(race::ResolvedAccess& ra);

/** resolve a single race */
inline void resolve_race(race::DecoratedRace& race) {
if (!race.is_resolved) {
resolve_symbols(race.first);
resolve_symbols(race.second);
}
race.is_resolved = true;
}
void resolve_race(race::DecoratedRace& race);

/**
* forward a single race to the sinks
Expand Down
22 changes: 22 additions & 0 deletions drace-client/include/race-filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class RaceFilter {
std::vector<std::string> rtos_list; // race top of stack
std::vector<std::string> race_list;
std::map<uint64_t, unsigned, std::greater<uint64_t>> addr_list;

void normalize_string(std::string &expr);

/**
Expand All @@ -52,6 +53,20 @@ class RaceFilter {
*/
bool check_rtos(const drace::race::DecoratedRace &race) const;

/**
* \brief check if the racy-address belongs to an excluded module
* \return true if suppressed
* \note threadsafe
*/
bool in_silent_module(const Detector::Race *race) const;

/**
* \brief at least one of the callstacks contains garbage data
* \return true if suppressed
* \note threadsafe
*/
bool stack_implausible(const Detector::Race *race) const;

/**
* \brief check if the racy memory-location is suppressed
* \return true if suppressed
Expand All @@ -77,6 +92,13 @@ class RaceFilter {
*/
bool check_suppress(const drace::race::DecoratedRace &race) const;

/**
* \brief check if the information in the race is plausible
* \return true if suppressed
* \note threadsafe
*/
bool check_implausible(const Detector::Race *r) const;

/// print a list of suppression criteria
void print_list() const;

Expand Down
1 change: 1 addition & 0 deletions drace-client/include/race/DecoratedRace.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class DecoratedRace {
public:
ResolvedAccess first;
ResolvedAccess second;
symbol::SymbolLocation resolved_addr;
std::chrono::milliseconds elapsed;
bool is_resolved{false};

Expand Down
16 changes: 9 additions & 7 deletions drace-client/include/sink/hr-text.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,29 @@ class HRText : public Sink {
file_t handle = _target->get();
dr_fprintf(handle, "----- DATA Race at %8lld ms runtime -----\n",
race.elapsed.count());
if (!race.resolved_addr.mod_name.empty()) {
dr_fprintf(handle, "Racy-address in module: %s",
race.resolved_addr.get_pretty().c_str());
}

for (int i = 0; i != 2; ++i) {
race::ResolvedAccess ac = (i == 0) ? race.first : race.second;

dr_fprintf(
handle,
"Access %i tid: %i %s to/from %p with size %i. Stack (size %i)\n", i,
ac.thread_id, (ac.write ? "write" : "read"),
(void *)ac.accessed_memory, ac.access_size, ac.stack_size);
dr_fprintf(handle, "Access %i tid: %i %s to/from %p with size %i\n", i,
ac.thread_id, (ac.write ? "write" : "read"),
(void *)ac.accessed_memory, ac.access_size);

if (ac.onheap) {
dr_fprintf(handle, "Block begin at %p, size %u\n", ac.heap_block_begin,
ac.heap_block_size);
}

dr_fprintf(handle, "Callstack (size %i)\n", ac.stack_size);
if (race.is_resolved) {
// stack is stored in reverse order, hence print inverted
int ssize = static_cast<int>(ac.resolved_stack.size());
for (int p = 0; p < ssize; ++p) {
std::string pretty(ac.resolved_stack[ssize - 1 - p].get_pretty());
dr_fprintf(handle, "%#04x %s", (int)p, pretty.c_str());
dr_fprintf(handle, "%#04x PC %s", (int)p, pretty.c_str());
}
} else {
dr_fprintf(handle, "-> (unresolved stack size: %u)\n", ac.stack_size);
Expand Down
9 changes: 6 additions & 3 deletions drace-client/src/module/Tracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Tracker::~Tracker() {
dr_rwlock_destroy(mod_lock);
}

Tracker::PMetadata Tracker::get_module_containing(const app_pc pc) const {
const Tracker::PMetadata Tracker::get_module_containing(const app_pc pc) const {
lock_read();
auto m_it = _modules_idx.lower_bound(pc);

Expand All @@ -86,7 +86,9 @@ Tracker::PMetadata Tracker::get_module_containing(const app_pc pc) const {

Tracker::PMetadata Tracker::register_module(const module_data_t *mod,
bool loaded) {
using INSTR_FLAGS = module::Metadata::INSTR_FLAGS;
using module::INSTR_FLAGS;
using module::MOD_TYPE_FLAGS;

// first check if module is already registered
lock_read();
auto modptr = get_module_containing(mod->start);
Expand All @@ -112,7 +114,7 @@ Tracker::PMetadata Tracker::register_module(const module_data_t *mod,
modptr->instrument = def_instr_flags;

#ifdef WINDOWS
if (modptr->modtype == Metadata::MANAGED && !shmdriver) {
if (modptr->modtype == MOD_TYPE_FLAGS::MANAGED && !shmdriver) {
LOG_WARN(0, "managed module detected, but MSR not available");
}
#endif
Expand Down Expand Up @@ -177,6 +179,7 @@ void event_module_load(void *drcontext, const module_data_t *mod, bool loaded) {
util::common_prefix(mod_name, "KERNELBASE") ||
util::common_prefix(mod_name, "libc")) {
funwrap::wrap_mutexes(mod, true);
funwrap::wrap_excludes(mod);
} else if (util::common_prefix(mod_name, "KERNEL")) {
funwrap::wrap_allocations(mod);
funwrap::wrap_thread_start_sys(mod);
Expand Down
24 changes: 12 additions & 12 deletions drace-client/src/race-collector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ RaceCollector* RaceCollector::_instance;

void RaceCollector::add_race(const Detector::Race* r) {
if (num_races() > MAX) return;
DR_ASSERT(nullptr != r);

#ifdef WINDOWS
auto ttr = std::chrono::duration_cast<std::chrono::milliseconds>(
Expand All @@ -38,7 +39,7 @@ void RaceCollector::add_race(const Detector::Race* r) {

std::lock_guard<DrLock> lock(_races_lock);

if (!filter_duplicates(r) && !filter_excluded(r)) {
if (!filter_duplicates(r) && !_filter->check_implausible(r)) {
DR_ASSERT(r->first.stack_size > 0);
DR_ASSERT(r->second.stack_size > 0);

Expand Down Expand Up @@ -84,17 +85,6 @@ void RaceCollector::race_collector_add_race(const Detector::Race* r) {
}
}

bool RaceCollector::filter_excluded(const Detector::Race* r) {
DR_ASSERT(r != nullptr);
if (r->first.stack_size == 0 || r->second.stack_size == 0) return false;

// PC is null
if (r->first.stack_trace[r->first.stack_size - 1] == 0x0) return true;
if (r->second.stack_trace[r->second.stack_size - 1] == 0x0) return true;

return false;
}

bool RaceCollector::filter_duplicates(const Detector::Race* r) {
// TODO: add more precise control over suppressions
if (params.suppression_level == 0) return false;
Expand Down Expand Up @@ -124,4 +114,14 @@ void RaceCollector::resolve_symbols(race::ResolvedAccess& ra) {
#endif
}

void RaceCollector::resolve_race(race::DecoratedRace& race) {
if (!race.is_resolved) {
race.resolved_addr =
_syms->get_symbol_info((app_pc)race.first.accessed_memory);
resolve_symbols(race.first);
resolve_symbols(race.second);
}
race.is_resolved = true;
}

} // namespace drace
Loading

0 comments on commit 6551431

Please sign in to comment.