diff options
-rw-r--r-- | lldb/source/Commands/CommandObjectBreakpointCommand.cpp | 5 | ||||
-rw-r--r-- | lldb/source/Interpreter/ScriptInterpreterPython.cpp | 271 |
2 files changed, 163 insertions, 113 deletions
diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index a3c62ebd394..3c3a85a0bde 100644 --- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -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\ diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index 511de8fc792..8d3ae4304c0 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -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. - for (int i = 0; i < num_lines; ++i) + if (num_lines == 1) { - 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) - { - // We've found the first line of a function. First, get the function name. + callback_data.AppendString (user_input.GetStringAtIndex (0)); + return true; + } - // Skip over the 'def '. - char *start = (char *) current_line + 4; + // 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. - // Skip over white space. - while (start[0] == ' ' || start[0] == '\t') - ++start; + bool inside_user_python_function_def = false; + std::string whitespace = " \t"; - // Find the end of the function name. - char *end = start; - while (isalnum (end[0]) || end[0] == '_') - ++end; + StringList auto_generated_function; + StringList user_defined_function; - int name_len = end - start; - std::string func_name = current_str.substr (4, name_len); + StringList *current_function_def = &auto_generated_function; + std::string auto_generated_function_name ("lldb_autogen_python_bp_callback_func_"); - // 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) + for (int i = 0; i < num_lines; ++i) + { + std::string current_line (user_input.GetStringAtIndex(i)); + size_t idx = current_line.find_first_of (whitespace); + if (idx != std::string::npos) + { + 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; + if (inside_user_python_function_def) + { + // Add this line to the user's python function definition. + current_function_def->AppendString (current_line.c_str()); + } else - ++i; + { + // 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()); + } } - 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))) + else // line does not start with indentation... { - 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) + // 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; + } + + // 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) { - 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>"); + // 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()); } - ExportFunctionDefinitionToInterpreter (new_function); - last_function_call = func_name + " ()"; - } + 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()); + + 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 + { + // There was no white space on the line (and therefore no indentation either). - // 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. + // 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. + } - StringList new_user_input; + // 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. - for (int i = 0; i < num_lines; ++i) + if (inside_user_python_function_def && (user_defined_function.GetSize() > 0)) { - std::string current_string = user_input.GetStringAtIndex (i); - if (current_string.compare (0, 13, "<lldb_delete>") == 0) - continue; - - new_user_input.AppendString (current_string.c_str()); + if (! ExportFunctionDefinitionToInterpreter (user_defined_function)) + { + callback_data.Clear(); + return false; + } } - num_lines = new_user_input.GetSize(); - if (num_lines > 0) + if (auto_generated_function.GetSize() > 0) { - if (num_lines == 1 - && strchr (new_user_input.GetStringAtIndex(0), '\n') == NULL) + // Export the auto-generated function to Python. + if (ExportFunctionDefinitionToInterpreter (auto_generated_function)) { - // If there's only one line of input, and it doesn't contain any newline characters.... - callback_data.AppendString (new_user_input.GetStringAtIndex (0)); + // 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 { - // 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; - - // Create the function call for the new function. - last_function_call = func_name.GetString() + " ()"; - - // 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() + " ():"; - - - // 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()); + // 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; } |