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:
Caroline Tice 2010-09-21 19:25:28 +00:00
parent 2989bfa88b
commit 650b92683a
2 changed files with 169 additions and 119 deletions

View File

@ -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\

View File

@ -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;
}