Intel Processor Trace

Overview

Intel PT 是一个处理器架构扩展, 它利用硬件来记录程序执行的 trace, 并且产生很小的开销. 控制流的信息通过数据包收集, 然后使用软件解码器解码. 这些数据包内容包括: 时间, 程序流信息 (e.g., 分支目标, 分支是否执行), program-induced mode related information (e.g., Intel TSX 状态转换, CR3 改变). Intel PT 后期的版本增加了 trace sources, 包括使用 PTWRITE 的 software trace instrumentation, 和 Power Event tracing.

Features and Capabilities

使用 PT 生成的数据包和程序的二进制文件, 可以重构出程序的执行 trace. 这些数据包记录的信息有: instruction pointers (IP), indirect branch targets, directions of conditional branches within contiguous code regions (basic blocks).

PT 可以使用 PTWRITE 来记录软件生成的数据包, 和一些处理器功耗的事件. 并且, Precise Event-based Sampling (PEBS) 也能通过配置, 在 PT 中记录.

PT 有几种控制和筛选机制, 完成自定义的 trace 信息收集. 比如可以通过 current privilege level 和 CR3 值进行筛选. 这些筛选可以通过设置 MSR 来进行.

Packet Summary

程序执行基本信息的数据包如下:

  • Packet Stream Boundary (PSB) packets: 心跳包, 每隔一定周期 (e.g., every 4K trace packet bytes) 自动生成. 可以作为数据包的边界来供 decoder 识别, decoder 解析的第一个包一定要是这个包.

  • Paging Information Packet (PIP): 记录 CR3 寄存器的修改情况. 通过结合操作系统中每个进程 CR3 的值, debugger 能够将线性地址和对应的进程 (源代码) 结合起来.

  • Time-Stamp Counter (TSC) packets: 记录时间.

  • Core Bus Ratio (CBR) packets: 包含 core:bus 的时钟频率比

  • Overflow (OVF) packets: 当处理器内部缓冲区溢出时设置, 可能其它的包被丢弃了, 解码器利用这个信息来同步正确的解码.

关于控制流信息的数据包如下:

  • Taken Not-Taken (TNT) packets: 记录直接条件分支的方向.

  • Target IP (TIP) packets: 记录间接分支, 异常, 中断和其他分支或事件的目的 IP. 里面存储的 IP 都是被压缩的, 并且存在不同类型的 TIP 包.

  • Flow Update Packets (FUP): 异步事件 (中断或者异常) 的源 IP. 还有其它不能从二进制文件中获取的源 IP 也通过这个包得到.

  • MODE packets: 提供解码器重要的处理器执行信息, 使得解码器能够解释反汇编的二进制程序和 trace log.

软件生成的数据包:

  • PTWRITE (PTW) packets: 包括传给 PTWRITE 指令的操作数的值.

Intel Processor Trace Operational Model

Change of Flow Instruction (COFI) Tracing

Basic block 之间的控制流转移指令叫做 COFI, 分为三种: 1. Direct transfer COFI, 2. Indirect transfer COFI, 3. Far transfer COFI.

同时, 按照不同的类型:

COFI Type Instructions
Conditional Branch Jcc , J*CXZ, LOOP
Unconditional Direct Branch JMP (E9 xx, EB xx), CALL (E8 xx)
Indirect Branch JMP (FF /4), CALL (FF /2)
Near Ret RET (C3, C2 xx)
Far Transfers INT1, INT3, INT n, INTO, IRE(T/TD/Q), JMP (EA xx, FF/5), CALL (9A xx, FF/3), RET (CB, CA xx), SYSCALL, SYSRET, SYSENTER, SYSEXIT, VMLANUCH, VMRESUME

Direct Transfer COFI

