• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- IOChannel.cpp -------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "IOChannel.h"
11 
12 #include <map>
13 
14 #include "lldb/API/SBCommandInterpreter.h"
15 #include "lldb/API/SBDebugger.h"
16 #include "lldb/API/SBError.h"
17 #include "lldb/API/SBEvent.h"
18 #include "lldb/API/SBFileSpec.h"
19 #include "lldb/API/SBHostOS.h"
20 #include "lldb/API/SBListener.h"
21 #include "lldb/API/SBStringList.h"
22 
23 #include <string.h>
24 #include <limits.h>
25 
26 using namespace lldb;
27 
28 typedef std::map<EditLine *, std::string> PromptMap;
29 const char *g_default_prompt = "(lldb) ";
30 PromptMap g_prompt_map;
31 
32 // Printing the following string causes libedit to back up to the beginning of the line & blank it out.
33 const char undo_prompt_string[4] = { (char) 13, (char) 27, (char) 91, (char) 75};
34 
35 static const char*
el_prompt(EditLine * el)36 el_prompt(EditLine *el)
37 {
38     PromptMap::const_iterator pos = g_prompt_map.find (el);
39     if (pos == g_prompt_map.end())
40         return g_default_prompt;
41     return pos->second.c_str();
42 }
43 
44 const char *
GetPrompt()45 IOChannel::GetPrompt ()
46 {
47     PromptMap::const_iterator pos = g_prompt_map.find (m_edit_line);
48     if (pos == g_prompt_map.end())
49         return g_default_prompt;
50     return pos->second.c_str();
51 }
52 
53 bool
EditLineHasCharacters()54 IOChannel::EditLineHasCharacters ()
55 {
56     const LineInfo *line_info  = el_line(m_edit_line);
57     if (line_info)
58     {
59         // Sometimes we get called after the user has submitted the line, but before editline has
60         // cleared the buffer.  In that case the cursor will be pointing at the newline.  That's
61         // equivalent to having no characters on the line, since it has already been submitted.
62         if (*line_info->cursor == '\n')
63             return false;
64         else
65             return line_info->cursor != line_info->buffer;
66     }
67     else
68         return false;
69 }
70 
71 
72 void
EraseCharsBeforeCursor()73 IOChannel::EraseCharsBeforeCursor ()
74 {
75     const LineInfo *line_info  = el_line(m_edit_line);
76     el_deletestr(m_edit_line, line_info->cursor - line_info->buffer);
77 }
78 
79 unsigned char
ElCompletionFn(EditLine * e,int ch)80 IOChannel::ElCompletionFn (EditLine *e, int ch)
81 {
82     IOChannel *io_channel;
83     if (el_get(e, EL_CLIENTDATA, &io_channel) == 0)
84     {
85         return io_channel->HandleCompletion (e, ch);
86     }
87     else
88     {
89         return CC_ERROR;
90     }
91 }
92 
93 void
ElResize()94 IOChannel::ElResize()
95 {
96     el_resize(m_edit_line);
97 }
98 
99 unsigned char
HandleCompletion(EditLine * e,int ch)100 IOChannel::HandleCompletion (EditLine *e, int ch)
101 {
102     assert (e == m_edit_line);
103 
104     const LineInfo *line_info  = el_line(m_edit_line);
105     SBStringList completions;
106     int page_size = 40;
107 
108     int num_completions = m_driver->GetDebugger().GetCommandInterpreter().HandleCompletion (line_info->buffer,
109                                                                                             line_info->cursor,
110                                                                                             line_info->lastchar,
111                                                                                             0,
112                                                                                             -1,
113                                                                                             completions);
114 
115     if (num_completions == -1)
116     {
117         el_insertstr (m_edit_line, m_completion_key);
118         return CC_REDISPLAY;
119     }
120     else if (num_completions == -2)
121     {
122         el_deletestr (m_edit_line, line_info->cursor - line_info->buffer);
123         el_insertstr (m_edit_line, completions.GetStringAtIndex(0));
124         return CC_REDISPLAY;
125     }
126 
127     // If we get a longer match display that first.
128     const char *completion_str = completions.GetStringAtIndex(0);
129     if (completion_str != NULL && *completion_str != '\0')
130     {
131         el_insertstr (m_edit_line, completion_str);
132         return CC_REDISPLAY;
133     }
134 
135     if (num_completions > 1)
136     {
137         const char *comment = "\nAvailable completions:";
138 
139         int num_elements = num_completions + 1;
140         OutWrite(comment,  strlen (comment), NO_ASYNC);
141         if (num_completions < page_size)
142         {
143             for (int i = 1; i < num_elements; i++)
144             {
145                 completion_str = completions.GetStringAtIndex(i);
146                 OutWrite("\n\t", 2, NO_ASYNC);
147                 OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
148             }
149             OutWrite ("\n", 1, NO_ASYNC);
150         }
151         else
152         {
153             int cur_pos = 1;
154             char reply;
155             int got_char;
156             while (cur_pos < num_elements)
157             {
158                 int endpoint = cur_pos + page_size;
159                 if (endpoint > num_elements)
160                     endpoint = num_elements;
161                 for (; cur_pos < endpoint; cur_pos++)
162                 {
163                     completion_str = completions.GetStringAtIndex(cur_pos);
164                     OutWrite("\n\t", 2, NO_ASYNC);
165                     OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
166                 }
167 
168                 if (cur_pos >= num_elements)
169                 {
170                     OutWrite("\n", 1, NO_ASYNC);
171                     break;
172                 }
173 
174                 OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "), NO_ASYNC);
175                 reply = 'n';
176                 got_char = el_getc(m_edit_line, &reply);
177                 if (got_char == -1 || reply == 'n')
178                     break;
179                 if (reply == 'a')
180                     page_size = num_elements - cur_pos;
181             }
182         }
183 
184     }
185 
186     if (num_completions == 0)
187         return CC_REFRESH_BEEP;
188     else
189         return CC_REDISPLAY;
190 }
191 
IOChannel(FILE * editline_in,FILE * editline_out,FILE * out,FILE * err,Driver * driver)192 IOChannel::IOChannel
193 (
194     FILE *editline_in,
195     FILE *editline_out,
196     FILE *out,
197     FILE *err,
198     Driver *driver
199 ) :
200     SBBroadcaster ("IOChannel"),
201     m_output_mutex (),
202     m_enter_elgets_time (),
203     m_driver (driver),
204     m_read_thread (LLDB_INVALID_HOST_THREAD),
205     m_read_thread_should_exit (false),
206     m_out_file (out),
207     m_err_file (err),
208     m_command_queue (),
209     m_completion_key ("\t"),
210     m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), editline_in, editline_out,  editline_out)),
211     m_history (history_init()),
212     m_history_event(),
213     m_getting_command (false),
214     m_expecting_prompt (false),
215 	m_prompt_str (),
216     m_refresh_request_pending (false)
217 {
218     assert (m_edit_line);
219     ::el_set (m_edit_line, EL_PROMPT, el_prompt);
220     ::el_set (m_edit_line, EL_EDITOR, "emacs");
221     ::el_set (m_edit_line, EL_HIST, history, m_history);
222 
223     el_set (m_edit_line, EL_ADDFN, "lldb_complete",
224             "LLDB completion function",
225             IOChannel::ElCompletionFn);
226     el_set (m_edit_line, EL_BIND, m_completion_key, "lldb_complete", NULL);
227     el_set (m_edit_line, EL_BIND, "^r", "em-inc-search-prev", NULL);  // Cycle through backwards search, entering string
228     el_set (m_edit_line, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does.
229     el_set (m_edit_line, EL_BIND, "\e[3~", "ed-delete-next-char", NULL); // Fix the delete key.
230     el_set (m_edit_line, EL_CLIENTDATA, this);
231 
232     // Source $PWD/.editrc then $HOME/.editrc
233     ::el_source (m_edit_line, NULL);
234 
235     assert (m_history);
236     ::history (m_history, &m_history_event, H_SETSIZE, 800);
237     ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
238     // Load history
239     HistorySaveLoad (false);
240 
241     // Set up mutex to make sure OutErr, OutWrite and RefreshPrompt do not interfere
242     // with each other when writing.
243 
244     int error;
245     ::pthread_mutexattr_t attr;
246     error = ::pthread_mutexattr_init (&attr);
247     assert (error == 0);
248     error = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
249     assert (error == 0);
250     error = ::pthread_mutex_init (&m_output_mutex, &attr);
251     assert (error == 0);
252     error = ::pthread_mutexattr_destroy (&attr);
253     assert (error == 0);
254 
255     // Initialize time that ::el_gets was last called.
256 
257     m_enter_elgets_time.tv_sec = 0;
258     m_enter_elgets_time.tv_usec = 0;
259 }
260 
~IOChannel()261 IOChannel::~IOChannel ()
262 {
263     // Save history
264     HistorySaveLoad (true);
265 
266     if (m_history != NULL)
267     {
268         ::history_end (m_history);
269         m_history = NULL;
270     }
271 
272     if (m_edit_line != NULL)
273     {
274         ::el_end (m_edit_line);
275         m_edit_line = NULL;
276     }
277 
278     ::pthread_mutex_destroy (&m_output_mutex);
279 }
280 
281 void
HistorySaveLoad(bool save)282 IOChannel::HistorySaveLoad (bool save)
283 {
284     if (m_history != NULL)
285     {
286         char history_path[PATH_MAX];
287         ::snprintf (history_path, sizeof(history_path), "~/.%s-history", SBHostOS::GetProgramFileSpec().GetFilename());
288         if ((size_t)SBFileSpec::ResolvePath (history_path, history_path, sizeof(history_path)) < sizeof(history_path) - 1)
289         {
290             const char *path_ptr = history_path;
291             if (save)
292                 ::history (m_history, &m_history_event, H_SAVE, path_ptr);
293             else
294                 ::history (m_history, &m_history_event, H_LOAD, path_ptr);
295         }
296     }
297 }
298 
299 void
LibeditOutputBytesReceived(void * baton,const void * src,size_t src_len)300 IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_len)
301 {
302 	// Make this a member variable.
303     // static std::string prompt_str;
304     IOChannel *io_channel = (IOChannel *) baton;
305     IOLocker locker (io_channel->m_output_mutex);
306     const char *bytes = (const char *) src;
307 
308     if (io_channel->IsGettingCommand() && io_channel->m_expecting_prompt)
309     {
310         io_channel->m_prompt_str.append (bytes, src_len);
311 		// Log this to make sure the prompt is really what you think it is.
312         if (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == 0)
313         {
314             io_channel->m_expecting_prompt = false;
315             io_channel->m_refresh_request_pending = false;
316             io_channel->OutWrite (io_channel->m_prompt_str.c_str(),
317                                   io_channel->m_prompt_str.size(), NO_ASYNC);
318             io_channel->m_prompt_str.clear();
319         }
320     }
321     else
322     {
323         if (io_channel->m_prompt_str.size() > 0)
324             io_channel->m_prompt_str.clear();
325         std::string tmp_str (bytes, src_len);
326         if (tmp_str.find (el_prompt (io_channel->m_edit_line)) == 0)
327             io_channel->m_refresh_request_pending = false;
328         io_channel->OutWrite (bytes, src_len, NO_ASYNC);
329     }
330 }
331 
332 IOChannel::LibeditGetInputResult
LibeditGetInput(std::string & new_line)333 IOChannel::LibeditGetInput (std::string &new_line)
334 {
335     IOChannel::LibeditGetInputResult retval = IOChannel::eLibeditGetInputResultUnknown;
336     if (m_edit_line != NULL)
337     {
338         int line_len = 0;
339 
340         // Set boolean indicating whether or not el_gets is trying to get input (i.e. whether or not to attempt
341         // to refresh the prompt after writing data).
342         SetGettingCommand (true);
343         m_expecting_prompt = true;
344 
345         // Call el_gets to prompt the user and read the user's input.
346         const char *line = ::el_gets (m_edit_line, &line_len);
347 
348         // Re-set the boolean indicating whether or not el_gets is trying to get input.
349         SetGettingCommand (false);
350 
351         if (line)
352         {
353             retval = IOChannel::eLibeditGetInputValid;
354             // strip any newlines off the end of the string...
355             while (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r'))
356                 --line_len;
357             if (line_len > 0)
358             {
359                 ::history (m_history, &m_history_event, H_ENTER, line);
360                 new_line.assign (line, line_len);   // Omit the newline
361             }
362             else
363             {
364                 retval = IOChannel::eLibeditGetInputEmpty;
365                 // Someone just hit ENTER, return the empty string
366                 new_line.clear();
367             }
368             // Return true to indicate success even if a string is empty
369             return retval;
370         }
371         else
372         {
373             retval = (line_len == 0 ? IOChannel::eLibeditGetInputEOF : IOChannel::eLibeditGetInputResultError);
374         }
375     }
376     // Return false to indicate failure. This can happen when the file handle
377     // is closed (EOF).
378     new_line.clear();
379     return retval;
380 }
381 
382 void *
IOReadThread(void * ptr)383 IOChannel::IOReadThread (void *ptr)
384 {
385     IOChannel *myself = static_cast<IOChannel *> (ptr);
386     myself->Run();
387     return NULL;
388 }
389 
390 void
Run()391 IOChannel::Run ()
392 {
393     SBListener listener("IOChannel::Run");
394     std::string new_line;
395 
396     SBBroadcaster interpreter_broadcaster (m_driver->GetDebugger().GetCommandInterpreter().GetBroadcaster());
397     listener.StartListeningForEvents (interpreter_broadcaster,
398                                       SBCommandInterpreter::eBroadcastBitResetPrompt |
399                                       SBCommandInterpreter::eBroadcastBitThreadShouldExit |
400                                       SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
401 
402     listener.StartListeningForEvents (*this,
403                                       IOChannel::eBroadcastBitThreadShouldExit);
404 
405     listener.StartListeningForEvents (*m_driver,
406                                       Driver::eBroadcastBitReadyForInput |
407                                       Driver::eBroadcastBitThreadShouldExit);
408 
409     // Let anyone know that the IO channel is up and listening and ready for events
410     BroadcastEventByType (eBroadcastBitThreadDidStart);
411     bool done = false;
412     while (!done)
413     {
414         SBEvent event;
415 
416         listener.WaitForEvent (UINT32_MAX, event);
417         if (!event.IsValid())
418             continue;
419 
420         const uint32_t event_type = event.GetType();
421 
422         if (event.GetBroadcaster().IsValid())
423         {
424             if (event.BroadcasterMatchesPtr (m_driver))
425             {
426                 if (event_type & Driver::eBroadcastBitReadyForInput)
427                 {
428                     std::string line;
429 
430                     if (CommandQueueIsEmpty())
431                     {
432                         IOChannel::LibeditGetInputResult getline_result = LibeditGetInput(line);
433                         if (getline_result == IOChannel::eLibeditGetInputEOF)
434                         {
435                             // EOF occurred
436                             // pretend that a quit was typed so the user gets a potential
437                             // chance to confirm
438                             line.assign("quit");
439                         }
440                         else if (getline_result == IOChannel::eLibeditGetInputResultError || getline_result == IOChannel::eLibeditGetInputResultUnknown)
441                         {
442                             // some random error occurred, exit and don't ask because the state might be corrupt
443                             done = true;
444                             continue;
445                         }
446                     }
447                     else
448                     {
449                         GetCommandFromQueue (line);
450                     }
451 
452                     // TO BE DONE: FIGURE OUT WHICH COMMANDS SHOULD NOT BE REPEATED IF USER PRESSES PLAIN 'RETURN'
453                     // AND TAKE CARE OF THAT HERE.
454 
455                     SBEvent line_event(IOChannel::eBroadcastBitHasUserInput,
456                              line.c_str(),
457                              line.size());
458                     BroadcastEvent (line_event);
459                 }
460                 else if (event_type & Driver::eBroadcastBitThreadShouldExit)
461                 {
462                     done = true;
463                     continue;
464                 }
465             }
466             else if (event.BroadcasterMatchesRef (interpreter_broadcaster))
467             {
468                 switch (event_type)
469                 {
470                 case SBCommandInterpreter::eBroadcastBitResetPrompt:
471                     {
472                         const char *new_prompt = SBEvent::GetCStringFromEvent (event);
473                         if (new_prompt)
474                             g_prompt_map[m_edit_line] = new_prompt;
475                     }
476                     break;
477 
478                 case SBCommandInterpreter::eBroadcastBitThreadShouldExit:
479                 case SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
480                     done = true;
481                     break;
482                 }
483             }
484             else if (event.BroadcasterMatchesPtr (this))
485             {
486                 if (event_type & IOChannel::eBroadcastBitThreadShouldExit)
487                 {
488                     done = true;
489                     continue;
490                 }
491             }
492         }
493     }
494     BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit);
495     m_driver = NULL;
496     m_read_thread = 0;
497 }
498 
499 bool
Start()500 IOChannel::Start ()
501 {
502     if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
503         return true;
504 
505     m_read_thread = SBHostOS::ThreadCreate ("<lldb.driver.commandline_io>", IOChannel::IOReadThread, this,
506                                             NULL);
507 
508     return (IS_VALID_LLDB_HOST_THREAD(m_read_thread));
509 }
510 
511 bool
Stop()512 IOChannel::Stop ()
513 {
514     if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
515         return true;
516 
517     BroadcastEventByType (eBroadcastBitThreadShouldExit);
518 
519     // Don't call Host::ThreadCancel since el_gets won't respond to this
520     // function call -- the thread will just die and all local variables in
521     // IOChannel::Run() won't get destructed down which is bad since there is
522     // a local listener holding onto broadcasters... To ensure proper shutdown,
523     // a ^D (control-D) sequence (0x04) should be written to other end of the
524     // the "in" file handle that was passed into the contructor as closing the
525     // file handle doesn't seem to make el_gets() exit....
526     return SBHostOS::ThreadJoin (m_read_thread, NULL, NULL);
527 }
528 
529 void
RefreshPrompt()530 IOChannel::RefreshPrompt ()
531 {
532     // If we are not in the middle of getting input from the user, there is no need to
533     // refresh the prompt.
534     IOLocker locker (m_output_mutex);
535     if (! IsGettingCommand())
536         return;
537 
538 	// If we haven't finished writing the prompt, there's no need to refresh it.
539     if (m_expecting_prompt)
540         return;
541 
542     if (m_refresh_request_pending)
543         return;
544 
545     ::el_set (m_edit_line, EL_REFRESH);
546     m_refresh_request_pending = true;
547 }
548 
549 void
OutWrite(const char * buffer,size_t len,bool asynchronous)550 IOChannel::OutWrite (const char *buffer, size_t len, bool asynchronous)
551 {
552     if (len == 0 || buffer == NULL)
553         return;
554 
555     // We're in the process of exiting -- IOChannel::Run() has already completed
556     // and set m_driver to NULL - it is time for us to leave now.  We might not
557     // print the final ^D to stdout in this case.  We need to do some re-work on
558     // how the I/O streams are managed at some point.
559     if (m_driver == NULL)
560     {
561         return;
562     }
563 
564     // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
565     IOLocker locker (m_output_mutex);
566     if (m_driver->EditlineReaderIsTop() && asynchronous)
567         ::fwrite (undo_prompt_string, 1, 4, m_out_file);
568     ::fwrite (buffer, 1, len, m_out_file);
569     if (asynchronous)
570         m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
571 }
572 
573 void
ErrWrite(const char * buffer,size_t len,bool asynchronous)574 IOChannel::ErrWrite (const char *buffer, size_t len, bool asynchronous)
575 {
576     if (len == 0 || buffer == NULL)
577         return;
578 
579     // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
580     IOLocker locker (m_output_mutex);
581     if (asynchronous)
582         ::fwrite (undo_prompt_string, 1, 4, m_err_file);
583     ::fwrite (buffer, 1, len, m_err_file);
584     if (asynchronous)
585         m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
586 }
587 
588 void
AddCommandToQueue(const char * command)589 IOChannel::AddCommandToQueue (const char *command)
590 {
591     m_command_queue.push (std::string(command));
592 }
593 
594 bool
GetCommandFromQueue(std::string & cmd)595 IOChannel::GetCommandFromQueue (std::string &cmd)
596 {
597     if (m_command_queue.empty())
598         return false;
599     cmd.swap(m_command_queue.front());
600     m_command_queue.pop ();
601     return true;
602 }
603 
604 int
CommandQueueSize() const605 IOChannel::CommandQueueSize () const
606 {
607     return m_command_queue.size();
608 }
609 
610 void
ClearCommandQueue()611 IOChannel::ClearCommandQueue ()
612 {
613     while (!m_command_queue.empty())
614         m_command_queue.pop();
615 }
616 
617 bool
CommandQueueIsEmpty() const618 IOChannel::CommandQueueIsEmpty () const
619 {
620     return m_command_queue.empty();
621 }
622 
623 bool
IsGettingCommand() const624 IOChannel::IsGettingCommand () const
625 {
626     return m_getting_command;
627 }
628 
629 void
SetGettingCommand(bool new_value)630 IOChannel::SetGettingCommand (bool new_value)
631 {
632     m_getting_command = new_value;
633 }
634 
IOLocker(pthread_mutex_t & mutex)635 IOLocker::IOLocker (pthread_mutex_t &mutex) :
636     m_mutex_ptr (&mutex)
637 {
638     if (m_mutex_ptr)
639         ::pthread_mutex_lock (m_mutex_ptr);
640 
641 }
642 
~IOLocker()643 IOLocker::~IOLocker ()
644 {
645     if (m_mutex_ptr)
646         ::pthread_mutex_unlock (m_mutex_ptr);
647 }
648