LYYL' Blog

勿忧拂意,勿喜快心,勿恃久安,勿惮初难。

0%

Intel Processor Trace

概览

Intel 在Intel Core M和第五代Intel处理其中引入了Intel Processor Trace(IPT),即程序追踪,通过采用专用的硬件将程序的控制流以包的形式记录下来,以达到最低的性能消耗和更高的记录效率。生成的数据包均为高度压缩的数据,因此需要使用相应的软件进行解码。生成的数据包包括时间,程序流信息(例如,分支目标,分支跳转)和程序诱导的模式相关信息(例如,Intel TSX状态转换,CR3寄存器的改变)。 这些数据包在发送到内存子系统或平台中可用的其他输出机制之前,可以在内部进行缓冲。 调试软件可以处理跟踪数据并重建程序流程。

特性和功能

英特尔PT的控制流跟踪会生成各种数据包,这些数据包在通过后处理工具与程序的二进制文件结合使用时,可用于生成精确的执行流跟踪。数据包记录连续信息区域(基本块)内的流信息,例如指令指针(IP),间接跳转目标和条件跳转的方向。还可以将Intel PT配置为使用PTWRITE记录软件生成的数据包以及描述处理器电源管理事件的数据包。此外,数据包还记录了其他上下文,时间和登录信息,从而可以对应用程序进行功能和性能调试。英特尔PT具有多种控制和过滤功能,可用于自定义收集的跟踪信息,并附加其他处理器状态和时序信息以启用调试。例如,有些模式允许基于当前特权级别(CPL)或CR3的值对数据包进行过滤。数据包生成和过滤功能的配置通过一组MSR寄存器进行编程。 MSR通常遵循IA32_RTIT_ *的命名约定。这些配置MSR提供的功能由CPUID枚举,请参见第36.3节。有关配置Intel PT的MSR的详细信息,请参见第36.2.7节。

数据包介绍

跟踪工具启用并配置了适当的MSR之后,处理器将收集并生成以下几类数据包中的跟踪信息(有关数据包的更多详细信息,请参阅第36.4节):

  • 有关程序执行基本信息的数据包:这些数据包包括:
    • 数据包流边界(PSB)数据包:PSB数据包充当定期生成的“心跳”数据包。 这些数据包使数据包解码器可以找到输出数据流中的数据包边界。 PSB数据包应该是解码器开始解码轨迹时要查找的第一个数据包。
    • page information packet(PIP):PIP记录对CR3寄存器所做的修改。 此信息以及来自操作系统的有关每个进程的CR3值的信息,使调试器找到该线性地址对应的应用程序。
    • 时间戳计数器(TSC)数据包:TSC数据包有助于跟踪挂钟时间,并且包含软件可见的时间戳计数器的某些部分。
    • Core Bus Ratio packets
    • 溢出(OVF)数据包:当处理器遇到内部缓冲区溢出而导致数据包丢失时,将发送OVF数据包。 该分组将丢失通知给解码器,并且可以帮助解码器对这种情况做出响应。
  • 有关控制流信息的数据包
    • TNT数据包:该数据包将记录程序执行过程中发生的直接条件跳转。直接函数调用和直接跳转则不会被记录
    • TIP数据包:TIP数据包记录间接分支,异常,中断以及其他分支或事件的目标IP。 这些数据包可以包含IP,这里保存的IP是通过消除与最后一个IP匹配的高字节进行压缩的IP值。 TIP数据包有多种类型。 它们在36.4.2.2节中有更详细的介绍。
    • FUP数据包:FUP提供异步事件(中断和异常)的源IP地址,以及无法从二进制文件确定源地址的其他情况。
    • MODE数据包:这些数据包为解码器提供了重要的处理器执行信息,以便它可以正确解释反汇编的二进制和跟踪日志。 MODE数据包具有指示详细信息的各种格式,例如执行模式(16位,32位或64位)。
  • 通过软件插入的数据包:
  • 有关处理器电源管理事件的数据包:

INTEL®处理器跟踪操作模型

