brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · 68d73f1 Raw
306 lines · cpp
1 2// This program creates NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS of pthreads,3// creates an lldb Debugger on each thread, creates targets, inserts two4// breakpoints, runs to the first breakpoint, backtraces, runs to the second5// breakpoint, backtraces, kills the inferior process, closes down the6// debugger.7 8// The main thread keeps track of which pthreads have completed and which9// pthreads have completed successfully, and exits when all pthreads have10// completed successfully, or our time limit has been exceeded.11 12// This test file helps to uncover race conditions and locking mistakes13// that are hit when lldb is being used to debug multiple processes14// simultaneously.15 16#include <inttypes.h>17#include <stdio.h>18#include <stdlib.h>19#include <string.h>20#include <unistd.h>21 22#include "lldb/API/LLDB.h"23#include "lldb/API/SBCommandInterpreter.h"24#include "lldb/API/SBCommandReturnObject.h"25#include "lldb/API/SBDebugger.h"26 27#include <chrono>28#include <csignal>29#include <thread>30 31#define NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS 1032 33#define DEBUG 034 35#define STR1(x) #x36#define STR(x) STR1(x)37 38using namespace lldb;39 40bool *completed_threads_array = 0;41bool *successful_threads_array  = 0;42 43const char *inferior_process_name = "testprog";44 45bool46wait_for_stop_event (SBProcess process, SBListener listener)47{48    bool stopped = false;49    while (!stopped)50    {51        SBEvent event;52        bool waitfor_ret = listener.WaitForEvent (2, event);53        if (event.GetType() == SBProcess::eBroadcastBitStateChanged)54        {55            if (process.GetState() == StateType::eStateStopped56                || process.GetState() == StateType::eStateCrashed57                || process.GetState() == StateType::eStateDetached58                || process.GetState() == StateType::eStateExited)59            {60                stopped = true;61            }62        }63    }64    return stopped;65}66 67bool68walk_stack_to_main (SBThread thread)69{70    if (thread.IsValid() == 0)71    {72        return false;73    }74 75    bool found_main = false;76    uint32_t curr_frame = 0;77    const uint32_t framecount = thread.GetNumFrames();78    while (!found_main && curr_frame < framecount)79    {80        SBFrame frame = thread.GetFrameAtIndex (curr_frame);81        if (strcmp (frame.GetFunctionName(), "main") == 0)82        {83            found_main = true;84            break;85        }86        curr_frame += 1;87    }88    return found_main;89}90 91void *do_one_debugger (void *in)92{93    uint64_t threadnum = (uint64_t) in;94 95#if defined (__APPLE__)96    char *threadname;97    asprintf (&threadname, "thread #%lld", threadnum);98    pthread_setname_np (threadname);99    free (threadname);100#endif101 102#if DEBUG == 1103    printf ("#%lld: Starting debug session\n", threadnum);104#endif105 106    SBDebugger debugger = lldb::SBDebugger::Create (false);107    if (debugger.IsValid ())108    {109        debugger.SetAsync (true);110        SBTarget target = debugger.CreateTargetWithFileAndArch(inferior_process_name,111                                                               STR(LLDB_HOST_ARCH));112        SBCommandInterpreter command_interp = debugger.GetCommandInterpreter();113        if (target.IsValid())114        {115            SBBreakpoint bar_br = target.BreakpointCreateByName ("bar", "testprog");116            if (!bar_br.IsValid())117            {118                printf ("#%" PRIu64 ": failed to set breakpoint on bar, exiting.\n", threadnum);119                exit (1);120            }121            SBBreakpoint foo_br = target.BreakpointCreateByName ("foo", "testprog");122            if (!foo_br.IsValid())123            {124                printf ("#%" PRIu64 ": Failed to set breakpoint on foo()\n", threadnum);125            }126 127            SBLaunchInfo launch_info (NULL);128            SBError error;129            SBProcess process = target.Launch (launch_info, error);130            if (process.IsValid())131            {132                SBListener listener = debugger.GetListener();133                SBBroadcaster broadcaster = process.GetBroadcaster();134                uint32_t rc = broadcaster.AddListener (listener, SBProcess::eBroadcastBitStateChanged);135                if (rc == 0)136                {137                    printf ("adding listener failed\n");138                    exit (1);139                }140 141                wait_for_stop_event (process, listener);142 143                if (!walk_stack_to_main (process.GetThreadAtIndex(0)))144                {145                    printf ("#%" PRIu64 ": backtrace while @ foo() failed\n", threadnum);146                    completed_threads_array[threadnum] = true;147                    return (void *) 1;148                }149 150                // On Linux the () are included.151                const char* hit_fn = process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName();152                if (strcmp (hit_fn, "foo") != 0 && strcmp (hit_fn, "foo()") != 0)153                {154#if DEBUG == 1155                    printf ("#%" PRIu64 ": First breakpoint did not stop at foo(), instead stopped at '%s'\n", threadnum, process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName());156#endif157                    completed_threads_array[threadnum] = true;158                    return (void*) 1;159                }160 161                process.Continue();162 163                wait_for_stop_event (process, listener);164 165                if (process.GetState() == StateType::eStateExited)166                {167                    printf ("#%" PRIu64 ": Process exited\n", threadnum);168                    completed_threads_array[threadnum] = true;169                    return (void *) 1;170                }171 172 173                if (!walk_stack_to_main (process.GetThreadAtIndex(0)))174                {175                    printf ("#%" PRIu64 ": backtrace while @ bar() failed\n", threadnum);176                    completed_threads_array[threadnum] = true;177                    return (void *) 1;178                }179 180                hit_fn = process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName();181                if (strcmp (hit_fn, "bar") != 0 && strcmp (hit_fn, "bar()") != 0)182                {183                    printf ("#%" PRIu64 ": First breakpoint did not stop at bar()\n", threadnum);184                    completed_threads_array[threadnum] = true;185                    return (void*) 1;186                }187 188                process.Kill();189 190                wait_for_stop_event (process, listener);191 192                SBDebugger::Destroy(debugger);193 194#if DEBUG == 1195                printf ("#%" PRIu64 ": All good!\n", threadnum);196#endif197                successful_threads_array[threadnum] = true;198                completed_threads_array[threadnum] = true;199                return (void*) 0;200            }201            else202            {203                printf("#%" PRIu64 ": process failed to launch\n", threadnum);204                successful_threads_array[threadnum] = false;205                completed_threads_array[threadnum] = true;206                return (void*) 0;207            }208        }209        else210        {211            printf ("#%" PRIu64 ": did not get valid target\n", threadnum);212            successful_threads_array[threadnum] = false;213            completed_threads_array[threadnum] = true;214            return (void*) 0;215        }216    }217    else218    {219        printf ("#%" PRIu64 ": did not get debugger\n", threadnum);220        successful_threads_array[threadnum] = false;221        completed_threads_array[threadnum] = true;222        return (void*) 0;223    }224    completed_threads_array[threadnum] = true;225    return (void*) 1;226}227 228int count_completed_threads(int num_threads) {229  int num_completed_threads = 0;230  for (int i = 0; i < num_threads; i++)231    if (completed_threads_array[i])232      num_completed_threads++;233  return num_completed_threads;234}235 236int count_successful_threads(int num_threads) {237  int num_successful_threads = 0;238  for (int i = 0; i < num_threads; i++)239    if (successful_threads_array[i])240      num_successful_threads++;241  return num_successful_threads;242}243 244int main (int argc, char **argv)245{246#if !defined(_MSC_VER)247  signal(SIGPIPE, SIG_IGN);248#endif249 250    SBDebugger::Initialize();251 252    completed_threads_array = (bool *) malloc (sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);253    memset (completed_threads_array, 0, sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);254    successful_threads_array = (bool *) malloc (sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);255    memset (successful_threads_array, 0, sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);256 257    if (argc > 1 && argv[1] != NULL)258    {259        inferior_process_name = argv[1];260    }261 262    std::thread threads[NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS];263    for (uint64_t i = 0; i< NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS; i++)264    {265        threads[i] = std::move(std::thread(do_one_debugger, (void*)i));266    }267 268 269    int max_time_to_wait = 40;  // 40 iterations, or 120 seconds270    if (getenv("ASAN_OPTIONS"))271      max_time_to_wait *= 4;272    for (int iter = 0; iter < max_time_to_wait; iter++) {273        std::this_thread::sleep_for(std::chrono::seconds(3));274        int successful_threads = count_successful_threads(NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);275        int total_completed_threads = count_completed_threads(NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);276 277        if (total_completed_threads == NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS)278        {279#if DEBUG == 1280            printf ("All threads completed.\n");281            printf ("%d threads completed successfully out of %d\n", successful_threads, NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);282#endif283            SBDebugger::Terminate();284            exit(0);285        }286        else287        {288#if DEBUG == 1289            printf ("%d threads completed so far (%d successfully), out of %d\n", total_completed_threads, successful_threads, NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);290#endif291        }292        if (iter == max_time_to_wait)293          printf("reached maximum timeout but only %d threads have completed "294                 "so far "295                 "(%d successfully), out of %d.  Exiting.\n",296                 total_completed_threads, successful_threads,297                 NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS);298    }299 300    // We do not call SBDebugger::Terminate() here because it will destroy301    // data that might be being used by threads that are still running. Which302    // would change the timeout into an unrelated crash.303    // _exit instead of exit, to skip more things that could cause a crash.304    _exit(1);305}306