Merge branch 'dyn_pc_integration' of ssh://wasabi.cs.wisc.edu/p/paradyn/development...
[dyninst.git] / testsuite / src / proccontrol / pc_thread.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 #include "proccontrol_comp.h"
33 #include "communication.h"
34
35 #include <set>
36 #include <utility>
37
38 using namespace std;
39 using namespace Dyninst;
40 using namespace ProcControlAPI;
41
42 class pc_threadMutator : public ProcControlMutator {
43 public:
44    virtual test_results_t executeTest();
45    virtual test_results_t pre_init(ParameterDict &param);
46    void registerCB(EventType et, Process::cb_func_t f);
47 };
48
49 extern "C" DLLEXPORT TestMutator* pc_thread_factory()
50 {
51    return new pc_threadMutator();
52 }
53
54 static bool has_lwp = false;
55 static bool has_thr = false;
56 static bool has_stack_info = true;
57 static bool has_initial_func_info = true;
58 static bool is_attach = false;
59 static bool has_error = false;
60 static int user_cb_count = 0;
61 static int lwp_cb_count = 0;
62 static int user_exit_cb_count = 0;
63 static int lwp_exit_cb_count = 0;
64
65 static set<pair<PID, THR_ID> > all_tids;
66 static set<pair<PID, LWP> > all_lwps;
67 static set<pair<PID, THR_ID> > pre_dead_tids;
68 static set<pair<PID, THR_ID> > post_dead_tids;
69 static set<pair<PID, LWP> > pre_dead_lwps;
70 static set<pair<PID, LWP> > post_dead_lwps;
71 static set<pair<PID, Address> > all_stack_addrs;
72 static set<pair<PID, Address> > all_tls;
73 static set<PID> all_initial_threads;
74
75
76 void pc_threadMutator::registerCB(EventType et, Process::cb_func_t f)
77 {
78    bool result = Process::registerEventCallback(et, f);
79    if (!result) {
80       logerror("Error registering thread callback\n");
81       has_error = true;
82    }
83 }
84
85 static Process::cb_ret_t handle_new_thread(Thread::const_ptr thr)
86 {
87    user_cb_count++;
88
89    if (!thr->haveUserThreadInfo()) {
90       logerror("Error.  Thread does not have thread info after thread create callback\n");
91       has_error = true;
92       return Process::cb_ret_t(Process::cbDefault, Process::cbDefault);
93    }
94
95    PID pid = thr->getProcess()->getPid();
96    LWP lwp = thr->getLWP();
97    THR_ID tid = thr->getTID();
98    if (tid == NULL_THR_ID) {
99       logerror("Error.  Thread does not have tid after new event\n");
100       has_error = true;
101       return Process::cb_ret_t(Process::cbDefault, Process::cbDefault);
102    }
103    
104    if (all_tids.find(pair<PID, THR_ID>(pid, tid)) != all_tids.end()) {
105       logerror("Error. Recieved duplicate callback, or threads share a tid value\n");
106       has_error = true;
107    }
108    all_tids.insert(pair<PID, THR_ID>(pid, tid));
109
110    // In create mode, we won't be able to simulate an lwp create event for the
111    // initial thread before this callback occurs so ignore the initial thread
112    // -- this is valid because the initial lwp should never generate a callback
113    // and thus, we don't need to check that it occurred
114    if (lwp_cb_count && !thr->isInitialThread() && all_lwps.find(pair<PID, LWP>(pid, lwp)) == all_lwps.end()) {
115       logerror("Error. LWPs supported, but no LWP callback before UserThread callback\n");
116       has_error = true;
117    }
118    
119    Dyninst::Address start_func = thr->getStartFunction();
120    if (has_initial_func_info && !start_func && !thr->isInitialThread()) {
121       logerror("Error.  Thread has no start function\n");
122       has_error = true;
123    }
124
125    Dyninst::Address stack_addr = thr->getStackBase();
126    if (has_stack_info && !stack_addr && !thr->isInitialThread()) {
127       logerror("Error.  Thread has no stack\n");
128       has_error = true;
129    }
130    if (has_stack_info && all_stack_addrs.find(pair<PID, Address>(pid, stack_addr)) != all_stack_addrs.end()) {
131       logerror("Error.  Threads have duplicate stack addresses\n");
132       has_error = true;
133    }
134    all_stack_addrs.insert(pair<PID, Address>(pid, stack_addr));
135    
136    unsigned long stack_size = thr->getStackSize();
137    if (has_stack_info && !stack_size && !thr->isInitialThread()) {
138       logerror("Error.  Stack has no size\n");
139       has_error = true;
140    }
141
142    Dyninst::Address tls_addr = thr->getTLS();
143    if (!tls_addr) {
144       logerror("Error.  Thread has no TLS\n");
145       has_error = true;
146    }
147    if (all_tls.find(pair<PID, Address>(pid, tls_addr)) != all_tls.end()) {
148       logerror("Error.  Threads have duplicate TLS\n");
149       has_error = true;
150    }
151    all_tls.insert(pair<PID, Address>(pid, tls_addr));
152    
153    logstatus("[User Create] %d/%d: TID - 0x%lx, Start Func - 0x%lx, Stack Base - 0x%lx, Stack Size = 0x%lu, TLS = 0x%lx\n",
154            (int) pid, (int) lwp, (unsigned long) tid, (unsigned long) start_func, (unsigned long) stack_addr, (unsigned long) stack_size, (unsigned long) tls_addr);
155    
156    return Process::cb_ret_t(Process::cbDefault, Process::cbDefault);
157 }
158
159 static Process::cb_ret_t uthr_create(Event::const_ptr ev)
160 {
161    EventNewUserThread::const_ptr tev = ev->getEventNewUserThread();
162    if (!tev) {
163       logerror("Error.  Improper event type passed to callback\n");
164       has_error = true;
165       return Process::cb_ret_t(Process::cbDefault, Process::cbDefault);
166    }
167
168    Thread::const_ptr thr = tev->getNewThread();
169    return handle_new_thread(thr);
170 }
171
172 static Process::cb_ret_t uthr_destroy(Event::const_ptr ev)
173 {
174    if( ev->getEventType().time() == EventType::Pre ) user_exit_cb_count++;
175
176    EventUserThreadDestroy::const_ptr tev = ev->getEventUserThreadDestroy();
177    if (!tev) {
178       logerror("Error.  Improper event type passed to callback\n");
179       has_error = true;
180       return Process::cb_ret_t(Process::cbDefault, Process::cbDefault);
181    }
182    Thread::const_ptr thr = tev->getThread();
183
184    PID pid = thr->getProcess()->getPid();
185    LWP lwp = thr->getLWP();
186    THR_ID tid = thr->getTID();
187    
188    if (all_tids.find(pair<PID, THR_ID>(pid, tid)) == all_tids.end())
189    {
190       logerror("Thread destroy on unknown thread\n");
191       has_error = true;
192    }
193
194    char *pstr = NULL;
195    if (ev->getEventType().time() == EventType::Pre)
196    {
197       if (pre_dead_tids.find(pair<PID, THR_ID>(pid, tid)) != pre_dead_tids.end()) {
198          logerror("User Thread pre-died twice\n");
199          has_error = true;
200       }
201       pre_dead_tids.insert(pair<PID, THR_ID>(pid, tid));
202       pstr = "Pre-";
203    }
204    else if (ev->getEventType().time() == EventType::Post)
205    {
206       if (post_dead_tids.find(pair<PID, THR_ID>(pid, tid)) != post_dead_tids.end()) {
207          logerror("User Thread post-died twice\n");
208          has_error = true;
209       }
210       post_dead_tids.insert(pair<PID, THR_ID>(pid, tid));
211       pstr = "Post-";
212    }
213
214    logstatus("[%sUser Delete] %d/%d: TID - 0x%lx\n", pstr, pid, lwp, tid);
215
216    return Process::cbDefault;
217 }
218
219 static Process::cb_ret_t handle_lwp_create(Thread::const_ptr thr)
220 {
221    lwp_cb_count++;
222
223    PID pid = thr->getProcess()->getPid();
224    LWP lwp = thr->getLWP();
225    if (all_lwps.find(pair<PID, LWP>(pid, lwp)) != all_lwps.end()) {
226       logerror("Error.  Duplicate LWP values\n");
227       has_error = true;
228    }
229    all_lwps.insert(pair<PID, LWP>(pid, lwp));
230
231    ThreadPool::const_iterator i = thr->getProcess()->threads().find(lwp);
232    if (i == thr->getProcess()->threads().end() || *i != thr) {
233       logerror("Threadpool does not contain thread\n");
234       has_error = true;
235    }
236
237    if (!thr->isLive()) {
238       logerror("Thread is not live after create\n");
239       has_error = true;
240    }
241
242    bool prev_initial_thread = (all_initial_threads.find(pid) != all_initial_threads.end());
243    bool is_initial_thread = thr->isInitialThread();
244    if (prev_initial_thread && is_initial_thread) {
245       logerror("Multiple initial threads\n");
246       has_error = true;
247    }
248    if (is_initial_thread) {
249       if (thr->getProcess()->threads().getInitialThread() != thr) {
250          logerror("Disagreement with threadpool over initial thread value\n");
251          has_error = true;
252       }
253       all_initial_threads.insert(pid);
254    }
255    
256    logstatus("[LWP Create] - %d/%d, initial: %s\n", pid, lwp, is_initial_thread ? "true" : "false");
257    return Process::cb_ret_t(Process::cbDefault, Process::cbDefault);
258 }
259
260 static Process::cb_ret_t lwp_create(Event::const_ptr ev)
261 {
262    EventNewLWP::const_ptr lev = ev->getEventNewLWP();
263    if (!lev) {
264       logerror("Error.  Improper event type passed to callback\n");
265       has_error = true;
266       return Process::cb_ret_t(Process::cbDefault, Process::cbDefault);
267    }
268    Thread::const_ptr thr = lev->getNewThread();
269    return handle_lwp_create(thr);
270 }
271
272 static Process::cb_ret_t lwp_destroy(Event::const_ptr ev)
273 {
274    if (ev->getEventType().time() == EventType::Post)
275       lwp_exit_cb_count++;
276
277    EventLWPDestroy::const_ptr tev = ev->getEventLWPDestroy();
278    if (!tev) {
279       logerror("Error.  Improper event type passed to callback\n");
280       has_error = true;
281       return Process::cb_ret_t(Process::cbDefault, Process::cbDefault);
282    }
283    Thread::const_ptr thr = tev->getThread();
284
285    PID pid = thr->getProcess()->getPid();
286    LWP lwp = thr->getLWP();
287
288    char *pstr = NULL;
289    if (ev->getEventType().time() == EventType::Pre)
290    {
291       if (pre_dead_lwps.find(pair<PID, LWP>(pid, lwp)) != pre_dead_lwps.end()) {
292          logerror("LWP pre-died twice\n");
293          has_error = true;
294       }
295       pre_dead_lwps.insert(pair<PID, LWP>(pid, lwp));
296       pstr = "Pre-";
297    }
298    else if (ev->getEventType().time() == EventType::Post)
299    {
300       if (post_dead_lwps.find(pair<PID, LWP>(pid, lwp)) != post_dead_lwps.end()) {
301          logerror("LWP post-died twice\n");
302          has_error = true;
303       }
304       post_dead_lwps.insert(pair<PID, LWP>(pid, lwp));
305       pstr = "Post-";
306    }
307
308    if (all_lwps.find(pair<PID, LWP>(pid, lwp)) == all_lwps.end())
309    {
310       logerror("Dead LWP for unknown LWP\n");
311       has_error = true;
312    }
313
314    logstatus("[%sLWP Delete] %d/%d\n", pstr ? pstr : "", pid, lwp);
315
316    return Process::cbDefault;
317 }
318
319 static void checkThreadMsg(threadinfo tinfo, Process::ptr proc)
320 {
321    if (tinfo.pid != proc->getPid()) {
322       logerror("Error.  Mismatched pids in checkThreadMsg\n");
323       has_error = true;
324    }
325
326    ThreadPool::iterator i = proc->threads().find(tinfo.lwp);
327    if (i == proc->threads().end()) {
328       logerror("Error.  Could not find LWP in checkThreadMsg\n");
329       has_error = true;
330    }
331    Thread::ptr thr = *i;
332    
333    if (has_thr) {
334       if (thr->getTID() != (Dyninst::THR_ID) tinfo.tid) {
335          logerror("Error.  Mismatched TID, %lx != %lx\n", (unsigned long) thr->getTID(), (unsigned long) tinfo.tid);
336          has_error = true;
337       }
338       Dyninst::Address a_stack_addr = (Dyninst::Address) tinfo.a_stack_addr;
339       if (has_stack_info && (thr->getStackBase() < a_stack_addr || thr->getStackBase() + thr->getStackSize() > a_stack_addr)) {
340          logerror("Error.  Mismatched stack addresses\n");
341          has_error = true;
342       }
343       if (has_initial_func_info && thr->getStartFunction() != (Dyninst::Address) tinfo.initial_func) {
344          logerror("Mismatched initial function (%lx != %lx\n", (unsigned long)thr->getStartFunction(),
345                  (unsigned long)tinfo.initial_func);
346          has_error = true;
347       }
348       Dyninst::Address tls_addr = (Dyninst::Address) tinfo.tls_addr;
349 #define VALID_TLS_RANGE (1024*1024)
350       if (tls_addr < thr->getTLS() - VALID_TLS_RANGE || tls_addr > thr->getTLS() + VALID_TLS_RANGE) {
351          logerror("Error.  Invalid TLS address, pc: %lx\tmut: %lx\n", (unsigned long) thr->getTLS(), (unsigned long) tls_addr);
352          has_error = true;
353       }
354    }
355 }
356
357 test_results_t pc_threadMutator::pre_init(ParameterDict &param)
358 {
359    has_error = false;
360    user_cb_count = 0;
361    lwp_cb_count = 0;
362    user_exit_cb_count = 0;
363    lwp_exit_cb_count = 0;
364
365    all_tids.clear();
366    all_lwps.clear();
367    all_stack_addrs.clear();
368    all_tls.clear();
369    all_initial_threads.clear();
370    pre_dead_tids.clear();
371    post_dead_tids.clear();
372    pre_dead_lwps.clear();
373    post_dead_lwps.clear();
374
375 #if defined(os_linux_test)
376    has_lwp = true;
377    has_thr = true;
378    has_stack_info = false;
379 #elif defined(os_freebsd_test)
380    has_lwp = false;
381    has_thr = true;
382    has_stack_info = false;
383    has_initial_func_info = false;
384 #elif defined(os_bluegene_test)
385    has_lwp = false;
386    has_thr = true;
387 #else
388 #error Unknown platform
389 #endif
390
391    registerCB(EventType::UserThreadCreate, uthr_create);
392    registerCB(EventType::UserThreadDestroy, uthr_destroy);
393    registerCB(EventType::LWPCreate, lwp_create);
394    registerCB(EventType::LWPDestroy, lwp_destroy);
395
396    is_attach = (create_mode_t) param["useAttach"]->getInt() == USEATTACH;
397    if (has_error) return FAILED;
398    return PASSED;
399 }
400
401 test_results_t pc_threadMutator::executeTest()
402 {
403    std::vector<Process::ptr>::iterator i;
404
405    if (is_attach) {
406       //If attaching then we missed all of the thread callbacks.  Run them.
407       for (i = comp->procs.begin(); i != comp->procs.end(); i++) {
408          Process::ptr proc = *i;
409          ThreadPool::iterator j;
410        
411          if (has_lwp)
412          {
413             handle_lwp_create(proc->threads().getInitialThread());
414             for (j = proc->threads().begin(); j != proc->threads().end(); j++) {
415                if ((*j)->isInitialThread())
416                   continue;
417                handle_lwp_create(*j);
418             }
419          }
420          if (has_thr)
421          {
422             handle_new_thread(proc->threads().getInitialThread());
423             for (j = proc->threads().begin(); j != proc->threads().end(); j++) {
424                if ((*j)->isInitialThread())
425                   continue;
426                handle_new_thread(*j);
427             }
428          }
429       }
430    }
431    else {
432       //We never get thread create callbacks for the initial thread (by design).  Fake it to setup
433       // some of the test data structures.
434       for (i = comp->procs.begin(); i != comp->procs.end(); i++) {
435          Process::ptr proc = *i;
436          Thread::ptr init_thr = proc->threads().getInitialThread();
437          handle_lwp_create(init_thr);
438       }
439    }
440
441    for (i = comp->procs.begin(); i != comp->procs.end(); i++) {
442       Process::ptr proc = *i;
443       bool result = proc->continueProc();
444       if (!result) {
445          logerror("Failed to continue process\n");
446          has_error = true;
447       }
448    }
449    
450
451    int num_thrds = comp->num_processes * comp->num_threads;
452    int num_noninit_thrds = comp->num_processes * (comp->num_threads - 1);
453
454    for (i = comp->procs.begin(); i != comp->procs.end(); i++) {
455       for (unsigned j=0; j < comp->num_threads; j++) {
456          threadinfo tinfo;
457          bool result = comp->recv_message((unsigned char *) &tinfo, sizeof(threadinfo), *i);
458          if (!result) {
459             logerror("Failed to recieve threadinfo message\n");
460             has_error = true;
461          }
462          checkThreadMsg(tinfo, *i);
463       }
464    }
465
466    syncloc loc;
467    loc.code = SYNCLOC_CODE;
468    bool result = comp->send_broadcast((unsigned char *) &loc, sizeof(syncloc));
469    if (!result) {
470       logerror("Failed to send sync broadcast\n");
471       has_error = true;
472    }   
473
474
475    while ((has_thr && user_exit_cb_count < num_noninit_thrds) ||
476           (has_lwp && lwp_exit_cb_count < num_noninit_thrds)) 
477    {
478       bool result = comp->block_for_events();
479       if (!result) {
480          logerror("Failed to wait for thread terminate events\n");
481          has_error = true;
482          break;
483       }
484    }
485    while (comp->poll_for_events());
486
487    return has_error ? FAILED : PASSED;
488 }
489
490