Direct Transfer COFI 是相对分支. 意味着他们的目标地址是当前的 IP 加上一个 offset. 因为二进制反汇编就可以得到直接跳转的 IP, 所以没有必要在 trace 中记录 IP. 对于条件分支, 只需要标记该分支是 taken or not 就行. 无条件分支都不需要任何记录.

  • Conditional Branch (Jcc, J*CXZ) and Loop: 编码一个 bit 的 TNT 就可以指示程序的控制流. 同时, 处理器会将多个 TNT bit 压缩成一个数据包.

  • Unconditional Direct Jumps: 不会生成 trace.

Indirect Transfer COFI

Indirect Transfer 指令会从寄存器或者内存地址中更新 IP, 所以 PT 就必须记录目的 IP, 使得 debugger 能够确定 COFI 的目的地址. 这个 IP 可能为 linear addres, 或 effective address.

Indirect Transfer 指令会生成一个包含目的地址的 Target IP Packet(TIP).

  • Near JMP Indirect and Near Call Indirect: 生成 TIP.

  • Near RET: 当 CALL 指令执行时, 它会将 CALL 后面那条指令的地址压栈. 在调用返回后, RET 指令会出栈这个返回i地址, 并 JMP 过去. 因为这个调用本身可能修改这个返回地址, 所以实际的返回地址在反汇编中仍不确定, 所以对于 RET 还是会生成一个 TIP 包.

    • RET Compression: 如果能保证 RET 的返回地址和压栈的返回地址完全一致, 可以仅生成一个 TNT 包表示走了这个分支. 不过这个得需要 decoder 作额外的处理.

Far Transfer COFI

所有改变 instruction pointer 的非 near jumps 指令都是 “far transfer”. 包括: 异常, 中断, trap, TSX abort, 和进行 far transfer 的指令.

所有的这些指令都会产生一个 TIP 数据包. 有一些 far transfer 在二进制代码中无法推断, 比如异步事件异常和中断, 这种会先产生 FUP 数据包提供事件源 IP, 再产生一个 TIP.

Software Trace Instrumentation with PTWRITE

PTWRITE 使得软件可以直接利用 PT trace. 每次将 64 bit 数据写入到 PT 产生的 PTW 数据包中. 解码器和分析软件能根据 PTWRITE 指令的 IP, 和数据内容确定这个数据的意义. PTWRITE 通过 IA32_RTIT_CTL.PTWEn[12]开启, 并且用户可以使用 IA32_RTIT_CTL.FUPonPTW[5] 在 PTW 包后面添加 FPU 包, 获取 PTWRITE 指令的 IP.

Power Event Tracing

Trace Filtering

Filtering by Current Privilege Level (CPL)

Intel PT 设置 trace 条件为 CPL = 0, 或者 CPL > 0, 使得 logical processor 生成对应 CPL 的数据包. CPL 筛选保证了只有满足条件的 IP 或者其它的架构信息能够被 trace, 比如说 trace 条件是 CPL > 0, 当软件执行 SYSCALL (CPL = 0)时, SYSCALL 的目的 IP 就不会出现在生成的数据包中.

在 real-address mode 和 virtual-8086 mode 时, CPL 分别为 0, 3.

Filtering by CR3

Intel PT 支持配置 CR3 筛选器, 能根据当前 CR3 的值生成 trace. 如果是多线程的程序, 可以通过切换 RTIT MSRs 的状态来分隔不同线程的输出.

设置 IA32_RTIT_CR3_MATCH MSR寄存器的值为目标 CR3 值, 然后设置 IA32_RTIT_CTL.CR3Filter, 就可以 trace 某个 CR3. 如果处理器被设置为 CPL = 0 时也能记录, 那么生成的 trace 中含有 PIP 数据包.

Filtering by IP

如果 CPUID.(EAX=14H, ECX=0):EBX[bit 2] = 1 时, Intel PT 能够仅在程序执行的 IP 在某个确定的范围内时, 生成 trace 数据包. 对 IA32_RTIT_CTL MSR 寄存器中的 ADDRn_CFG 域进行设置, 可以启用 IP filtering. 这个 n 是从零开始的数字, 用来选择配置的是哪个地址范围. 每个 ADDRn_CFG 都确定一组寄存器对的值 [base, limit], [IA32_RTIT_ADDRn_A, IA32_RTIT_ADDRn_B]. 选定的地址范围个数可以通过 CPUID 查看.

