Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query capabilities directly into the C# language. Traditionally, queries against data are expressed as simple strings without type checking at compile time or IntelliSense support. Furthermore, you have to learn a different query language for each type of data source: SQL databases, XML documents, various Web services, and so on. With LINQ, a query is a first-class language construct, just like classes, methods, events. You write queries against strongly typed collections of objects by using language keywords and familiar operators. The LINQ family of technologies provides a consistent query experience for objects (LINQ to Objects), relational databases (LINQ to SQL), and XML (LINQ to XML).
受沈沉舟前辈《TTD历史回顾^14》一文启发,我对TTD进行了一番互联网考古。发现在互联网历史中人们更习惯说Reverse Debugging,而非Time Traveling Debugging,Jakob在《A new (and old) Reverse Debugger – Microsoft WinDbg^15》一文最后 TTD? Reverse? 一节里写到说目前为止,还是很多工具、项目和公司用的是反向调试。
It seems that time-traveling debug or time travel debugging is becoming more common as a term (again). Still, most tools and companies and projects still talk about reverse debugging. Undo, RR, gdb, and Simics all use “reverse” to describe the feature. If I look at the history of the field as far as I have been able to trace it, most people call it reverse until the a 2005 paper introduces “time-traveling virtual machines”.
For more on the history of reverse debuggers, see my three-part series of blogs from 2012 that I have since updated as new products and tools have appeared or been found in the archive of history: history 1, history 2, history 3.
一方面,这种基于录制的Trace-based debugging只是反向调试的一种,主要体现为调试工作都在trace上进行,在《Reverse History Part One^17》文中有段有详细写到:
Trace-based debugging is based on recording everything a system does into a trace, and once the recording is done, debugger works on the trace rather than using the log to drive an actual system. Reverse debug is implemented by recreating the state of a system by reading the trace, and finding points in the trace where breakpoint conditions are true. This is also known as post-mortem debug, since you debug after the target system has finished executing (typically). A log can be captured by a hardware device, or by software being instrumented to log everything that is going on. The technology can also be used to implement record-replay debugging.
Simics reverse execution and reverse debugging is a unique and very powerful feature of the simulator. In this blog post and accompanying video, we will look at what exactly it is you can do with reverse execution in Simics. It is not just a matter of running backwards to a breakpoint or stepping instructions (pick up my 2012 S4D article for more on reverse debugging). Reverse execution fundamentally is about undoing arbitrary operations on the target and going back to a prior state from a previous point in time. Furthermore, with Simics, you can go back in time and choose to do something different than you did in the original execution.
另一方面,像TTD的话,不完全是Trace-based,还混合了重执行技术,Jakob在《A new (and old) Reverse Debugger – Microsoft WinDbg^15》文中称为“a mix of re-execution and trace-based reverse debug”,
There is mention of the emulator-based approach in the docs – it is found in a note about “derailment”, where the reverse debugger realizes that it has created an inconsistent current state of the program during reverse. From the TTD docs:
“TTD works by running an emulator inside of the debugger, which executes the instructions of the debugged process in order to replicate the state of that process at every position in the recording. Derailments happen when this emulator observes some sort of discrepancy between the resulting state and information found in the trace file.”
The key to making this work efficiently and without gigantic trace files is to only record the memory values that cannot be reconstructed by running the code. Thus, we have a mix of re-execution and trace-based reverse debug, where the re-execution engine is used for short sequences of instructions, before getting the state forced back to the trace as needed.
The “key frames” used in the time concept are more like checkpoints in Simics reverse debugging, in that they represent a complete state across all threads. It makes it easy for the debugger to jump to certain points in the execution and set up a consistent state across the threads there. Neat and useful.
Furthermore, since debugging is the process of tracing effects to their causes, it's much easier if your debugger can execute backwards in time. It's well-known that given a record/replay system which provides restartable checkpoints during replay, you can simulate reverse execution to a particular point in time by restoring the previous checkpoint and executing forwards to the desired point.
5.ttdcursor.ReplayForward(&replayrez, last, -1),第三个形参是-1的话,无法触发call、ret回调函数,这个坑让我十分困惑,不过没多久我在仓库的issues里面发现yara-ttd的作者atxr提了issue描述了这个问题(github.com/commial/ttd-bindings/issues/27)。。。
uint64_t pc = thread_view->IThreadView->GetProgramCounter(thread_view);
TTD::Position* position = thread_view->IThreadView->GetPosition(thread_view);
if( pc > calcViewModelStart and pc < calcViewModelStart + calcViewModelSize) {
printf("(%llx) [%llx:%llx] Enter CalcViewModel, start stepping-by-steping to search for calc instructions.\n", addr_func, position->Major, position->Minor);