本节介绍了总体英特尔处理器跟踪机制以及与它的工作方式有关的基本概念。

指令流追踪(COFI)

基本块是一段不会发生跳转或分支的顺序执行的代码块。 无需跟踪此代码块中的指令指针(IP),因为处理器将从基本块的起始执行到基本块的结束。 诸如分支之类的指令以及诸如异常或中断之类的事件可以改变程序执行流。 这些改变程序流程的指令和事件称为流程变更指令(Change of Flow Instruction, COFI)。 COFI分为三类:

  • 直接转移COFI
  • 间接转移COFI
  • 长距离转移COFI

以下小节介绍了导致跟踪数据包生成的COFI事件。 表36-1按COFI类型列出了分支指令。 有关特定说明的详细说明,请参阅《英特尔®64和IA-32架构软件开发人员手册》。

2020-04-13_100548.jpg

直接跳转指令流追踪

直接转移COFI是相对分支。 这意味着它们的目标是一个IP,其与当前IP的偏移量嵌入在指令字节中。 无需在跟踪输出中指示这些指令的目标,因为可以通过二进制文件分析来获得目标地址。 条件分支仅需要指示是否已采取分支。 无条件分支在跟踪输出中不需要任何记录。 有两个子类别:

  • 条件分支(Jcc,J * CXZ)和LOOP

    为了跟踪此类指令,处理器对单个位(taken or not taken – TNT)进行编码,以指示指令之后的程序流程。 可以使用TNT位跟踪Jcc,J * CXZ和LOOP。 为了提高跟踪数据包的输出效率,处理器会将几个TNT位压缩为一个数据包。

  • 无条件直接跳转

    直接无条件跳转不需要任何跟踪输出,因为可以从应用程序组装中直接推断出它们。 尽管TIP.PGD和TIP.PGE数据包可以通过无条件直接跳转来切换Intel PT启用,但直接无条件跳转不会生成TNT或TIP数据包(请参阅第36.2.5节)。

间接跳转指令流追踪

间接传输指令涉及从寄存器或存储器位置更新IP。 由于寄存器或存储器的内容可以在执行期间的任何时间变化,因此在读取寄存器或存储器的内容之前,无法知道间接转移的目标。而且反汇编的代码不足以确定这种类型的COFI的目标。 因此,跟踪硬件必须在跟踪数据包中包含目标IP,以便调试软件确定COFI的目标地址。 请注意,该IP地址可以是线性地址或有效地址(请参见第36.3.1.1节)。 间接传输指令会生成目标IP数据包(TIP),其中包含分支的目标地址。 有两个子类别:

  • Near JMP indirect和Near Call indirect

    如前所述,间接COFI的目标位于寄存器或内存位置的内容中。 因此,处理器必须生成一个包含此目标地址的数据包,以允许解码器确定程序流。

  • Near RET

    执行CALL指令时,会将CALL之后的下一条指令的地址压入堆栈。 调用过程完成后,通常使用RET指令将返回地址弹出调用堆栈,并将代码流重定向回CALL之后的指令。 RET指令只是将程序流转移到它从堆栈弹出的地址。 由于被调用的过程可能会在执行RET指令之前更改堆栈上的返回地址,因此如果调试软件假定代码流将返回到最后一个CALL之后的指令,则可能会误导调试软件。 因此,即使对于 near RET,也会产生TIP数据包。

    • RET压缩

      如果RET的目标与跟踪CALL堆栈所期望的一致,则采用特殊情况。 如果确定解码器已经看到对应的CALL(“对应”定义为堆栈深度匹配的CALL),并且RET目标是该CALL之后的指令,则RET目标可以被“压缩”。 在这种情况下,仅生成一个TNT位“ taken”而不是TIP数据包。 为了确保在RET压缩的情况下不会使解码器混淆,可以在给定的逻辑处理器中压缩与自最后一个PSB数据包以来已经看到的CALL对应的RET。 有关详细信息,请参见第36.4.2.2节中的“针对ret的间接转移压缩”。

长跳转指令流追踪