这个 base 和 limit 是 inclusive 的, 所以他包含边界.

TraceStop: 可以通过配置 IP 范围, 不对某些地址进行 trace, 若上述范围重叠, 重叠部分不 trace.

Packet Generation Enable Controls

Intel PT 包含多种控制机制来确定是否生成数据包. 一般来讲, 只要 Packet Enable (PacketEn) 被设置, 大多数数据包都会生成. PacketEn 是硬件的内部状态, 软件只能通过对 MSR 寄存器进行修改来对他进行配置.

Packet Enable (PacketEn)

当 PacketEn 被设置时, 处理器就能使用 PT 生成 trace. PacketEn 是几种状态的组合: PacketEn <- TriggerEn AND ContextEn AND FilterEn AND BranchEn. PacketEn 是处理器是否生成 trace 数据包的最根本的因素. 当它 enable 时, 所有的控制流数据包都会被 enable, 当它被 clear 时, 只有一些其它的数据包 (timing and bookkeeping packets) 生成. 不支持 IP Filtering 的处理器中 (i.e., CPUID.(EAX=14H, ECX=0):EBX.IPFILT_WRSTPRSV[bit 2] = 0), FilterEn 总是被 set.

Trigger Enable (TriggerEn)

Trigger Enable (TriggerEn) 是最主要的生成数据包的指示器. 使用 IA32_RTIT_CTL.TraceEn 来对它 set. 通过以下任意一个条件来 clear 它: (i) 使用软件 clear IA32_RTIT_CTL.TraceEn, (ii) 满足 TraceStop 条件, 并且 IA32_RTIT_STATUES.Stopped 被 set, (iii) IA32_RTIT_STATUS.ERROR 被 set. 软件可以通过查询 IA32_RTIT_STATUS.TriggerEn 来获取当前 TriggerEn 的值.

Context Enable (ContextEn)

Context Enable (ContextEn) 指示了处理器的 state 和 mode 是否满足软件之前的设置. 例如, 如果在 CPL = 0 状态下的代码执行没有被 trace (IA32_RTIT_CTL.OS = 0), 那么表明 CPL = 0 时, ContextEn 为 0. 软件可以通过查询 IA32_RTIT_STATUS.ContextEn 获取当前 ContextEn 的值.

1
2
3
4
ContextEn = !((IA32_RTIT_CTL.OS = 0 AND CPL = 0)
OR (IA32_RTIT_CTL.USER = 0 AND CPL > 0)
OR (IS_IN_A_PRODUCTION_ENCLAVE)
OR (IA32_RTIT_CTL.CR3Filter = 1 AND IA32_RTIT_CR3_MATCH does not match cr3))

如果 clear ContextEn 导致 PacketEn 被 clear, 就会生成一个 Packet Generation Disable (TIP.PGD) 数据包, 但是里面并没有 IP. 如果 set ContextEn 导致 PacketEn set, 那么 Packet Generation Enable (TIP.PGE) 就会生成.

当 ContextEn 被 clear, 控制流相关数据包 (TNT, FUP, TIP.*, MODE.*) 都不会生成, 并且不会暴露出 IP. 其它的包可能会生成.

只有当 TriggerEn = 1 时, ContextEn 的值才会变化, TriggerEn = 0 时, ContextEn 不会改变.

Branch Enable (BranchEn)

BranchEn 基于 IA32_RTIT_CTL.BranchEn 的值, 如果 BranchEn 没有被 set, 那么相关的 COFI 数据包 (TNT, TIP.*, FUP, MODE.*) 不会生成.

Filter Enable (FilterEn)

FilterEn 表示 IP 位于之前配置好的 IP 范围中. 软件可以查询 IA32_RTIT_STATUS.FilterEn 获取 FilterEn 的状态.

