| 42 | off_t tid_offset_in_pthread_struct = 0; |
| 43 | |
| 44 | static off_t |
| 45 | findPthreadTidOffset( |
| 46 | const std::shared_ptr<const AbstractProcessManager>& manager, |
| 47 | remote_addr_t interp_state_addr) |
| 48 | { |
| 49 | LOG(DEBUG) << "Attempting to locate tid offset in pthread structure"; |
| 50 | Structure<py_is_v> is(manager, interp_state_addr); |
| 51 | |
| 52 | auto current_thread_addr = is.getField(&py_is_v::o_tstate_head); |
| 53 | |
| 54 | auto thread_head = current_thread_addr; |
| 55 | |
| 56 | // Iterate over all Python threads until we find a thread that has a tid equal to |
| 57 | // the process pid. This works because in the main thread the tid is equal to the pid, |
| 58 | // so when this happens it has to happen on the main thread. Note that the main thread |
| 59 | // is not necessarily at the head of the Python thread linked list |
| 60 | |
| 61 | #if defined(__GLIBC__) |
| 62 | // If we detect GLIBC, we can try the two main known structs for 'struct |
| 63 | // pthread' that we know about to avoid having to do guess-work by doing a |
| 64 | // linear scan over the struct. |
| 65 | while (current_thread_addr != (remote_addr_t) nullptr) { |
| 66 | Structure<py_thread_v> current_thread(manager, current_thread_addr); |
| 67 | auto pthread_id_addr = current_thread.getField(&py_thread_v::o_thread_id); |
| 68 | |
| 69 | pid_t the_tid; |
| 70 | std::vector<off_t> glibc_pthread_offset_candidates = { |
| 71 | offsetof(_pthread_structure_with_simple_header, tid), |
| 72 | offsetof(_pthread_structure_with_tcbhead, tid)}; |
| 73 | for (off_t candidate : glibc_pthread_offset_candidates) { |
| 74 | manager->copyObjectFromProcess((remote_addr_t)(pthread_id_addr + candidate), &the_tid); |
| 75 | if (the_tid == manager->Pid()) { |
| 76 | LOG(DEBUG) << "Tid offset located using GLIBC offsets at offset " << std::showbase |
| 77 | << std::hex << candidate << " in pthread structure"; |
| 78 | return candidate; |
| 79 | } |
| 80 | } |
| 81 | remote_addr_t next_thread_addr = current_thread.getField(&py_thread_v::o_next); |
| 82 | if (next_thread_addr == current_thread_addr) { |
| 83 | break; |
| 84 | } |
| 85 | current_thread_addr = next_thread_addr; |
| 86 | } |
| 87 | #endif |
| 88 | |
| 89 | current_thread_addr = thread_head; |
| 90 | |
| 91 | while (current_thread_addr != (remote_addr_t) nullptr) { |
| 92 | Structure<py_thread_v> current_thread(manager, current_thread_addr); |
| 93 | auto pthread_id_addr = current_thread.getField(&py_thread_v::o_thread_id); |
| 94 | |
| 95 | // Attempt to locate a field in the pthread struct that's equal to the pid. |
| 96 | uintptr_t buffer[100]; |
| 97 | size_t buffer_size = sizeof(buffer); |
| 98 | while (buffer_size > 0) { |
| 99 | try { |
| 100 | LOG(DEBUG) << "Trying to copy a buffer of " << buffer_size << " bytes to get pthread ID"; |
| 101 | manager->copyMemoryFromProcess(pthread_id_addr, buffer_size, &buffer); |
no test coverage detected