更改指令指针且不为near jmp的所有操作均为“长距离转移”。 这包括异常,中断,陷阱,TSX中止以及进行长距离跳转的指令。 所有的长距离转移都将产生TIP数据包,该数据包将提供目标IP地址。 对于无法从二进制源推断出的那些长距离转移(例如,诸如异常和中断之类的异步事件),在TIP之前将添加一个流更新包(FUP),该包提供事件发生时的源IP地址。表36-23准确显示了长距离跳转生成的FUP中将包括哪个IP。

image-20200421151658717

// PWRITE和电源事件追踪

Trace过滤

英特尔处理器跟踪提供了过滤功能,调试/配置工具可通过该功能控制要跟踪的代码。

按当前特权级别(CPL)过滤

英特尔PT提供了将逻辑处理器配置为仅在CPL = 0,CPL> 0或与CPL无关时才生成跟踪数据包的功能。

CPL过滤可确保在日志中看不到与过滤后的CPL相关的IP或其他体系结构状态信息。 例如,如果将处理器配置为仅在CPL> 0时进行跟踪,当软件执行SYSCALL(将CPL更改为0)的时候,生成的数据包中不会包含SYSCALL的目标IP(请参见 36.4.2.5节)。 应该注意的是,在real-address模式下CPL始终为0,而在虚拟8086模式下CPL始终为3。 要在这些模式下跟踪代码,应配置相应的过滤。 在未启用的CPL情况下中执行软件时,将清除ContextEn。 有关详细信息,请参见第36.2.5.1节。

通过CR3寄存器过滤

IPT支持CR3过滤机制,通过该机制,可以基于CR3的值来启用或禁用包含体系结构状态的数据包的生成。调试器可以使用CR3筛选来仅跟踪单个应用程序,而无需上下文切换RTIT MSR的状态。为了从具有多个线程的软件中重建执行流,调试软件可能希望对RTIT MSR的状态进行上下文切换(如果操作系统不提供上下文切换支持),以将不同线程的输出分开(请参见 36.3.5,“上下文切换注意事项”)。

要仅跟踪单个CR3值,软件可以将该值写入IA32_RTIT_CR3_MATCH MSR,并设置IA32_RTIT_CTL.CR3Filter。当CR3值与IA32_RTIT_CR3_MATCH和IA32_RTIT_CTL.CR3Filter不匹配时,ContextEn被强制设置为为0,并且不会生成包含体系结构状态的数据包。当ContextEn为0时,可能会生成其他一些数据包。有关详细信息,请参见第36.2.5.3节。当CR3与IA32_RTIT_CR3_MATCH匹配时(或当IA32_RTIT_CTL.CR3Filter为0时),CR3过滤不会将ContextEn强制设置为0(尽管由于其他过滤器或模式,它可能为0)。

如果两个寄存器的位63:12相同,或处于PAE分页模式时的63:5,则CR3与IA32_RTIT_CR3_MATCH匹配; CR3和IA32_RTIT_CR3_MATCH的低5位被忽略。 CR3过滤与CR0.PG的值无关。使用CR3过滤时,如果处理器配置为在CPL = 0(IA32_RTIT_CTL.OS = 1)时进行跟踪,则仍可以在日志中看到PIP数据包。如果没有,将看不到PIP数据包。

通过IP进行过滤