当 clear FilterEn 之后, 一个 Packet Generation Disable (PGD) 数据包会生成, 但和 ContextEn 不同的是, 目标 IP 数据还是在里面的. 所以可能会有范围之外的 IP 出现在 trace log 中. 当 FilterEn clear, 控制流的数据包就不会生成.

若处理器没有配置 trace range of IP, 或者处理器不支持 IP filtering, 那么 FilterEn 总是被 set. FilterEn 仅仅只会在 TraceEn 和 ContextEn 均为 1 的情况下, 同时在配置好 trace range 之后被开启关闭.

Trace Output

Intel PT 的输出和 trace 内容, 筛选机制独立. 不同的处理器和平台, 支持不同的输出选项. 使用 IA32_RTIT_CTL 中 ToPA 和 FabricEn 域配置输出策略为以下的一种:

  • 单个, 连续的物理内存地址空间.

  • 多个不同大小的物理内存区域的集合. 这些区域通过一个表来连接和索引, 即 Table of Physical Addresses (ToPA). Trace 的输出绕过 cache 和 TLB 直接写入物理内存, 这个输出策略对性能影响最小, 但输出不一定是序列化的.

  • 平台特定的 trace 传输子系统.

不管选择哪个输出策略, 输出都会绕过 cache. 这保证了 trace 不会消耗宝贵的 cache 空间, 但是和一般的 uncacheable 内存区域的写入不同, trace 输出的写入并不是序列化的. 不要对输出的物理地址区域使用 MTRR 或者 PTE 配置 UnCacheable.

我们并不能控制 trace 在何时输出到物理内存中. 唯一能保证的就是, 将 TraceEn clear, 停止 trace, 并执行 store, fence 或者序列化指令, 从而将处理器内存缓冲区的所有 trace 数据包 flush 到物理内存中.

Single Range Out

当 IA32_RTIT_CTL.ToPA 和 IA32_RTIT_CTL.FabricEn 的 bit 是 clear 状态时, trace 数据包会发送到一块连续的物理内存空间 (or MMIO) 中. 这个物理内存空间通过 IA32_RTIT_OUTPUT_BASE 和 IA32_RTIT_OUTPUT_MASK_PTRS 中的 mask 值来确定. 当前的写入指针也存储在 IA32_RTIT_OUTPUT_MASK_PTRS 中, 这个范围是环形的, 在到达缓冲区末尾之后会重新将写入指针移动到缓冲区的 base.

这个方法最好是用在以下场景:

  • DRAM 中有足够大的连续空间时

  • 输出到 MMIO 调试端口.

Table of Physical Addresses

当 IA32_RTIT_CTL.ToPA 是 set, IA32_RTIT_CTL.FabricEn 是 clear 时, 就使用 ToPA 机制. ToPA 使用的是一个环形链表, 每个节点都是一个 table. Table 中的每个 entry 都包含一个物理内存区域 (output region) 的 base 指针和大小, 如果是最后一个 entry, 那就可能存放下一个 table 的物理内存地址.

处理器将这些物理内存区域看作一个统一的 buffer, 所以一个数据包可能横跨两个 output region.

ToPA 机制可以用以下三个值来控制:

  • proc_trace_table_base: 这是当前 table 的物理地址. 从 IA32_RTIT_OUTPUT_BASE MSR 寄存器中获取.

  • proc_trace_table_offset: 当前 table 正在被使用的 entry. 从 IA32_RTIT_OUTPUT_MASK_PTRS 中的 31:7 位获取.

  • proc_trace_output_offset: 当前 output region 中的指针. 从 IA32_RTIT_OUTPUT_MASK_PTRS 中的 63:32 位获取.

当 trace packet 按照规则写入物理内存时, 若碰到有 entry 标记为 END, 就需要更新 table_base 来切换到下个 table. 若为 STOP,在充满当前 output region 之后停止 trace. 如果一直没有 END 标记或者 STOP 标记, 那么在到达最大 table 大小 (proc_trace_table_offset = 0x0ffffff8h) 之后, 会将 table_offset 和 output_offset 置 0, 循环输出.

