forked from OSchip/llvm-project
Re-write/clean up code that generated Python breakpoint commands.
Add a warning if no command was attached to the breakpoint. Update the help slightly. llvm-svn: 114467
This commit is contained in:
parent
2989bfa88b
commit
650b92683a
|
@ -225,6 +225,11 @@ initialized: \n\
|
|||
\n\
|
||||
(lldb) \n\
|
||||
\n\
|
||||
\n\
|
||||
Final Note: If you get a warning that no breakpoint command was generated, \n\
|
||||
but you did not get any syntax errors, you probably forgot to add a call \n\
|
||||
to your functions. \n\
|
||||
\n\
|
||||
Special information about debugger command breakpoint commands \n\
|
||||
-------------------------------------------------------------- \n\
|
||||
\n\
|
||||
|
|
|
@ -626,6 +626,8 @@ ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback
|
|||
bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
|
||||
}
|
||||
}
|
||||
else
|
||||
::fprintf (out_fh, "Warning: No command attached to breakpoint.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -714,150 +716,193 @@ bool
|
|||
ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user_input, StringList &callback_data)
|
||||
{
|
||||
static int num_created_functions = 0;
|
||||
|
||||
user_input.RemoveBlankLines ();
|
||||
int num_lines = user_input.GetSize();
|
||||
std::string last_function_call;
|
||||
|
||||
// Go through lines of input looking for any function definitions. For each function definition found,
|
||||
// export the function definition to Python, create a potential function call for the function, and
|
||||
// mark the lines of the function to be removed from the user input.
|
||||
if (num_lines == 1)
|
||||
{
|
||||
callback_data.AppendString (user_input.GetStringAtIndex (0));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Traverse user_input exactly once. At each line, either copy line into new, auto-generated function,
|
||||
// increasing indentation by 5 spaces... ...or copy it exactly as is into the user-written
|
||||
// currently-to-be-pushed-to-Python function def. At the end of each Python function def, push the function
|
||||
// to Python, and clear the function string, to start again. At the end of it all, if there is anything in
|
||||
// the auto-generated function, push it to Python and add the function call to it to the callback data.
|
||||
|
||||
bool inside_user_python_function_def = false;
|
||||
std::string whitespace = " \t";
|
||||
|
||||
StringList auto_generated_function;
|
||||
StringList user_defined_function;
|
||||
|
||||
StringList *current_function_def = &auto_generated_function;
|
||||
std::string auto_generated_function_name ("lldb_autogen_python_bp_callback_func_");
|
||||
|
||||
for (int i = 0; i < num_lines; ++i)
|
||||
{
|
||||
int function_start = i;
|
||||
std::string current_str = user_input.GetStringAtIndex (i);
|
||||
const char *current_line = current_str.c_str();
|
||||
int len = 0;
|
||||
if (current_line)
|
||||
len = strlen (current_line);
|
||||
|
||||
// Check to see if the current line is the start of a Python function definition.
|
||||
if (len > 4 && strncmp (current_line, "def ", 4) == 0)
|
||||
std::string current_line (user_input.GetStringAtIndex(i));
|
||||
size_t idx = current_line.find_first_of (whitespace);
|
||||
if (idx != std::string::npos)
|
||||
{
|
||||
// We've found the first line of a function. First, get the function name.
|
||||
|
||||
// Skip over the 'def '.
|
||||
char *start = (char *) current_line + 4;
|
||||
|
||||
// Skip over white space.
|
||||
while (start[0] == ' ' || start[0] == '\t')
|
||||
++start;
|
||||
|
||||
// Find the end of the function name.
|
||||
char *end = start;
|
||||
while (isalnum (end[0]) || end[0] == '_')
|
||||
++end;
|
||||
|
||||
int name_len = end - start;
|
||||
std::string func_name = current_str.substr (4, name_len);
|
||||
|
||||
// Now to find the last line of the function. That will be the first line that does not begin with
|
||||
// any white space (thanks to Python's indentation rules).
|
||||
++i;
|
||||
bool found = false;
|
||||
while (i < num_lines && !found)
|
||||
if (idx == 0) // line starts with indentation...
|
||||
{
|
||||
std::string next_str = user_input.GetStringAtIndex (i);
|
||||
const char *next_line = next_str.c_str();
|
||||
if (next_line[0] != ' ' && next_line[0] != '\t')
|
||||
found = true;
|
||||
else
|
||||
++i;
|
||||
}
|
||||
if (found)
|
||||
--i; // Make 'i' correspond to the last line of the function.
|
||||
int function_end = i;
|
||||
|
||||
// Special case: All of user_input is one big function definition.
|
||||
if ((function_start == 0) && (function_end == (num_lines - 1)))
|
||||
{
|
||||
ExportFunctionDefinitionToInterpreter (user_input);
|
||||
last_function_call = func_name + " ()";
|
||||
callback_data.AppendString (last_function_call.c_str());
|
||||
return callback_data.GetSize() > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make a copy of the function definition:
|
||||
StringList new_function;
|
||||
for (int k = function_start; k <= function_end; ++k)
|
||||
if (inside_user_python_function_def)
|
||||
{
|
||||
new_function.AppendString (user_input.GetStringAtIndex (k));
|
||||
// Mark the string to be deleted from user_input.
|
||||
user_input.DeleteStringAtIndex (k);
|
||||
user_input.InsertStringAtIndex (k, "<lldb_delete>");
|
||||
// Add this line to the user's python function definition.
|
||||
current_function_def->AppendString (current_line.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add this line to our auto-generated function; increase original indentation by 5.
|
||||
StreamString tmp_str;
|
||||
tmp_str.Printf (" %s", current_line.c_str());
|
||||
current_function_def->AppendString (tmp_str.GetData());
|
||||
}
|
||||
ExportFunctionDefinitionToInterpreter (new_function);
|
||||
last_function_call = func_name + " ()";
|
||||
}
|
||||
}
|
||||
}
|
||||
else // line does not start with indentation...
|
||||
{
|
||||
// First, check to see if we just finished a user-written function definition; if so,
|
||||
// wrap it up and send it to Python.
|
||||
|
||||
// Now instead of trying to really delete the marked lines from user_input, we will just copy all the
|
||||
// unmarked lines into a new StringList.
|
||||
if (inside_user_python_function_def && (user_defined_function.GetSize() > 0))
|
||||
{
|
||||
if (! ExportFunctionDefinitionToInterpreter (user_defined_function))
|
||||
{
|
||||
// User entered incorrect Python syntax. We should not attempt to continue.
|
||||
// Clear the callback data, and return immediately.
|
||||
callback_data.Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
StringList new_user_input;
|
||||
// User defined function was successfully sent to Python. Clean up after it.
|
||||
user_defined_function.Clear();
|
||||
inside_user_python_function_def = false;
|
||||
current_function_def = &auto_generated_function;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_lines; ++i)
|
||||
{
|
||||
std::string current_string = user_input.GetStringAtIndex (i);
|
||||
if (current_string.compare (0, 13, "<lldb_delete>") == 0)
|
||||
continue;
|
||||
// Next, check to see if we are at the start of a user-defined Python function.
|
||||
std::string first_word = current_line.substr (0, idx);
|
||||
if (first_word.compare ("def") == 0)
|
||||
{
|
||||
// Start the user defined function properly:
|
||||
inside_user_python_function_def = true;
|
||||
current_function_def = &user_defined_function;
|
||||
current_function_def->AppendString (current_line.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are in "loose" Python code that we need to collect and put into the auto-generated
|
||||
// function.
|
||||
StreamString tmp_str;
|
||||
current_function_def = &auto_generated_function;
|
||||
if (current_function_def->GetSize() == 0)
|
||||
{
|
||||
// Create the function name, and add insert the function def line.
|
||||
tmp_str.Printf ("%d", num_created_functions);
|
||||
++num_created_functions;
|
||||
auto_generated_function_name.append (tmp_str.GetData());
|
||||
|
||||
new_user_input.AppendString (current_string.c_str());
|
||||
}
|
||||
|
||||
num_lines = new_user_input.GetSize();
|
||||
|
||||
if (num_lines > 0)
|
||||
{
|
||||
if (num_lines == 1
|
||||
&& strchr (new_user_input.GetStringAtIndex(0), '\n') == NULL)
|
||||
{
|
||||
// If there's only one line of input, and it doesn't contain any newline characters....
|
||||
callback_data.AppendString (new_user_input.GetStringAtIndex (0));
|
||||
tmp_str.Clear();
|
||||
tmp_str.Printf ("def %s ():", auto_generated_function_name.c_str());
|
||||
current_function_def->AppendString (tmp_str.GetData());
|
||||
}
|
||||
tmp_str.Clear();
|
||||
|
||||
// Indent the line an extra 5 spaces and add it to our auto-generated function.
|
||||
tmp_str.Printf (" %s", current_line.c_str());
|
||||
current_function_def->AppendString (tmp_str.GetData());
|
||||
} // else we are in loose Python code
|
||||
} // else current line does not start with indentatin
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the new function name.
|
||||
StreamString func_name;
|
||||
func_name.Printf ("lldb_bp_callback_func_%d", num_created_functions);
|
||||
//std::string func_name = "lldb_bp_callback_func_" + num_created_functions;
|
||||
++num_created_functions;
|
||||
// There was no white space on the line (and therefore no indentation either).
|
||||
|
||||
// Create the function call for the new function.
|
||||
last_function_call = func_name.GetString() + " ()";
|
||||
// First, check to see if we just finished a user-written function definition; if so,
|
||||
// wrap it up and send it to Python.
|
||||
|
||||
if (inside_user_python_function_def && (user_defined_function.GetSize() > 0))
|
||||
{
|
||||
if (! ExportFunctionDefinitionToInterpreter (user_defined_function))
|
||||
{
|
||||
// User entered incorrect Python syntax. We should not attempt to continue.
|
||||
// Clear the callback data, and return immediately.
|
||||
callback_data.Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// User defined function was successfully sent to Python. Clean up after it.
|
||||
user_defined_function.Clear();
|
||||
inside_user_python_function_def = false;
|
||||
current_function_def = &auto_generated_function;
|
||||
}
|
||||
|
||||
// We cannot be at the start of a function definition (they contain white space) so we
|
||||
// must have "loose" python code.
|
||||
|
||||
StreamString tmp_str;
|
||||
current_function_def = &auto_generated_function;
|
||||
if (current_function_def->GetSize() == 0)
|
||||
{
|
||||
// Create the function name, and add insert the function def line.
|
||||
tmp_str.Printf ("%d", num_created_functions);
|
||||
++num_created_functions;
|
||||
auto_generated_function_name.append (tmp_str.GetData());
|
||||
|
||||
tmp_str.Clear();
|
||||
tmp_str.Printf ("def %s ():", auto_generated_function_name.c_str());
|
||||
current_function_def->AppendString (tmp_str.GetData());
|
||||
}
|
||||
tmp_str.Clear();
|
||||
|
||||
// Indent the line an extra 5 spaces and add it to our auto-generated function.
|
||||
tmp_str.Printf (" %s", current_line.c_str());
|
||||
current_function_def->AppendString (tmp_str.GetData());
|
||||
|
||||
} // else there was no white space on the line.
|
||||
}
|
||||
|
||||
// Create the Python function definition line (which will have to be inserted at the beginning of
|
||||
// the function).
|
||||
std::string def_line = "def " + func_name.GetString() + " ():";
|
||||
// Perhaps the last line of input was also the last line of a user-defined function; if so,
|
||||
// attempt to push the function down to Python.
|
||||
|
||||
if (inside_user_python_function_def && (user_defined_function.GetSize() > 0))
|
||||
{
|
||||
if (! ExportFunctionDefinitionToInterpreter (user_defined_function))
|
||||
{
|
||||
callback_data.Clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Indent all lines an additional four spaces (as they are now being put inside a function definition).
|
||||
for (int i = 0; i < num_lines; ++i)
|
||||
{
|
||||
const char *temp_cstring = new_user_input.GetStringAtIndex(i);
|
||||
std::string temp2 = " ";
|
||||
temp2.append(temp_cstring);
|
||||
new_user_input.DeleteStringAtIndex (i);
|
||||
new_user_input.InsertStringAtIndex (i, temp2.c_str());
|
||||
}
|
||||
|
||||
// Insert the function definition line at the top of the new function.
|
||||
new_user_input.InsertStringAtIndex (0, def_line.c_str());
|
||||
|
||||
ExportFunctionDefinitionToInterpreter (new_user_input);
|
||||
callback_data.AppendString (last_function_call.c_str());
|
||||
if (auto_generated_function.GetSize() > 0)
|
||||
{
|
||||
// Export the auto-generated function to Python.
|
||||
if (ExportFunctionDefinitionToInterpreter (auto_generated_function))
|
||||
{
|
||||
// The export succeeded; the syntax must be ok. Generate the function call and put
|
||||
// it in the callback data.
|
||||
StreamString tmp_str;
|
||||
tmp_str.Printf ("%s ()", auto_generated_function_name.c_str());
|
||||
callback_data.AppendString (tmp_str.GetData());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Syntax error!
|
||||
callback_data.Clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!last_function_call.empty())
|
||||
callback_data.AppendString (last_function_call.c_str());
|
||||
// If there was any code, it consisted entirely of function defs, without any calls to the functions.
|
||||
// No actual exectuable code was therefore generated. (Function calls would have looked like "loose" python,
|
||||
// and would have been collected into the auto-generated function.)
|
||||
return false;
|
||||
}
|
||||
|
||||
return callback_data.GetSize() > 0;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -881,8 +926,8 @@ ScriptInterpreterPython::BreakpointCallbackFunction
|
|||
bool success = context->exe_ctx.target->GetDebugger().
|
||||
GetCommandInterpreter().
|
||||
GetScriptInterpreter()->ExecuteOneLineWithReturn (python_string,
|
||||
ScriptInterpreter::eBool,
|
||||
(void *) &temp_bool);
|
||||
ScriptInterpreter::eBool,
|
||||
(void *) &temp_bool);
|
||||
if (success)
|
||||
ret_value = temp_bool;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue