| /* Copyright (c) 2008-2010, 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. |
| * * 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 THE COPYRIGHT |
| * OWNER 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 file is part of ThreadSanitizer, a dynamic data race detector. |
| // Author: Konstantin Serebryany. |
| //--------- Head ------------------- {{{1 |
| #ifndef THREAD_SANITIZER_H_ |
| #define THREAD_SANITIZER_H_ |
| |
| #include "ts_util.h" |
| #include "ts_atomic.h" |
| |
| //--------- Utils ------------------- {{{1 |
| |
| void Report(const char *format, ...); |
| void PcToStrings(uintptr_t pc, bool demangle, |
| string *img_name, string *rtn_name, |
| string *file_name, int *line_no); |
| string PcToRtnNameAndFilePos(uintptr_t pc); |
| string PcToRtnName(uintptr_t pc, bool demangle); |
| string Demangle(const char *str); |
| |
| |
| //--------- FLAGS ---------------------------------- {{{1 |
| struct FLAGS { |
| string input_type; // for ts_offline. |
| // Possible values: str, bin, decode. |
| bool ignore_stack; |
| intptr_t verbosity; |
| intptr_t show_stats; // 0 -- no stats; 1 -- some stats; 2 more stats. |
| bool trace_profile; |
| bool show_expected_races; |
| uintptr_t trace_addr; |
| uintptr_t segment_set_recycle_queue_size; |
| uintptr_t recent_segments_cache_size; |
| vector<string> file_prefix_to_cut; |
| vector<string> ignore; |
| vector<string> whitelist; |
| bool ignore_unknown_pcs; // Ignore PCs with no debug info. |
| vector<string> cut_stack_below; |
| string summary_file; |
| string log_file; |
| bool offline; |
| intptr_t max_n_threads; |
| bool compress_cache_lines; |
| bool unlock_on_mutex_destroy; |
| |
| intptr_t sample_events; |
| intptr_t sample_events_depth; |
| |
| intptr_t num_callers; |
| |
| intptr_t keep_history; |
| bool pure_happens_before; |
| bool free_is_write; |
| bool exit_after_main; |
| bool demangle; |
| bool announce_threads; |
| bool full_output; |
| bool show_states; |
| bool show_proc_self_status; |
| bool show_valgrind_context; // debug-only |
| bool suggest_happens_before_arcs; |
| bool show_pc; |
| bool full_stack_frames; |
| bool color; // Colorify terminal output. |
| bool html; // Output in html format. |
| bool show_pid; |
| |
| intptr_t debug_level; |
| bool save_ignore_context; // print stack if ignore_end was forgotten. |
| vector<string> debug_phase; |
| intptr_t trace_level; |
| |
| intptr_t dry_run; |
| intptr_t max_sid; |
| intptr_t max_sid_before_flush; |
| intptr_t max_mem_in_mb; |
| intptr_t num_callers_in_history; |
| intptr_t flush_period; |
| |
| intptr_t literace_sampling; |
| bool start_with_global_ignore_on; |
| |
| intptr_t locking_scheme; // Used for internal experiments with locking. |
| |
| bool report_races; |
| bool thread_coverage; |
| bool atomicity; |
| bool call_coverage; |
| string dump_events; // The name of log file. Debug mode only. |
| bool symbolize; |
| bool attach_mode; |
| |
| string tsan_program_name; |
| string tsan_url; |
| |
| vector<string> suppressions; |
| bool generate_suppressions; |
| |
| intptr_t error_exitcode; |
| bool trace_children; |
| |
| vector<string> race_verifier; |
| vector<string> race_verifier_extra; |
| intptr_t race_verifier_sleep_ms; |
| |
| bool nacl_untrusted; |
| |
| bool threaded_analysis; |
| |
| bool sched_shake; |
| bool api_ambush; |
| |
| bool enable_atomic; |
| }; |
| |
| extern FLAGS *G_flags; |
| |
| extern bool g_race_verifier_active; |
| |
| extern bool debug_expected_races; |
| extern bool debug_malloc; |
| extern bool debug_free; |
| extern bool debug_thread; |
| extern bool debug_rtn; |
| extern bool debug_wrap; |
| extern bool debug_ins; |
| extern bool debug_shadow_stack; |
| extern bool debug_race_verifier; |
| |
| // -------- CallStack ------------- {{{1 |
| const size_t kMaxCallStackSize = 1 << 12; |
| |
| struct CallStackPod { |
| uintptr_t *end_; |
| uintptr_t pcs_[kMaxCallStackSize]; |
| }; |
| |
| struct CallStack: public CallStackPod { |
| |
| CallStack() { Clear(); } |
| |
| size_t size() { return (size_t)(end_ - pcs_); } |
| uintptr_t *pcs() { return pcs_; } |
| |
| bool empty() { return end_ == pcs_; } |
| |
| uintptr_t &back() { |
| DCHECK(!empty()); |
| return *(end_ - 1); |
| } |
| |
| void pop_back() { |
| DCHECK(!empty()); |
| end_--; |
| } |
| |
| void push_back(uintptr_t pc) { |
| DCHECK(size() < kMaxCallStackSize); |
| *end_ = pc; |
| end_++; |
| } |
| |
| void Clear() { |
| end_ = pcs_; |
| } |
| |
| uintptr_t &operator[] (size_t i) { |
| DCHECK(i < size()); |
| return pcs_[i]; |
| } |
| |
| }; |
| |
| //--------- TS Exports ----------------- {{{1 |
| #include "ts_events.h" |
| #include "ts_trace_info.h" |
| |
| struct TSanThread; |
| void ThreadSanitizerInit(); |
| void ThreadSanitizerFini(); |
| // TODO(glider): this is a temporary solution to avoid deadlocks after fork(). |
| #ifdef TS_LLVM |
| void ThreadSanitizerLockAcquire(); |
| void ThreadSanitizerLockRelease(); |
| #endif |
| void ThreadSanitizerHandleOneEvent(Event *event); |
| TSanThread *ThreadSanitizerGetThreadByTid(int32_t tid); |
| void ThreadSanitizerHandleTrace(int32_t tid, TraceInfo *trace_info, |
| uintptr_t *tleb); |
| void ThreadSanitizerHandleTrace(TSanThread *thr, TraceInfo *trace_info, |
| uintptr_t *tleb); |
| void ThreadSanitizerHandleOneMemoryAccess(TSanThread *thr, MopInfo mop, |
| uintptr_t addr); |
| void ThreadSanitizerParseFlags(vector<string>* args); |
| bool ThreadSanitizerWantToInstrumentSblock(uintptr_t pc); |
| bool ThreadSanitizerWantToCreateSegmentsOnSblockEntry(uintptr_t pc); |
| bool ThreadSanitizerIgnoreAccessesBelowFunction(uintptr_t pc); |
| |
| typedef int (*ThreadSanitizerUnwindCallback)(uintptr_t* stack, int size, uintptr_t pc); |
| void ThreadSanitizerSetUnwindCallback(ThreadSanitizerUnwindCallback cb); |
| |
| /** Atomic operation handler. |
| * @param tid ID of a thread that issues the operation. |
| * @param pc Program counter that should be associated with the operation. |
| * @param op Type of the operation (load, store, etc). |
| * @param mo Memory ordering associated with the operation |
| * (relaxed, acquire, release, etc). NB there are some restrictions on |
| * what memory orderings can be used with what types of operations. |
| * E.g. a store can't have an acquire semantics |
| * (see C++0x standard draft for details). |
| * @param fail_mo Memory ordering the operation has if it fails, |
| * applicable only to compare_exchange oprations. |
| * @param size Size of the memory access in bytes (1, 2, 4 or 8). |
| * @param a Address of the memory access. |
| * @param v Operand for the operation (e.g. a value to store). |
| * @param cmp Comparand for compare_exchange oprations. |
| * @return Result of the operation (e.g. loaded value). |
| */ |
| uint64_t ThreadSanitizerHandleAtomicOp(int32_t tid, |
| uintptr_t pc, |
| tsan_atomic_op op, |
| tsan_memory_order mo, |
| tsan_memory_order fail_mo, |
| size_t size, |
| void volatile* a, |
| uint64_t v, |
| uint64_t cmp); |
| |
| enum IGNORE_BELOW_RTN { |
| IGNORE_BELOW_RTN_UNKNOWN, |
| IGNORE_BELOW_RTN_NO, |
| IGNORE_BELOW_RTN_YES |
| }; |
| |
| void ThreadSanitizerHandleRtnCall(int32_t tid, uintptr_t call_pc, |
| uintptr_t target_pc, |
| IGNORE_BELOW_RTN ignore_below); |
| |
| void ThreadSanitizerHandleRtnExit(int32_t tid); |
| |
| void ThreadSanitizerPrintUsage(); |
| extern "C" const char *ThreadSanitizerQuery(const char *query); |
| bool PhaseDebugIsOn(const char *phase_name); |
| |
| extern bool g_has_entered_main; |
| extern bool g_has_exited_main; |
| |
| // -------- Stats ------------------- {{{1 |
| #include "ts_stats.h" |
| extern Stats *G_stats; |
| |
| // -------- Expected Race ---------------------- {{{1 |
| // Information about expected races. |
| struct ExpectedRace { |
| uintptr_t ptr; |
| uintptr_t size; |
| bool is_verifiable; |
| bool is_nacl_untrusted; |
| int count; |
| const char *description; |
| uintptr_t pc; |
| }; |
| |
| ExpectedRace* ThreadSanitizerFindExpectedRace(uintptr_t addr); |
| |
| // Tell ThreadSanitizer about the location of NaCl untrusted region. |
| void ThreadSanitizerNaclUntrustedRegion(uintptr_t mem_start, uintptr_t mem_end); |
| |
| // Returns true if accesses and locks at the given address should be ignored |
| // according to the current NaCl flags (--nacl-untrusted). Always false if not a |
| // NaCl program. |
| bool ThreadSanitizerIgnoreForNacl(uintptr_t addr); |
| |
| // end. {{{1 |
| #endif // THREAD_SANITIZER_H_ |
| |
| // vim:shiftwidth=2:softtabstop=2:expandtab |