很重要的一点是, 处理器对 IA32_RTIT_OUTPUT_BASE 和 IA32_RTIT_OUTPUT_MASK_PTRS MSR 寄存器的更新和指令执行是异步的, 所以直接读取 MSR 得到的值可能是旧的值. 要得到正确的值必须先停止 trace 数据包生成 (clear IA32_RTIT_CTL.TraceEn), 再读取.

同时, 处理器可能会内部 cache 一些 table 的 entry. 如果要修改这些 entry, 也得先停止 trace 再更改.

第一代实现 PT 的处理器只能将 ToPA 配置为 single output region 的模式.

以下是几个 entry 标记的用途:

  • ToPA STOP: 当前 output region 满了之后, set IA32_RTIT_STATUS.Stopped 位, 停止 trace. 这类停止没有 TIP.PGD 数据包发出, 并且意味着 CPU 内部缓冲区中的数据包就被丢弃了.

  • ToPA PMI: 当 INT 标记被设置时, 当前 output region 充满之后就会发出一个 performance-monitoring interrupt 中断. 这个中断也是异步的, 不精确. 并且中断处理的过程也能被 trace, 可以通过 filtering 来解决这个污染. 所以, PMI handle 如果想读取 trace 数据包, 一定要先 clear TraceEn, 停止 trace.

管理 Intel PT ToPA PMI 和 XSAVES/XSTORES 的算法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
IF (IA32_PERF_GLOBAL_STATUS.ToPA)
Save IA32_RTIT_CTL Value;
IF (IA32_RTIT_CTL.TraceEn)
Disable Intel PT by clearing TraceEn;
FI;
IF (There is space available to grow the current ToPA table)
Add one more ToPA entries after the last entry in the ToPA table;
Point new ToPA entry address fields to new output region base;
ELSE
Modify an upcoming ToPA entry in the current table to have END = 1;
IF (out put should translation to a new ToPA table)
Point the address of the "END = 1" entry of the current table to the new table address base;
ELSE
/* make a circular*/
Point the address of the "END = 1" entry to the base of the current table;
Modify the ToPA entry address fields for filled output regions to point to new, unused output regions;
FI;
FI;
Restore saved IA32_RTIT_CTL.value;
FI;

Trace Transport Subsystem

Restricted Memory Access

Trace 数据包的输出的目的内存区域不能为限制的区域, 比如说所有的输出区域都会受到 SMRR (System-Management Range Register) 的限制, 所有和它重叠的区域都不能作为 output region.

可以先关闭 trace 数据包生成, 再修改 SMRR, 然后再生成数据包.

Enabling and Configuration MSRs

General Consideration

Trace 数据包的生成可以通过一系列 MSRs 来进行维护:

  • 处理器不支持 Intel PT 时, 使用 RDMSR 或 WRMSR 操作 IA32_RTIT_* 系列的 MSRs 都会造成 #GP.

  • 在改变 MSRs 之前, 一定要先 clear IA32_RTIT_CTL.TraceEn, 不然也会 #GP.

  • 每个 logical processor 都是一套不同的 MSRs. 意思是每次配置, 都是在一个 logical processor 上配置的.

  • 在 cold REST 之后, 所有的 MSRs 配置都被清除

    • 如果 CPUID.(EAX = 14H, ECX = 0):EBX.IPFILT_WRSTPRSV[bit 2] = 1, 那么在 warm REST 之后, 只有 TraceEn bit 被清除, 同时可能影响 IA32_RTIT_STATUS. 但是其它 MSRs 不受影响.
  • 除了可以通过 WRMSR 来显式修改外, 还可以使用 VM-exit 或者 VM-entry, XRSTORS, XSAVE 来修改.

IA32_RTIT_CTL MSR