如果CPUID.(EAX = 14H,ECX = 0):EBX [bit 2] = 1,则支持通过IP可配置过滤的跟踪数据包生成。Intel PT可配置为仅在处理器为在特定IP范围内执行代码。如果IP不在这些范围内,则会阻止某些数据包的生成。使用IA32_RTIT_CTL MSR(第36.2.7.2节)中的ADDRn_CFG字段启用IP过滤,其中数字“ n”是从零开始的数字,用于选择要配置的地址范围。每个ADDRn_CFG字段配置寄存器对IA32_RTIT_ADDRn_A和IA32_RTIT_ADDRn_B的使用(第36.2.7.5节)。 IA32_RTIT_ADDRn_A定义了基数,IA32_RTIT_ADDRn_B指定了启用跟踪的范围的限制。因此,每个范围(称为ADDRn范围)由[IA32_RTIT_ADDRn_A]定义。 IA32_RTIT_ADDRn_B]。可以有多个这样的范围,软件可以查询CPUID(第36.3.1节)以获取处理器支持的范围数。默认行为(ADDRn_CFG = 0)没有定义IP过滤器范围,这意味着始终设置FilterEn。在这种情况下,可以跟踪任何IP上的代码,尽管其他过滤器(例如CR3或CPL)可能会限制跟踪。当将ADDRn_CFG设置为启用IP过滤(请参阅第36.3.1节)时,将在看到目标地址在ADDRn范围内的已采用分支或事件时开始跟踪。在跟踪区域内并设置FilterEn时,只有在目标范围之外的已采取分支或事件被淘汰后,才能检测到离开跟踪区域。如果通过执行下一条顺序指令(而不是通过控制流传输)进入或退出ADDRn范围,FilterEn可能不会立即切换。有关FilterEn的更多详细信息,请参见第36.2.5.5节。请注意,这些地址范围的基值和极限值是包括在内的,因此该范围包括第一条指令和最后一条指令,其第一条指令字节在ADDRn范围内。根据处理器的实现,IP过滤可以基于线性或有效地址。如果CSbase不等于零或处于实模式,则这可能导致实现之间的行为不同。有关详细信息,请参见第36.3.1.1节。软件可以查询CPUID来确定过滤器是基于线性地址还是有效地址(第36.3.1节)。

请注意,某些数据包,例如MTC(第36.3.7节)和其他计时数据包,不依赖FilterEn。 有关哪些数据包依赖FilterEn并因此受IP过滤影响的详细信息,请参见第36.4.1节。

Trace Stop

ADDRn范围也可以配置为导致在进入指定区域时禁用跟踪。这旨在用于执行意外代码的情况,并且用户希望立即停止生成数据包,以避免覆盖先前写入的数据包。 TraceStop机制的工作方式与IP过滤非常相似,并且使用相同的地址比较逻辑。 TraceStop区域的基准值和极限值被编程为一个或多个ADDRn范围,但是IA32_RTIT_CTL.ADDRn_CFG使用TraceStop编码进行配置。与FilterEn一样,当分支或事件进入TraceStop区域时,也会检测到TraceStop。此外,TraceStop要求分支/事件的开始处的TriggerEn = 1,分支/事件完成时的ContextEn = 1。发生这种情况时,CPU将设置IA32_RTIT_STATUS.Stopped,从而清除TriggerEn,从而禁用包生成。这可能会生成带有进入TraceStop区域的分支或事件的目标IP的TIP.PGD数据包。最后,将插入一个TraceStop数据包,以表明该条件已达到。如果在缓冲区溢出期间遇到TraceStop条件(第36.3.8节),则不会丢弃该条件,而是在解决了溢出后立即发出信号。请注意,TraceStop事件不能保证所有内部缓冲的数据包都从内部缓冲区中清除。为确保发生这种情况,用户应清除TraceEn。要在TraceStop事件之后恢复跟踪,用户必须先通过清除IA32_RTIT_CTL.TraceEn来禁用Intel PT,然后才能清除IA32_RTIT_STATUS.Stopped位。此时,可以重新配置Intel PT,并恢复跟踪。注意,IA32_RTIT_STATUS.Stopped位也可以使用ToPA STOP位设置。参见第36.2.6.2节。

IP filtering Example

下表提供了IP过滤行为的示例。 假设IA32_RTIT_ADDRn_A = RangeBase的IP,并且IA32_RTIT_ADDRn_B = RangeLimit的IP,而IA32_RTIT_CTL.ADDRn_CFG = 0x1(启用ADDRn范围作为FilterEn范围)。

image-20200413162559773

IP Filtering and TraceStop

用户可以配置重叠的IP过滤器范围和TraceStop范围。 在这种情况下,在任一范围的非重叠部分中执行的代码将按照该范围的预期运行。 在重叠范围内执行的代码将获得TraceStop行为。