Compile gdbserver for Android(gdb 7.1) - xianjimli/misc GitHub Wiki

前几天发现Prebuild的gdbserver在我们的平台上无法运行,只好自己去编译。按照网上的方法编译不过去,虽然折腾半天之后编译成功了,但是运行时只能看到一个线程。后来研究了一下代码,发现里面确实是有问题的:

td_ta_thr_iter是用来获取进程中线程的方法,在Android的实现在bionic/libthread_db/libthread_db.c里,它的实现很简单,遍历/proc/%d/task/目录即可。

td_err_e
td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie,
              td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags)
{
    td_err_e err = TD_OK;
    char path[32];
    DIR * dir;
    struct dirent * entry;
    td_thrhandle_t handle;

    snprintf(path, sizeof(path), "/proc/%d/task/", agent->pid);
    dir = opendir(path);
    if (!dir) {
       return TD_NOEVENT;
    }
    handle.pid = agent->pid;
    while ((entry = readdir(dir)) != NULL) {
       if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
           continue;
       }
       handle.tid = atoi(entry->d_name);
       err = func(&handle, cookie);
       if (err) {
           break;
       }
    }

    closedir(dir);

    return err;
}

这里的agent->pid是在td_ta_new里初始化的,它从proc_handle->pid而来。

td_err_e
td_ta_new(struct ps_prochandle const * proc_handle, td_thragent_t ** agent_out)
{
    td_thragent_t * agent;

    agent = (td_thragent_t *)malloc(sizeof(td_thragent_t));
    if (!agent) {
       return TD_MALLOC;
    }

    agent->pid = proc_handle->pid;
    *agent_out = agent;

    return TD_OK;
}

问题是在调用tdb.td_ta_new_p时,proc_handle->pid根本就没有初始化,所以找不到进程中的线程。为了解决这个问题,我只强制把agent->pid设置为被调试的进程ID。

 /* Attempt to open a connection to the thread library.  */
 err = tdb.td_ta_new_p (&tdb.proc_handle, &tdb.thread_agent);
 if (err != TD_OK)
    {
     if (debug_threads)
    fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err));
     return 0;
    }

 //Li XianJing td_ta_new use tdb.proc_handle.pid to initialize tdb.thread_agent->pid,
 //but tdb.proc_handle.pid is unknown, so I assign signal_pid to tdb.thread_agent->pid directly.
 tdb.thread_agent->pid = signal_pid;

另外就是链接libthread_db.so的问题,无论用dlopen的方式或者还是编译链接都不行。我只好静态链接libthread_db.a,最后还要加几个空函数才能编译过去。