Position Bit Name At Reset Bit Description
0 TraceEn 0 1: tracing, 0: tracing disabled. 从 1 到 0 时, CPU 内部缓冲区会被 flush
1 CYCEn 0 0: disables CYC Packet, 1: enable CYC Packets
2 OS 0 0: 当 CPL = 0 时,不生成数据包, 1: CPL = 0 时生成数据包
3 User 0 0: 当 CPL > 0 时, 不生成数据包, 1: 当 CPL > 0 时, 生成数据包
4 PwrEvtEn
5 FUPonPTW 0 0: PTW 包后面不跟 FUP 包, 1: 跟
6 FabricEN 0 0: 使用 ToPA, 1: 不使用
7 CR3Filter 0 0: 关闭 CR3 filtering, 1: 开启
8 ToPA 0 0: Single-range output, 1: ToPA output
9 MTCEn 0 0: disable MTC packets, 1: enable
10 TSCEn 0
11 DisRETC 0 0: enable RET compression, 1: disable
12 PTWEn 0 0: PTWRITE Packet generation disabled, 1: enable
13 BranchEn 0 0: disable COFI-based packets, 1:enable
17:14 MTCFreq 0 定义 MTC 数据包的频率, 可以基于 Always Running Timer (ART).
22:19 CycThresh 0 CYC packet threshold.
27:24 PSBFreq 0 控制 PSB 的生成频率, 但是不精确
35:32 ADDR0_CFG 0 0: 不使用 ADDR0, 1: 相关的 MSRs 定义了 IP Filter 的上下界, 2: 相关的 MSRs 定义了 TraceStop 上下界
39:36 ADDR1_CFG 0
43:40 ADDR2_CFG 0
47:44 ADDR3_CFG 0
56 InjectPsbPmiOnEnable 0 1: Enable IA32RTIT_STATUS 的 PendPSB, PendTopaPMI, 0: disable

Enabling and Disabling Packet Generation wth TraceEn

当 TraceEn 从 0 到 1 时, Intel PT 就开始工作, 一系列的数据包开始生成. 这些包能帮助 decoder 获取处理器的状态. 如果 IA32_RTIT_STATUS.PacketByteCnt = 0, 那么就会生成 full PSB+, 如果不为 0, 那么会生成和 timing 相关的数据包, TSC, TMA, CRR 等.

除了上述包, 还可能会有 TIP.PGE 数据包生成. 当处理器生成 trace 时, CPU 会将 ToPA 相应的数据结构放入 cache 提高性能, 所以要修改 ToPA tables 的话, 必须先停止 TraceEn, 再修改.

IA32_RTIT_STATUS MSR

IA32_RTIT_STATUS MSR 是可以使用软件来读写的, 但是有一些位 ContextEn, TriggerEn, 不能直接被修改.

Position Bit Name At Reset Bit Description
0 FilterEn 0 表示当前 IP 是能被 trace 的
1 ContextEn 0 当前上下文是能被 trace 的
2 TriggerEn 0 表示 trace 开启
4 Error 0 表示操作出错, 当它被 set 时, TriggerEn 被 clear, trace 终止
5 Stopped 0 表示 ToPA STOP 标志
6 PendPSB 0 set 时会插入一个 PSB+ 到 trace 中, 插入后 clear
7 PendTopaPMI 0 set 时表示要触发 PMI, 触发完毕就 clear
48:32 PacketByteCnt 0 表示已经发出数据包的 bytes, 可以用它来触发下一个 PSB 包的发送, 在 trace 过程中, 处理器会一直修改这个值.

IA32_RTIT_ADDRn_A and IA32_RTIT_ADDRn_B MSRs

这些 MSRs 可以通过 IA32_RTIT_CTL 中的 ADDRn_CFG 域来启用.

IA32_RTIT_CR3_MATCH MSR

当 IA32_RTIT_CTL.CR3Filter = 1 时, 会把它与当前 CR3 作比较. 63:5 这几位保存了 CR3 的值.

IA32_RTIT_OUTPUT_BASE MSR

这个是用来配置 trace 输出的目的物理地址, 它的大小受到最大物理地址宽度的限制 (MAXPHYADDR), 从 CPUID.80000008H:EAX[7:0]获取.

当使用 ToPA 输出模式时, 处理器可能会更新这个 MSR 的值, 但是指令的执行和处理器的更新是异步的, 所以这个 MSR 里面的值在 trace 期间是 unreliable 的.

IA32_RTIT_OUTPUT_MASK_PTRS MSR

这个 MSR 存储的是 trace 下一个 byte 输出的位置. 和上面一样, 异步更新, unreliable.

Position Bit Name At Rest Bit Description
6:0 LowerMask 7FH 强制为 1
31:7 MaskOrTableOffset 0 这个值的意义取决于 IA32_RTIT_CTL.ToPA 的值. 若 ToPA = 0, 表示这就是 single, contiguous physical output region 的 mask value. 所以, 这个区域的大小一定是在 128B 到 4GB. 若 ToPA = 1, 表示的是当前 ToPA table 中 offset pointer 的 27:3 bits, 加上上面的 IA32_RTIT_OUTPUT_BASE 可以获取当前 entry 的指针. 每个 table 大小最大为 256 MB.
63:32 Output offset 0 这个值的意义取决于 IA32_RTIT_CTL.ToPA 的值. 若 ToPA = 0, 表示这个是 single, contiguous physical output region 的 offset pointer. 加上 IA32_RTIT_OUTPUT_BASE 的值就可以得到下个 byte 要写入的地址. 这个值一定要小于等于 MaskOrTableOffset. 若 ToPA = 1, 这个是当前 ToPA output region 的 offset pointer. 加上 output region 的 base 之后, 可以获得下个 byte 写入的地址

Interaction of Intel Processor Trace and Other Processor Features

TODO

CONFIGURATION AND PROGRAMMING GUIDELINE

Detection of Intel Processor Trace and Capability Enumeration

见代码

Packet Decoding of RIP versus LIP

FUP, TIP, TIP.PEG 和 TIP.PGD 可能会包含 IP payload. 在有些处理器中, 这个 payload 是 effective address (RIP), 其它就是 linear address (LIP). 前面的模式下, payload 里面的值是距离 code segment base (CS) 的偏移, 后面的是偏移加上 code segment base. 对于执行过程中 CS base address 为 0 的软件 (64 bit mode), 这两者没有区别.

对于 IP filtering 和 TraceStop 中配置的 IP 类型, 也需要和这个保持一致.

Model Specific Capability Restrictions

有一些处理器在进行 trace 的过程中, 限制了对 LBRs/BTS/BTM/LERs 等 MSRs 的使用.

Enabling and Configuration of Trace Packet Generation

首先检测是否支持 Intel PT, 然后再配置一系列 MSRs 进行 Trace.

以下是 Skylake (6th gen), Kaby Lake (7th gen), Coffee Lake (8th gen and 9th gen), Cannon Lake (8th gen i3) 的 PT 相关 MSRs.

Hex Dec Register Name Scope Desc
0x560H 1376 IA32_OUTPUT_BASE Thread Trace Output Base Register (R/W)
0x561H 1377 IA32_OUTPUT_MASK_PTRS Thread Trace Output Mask Pointer Register (R/W)
0x570H 1392 IA32_RTIT_CTL Thread Trace Control Register (R/W)
0x571H 1393 IA32_RTIT_STATUS Thread Tracing Status Register (R/W)
0x572H 1394 IA32_RTIT_CR3_MATCH Thread Trace Filter CR3 Match Register (R/W)
0x580H 1408 IA32_RTIT_ADDR0_A Thread Region 0 Start Address (R/W)
0x581H 1409 IA32_RTIT_ADDR0_B Thread Region 0 End Address (R/W)
0x582H 1410 IA32_RTIT_ADDR1_A Thread Region 1 Start Address (R/W)
0x583H 1411 IA32_RTIT_ADDR1_A Thread Region 1 End Address (R/W)

