void listener_func() {
  while (!g_done) {
    SBEvent event;
    bool got_event = g_listener.WaitForEvent(1, event);
    if (got_event) {
      if (!event.IsValid())
        throw Exception("event is not valid in listener thread");
        // send process description
        SBProcess process = SBProcess::GetProcessFromEvent(event);
        if (!process.IsValid())
            throw Exception("process is not valid");
        if (SBProcess::GetStateFromEvent(event) != lldb::eStateStopped || SBProcess::GetRestartedFromEvent(event))
            continue; // Only interested in "stopped" events.

        SBStream description;

        for (int i = 0; i < process.GetNumThreads(); ++i) {
            // send each thread description
            SBThread thread = process.GetThreadAtIndex(i);
            // send each frame function name
            uint32_t num_frames = thread.GetNumFrames();
            for(int j = 0; j < num_frames; ++j) {
                const char* function_name = thread.GetFrameAtIndex(j).GetSymbol().GetName();
                if (function_name)
                    g_frame_functions.push(string(function_name));
            }
        }
    }
  }
}
示例#2
0
void
SBDebugger::HandleProcessEvent (const SBProcess &process, const SBEvent &event, FILE *out, FILE *err)
{
    if (!process.IsValid())
        return;

    TargetSP target_sp (process.GetTarget().GetSP());
    if (!target_sp)
        return;

    const uint32_t event_type = event.GetType();
    char stdio_buffer[1024];
    size_t len;

    Mutex::Locker api_locker (target_sp->GetAPIMutex());
    
    if (event_type & (Process::eBroadcastBitSTDOUT | Process::eBroadcastBitStateChanged))
    {
        // Drain stdout when we stop just in case we have any bytes
        while ((len = process.GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
            if (out != NULL)
                ::fwrite (stdio_buffer, 1, len, out);
    }
    
    if (event_type & (Process::eBroadcastBitSTDERR | Process::eBroadcastBitStateChanged))
    {
        // Drain stderr when we stop just in case we have any bytes
        while ((len = process.GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
            if (err != NULL)
                ::fwrite (stdio_buffer, 1, len, err);
    }
    
    if (event_type & Process::eBroadcastBitStateChanged)
    {
        StateType event_state = SBProcess::GetStateFromEvent (event);
        
        if (event_state == eStateInvalid)
            return;
        
        bool is_stopped = StateIsStoppedState (event_state);
        if (!is_stopped)
            process.ReportEventState (event, out);
    }
}
示例#3
0
size_t
Driver::EditLineInputReaderCallback 
(
    void *baton, 
    SBInputReader *reader, 
    InputReaderAction notification,
    const char *bytes, 
    size_t bytes_len
)
{
    Driver *driver = (Driver *)baton;

    switch (notification)
    {
    case eInputReaderActivate:
        break;

    case eInputReaderReactivate:
        driver->ReadyForCommand();
        break;

    case eInputReaderDeactivate:
        break;
        
    case eInputReaderAsynchronousOutputWritten:
        if (driver->m_io_channel_ap.get() != NULL)
            driver->m_io_channel_ap->RefreshPrompt();
        break;

    case eInputReaderInterrupt:
        if (driver->m_io_channel_ap.get() != NULL)
        {
            SBProcess process = driver->GetDebugger().GetSelectedTarget().GetProcess();
            if (!driver->m_io_channel_ap->EditLineHasCharacters()
                &&  process.IsValid() && process.GetState() == lldb::eStateRunning)
            {
                process.Stop();
            }
            else
            {
                driver->m_io_channel_ap->OutWrite ("^C\n", 3, NO_ASYNC);
                // I wish I could erase the entire input line, but there's no public API for that.
                driver->m_io_channel_ap->EraseCharsBeforeCursor();
                driver->m_io_channel_ap->RefreshPrompt();
            }
        }
        break;
        
    case eInputReaderEndOfFile:
        if (driver->m_io_channel_ap.get() != NULL)
        {
            driver->m_io_channel_ap->OutWrite ("^D\n", 3, NO_ASYNC);
            driver->m_io_channel_ap->RefreshPrompt ();
        }
#ifdef __unix__
        write (driver->m_editline_pty.GetMasterFileDescriptor(), "quit\n", 5);
#endif
        break;

    case eInputReaderGotToken:
#ifdef __unix__
        write (driver->m_editline_pty.GetMasterFileDescriptor(), bytes, bytes_len);
#endif
        break;
        
    case eInputReaderDone:
        break;
    }
    return bytes_len;
}
示例#4
0
// This function handles events that were broadcast by the process.
void
Driver::HandleProcessEvent (const SBEvent &event)
{
    using namespace lldb;
    const uint32_t event_type = event.GetType();

    if (event_type & SBProcess::eBroadcastBitSTDOUT)
    {
        // The process has stdout available, get it and write it out to the
        // appropriate place.
        GetProcessSTDOUT ();
    }
    else if (event_type & SBProcess::eBroadcastBitSTDERR)
    {
        // The process has stderr available, get it and write it out to the
        // appropriate place.
        GetProcessSTDERR ();
    }
    else if (event_type & SBProcess::eBroadcastBitStateChanged)
    {
        // Drain all stout and stderr so we don't see any output come after
        // we print our prompts
        GetProcessSTDOUT ();
        GetProcessSTDERR ();
        // Something changed in the process;  get the event and report the process's current status and location to
        // the user.
        StateType event_state = SBProcess::GetStateFromEvent (event);
        if (event_state == eStateInvalid)
            return;

        SBProcess process (SBProcess::GetProcessFromEvent (event));
        assert (process.IsValid());

        switch (event_state)
        {
        case eStateInvalid:
        case eStateUnloaded:
        case eStateConnected:
        case eStateAttaching:
        case eStateLaunching:
        case eStateStepping:
        case eStateDetached:
            {
                char message[1024];
                int message_len = ::snprintf (message, sizeof(message), "Process %llu %s\n", process.GetProcessID(),
                                              m_debugger.StateAsCString (event_state));
                m_io_channel_ap->OutWrite(message, message_len, ASYNC);
            }
            break;

        case eStateRunning:
            // Don't be chatty when we run...
            break;

        case eStateExited:
            {
                SBCommandReturnObject result;
                m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false);
                m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC);
                m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC);
            }
            break;

        case eStateStopped:
        case eStateCrashed:
        case eStateSuspended:
            // Make sure the program hasn't been auto-restarted:
            if (SBProcess::GetRestartedFromEvent (event))
            {
                // FIXME: Do we want to report this, or would that just be annoyingly chatty?
                char message[1024];
                int message_len = ::snprintf (message, sizeof(message), "Process %llu stopped and was programmatically restarted.\n",
                                              process.GetProcessID());
                m_io_channel_ap->OutWrite(message, message_len, ASYNC);
            }
            else
            {
                if (GetDebugger().GetSelectedTarget() == process.GetTarget())
                {
                    SBCommandReturnObject result;
                    UpdateSelectedThread ();
                    m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false);
                    m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC);
                    m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC);
                }
                else
                {
                    SBStream out_stream;
                    uint32_t target_idx = GetDebugger().GetIndexOfTarget(process.GetTarget());
                    if (target_idx != UINT32_MAX)
                        out_stream.Printf ("Target %d: (", target_idx);
                    else
                        out_stream.Printf ("Target <unknown index>: (");
                    process.GetTarget().GetDescription (out_stream, eDescriptionLevelBrief);
                    out_stream.Printf (") stopped.\n");
                    m_io_channel_ap->OutWrite (out_stream.GetData(), out_stream.GetSize(), ASYNC);
                }
            }
            break;
        }
    }
}
示例#5
0
int
main (int argc, char **argv, char **envp)
{
	int narg;
	fd_set set;
	char commandLine[BIG_LINE_MAX];		// data from cdt
	char consoleLine[LINE_MAX];			// data from eclipse's console
	long chars;
	struct timeval timeout;
	int isVersion=0, isInterpreter=0;
	const char *testCommand=NULL;
	int  isLog=0;
	int  logmask=LOG_ALL;

	state.ptyfd = EOF;
	state.gdbPrompt = "GNU gdb (GDB) 7.7.1\n";
	sprintf (state.lldbmi2Prompt, "lldbmi2 version %s\n", LLDBMI2_VERSION);
	state.cdtbufferB.grow(BIG_LINE_MAX);

	limits.frames_max = FRAMES_MAX;
	limits.children_max = CHILDREN_MAX;
	limits.walk_depth_max = WALK_DEPTH_MAX;
	limits.change_depth_max = CHANGE_DEPTH_MAX;

	// get args
	for (narg=0; narg<argc; narg++) {
		logarg (argv[narg]);
		if (strcmp (argv[narg],"--version") == 0)
			isVersion = 1;
		else if (strcmp (argv[narg],"--interpreter") == 0 ) {
			isInterpreter = 1;
			if (++narg<argc)
				logarg(argv[narg]);
		}
		else if (strcmp (argv[narg],"--test") == 0 ) {
			limits.istest = true;
			if (++narg<argc)
				sscanf (logarg(argv[narg]), "%d", &state.test_sequence);
			if (state.test_sequence)
				setTestSequence (state.test_sequence);
		}
		else if (strcmp (argv[narg],"--script") == 0 ) {
			limits.istest = true;
			if (++narg<argc)
				strcpy (state.test_script, logarg(argv[narg]));		// no spaces allowed in the name
			if (state.test_script[0])
				setTestScript (state.test_script);
		}
		else if (strcmp (argv[narg],"--log") == 0 )
			isLog = 1;
		else if (strcmp (argv[narg],"--logmask") == 0 ) {
			isLog = 1;
			if (++narg<argc)
				sscanf (logarg(argv[narg]), "%x", &logmask);
		}
		else if (strcmp (argv[narg],"--frames") == 0 ) {
			if (++narg<argc)
				sscanf (logarg(argv[narg]), "%d", &limits.frames_max);
		}
		else if (strcmp (argv[narg],"--children") == 0 ) {
			if (++narg<argc)
				sscanf (logarg(argv[narg]), "%d", &limits.children_max);
		}
		else if (strcmp (argv[narg],"--walkdepth") == 0 ) {
			if (++narg<argc)
				sscanf (logarg(argv[narg]), "%d", &limits.walk_depth_max);
		}
		else if (strcmp (argv[narg],"--changedepth") == 0 ) {
			if (++narg<argc)
				sscanf (logarg(argv[narg]), "%d", &limits.change_depth_max);
		}
	}

	// create a log filename from program name and open log file
	if (isLog) {
		if (limits.istest)
			setlogfile (state.logfilename, sizeof(state.logfilename), argv[0], "lldbmi2t.log");
		else
			setlogfile (state.logfilename, sizeof(state.logfilename), argv[0], "lldbmi2.log");
		openlog (state.logfilename);
		setlogmask (logmask);
	}

	// log program args
	addlog("\n");
	logprintf (LOG_ARGS, NULL);

	state.envp[0] = NULL;
	state.envpentries = 0;
	state.envspointer = state.envs;
	const char *wl = "PWD=";		// want to get eclipse project_loc if any
	int wll = strlen(wl);
	// copy environment for tested program
	for (int ienv=0; envp[ienv]; ienv++) {
		addEnvironment (&state, envp[ienv]);
		if (strncmp(envp[ienv], wl, wll)==0)
			strcpy (state.project_loc, envp[ienv]+wll);
	}

	// return gdb version if --version
	if (isVersion) {
		writetocdt (state.gdbPrompt);
		writetocdt (state.lldbmi2Prompt);
		return EXIT_SUCCESS;
	}
	// check if --interpreter mi2
	else if (!isInterpreter) {
		help (&state);
		return EXIT_FAILURE;
	}

	initializeSB (&state);
	signal (SIGINT, signalHandler);
	signal (SIGSTOP, signalHandler);

	cdtprintf ("(gdb)\n");

	// main loop
	FD_ZERO (&set);
	while (!state.eof) {
		if (limits.istest)
			logprintf (LOG_NONE, "main loop\n");
		// get inputs
		timeout.tv_sec  = 0;
		timeout.tv_usec = 200000;
		// check command from CDT
		FD_SET (STDIN_FILENO, &set);
		if (state.ptyfd != EOF) {
			// check data from Eclipse's console
			FD_SET (state.ptyfd, &set);
			select(state.ptyfd+1, &set, NULL, NULL, &timeout);
		}
		else
			select(STDIN_FILENO+1, &set, NULL, NULL, &timeout);
		if (FD_ISSET(STDIN_FILENO, &set) && !state.eof && !limits.istest) {
			logprintf (LOG_NONE, "read in\n");
			chars = read (STDIN_FILENO, commandLine, sizeof(commandLine)-1);
			logprintf (LOG_NONE, "read out %d chars\n", chars);
			if (chars>0) {
				commandLine[chars] = '\0';
				while (fromCDT (&state,commandLine,sizeof(commandLine)) == MORE_DATA)
					commandLine[0] = '\0';
			}
			else
				state.eof = true;
		}
		if (state.ptyfd!=EOF && state.isrunning) {			// input from user to program
			if (FD_ISSET(state.ptyfd, &set) && !state.eof && !limits.istest) {
				logprintf (LOG_NONE, "pty read in\n");
				chars = read (state.ptyfd, consoleLine, sizeof(consoleLine)-1);
				logprintf (LOG_NONE, "pty read out %d chars\n", chars);
				if (chars>0) {
					logprintf (LOG_PROG_OUT, "pty read %d chars\n", chars);
					consoleLine[chars] = '\0';
					SBProcess process = state.process;
					if (process.IsValid())
						process.PutSTDIN (consoleLine, chars);
				}
			}
		}
		// execute test command if test mode
		if (!state.eof && limits.istest && !state.isrunning) {
			if ((testCommand=getTestCommand ())!=NULL) {
				snprintf (commandLine, sizeof(commandLine), "%s\n", testCommand);
				fromCDT (&state, commandLine, sizeof(commandLine));
			}
		}
		// execute stacked commands if many command arrived once
		if (!state.eof && state.cdtbufferB.size()>0) {
			commandLine[0] = '\0';
			while (fromCDT (&state, commandLine, sizeof(commandLine)) == MORE_DATA)
				;
		}
	}

	if (state.ptyfd != EOF)
		close (state.ptyfd);
	terminateSB ();

	logprintf (LOG_INFO, "main exit\n");
	closelog ();

	return EXIT_SUCCESS;
}