130fdc8d8SChris Lattner //===-- MachThread.cpp ------------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner //
1030fdc8d8SChris Lattner //  Created by Greg Clayton on 6/19/07.
1130fdc8d8SChris Lattner //
1230fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1330fdc8d8SChris Lattner 
1430fdc8d8SChris Lattner #include "MachThread.h"
1530fdc8d8SChris Lattner #include "MachProcess.h"
1630fdc8d8SChris Lattner #include "DNBLog.h"
1730fdc8d8SChris Lattner #include "DNB.h"
1830fdc8d8SChris Lattner 
1930fdc8d8SChris Lattner static uint32_t
2030fdc8d8SChris Lattner GetSequenceID()
2130fdc8d8SChris Lattner {
2230fdc8d8SChris Lattner     static uint32_t g_nextID = 0;
2330fdc8d8SChris Lattner     return ++g_nextID;
2430fdc8d8SChris Lattner }
2530fdc8d8SChris Lattner 
2630fdc8d8SChris Lattner MachThread::MachThread (MachProcess *process, thread_t thread) :
2730fdc8d8SChris Lattner     m_process (process),
2830fdc8d8SChris Lattner     m_tid (thread),
2930fdc8d8SChris Lattner     m_seq_id (GetSequenceID()),
3030fdc8d8SChris Lattner     m_state (eStateUnloaded),
3130fdc8d8SChris Lattner     m_state_mutex (PTHREAD_MUTEX_RECURSIVE),
3230fdc8d8SChris Lattner     m_breakID (INVALID_NUB_BREAK_ID),
33cdc7322bSGreg Clayton     m_suspendCount (0),
343af9ea56SGreg Clayton     m_arch_ap (DNBArchProtocol::Create (this)),
35cdc7322bSGreg Clayton     m_reg_sets (m_arch_ap->GetRegisterSetInfo (&n_num_reg_sets))
3630fdc8d8SChris Lattner {
371b946bf6SGreg Clayton     // Get the thread state so we know if a thread is in a state where we can't
381b946bf6SGreg Clayton     // muck with it and also so we get the suspend count correct in case it was
391b946bf6SGreg Clayton     // already suspended
40cdc7322bSGreg Clayton     GetBasicInfo();
4130fdc8d8SChris Lattner     DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::MachThread ( process = %p, tid = 0x%4.4x, seq_id = %u )", &m_process, m_tid, m_seq_id);
4230fdc8d8SChris Lattner }
4330fdc8d8SChris Lattner 
4430fdc8d8SChris Lattner MachThread::~MachThread()
4530fdc8d8SChris Lattner {
4630fdc8d8SChris Lattner     DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::~MachThread() for tid = 0x%4.4x (%u)", m_tid, m_seq_id);
4730fdc8d8SChris Lattner }
4830fdc8d8SChris Lattner 
4930fdc8d8SChris Lattner 
5030fdc8d8SChris Lattner 
51*9411ddb6SJim Ingham void
5230fdc8d8SChris Lattner MachThread::Suspend()
5330fdc8d8SChris Lattner {
5430fdc8d8SChris Lattner     DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
5530fdc8d8SChris Lattner     if (ThreadIDIsValid(m_tid))
5630fdc8d8SChris Lattner     {
5730fdc8d8SChris Lattner         DNBError err(::thread_suspend (m_tid), DNBError::MachKernel);
5830fdc8d8SChris Lattner         if (err.Success())
59cdc7322bSGreg Clayton             m_suspendCount++;
6030fdc8d8SChris Lattner         if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
6130fdc8d8SChris Lattner             err.LogThreaded("::thread_suspend (%4.4x)", m_tid);
6230fdc8d8SChris Lattner     }
6330fdc8d8SChris Lattner }
6430fdc8d8SChris Lattner 
65*9411ddb6SJim Ingham void
66*9411ddb6SJim Ingham MachThread::Resume(bool others_stopped)
6730fdc8d8SChris Lattner {
6830fdc8d8SChris Lattner     DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
6930fdc8d8SChris Lattner     if (ThreadIDIsValid(m_tid))
7030fdc8d8SChris Lattner     {
71*9411ddb6SJim Ingham         SetSuspendCountBeforeResume(others_stopped);
7230fdc8d8SChris Lattner     }
7330fdc8d8SChris Lattner }
7430fdc8d8SChris Lattner 
7530fdc8d8SChris Lattner bool
76*9411ddb6SJim Ingham MachThread::SetSuspendCountBeforeResume(bool others_stopped)
7730fdc8d8SChris Lattner {
78cdc7322bSGreg Clayton     DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
7930fdc8d8SChris Lattner     DNBError err;
8030fdc8d8SChris Lattner     if (ThreadIDIsValid(m_tid) == false)
8130fdc8d8SChris Lattner         return false;
82*9411ddb6SJim Ingham 
83*9411ddb6SJim Ingham     size_t times_to_resume;
84*9411ddb6SJim Ingham 
85*9411ddb6SJim Ingham     if (others_stopped)
86*9411ddb6SJim Ingham     {
87*9411ddb6SJim Ingham         times_to_resume = GetBasicInfo()->suspend_count;
88*9411ddb6SJim Ingham         m_suspendCount = - (times_to_resume - m_suspendCount);
89*9411ddb6SJim Ingham     }
90*9411ddb6SJim Ingham     else
91*9411ddb6SJim Ingham     {
92*9411ddb6SJim Ingham         times_to_resume = m_suspendCount;
93*9411ddb6SJim Ingham         m_suspendCount = 0;
94*9411ddb6SJim Ingham     }
95*9411ddb6SJim Ingham 
96*9411ddb6SJim Ingham     if (times_to_resume > 0)
97*9411ddb6SJim Ingham     {
98*9411ddb6SJim Ingham         while (times_to_resume > 0)
99*9411ddb6SJim Ingham         {
100*9411ddb6SJim Ingham             err = ::thread_resume (m_tid);
101*9411ddb6SJim Ingham             if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
102*9411ddb6SJim Ingham                 err.LogThreaded("::thread_resume (%4.4x)", m_tid);
103*9411ddb6SJim Ingham             if (err.Success())
104*9411ddb6SJim Ingham                 --times_to_resume;
105*9411ddb6SJim Ingham             else
106*9411ddb6SJim Ingham             {
107*9411ddb6SJim Ingham                 if (GetBasicInfo())
108*9411ddb6SJim Ingham                     times_to_resume = m_basicInfo.suspend_count;
109*9411ddb6SJim Ingham                 else
110*9411ddb6SJim Ingham                     times_to_resume = 0;
111*9411ddb6SJim Ingham                 return false; // ???
112*9411ddb6SJim Ingham             }
113*9411ddb6SJim Ingham         }
114*9411ddb6SJim Ingham     }
115*9411ddb6SJim Ingham     return true;
116*9411ddb6SJim Ingham }
117*9411ddb6SJim Ingham 
118*9411ddb6SJim Ingham bool
119*9411ddb6SJim Ingham MachThread::RestoreSuspendCountAfterStop ()
120*9411ddb6SJim Ingham {
121*9411ddb6SJim Ingham     DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
122*9411ddb6SJim Ingham     DNBError err;
123*9411ddb6SJim Ingham     if (ThreadIDIsValid(m_tid) == false)
124*9411ddb6SJim Ingham         return false;
125*9411ddb6SJim Ingham 
126cdc7322bSGreg Clayton     if (m_suspendCount > 0)
12730fdc8d8SChris Lattner     {
128cdc7322bSGreg Clayton         while (m_suspendCount > 0)
12930fdc8d8SChris Lattner         {
13030fdc8d8SChris Lattner             err = ::thread_resume (m_tid);
13130fdc8d8SChris Lattner             if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
132cdc7322bSGreg Clayton                 err.LogThreaded("::thread_resume (%4.4x)", m_tid);
13330fdc8d8SChris Lattner             if (err.Success())
134cdc7322bSGreg Clayton                 --m_suspendCount;
1350dd2c627SGreg Clayton             else
1360dd2c627SGreg Clayton             {
137cdc7322bSGreg Clayton                 if (GetBasicInfo())
138cdc7322bSGreg Clayton                     m_suspendCount = m_basicInfo.suspend_count;
1390dd2c627SGreg Clayton                 else
140cdc7322bSGreg Clayton                     m_suspendCount = 0;
1410dd2c627SGreg Clayton                 return false; // ???
14230fdc8d8SChris Lattner             }
14330fdc8d8SChris Lattner         }
1440dd2c627SGreg Clayton     }
145*9411ddb6SJim Ingham     else if (m_suspendCount < 0)
146*9411ddb6SJim Ingham     {
147*9411ddb6SJim Ingham         while (m_suspendCount < 0)
148*9411ddb6SJim Ingham         {
149*9411ddb6SJim Ingham             err = ::thread_suspend (m_tid);
150*9411ddb6SJim Ingham             if (err.Success())
151*9411ddb6SJim Ingham                 ++m_suspendCount;
152*9411ddb6SJim Ingham             if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
153*9411ddb6SJim Ingham                 err.LogThreaded("::thread_suspend (%4.4x)", m_tid);
154*9411ddb6SJim Ingham         }
155*9411ddb6SJim Ingham     }
1560dd2c627SGreg Clayton     return true;
15730fdc8d8SChris Lattner }
15830fdc8d8SChris Lattner 
15930fdc8d8SChris Lattner 
16030fdc8d8SChris Lattner const char *
16130fdc8d8SChris Lattner MachThread::GetBasicInfoAsString () const
16230fdc8d8SChris Lattner {
16330fdc8d8SChris Lattner     static char g_basic_info_string[1024];
16430fdc8d8SChris Lattner     struct thread_basic_info basicInfo;
16530fdc8d8SChris Lattner 
16630fdc8d8SChris Lattner     if (GetBasicInfo(m_tid, &basicInfo))
16730fdc8d8SChris Lattner     {
16830fdc8d8SChris Lattner 
16930fdc8d8SChris Lattner //        char run_state_str[32];
17030fdc8d8SChris Lattner //        size_t run_state_str_size = sizeof(run_state_str);
17130fdc8d8SChris Lattner //        switch (basicInfo.run_state)
17230fdc8d8SChris Lattner //        {
17330fdc8d8SChris Lattner //        case TH_STATE_RUNNING:          strncpy(run_state_str, "running", run_state_str_size); break;
17430fdc8d8SChris Lattner //        case TH_STATE_STOPPED:          strncpy(run_state_str, "stopped", run_state_str_size); break;
17530fdc8d8SChris Lattner //        case TH_STATE_WAITING:          strncpy(run_state_str, "waiting", run_state_str_size); break;
17630fdc8d8SChris Lattner //        case TH_STATE_UNINTERRUPTIBLE:  strncpy(run_state_str, "uninterruptible", run_state_str_size); break;
17730fdc8d8SChris Lattner //        case TH_STATE_HALTED:           strncpy(run_state_str, "halted", run_state_str_size); break;
17830fdc8d8SChris Lattner //        default:                        snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break;    // ???
17930fdc8d8SChris Lattner //        }
18030fdc8d8SChris Lattner         float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
18130fdc8d8SChris Lattner         float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
18230fdc8d8SChris Lattner         snprintf(g_basic_info_string, sizeof(g_basic_info_string), "Thread 0x%4.4x: user=%f system=%f cpu=%d sleep_time=%d",
18330fdc8d8SChris Lattner             InferiorThreadID(),
18430fdc8d8SChris Lattner             user,
18530fdc8d8SChris Lattner             system,
18630fdc8d8SChris Lattner             basicInfo.cpu_usage,
18730fdc8d8SChris Lattner             basicInfo.sleep_time);
18830fdc8d8SChris Lattner 
18930fdc8d8SChris Lattner         return g_basic_info_string;
19030fdc8d8SChris Lattner     }
19130fdc8d8SChris Lattner     return NULL;
19230fdc8d8SChris Lattner }
19330fdc8d8SChris Lattner 
19430fdc8d8SChris Lattner thread_t
19530fdc8d8SChris Lattner MachThread::InferiorThreadID() const
19630fdc8d8SChris Lattner {
19730fdc8d8SChris Lattner     mach_msg_type_number_t i;
19830fdc8d8SChris Lattner     mach_port_name_array_t names;
19930fdc8d8SChris Lattner     mach_port_type_array_t types;
20030fdc8d8SChris Lattner     mach_msg_type_number_t ncount, tcount;
20130fdc8d8SChris Lattner     thread_t inferior_tid = INVALID_NUB_THREAD;
20230fdc8d8SChris Lattner     task_t my_task = ::mach_task_self();
20330fdc8d8SChris Lattner     task_t task = m_process->Task().TaskPort();
20430fdc8d8SChris Lattner 
20530fdc8d8SChris Lattner     kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount);
20630fdc8d8SChris Lattner     if (kret == KERN_SUCCESS)
20730fdc8d8SChris Lattner     {
20830fdc8d8SChris Lattner 
20930fdc8d8SChris Lattner         for (i = 0; i < ncount; i++)
21030fdc8d8SChris Lattner         {
21130fdc8d8SChris Lattner             mach_port_t my_name;
21230fdc8d8SChris Lattner             mach_msg_type_name_t my_type;
21330fdc8d8SChris Lattner 
21430fdc8d8SChris Lattner             kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type);
21530fdc8d8SChris Lattner             if (kret == KERN_SUCCESS)
21630fdc8d8SChris Lattner             {
21730fdc8d8SChris Lattner                 ::mach_port_deallocate (my_task, my_name);
21830fdc8d8SChris Lattner                 if (my_name == m_tid)
21930fdc8d8SChris Lattner                 {
22030fdc8d8SChris Lattner                     inferior_tid = names[i];
22130fdc8d8SChris Lattner                     break;
22230fdc8d8SChris Lattner                 }
22330fdc8d8SChris Lattner             }
22430fdc8d8SChris Lattner         }
22530fdc8d8SChris Lattner         // Free up the names and types
22630fdc8d8SChris Lattner         ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t));
22730fdc8d8SChris Lattner         ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t));
22830fdc8d8SChris Lattner     }
22930fdc8d8SChris Lattner     return inferior_tid;
23030fdc8d8SChris Lattner }
23130fdc8d8SChris Lattner 
23230fdc8d8SChris Lattner bool
2331b946bf6SGreg Clayton MachThread::IsUserReady()
2341b946bf6SGreg Clayton {
235cdc7322bSGreg Clayton     if (m_basicInfo.run_state == 0)
236cdc7322bSGreg Clayton         GetBasicInfo ();
2371b946bf6SGreg Clayton 
238cdc7322bSGreg Clayton     switch (m_basicInfo.run_state)
2391b946bf6SGreg Clayton     {
2401b946bf6SGreg Clayton     default:
2411b946bf6SGreg Clayton     case TH_STATE_UNINTERRUPTIBLE:
2421b946bf6SGreg Clayton         break;
2431b946bf6SGreg Clayton 
2441b946bf6SGreg Clayton     case TH_STATE_RUNNING:
2451b946bf6SGreg Clayton     case TH_STATE_STOPPED:
2461b946bf6SGreg Clayton     case TH_STATE_WAITING:
2471b946bf6SGreg Clayton     case TH_STATE_HALTED:
2481b946bf6SGreg Clayton         return true;
2491b946bf6SGreg Clayton     }
2501b946bf6SGreg Clayton     return false;
2511b946bf6SGreg Clayton }
2521b946bf6SGreg Clayton 
2531b946bf6SGreg Clayton struct thread_basic_info *
254cdc7322bSGreg Clayton MachThread::GetBasicInfo ()
2551b946bf6SGreg Clayton {
256cdc7322bSGreg Clayton     if (MachThread::GetBasicInfo(m_tid, &m_basicInfo))
257cdc7322bSGreg Clayton         return &m_basicInfo;
2581b946bf6SGreg Clayton     return NULL;
2591b946bf6SGreg Clayton }
2601b946bf6SGreg Clayton 
2611b946bf6SGreg Clayton 
2621b946bf6SGreg Clayton bool
26330fdc8d8SChris Lattner MachThread::GetBasicInfo(thread_t thread, struct thread_basic_info *basicInfoPtr)
26430fdc8d8SChris Lattner {
26530fdc8d8SChris Lattner     if (ThreadIDIsValid(thread))
26630fdc8d8SChris Lattner     {
26730fdc8d8SChris Lattner         unsigned int info_count = THREAD_BASIC_INFO_COUNT;
26830fdc8d8SChris Lattner         kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count);
26930fdc8d8SChris Lattner         if (err == KERN_SUCCESS)
27030fdc8d8SChris Lattner             return true;
27130fdc8d8SChris Lattner     }
27230fdc8d8SChris Lattner     ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info));
27330fdc8d8SChris Lattner     return false;
27430fdc8d8SChris Lattner }
27530fdc8d8SChris Lattner 
27630fdc8d8SChris Lattner 
27730fdc8d8SChris Lattner bool
27830fdc8d8SChris Lattner MachThread::ThreadIDIsValid(thread_t thread)
27930fdc8d8SChris Lattner {
28030fdc8d8SChris Lattner     return thread != THREAD_NULL;
28130fdc8d8SChris Lattner }
28230fdc8d8SChris Lattner 
28330fdc8d8SChris Lattner bool
28430fdc8d8SChris Lattner MachThread::GetRegisterState(int flavor, bool force)
28530fdc8d8SChris Lattner {
2863af9ea56SGreg Clayton     return m_arch_ap->GetRegisterState(flavor, force) == KERN_SUCCESS;
28730fdc8d8SChris Lattner }
28830fdc8d8SChris Lattner 
28930fdc8d8SChris Lattner bool
29030fdc8d8SChris Lattner MachThread::SetRegisterState(int flavor)
29130fdc8d8SChris Lattner {
2923af9ea56SGreg Clayton     return m_arch_ap->SetRegisterState(flavor) == KERN_SUCCESS;
29330fdc8d8SChris Lattner }
29430fdc8d8SChris Lattner 
29530fdc8d8SChris Lattner uint64_t
29630fdc8d8SChris Lattner MachThread::GetPC(uint64_t failValue)
29730fdc8d8SChris Lattner {
29830fdc8d8SChris Lattner     // Get program counter
2993af9ea56SGreg Clayton     return m_arch_ap->GetPC(failValue);
30030fdc8d8SChris Lattner }
30130fdc8d8SChris Lattner 
30230fdc8d8SChris Lattner bool
30330fdc8d8SChris Lattner MachThread::SetPC(uint64_t value)
30430fdc8d8SChris Lattner {
30530fdc8d8SChris Lattner     // Set program counter
3063af9ea56SGreg Clayton     return m_arch_ap->SetPC(value);
30730fdc8d8SChris Lattner }
30830fdc8d8SChris Lattner 
30930fdc8d8SChris Lattner uint64_t
31030fdc8d8SChris Lattner MachThread::GetSP(uint64_t failValue)
31130fdc8d8SChris Lattner {
31230fdc8d8SChris Lattner     // Get stack pointer
3133af9ea56SGreg Clayton     return m_arch_ap->GetSP(failValue);
31430fdc8d8SChris Lattner }
31530fdc8d8SChris Lattner 
31630fdc8d8SChris Lattner nub_process_t
31730fdc8d8SChris Lattner MachThread::ProcessID() const
31830fdc8d8SChris Lattner {
31930fdc8d8SChris Lattner     if (m_process)
32030fdc8d8SChris Lattner         return m_process->ProcessID();
32130fdc8d8SChris Lattner     return INVALID_NUB_PROCESS;
32230fdc8d8SChris Lattner }
32330fdc8d8SChris Lattner 
32430fdc8d8SChris Lattner void
32530fdc8d8SChris Lattner MachThread::Dump(uint32_t index)
32630fdc8d8SChris Lattner {
32730fdc8d8SChris Lattner     const char * thread_run_state = NULL;
32830fdc8d8SChris Lattner 
329cdc7322bSGreg Clayton     switch (m_basicInfo.run_state)
33030fdc8d8SChris Lattner     {
33130fdc8d8SChris Lattner     case TH_STATE_RUNNING:          thread_run_state = "running"; break;    // 1 thread is running normally
33230fdc8d8SChris Lattner     case TH_STATE_STOPPED:          thread_run_state = "stopped"; break;    // 2 thread is stopped
33330fdc8d8SChris Lattner     case TH_STATE_WAITING:          thread_run_state = "waiting"; break;    // 3 thread is waiting normally
33430fdc8d8SChris Lattner     case TH_STATE_UNINTERRUPTIBLE:  thread_run_state = "uninter"; break;    // 4 thread is in an uninterruptible wait
33530fdc8d8SChris Lattner     case TH_STATE_HALTED:           thread_run_state = "halted "; break;     // 5 thread is halted at a
33630fdc8d8SChris Lattner     default:                        thread_run_state = "???"; break;
33730fdc8d8SChris Lattner     }
33830fdc8d8SChris Lattner 
339e2d4f0d7SGreg Clayton     DNBLogThreaded("[%3u] #%3u tid: 0x%4.4x, pc: 0x%16.16llx, sp: 0x%16.16llx, breakID: %3d, user: %d.%06.6d, system: %d.%06.6d, cpu: %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d",
34030fdc8d8SChris Lattner         index,
34130fdc8d8SChris Lattner         m_seq_id,
342e2d4f0d7SGreg Clayton         m_tid,
34330fdc8d8SChris Lattner         GetPC(INVALID_NUB_ADDRESS),
34430fdc8d8SChris Lattner         GetSP(INVALID_NUB_ADDRESS),
34530fdc8d8SChris Lattner         m_breakID,
346cdc7322bSGreg Clayton         m_basicInfo.user_time.seconds,      m_basicInfo.user_time.microseconds,
347cdc7322bSGreg Clayton         m_basicInfo.system_time.seconds,    m_basicInfo.system_time.microseconds,
348cdc7322bSGreg Clayton         m_basicInfo.cpu_usage,
349cdc7322bSGreg Clayton         m_basicInfo.policy,
350cdc7322bSGreg Clayton         m_basicInfo.run_state,
35130fdc8d8SChris Lattner         thread_run_state,
352cdc7322bSGreg Clayton         m_basicInfo.flags,
353cdc7322bSGreg Clayton         m_basicInfo.suspend_count, m_suspendCount,
354cdc7322bSGreg Clayton         m_basicInfo.sleep_time);
35530fdc8d8SChris Lattner     //DumpRegisterState(0);
35630fdc8d8SChris Lattner }
35730fdc8d8SChris Lattner 
35830fdc8d8SChris Lattner void
359*9411ddb6SJim Ingham MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action, bool others_stopped)
36030fdc8d8SChris Lattner {
36130fdc8d8SChris Lattner     if (thread_action->addr != INVALID_NUB_ADDRESS)
36230fdc8d8SChris Lattner         SetPC (thread_action->addr);
363cdc7322bSGreg Clayton 
36430fdc8d8SChris Lattner     SetState (thread_action->state);
36530fdc8d8SChris Lattner     switch (thread_action->state)
36630fdc8d8SChris Lattner     {
36730fdc8d8SChris Lattner     case eStateStopped:
36830fdc8d8SChris Lattner     case eStateSuspended:
369*9411ddb6SJim Ingham         assert (others_stopped == false);
37030fdc8d8SChris Lattner         Suspend();
37130fdc8d8SChris Lattner         break;
37230fdc8d8SChris Lattner 
37330fdc8d8SChris Lattner     case eStateRunning:
374b1e11121SJim Ingham     case eStateStepping:
375*9411ddb6SJim Ingham         Resume(others_stopped);
376b1e11121SJim Ingham         break;
377effe5c95SGreg Clayton     default:
378effe5c95SGreg Clayton         break;
37930fdc8d8SChris Lattner     }
3803af9ea56SGreg Clayton     m_arch_ap->ThreadWillResume();
38130fdc8d8SChris Lattner     m_stop_exception.Clear();
38230fdc8d8SChris Lattner }
38330fdc8d8SChris Lattner 
384c4e411ffSGreg Clayton nub_break_t
385c4e411ffSGreg Clayton MachThread::CurrentBreakpoint()
386c4e411ffSGreg Clayton {
387c4e411ffSGreg Clayton     return m_process->Breakpoints().FindIDByAddress(GetPC());
388c4e411ffSGreg Clayton }
389c4e411ffSGreg Clayton 
39030fdc8d8SChris Lattner bool
39130fdc8d8SChris Lattner MachThread::ShouldStop(bool &step_more)
39230fdc8d8SChris Lattner {
39330fdc8d8SChris Lattner     // See if this thread is at a breakpoint?
39430fdc8d8SChris Lattner     nub_break_t breakID = CurrentBreakpoint();
39530fdc8d8SChris Lattner 
39630fdc8d8SChris Lattner     if (NUB_BREAK_ID_IS_VALID(breakID))
39730fdc8d8SChris Lattner     {
39830fdc8d8SChris Lattner         // This thread is sitting at a breakpoint, ask the breakpoint
39930fdc8d8SChris Lattner         // if we should be stopping here.
40030fdc8d8SChris Lattner         if (Process()->Breakpoints().ShouldStop(ProcessID(), ThreadID(), breakID))
40130fdc8d8SChris Lattner             return true;
40230fdc8d8SChris Lattner         else
40330fdc8d8SChris Lattner         {
40430fdc8d8SChris Lattner             // The breakpoint said we shouldn't stop, but we may have gotten
40530fdc8d8SChris Lattner             // a signal or the user may have requested to stop in some other
40630fdc8d8SChris Lattner             // way. Stop if we have a valid exception (this thread won't if
40730fdc8d8SChris Lattner             // another thread was the reason this process stopped) and that
40830fdc8d8SChris Lattner             // exception, is NOT a breakpoint exception (a common case would
40930fdc8d8SChris Lattner             // be a SIGINT signal).
41030fdc8d8SChris Lattner             if (GetStopException().IsValid() && !GetStopException().IsBreakpoint())
41130fdc8d8SChris Lattner                 return true;
41230fdc8d8SChris Lattner         }
41330fdc8d8SChris Lattner     }
41430fdc8d8SChris Lattner     else
41530fdc8d8SChris Lattner     {
4163af9ea56SGreg Clayton         if (m_arch_ap->StepNotComplete())
41730fdc8d8SChris Lattner         {
41830fdc8d8SChris Lattner             step_more = true;
41930fdc8d8SChris Lattner             return false;
42030fdc8d8SChris Lattner         }
42130fdc8d8SChris Lattner         // The thread state is used to let us know what the thread was
42230fdc8d8SChris Lattner         // trying to do. MachThread::ThreadWillResume() will set the
42330fdc8d8SChris Lattner         // thread state to various values depending if the thread was
42430fdc8d8SChris Lattner         // the current thread and if it was to be single stepped, or
42530fdc8d8SChris Lattner         // resumed.
42630fdc8d8SChris Lattner         if (GetState() == eStateRunning)
42730fdc8d8SChris Lattner         {
42830fdc8d8SChris Lattner             // If our state is running, then we should continue as we are in
42930fdc8d8SChris Lattner             // the process of stepping over a breakpoint.
43030fdc8d8SChris Lattner             return false;
43130fdc8d8SChris Lattner         }
43230fdc8d8SChris Lattner         else
43330fdc8d8SChris Lattner         {
43430fdc8d8SChris Lattner             // Stop if we have any kind of valid exception for this
43530fdc8d8SChris Lattner             // thread.
43630fdc8d8SChris Lattner             if (GetStopException().IsValid())
43730fdc8d8SChris Lattner                 return true;
43830fdc8d8SChris Lattner         }
43930fdc8d8SChris Lattner     }
44030fdc8d8SChris Lattner     return false;
44130fdc8d8SChris Lattner }
44230fdc8d8SChris Lattner bool
44330fdc8d8SChris Lattner MachThread::IsStepping()
44430fdc8d8SChris Lattner {
445c4e411ffSGreg Clayton #if ENABLE_AUTO_STEPPING_OVER_BP
44630fdc8d8SChris Lattner     // Return true if this thread is currently being stepped.
44730fdc8d8SChris Lattner     // MachThread::ThreadWillResume currently determines this by looking if we
44830fdc8d8SChris Lattner     // have been asked to single step, or if we are at a breakpoint instruction
44930fdc8d8SChris Lattner     // and have been asked to resume. In the latter case we need to disable the
45030fdc8d8SChris Lattner     // breakpoint we are at, single step, re-enable and continue.
45130fdc8d8SChris Lattner     nub_state_t state = GetState();
452c4e411ffSGreg Clayton     return ((state == eStateStepping) ||
453c4e411ffSGreg Clayton             (state == eStateRunning && NUB_BREAK_ID_IS_VALID(CurrentBreakpoint())));
454c4e411ffSGreg Clayton #else
455c4e411ffSGreg Clayton     return GetState() == eStateStepping;
456c4e411ffSGreg Clayton #endif
45730fdc8d8SChris Lattner }
45830fdc8d8SChris Lattner 
45930fdc8d8SChris Lattner 
46030fdc8d8SChris Lattner bool
46130fdc8d8SChris Lattner MachThread::ThreadDidStop()
46230fdc8d8SChris Lattner {
46330fdc8d8SChris Lattner     // This thread has existed prior to resuming under debug nub control,
46430fdc8d8SChris Lattner     // and has just been stopped. Do any cleanup that needs to be done
46530fdc8d8SChris Lattner     // after running.
46630fdc8d8SChris Lattner 
46730fdc8d8SChris Lattner     // The thread state and breakpoint will still have the same values
46830fdc8d8SChris Lattner     // as they had prior to resuming the thread, so it makes it easy to check
46930fdc8d8SChris Lattner     // if we were trying to step a thread, or we tried to resume while being
47030fdc8d8SChris Lattner     // at a breakpoint.
47130fdc8d8SChris Lattner 
47230fdc8d8SChris Lattner     // When this method gets called, the process state is still in the
47330fdc8d8SChris Lattner     // state it was in while running so we can act accordingly.
4743af9ea56SGreg Clayton     m_arch_ap->ThreadDidStop();
47530fdc8d8SChris Lattner 
47630fdc8d8SChris Lattner 
47730fdc8d8SChris Lattner     // We may have suspended this thread so the primary thread could step
47830fdc8d8SChris Lattner     // without worrying about race conditions, so lets restore our suspend
47930fdc8d8SChris Lattner     // count.
480*9411ddb6SJim Ingham     RestoreSuspendCountAfterStop();
48130fdc8d8SChris Lattner 
48230fdc8d8SChris Lattner     // Update the basic information for a thread
483cdc7322bSGreg Clayton     MachThread::GetBasicInfo(m_tid, &m_basicInfo);
48430fdc8d8SChris Lattner 
485c4e411ffSGreg Clayton #if ENABLE_AUTO_STEPPING_OVER_BP
48630fdc8d8SChris Lattner     // See if we were at a breakpoint when we last resumed that we disabled,
48730fdc8d8SChris Lattner     // re-enable it.
48830fdc8d8SChris Lattner     nub_break_t breakID = CurrentBreakpoint();
48930fdc8d8SChris Lattner 
49030fdc8d8SChris Lattner     if (NUB_BREAK_ID_IS_VALID(breakID))
49130fdc8d8SChris Lattner     {
49230fdc8d8SChris Lattner         m_process->EnableBreakpoint(breakID);
493cdc7322bSGreg Clayton         if (m_basicInfo.suspend_count > 0)
49430fdc8d8SChris Lattner         {
49530fdc8d8SChris Lattner             SetState(eStateSuspended);
49630fdc8d8SChris Lattner         }
49730fdc8d8SChris Lattner         else
49830fdc8d8SChris Lattner         {
49930fdc8d8SChris Lattner             // If we last were at a breakpoint and we single stepped, our state
50030fdc8d8SChris Lattner             // will be "running" to indicate we need to continue after stepping
50130fdc8d8SChris Lattner             // over the breakpoint instruction. If we step over a breakpoint
50230fdc8d8SChris Lattner             // instruction, we need to stop.
50330fdc8d8SChris Lattner             if (GetState() == eStateRunning)
50430fdc8d8SChris Lattner             {
50530fdc8d8SChris Lattner                 // Leave state set to running so we will continue automatically
50630fdc8d8SChris Lattner                 // from this breakpoint
50730fdc8d8SChris Lattner             }
50830fdc8d8SChris Lattner             else
50930fdc8d8SChris Lattner             {
51030fdc8d8SChris Lattner                 SetState(eStateStopped);
51130fdc8d8SChris Lattner             }
51230fdc8d8SChris Lattner         }
51330fdc8d8SChris Lattner     }
51430fdc8d8SChris Lattner     else
51530fdc8d8SChris Lattner     {
516cdc7322bSGreg Clayton         if (m_basicInfo.suspend_count > 0)
51730fdc8d8SChris Lattner         {
51830fdc8d8SChris Lattner             SetState(eStateSuspended);
51930fdc8d8SChris Lattner         }
52030fdc8d8SChris Lattner         else
52130fdc8d8SChris Lattner         {
52230fdc8d8SChris Lattner             SetState(eStateStopped);
52330fdc8d8SChris Lattner         }
52430fdc8d8SChris Lattner     }
525c4e411ffSGreg Clayton #else
526cdc7322bSGreg Clayton     if (m_basicInfo.suspend_count > 0)
527c4e411ffSGreg Clayton         SetState(eStateSuspended);
528c4e411ffSGreg Clayton     else
529c4e411ffSGreg Clayton         SetState(eStateStopped);
530c4e411ffSGreg Clayton #endif
53130fdc8d8SChris Lattner     return true;
53230fdc8d8SChris Lattner }
53330fdc8d8SChris Lattner 
53430fdc8d8SChris Lattner bool
53530fdc8d8SChris Lattner MachThread::NotifyException(MachException::Data& exc)
53630fdc8d8SChris Lattner {
53730fdc8d8SChris Lattner     if (m_stop_exception.IsValid())
53830fdc8d8SChris Lattner     {
53930fdc8d8SChris Lattner         // We may have more than one exception for a thread, but we need to
54030fdc8d8SChris Lattner         // only remember the one that we will say is the reason we stopped.
54130fdc8d8SChris Lattner         // We may have been single stepping and also gotten a signal exception,
54230fdc8d8SChris Lattner         // so just remember the most pertinent one.
54330fdc8d8SChris Lattner         if (m_stop_exception.IsBreakpoint())
54430fdc8d8SChris Lattner             m_stop_exception = exc;
54530fdc8d8SChris Lattner     }
54630fdc8d8SChris Lattner     else
54730fdc8d8SChris Lattner     {
54830fdc8d8SChris Lattner         m_stop_exception = exc;
54930fdc8d8SChris Lattner     }
5503af9ea56SGreg Clayton     bool handled = m_arch_ap->NotifyException(exc);
55130fdc8d8SChris Lattner     if (!handled)
55230fdc8d8SChris Lattner     {
55330fdc8d8SChris Lattner         handled = true;
554c4e411ffSGreg Clayton //        switch (exc.exc_type)
555c4e411ffSGreg Clayton //        {
556c4e411ffSGreg Clayton //        case EXC_BAD_ACCESS:
557c4e411ffSGreg Clayton //            break;
558c4e411ffSGreg Clayton //        case EXC_BAD_INSTRUCTION:
559c4e411ffSGreg Clayton //            break;
560c4e411ffSGreg Clayton //        case EXC_ARITHMETIC:
561c4e411ffSGreg Clayton //            break;
562c4e411ffSGreg Clayton //        case EXC_EMULATION:
563c4e411ffSGreg Clayton //            break;
564c4e411ffSGreg Clayton //        case EXC_SOFTWARE:
565c4e411ffSGreg Clayton //            break;
566c4e411ffSGreg Clayton //        case EXC_BREAKPOINT:
567c4e411ffSGreg Clayton //            break;
568c4e411ffSGreg Clayton //        case EXC_SYSCALL:
569c4e411ffSGreg Clayton //            break;
570c4e411ffSGreg Clayton //        case EXC_MACH_SYSCALL:
571c4e411ffSGreg Clayton //            break;
572c4e411ffSGreg Clayton //        case EXC_RPC_ALERT:
573c4e411ffSGreg Clayton //            break;
574c4e411ffSGreg Clayton //        }
57530fdc8d8SChris Lattner     }
57630fdc8d8SChris Lattner     return handled;
57730fdc8d8SChris Lattner }
57830fdc8d8SChris Lattner 
57930fdc8d8SChris Lattner 
58030fdc8d8SChris Lattner nub_state_t
58130fdc8d8SChris Lattner MachThread::GetState()
58230fdc8d8SChris Lattner {
58330fdc8d8SChris Lattner     // If any other threads access this we will need a mutex for it
58430fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
58530fdc8d8SChris Lattner     return m_state;
58630fdc8d8SChris Lattner }
58730fdc8d8SChris Lattner 
58830fdc8d8SChris Lattner void
58930fdc8d8SChris Lattner MachThread::SetState(nub_state_t state)
59030fdc8d8SChris Lattner {
59130fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
59230fdc8d8SChris Lattner     m_state = state;
59330fdc8d8SChris Lattner     DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%4.4x", DNBStateAsString(state), m_tid);
59430fdc8d8SChris Lattner }
59530fdc8d8SChris Lattner 
59630fdc8d8SChris Lattner uint32_t
59730fdc8d8SChris Lattner MachThread::GetNumRegistersInSet(int regSet) const
59830fdc8d8SChris Lattner {
5993af9ea56SGreg Clayton     if (regSet < n_num_reg_sets)
6003af9ea56SGreg Clayton         return m_reg_sets[regSet].num_registers;
60130fdc8d8SChris Lattner     return 0;
60230fdc8d8SChris Lattner }
60330fdc8d8SChris Lattner 
60430fdc8d8SChris Lattner const char *
60530fdc8d8SChris Lattner MachThread::GetRegisterSetName(int regSet) const
60630fdc8d8SChris Lattner {
6073af9ea56SGreg Clayton     if (regSet < n_num_reg_sets)
6083af9ea56SGreg Clayton         return m_reg_sets[regSet].name;
60930fdc8d8SChris Lattner     return NULL;
61030fdc8d8SChris Lattner }
61130fdc8d8SChris Lattner 
61230fdc8d8SChris Lattner const DNBRegisterInfo *
61330fdc8d8SChris Lattner MachThread::GetRegisterInfo(int regSet, int regIndex) const
61430fdc8d8SChris Lattner {
6153af9ea56SGreg Clayton     if (regSet < n_num_reg_sets)
6163af9ea56SGreg Clayton         if (regIndex < m_reg_sets[regSet].num_registers)
6173af9ea56SGreg Clayton             return &m_reg_sets[regSet].registers[regIndex];
61830fdc8d8SChris Lattner     return NULL;
61930fdc8d8SChris Lattner }
62030fdc8d8SChris Lattner void
62130fdc8d8SChris Lattner MachThread::DumpRegisterState(int regSet)
62230fdc8d8SChris Lattner {
62330fdc8d8SChris Lattner     if (regSet == REGISTER_SET_ALL)
62430fdc8d8SChris Lattner     {
6253af9ea56SGreg Clayton         for (regSet = 1; regSet < n_num_reg_sets; regSet++)
62630fdc8d8SChris Lattner             DumpRegisterState(regSet);
62730fdc8d8SChris Lattner     }
62830fdc8d8SChris Lattner     else
62930fdc8d8SChris Lattner     {
6303af9ea56SGreg Clayton         if (m_arch_ap->RegisterSetStateIsValid(regSet))
63130fdc8d8SChris Lattner         {
63230fdc8d8SChris Lattner             const size_t numRegisters = GetNumRegistersInSet(regSet);
63330fdc8d8SChris Lattner             size_t regIndex = 0;
63430fdc8d8SChris Lattner             DNBRegisterValueClass reg;
63530fdc8d8SChris Lattner             for (regIndex = 0; regIndex < numRegisters; ++regIndex)
63630fdc8d8SChris Lattner             {
6373af9ea56SGreg Clayton                 if (m_arch_ap->GetRegisterValue(regSet, regIndex, &reg))
63830fdc8d8SChris Lattner                 {
63930fdc8d8SChris Lattner                     reg.Dump(NULL, NULL);
64030fdc8d8SChris Lattner                 }
64130fdc8d8SChris Lattner             }
64230fdc8d8SChris Lattner         }
64330fdc8d8SChris Lattner         else
64430fdc8d8SChris Lattner         {
64530fdc8d8SChris Lattner             DNBLog("%s: registers are not currently valid.", GetRegisterSetName(regSet));
64630fdc8d8SChris Lattner         }
64730fdc8d8SChris Lattner     }
64830fdc8d8SChris Lattner }
64930fdc8d8SChris Lattner 
65030fdc8d8SChris Lattner const DNBRegisterSetInfo *
65130fdc8d8SChris Lattner MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const
65230fdc8d8SChris Lattner {
6533af9ea56SGreg Clayton     *num_reg_sets = n_num_reg_sets;
6543af9ea56SGreg Clayton     return &m_reg_sets[0];
65530fdc8d8SChris Lattner }
65630fdc8d8SChris Lattner 
65730fdc8d8SChris Lattner bool
65830fdc8d8SChris Lattner MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value )
65930fdc8d8SChris Lattner {
6603af9ea56SGreg Clayton     return m_arch_ap->GetRegisterValue(set, reg, value);
66130fdc8d8SChris Lattner }
66230fdc8d8SChris Lattner 
66330fdc8d8SChris Lattner bool
66430fdc8d8SChris Lattner MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value )
66530fdc8d8SChris Lattner {
6663af9ea56SGreg Clayton     return m_arch_ap->SetRegisterValue(set, reg, value);
66730fdc8d8SChris Lattner }
66830fdc8d8SChris Lattner 
66930fdc8d8SChris Lattner nub_size_t
67030fdc8d8SChris Lattner MachThread::GetRegisterContext (void *buf, nub_size_t buf_len)
67130fdc8d8SChris Lattner {
6723af9ea56SGreg Clayton     return m_arch_ap->GetRegisterContext(buf, buf_len);
67330fdc8d8SChris Lattner }
67430fdc8d8SChris Lattner 
67530fdc8d8SChris Lattner nub_size_t
67630fdc8d8SChris Lattner MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len)
67730fdc8d8SChris Lattner {
6783af9ea56SGreg Clayton     return m_arch_ap->SetRegisterContext(buf, buf_len);
67930fdc8d8SChris Lattner }
68030fdc8d8SChris Lattner 
68130fdc8d8SChris Lattner uint32_t
68230fdc8d8SChris Lattner MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp)
68330fdc8d8SChris Lattner {
68430fdc8d8SChris Lattner     if (bp != NULL && bp->IsBreakpoint())
6853af9ea56SGreg Clayton         return m_arch_ap->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize());
68630fdc8d8SChris Lattner     return INVALID_NUB_HW_INDEX;
68730fdc8d8SChris Lattner }
68830fdc8d8SChris Lattner 
68930fdc8d8SChris Lattner uint32_t
69030fdc8d8SChris Lattner MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp)
69130fdc8d8SChris Lattner {
69230fdc8d8SChris Lattner     if (wp != NULL && wp->IsWatchpoint())
6933af9ea56SGreg Clayton         return m_arch_ap->EnableHardwareWatchpoint(wp->Address(), wp->ByteSize(), wp->WatchpointRead(), wp->WatchpointWrite());
69430fdc8d8SChris Lattner     return INVALID_NUB_HW_INDEX;
69530fdc8d8SChris Lattner }
69630fdc8d8SChris Lattner 
69730fdc8d8SChris Lattner bool
69830fdc8d8SChris Lattner MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp)
69930fdc8d8SChris Lattner {
70030fdc8d8SChris Lattner     if (bp != NULL && bp->IsHardware())
7013af9ea56SGreg Clayton         return m_arch_ap->DisableHardwareBreakpoint(bp->GetHardwareIndex());
70230fdc8d8SChris Lattner     return false;
70330fdc8d8SChris Lattner }
70430fdc8d8SChris Lattner 
70530fdc8d8SChris Lattner bool
70630fdc8d8SChris Lattner MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp)
70730fdc8d8SChris Lattner {
70830fdc8d8SChris Lattner     if (wp != NULL && wp->IsHardware())
7093af9ea56SGreg Clayton         return m_arch_ap->DisableHardwareWatchpoint(wp->GetHardwareIndex());
71030fdc8d8SChris Lattner     return false;
71130fdc8d8SChris Lattner }
71230fdc8d8SChris Lattner 
71330fdc8d8SChris Lattner bool
71430fdc8d8SChris Lattner MachThread::GetIdentifierInfo ()
71530fdc8d8SChris Lattner {
71630fdc8d8SChris Lattner #ifdef THREAD_IDENTIFIER_INFO_COUNT
717f2c6ccf0SJim Ingham         // Don't try to get the thread info once and cache it for the life of the thread.  It changes over time, for instance
718f2c6ccf0SJim Ingham         // if the thread name changes, then the thread_handle also changes...  So you have to refetch it every time.
71930fdc8d8SChris Lattner         mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
720f2c6ccf0SJim Ingham         kern_return_t kret = ::thread_info (ThreadID(), THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);
721f2c6ccf0SJim Ingham         return kret == KERN_SUCCESS;
72230fdc8d8SChris Lattner #endif
72330fdc8d8SChris Lattner 
72430fdc8d8SChris Lattner     return false;
72530fdc8d8SChris Lattner }
72630fdc8d8SChris Lattner 
72730fdc8d8SChris Lattner 
72830fdc8d8SChris Lattner const char *
72930fdc8d8SChris Lattner MachThread::GetName ()
73030fdc8d8SChris Lattner {
73130fdc8d8SChris Lattner     if (GetIdentifierInfo ())
73230fdc8d8SChris Lattner     {
73330fdc8d8SChris Lattner         int len = ::proc_pidinfo (m_process->ProcessID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo));
73430fdc8d8SChris Lattner 
73530fdc8d8SChris Lattner         if (len && m_proc_threadinfo.pth_name[0])
73630fdc8d8SChris Lattner             return m_proc_threadinfo.pth_name;
73730fdc8d8SChris Lattner     }
73830fdc8d8SChris Lattner     return NULL;
73930fdc8d8SChris Lattner }
74030fdc8d8SChris Lattner 
741