Enabling Packet Generation

set IA32_RTIT_CTL 中的 TraceEn.

Disabling Packet Generation

clear IA32_RTIT_CTL 中的 TraceEn, 然后再看看 IA32_RTIT_STATUS MSR 中的 Error bit 和 Stopped bit, 判断停止 trace 的原因.

Flushing Trace Output

数据包都是在 CPU 内部 buffer 中被异步的写入内存. 所以解码器必须先停止 trace 使得所有的数据包都被 flush out.

Warm reset

在 Warm reset 时, MSR 里面配置的内容不会丢失, 除了 TraceEn, 和 IA32_RTIT_STATUS 中的某些 bit.

Manual Trace Configuration Context Switch

可以通过 RDMSR, WRMSR 来将配置进行 save, 和 restore. 保存 trace 配置上下文的方法如下:

  1. RDMSR IA32_RTIT_CTL, 将值保存到内存

  2. WRMSR IA32_RTIT_CTL, 将上面保存的值写入 MSR, 但是注意写入之前 clear TraceEn

  3. 将其它的 MSR 的配置使用 RDMSR 读取, 将更改后的值保存在内存中

恢复 trace 配置上下文过程:

  1. 将保存在内存的值写入到 MSR, 除了 IA32_RTIT_CTL

  2. 将保存在内存中 IA32_RTIT_CTL 的值写入 MSR

Trace Configuration Context Switch Using XSAVES/XRSTORS

TODO

Cycle-Accurate Mode

CYC 数据包提供处理器 core clock domain 的底层信息. 只和指令执行的 时间 相关.

TODO

Decoder Synchronization (PSB+)

Decoder 使用 PSB 数据包作为 trace log 的同步点. 除了简单的同步之外, decoder 还需要知道一些状态 (state) 信息和潜在的时间信息. Decoder 每次获取的信息一定是在两个 PSB 之间的, 比如 LastIP, call stack, compound packet event.

当 PSB 生成时, 在它之后会有一个 PSBEND 数据包. 在这两个数据包之间的是 decoder 需要了解的处理器状态 (state) 信息. 这些数据包就是 PSB+, 他们表示的是 status, 并不会改变 PSB 的 state, 也和其它指令没什么关系. PSB+ 可以包括当前的 Timestamp.

Internal Buffer Overflow

TODO

Trace Packets and Data Types

Packet Relationships and Ordering

这一节主要讲, 怎么把这些数据包中和反汇编的的代码绑定 (binding) 起来. 有一些数据包 (TIP, FUP) 的 payload 就有关联的 IP, 其它的数据包 (TNT) 需要由 decoder 来查找具体的指令来绑定. Decoder 都需要考虑到这些数据包之间的关系, 然后使用这些关系来确定如何 bind 这些数据包.

有一些叫做 “compound packet event” 的事件, 比如中断, 异常等, 只需要一条指令就能产生多个数据包. 这些 compound event 生成的数据包很多都是以 FUP 开头来表示 source address, 然后以 TIP 或者 TIP.PGD 结尾来表示 destination address. 在这个场景下, 就可以说 FUP is “coupled with” TIP. 有一些其它的包可能处于这两者中间, 比如和时间相关的, 和状态相关的.

Event Type Beginning Middle End Comment
Unconditional, uncompressed control-flow transfer FUP, or none Any combination of PIP, VMCS, Mode.Exec, or None TIP or TIP.PGD FUP only for asynchronous events. Order of middle packets may vary. PIP/VMCS/MODE only if the operation modifies the state tracked by these respective packets
TSX Update MODE.TSX, and (FUP or none) None TIP, TIP.PGD, or none FUP TIP/TIP.PGD only for TSX abort case
Overflow OVF PSB, PSBEND, or none FUP or TIP.PGE FUP if overflow resolves while ContextEn = 1, else TIP.PGE

Packet Blocks

Packet blocks 是用来 dump 一些状态值的. 具体看手册.