//-------------------------------------------------------------------------- ea_t wince_debmod_t::is_hwbpt_triggered(thid_t id, bool /*is_stepping*/) { if ( is_xscale ) { uint32 dcsr = SetDebugControlAndStatus(0, 0); int moe = (dcsr >> 2) & 7; // method of entry (exception reason) // msg("moe=%d\n", moe); switch ( moe ) { case 1: // Instruction Breakpoint Hit case 2: // Data Breakpoint Hit { SetDebugControlAndStatus(0, 7<<2); // clean moe CONTEXT Context; Context.ContextFlags = CONTEXT_CONTROL; HANDLE h = get_thread_handle(id); if ( GetThreadContext(h, &Context) ) { ea_t ea = s0tops(Context.Pc); if ( s0tops(codebpts[0]) == ea || s0tops(codebpts[1]) == ea ) { // msg("HARDWARE CODE BREAKPOINT!\n"); return ea; } // This is a data breakpoint // Set PC to the next instruction since the data bpts always occur // AFTER the instruction #define THUMB_STATE 0x0020 Context.Pc += (Context.Psr & THUMB_STATE)? 2 : 4; SetThreadContext(h, &Context); } // FIXME: determine which data bpt really caused the exception // Currently we just return the first active bpt return databpts[0] != BADADDR ? databpts[0] : databpts[1]; } case 0: // Processor Reset case 3: // BKPT Instruction Executed case 4: // External Debug Event (JTAG Debug Break or SOC Debug Break) case 5: // Vector Trap Occurred case 6: // Trace Buffer Full Break case 7: // Reserved break; } } return BADADDR; }
//-------------------------------------------------------------------------- ea_t pc_debmod_t::is_hwbpt_triggered(thid_t id) { CONTEXT Context; Context.ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_CONTROL; HANDLE h = get_thread_handle(id); if ( GetThreadContext(h, &Context) ) { for ( int i=0; i < MAX_BPT; i++ ) { if ( (Context.Dr7 & uint32(1 << (i*2))) && (Context.Dr6 & uint32(1 << i)) ) // Local hardware breakpoint 'i' { ULONG_PTR *dr = NULL; switch ( i ) { case 0: dr = &Context.Dr0; break; case 1: dr = &Context.Dr1; break; case 2: dr = &Context.Dr2; break; case 3: dr = &Context.Dr3; break; } if ( dr == NULL ) break; if ( hwbpt_ea[i] == *dr ) { set_hwbpts(h); // Clear the status bits return hwbpt_ea[i]; } //? TRACING else // debdeb("System hardware breakpoint at %08X ???\n", *dr); //? // what to do ?: // reset it, and continue as if no event were received ? // send it to IDA, and let the user setup a "stop on non-debugger hardware breakpoint" option ? } } } return BADADDR; }
int main(int argc, char *argv[]) { auto db = get_database(argc, argv); const int NUM_THREADS = 50; test_init(7 + NUM_THREADS); db->execute("CREATE TABLE rusqltest (`value` INT(2) NOT NULL)"); db->execute("INSERT INTO rusqltest VALUES (20)"); { auto statement = db->prepare("SELECT value FROM rusqltest"); statement.execute(); boost::thread thread([&db]() { auto thread_handle = db->get_thread_handle(); db->execute("UPDATE rusqltest SET value=30"); }); thread.join(); uint64_t value = 10; statement.bind_results(value); test(statement.fetch(), "one result"); test(value == 20, "value was correct (" + std::to_string(value) + ")"); test(!statement.fetch(), "exactly one result"); statement.execute(); statement.bind_results(value); test(statement.fetch(), "one result"); test(value == 30, "value was correct (" + std::to_string(value) + ")"); test(!statement.fetch(), "exactly one result"); } db->execute("DELETE FROM rusqltest"); db->execute("INSERT INTO rusqltest VALUES (0)"); // Test simultaneous use of the database std::vector<std::shared_ptr<boost::thread>> threads; boost::mutex output_mutex; for(int i = 0; i < NUM_THREADS; ++i) { threads.emplace_back(std::make_shared<boost::thread>([i, &db, &output_mutex]() { auto thread_handle = db->get_thread_handle(); try { for(int j = 0; j < 1000; ++j) { std::string iteration = std::to_string(i) + "," + std::to_string(j); { auto statement = db->prepare("SELECT value FROM rusqltest"); statement.execute(); uint64_t value; statement.bind_results(value); if(!statement.fetch()) { boost::mutex::scoped_lock lock(output_mutex); fail("First statement should succeed (iteration " + iteration + ")"); return; } if(statement.fetch()) { boost::mutex::scoped_lock lock(output_mutex); fail("Second statement should fail (iteration " + iteration + ")"); return; } } db->execute("UPDATE rusqltest SET value=value+1"); } { boost::mutex::scoped_lock lock(output_mutex); pass("Thread " + std::to_string(i) + " succeeded"); } } catch(...) { boost::mutex::scoped_lock lock(output_mutex); fail("Thread " + std::to_string(i) + " threw an exception"); } })); } for(auto &thread : threads) { thread->join(); } { auto statement = db->prepare("SELECT value FROM rusqltest"); statement.execute(); uint64_t result; statement.bind_results(result); statement.fetch(); test(result == NUM_THREADS * 1000, "the right amount of increments was done"); } db->execute("DROP TABLE rusqltest"); }