You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QEMU用户态多线程程序线程区分与执行路径记录异常问题

QEMU用户态多线程执行路径追踪问题解决

问题背景

环境:Ubuntu 22.10,QEMU 6.0.0用户态
需求:不修改目标C++多线程源码,通过记录基本块首地址追踪每个线程的执行路径
问题:在cpu_tb_exec函数中打印cpu->thread_id始终为同一值,无法区分目标程序的不同线程

目标测试代码:

#include <thread>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>

using namespace std;

void func1(){
    while(1){
        std::cout<<"thread 1\n";
        sleep(1);
    }
    return;
}
void func2(){
    while(1){
        std::cout<<"thread 2\n";
        sleep(1);
    }
    return;
}
void func3(){
    while(1){
        std::cout<<"thread 3\n";
        sleep(1);
    }
    return;
}
void func4(){
    while(1){
        std::cout<<"thread 4\n";
        sleep(1);
    }
    return;
}

int main(){
    thread t1=thread(func1);
    thread t2=thread(func2);
    thread t3=thread(func3);
    thread t4=thread(func4);
    cout<<"this is main\n";
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

问题原因

QEMU用户态采用单进程模拟模式,目标程序的多线程是交由宿主系统的线程调度器处理的。QEMU的CPU结构体在用户态下是单实例,cpu->thread_id标识的是QEMU自身的模拟线程ID(用户态下只有一个),而非目标程序的线程ID,因此无论目标程序哪个线程执行,这个值都不会变化。

解决方案

要区分目标程序的不同线程,需要获取目标程序自身的线程ID(TID),而非QEMU模拟线程的ID。在QEMU linux-user模式下,可以通过访问目标进程的task_struct结构体来获取TID。

具体修改步骤

  1. 在/qemu-6.0.0/accel/tcg/ecp-exec.c的cpu_tb_exec函数中,先添加所需头文件:
#include "linux-user/linux_syscall.h"
  1. 替换cpu->thread_id为目标线程的TID,修改后的代码片段:
const void *tb_ptr = itb->tc.ptr;
+    static unsigned int count=0;
+    // 获取目标程序的线程ID
+    struct task_struct *ts = get_current_task(cpu);
+    target_ulong tid = ts->tid;
+    {
+        char filename[100]={0};
+        sprintf(filename,"/home/admin/work/qemu/log/log_%ld", (long)tid);
+        FILE *fp=fopen(filename,"a");
+        if(fp==NULL) {
+            exit(1);
+        }
+        fprintf(fp,"%d: 0x%08llx\n",count++,(unsigned long long)itb->pc);
+        fclose(fp);
+     }

// 原有的日志代码保持不变
qemu_log_mask_and_addr(CPU_LOG_EXEC, itb->pc,
                       "Trace %d: %p ["
                       TARGET_FMT_lx "/" TARGET_FMT_lx "/%#x] %s\n",
                       cpu->cpu_index, itb->tc.ptr,
                       itb->cs_base, itb->pc, itb->flags,
                       lookup_symbol(itb->pc));

额外优化建议

  • 频繁打开/关闭文件会导致性能损耗,可以为每个线程ID缓存对应的文件指针,避免重复IO操作
  • 若目标架构不是x86_64,需要根据对应架构的线程存储方式调整获取TID的逻辑

内容的提问来源于stack exchange,提问作者Arashimu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 07:30:30