Example #1
0
// Return next display info from GDB_ANSWER; "" if none.
string read_next_disp_info (string& gdb_answer, GDBAgent *gdb)
{
    switch (gdb->type())
    {
    case GDB:
    case PYDB:
    {
	int startpos = gdb_answer.index (": ");
	int i = startpos + 2;

	for (;;)
	{
	    while (i < int(gdb_answer.length()) && gdb_answer[i] != '\n')
		i++;
	    if (i >= int(gdb_answer.length()))
	    {
		// Take entire remaining output as display
		string next_disp_info = gdb_answer;
		gdb_answer = "";
		return next_disp_info;
	    }

	    assert(gdb_answer[i] == '\n');
	    if (gdb_answer.contains(rxgdb_begin_of_display_info, i + 1))
	    {
		// Use output up to `\n[0-9]' as display
		string next_disp_info = gdb_answer.before(i);
		gdb_answer = gdb_answer.after(i);
		return next_disp_info;
	    }

	    i++;
	}
    }

    case DBX:
    {
	string next_disp_info;
	int i = gdb_answer.index('\n');
	if (i > 0)
	{
	    next_disp_info = gdb_answer.before(i);
	    gdb_answer = gdb_answer.after(i);
	}
	else
	{
	    next_disp_info = gdb_answer;
	    gdb_answer = "";
	}
	return next_disp_info;
    }

    case XDB:
    case JDB:
    case PERL:
	break;			// FIXME
    }

    return "";
}
Example #2
0
void PosBuffer::filter_pydb(string& answer)
{
    if (already_read != PosComplete && !answer.contains('\n'))
    {
	// Position info is incomplete
	answer_buffer = answer;
	answer = "";
	already_read = PosPart;
	return;
    }

    // `Breakpoint N, FUNCTION (ARGS...) at file:line_no'
    // rxstopped_func defined for GDB...if it changes, change here
    int fn_index = index(answer, rxstopped_func, "Breakpoint");
    if (fn_index >= 0)
    {
	fetch_function(answer, fn_index, func_buffer);
    }
    else
    {
	// `#FRAME FUNCTION(args) at file:line_no'
	// Likewise rxframe_func defined for GDB
	int frame_index = index(answer, rxframe_addr, "#");
	if (frame_index == 0
	    || frame_index > 0 && answer[frame_index - 1] == '\n')
	{
	    fetch_function(answer, frame_index, func_buffer);
	}
    }

    int lineinfo  = answer.index("Lineinfo");
    // Lineinfo <function> at file:lineno
    if (lineinfo == 0 || (lineinfo > 0 && answer[lineinfo - 1] == '\n'))
    {
	answer = answer.after('<');
	func_buffer = answer.before('>');
    }

    string result = answer.after(" at ");
    result = result.before('\n');
    if (result.contains(':'))
    {
	pos_buffer = result;
	already_read = PosComplete;
    }

    // Don't need the answer anymore when line matches 'Lineinfo'
    if (lineinfo >= 0)
    {
	answer = "";
    }
}
Example #3
0
// Add ARG to the list of arguments
static void add_argument(string arg, StringArray& arguments, 
			 string& last, bool& updated)
{
    strip_trailing_space(arg);
    while (arg.length() > 0 && isspace(arg[0]))
	arg = arg.after(0);

    last = arg;

    // Insertion sort
    int i;
    for (i = 0; i < arguments.size(); i++)
    {
	int cmp = compare(arguments[i], arg);
	if (cmp == 0)
	    return;		// Already present
	if (cmp > 0)
	    break;
    }

    arguments += "<dummy>";

    for (int j = arguments.size() - 1; j > i; j--)
	arguments[j] = arguments[j - 1];
    arguments[i] = arg;

    updated = false;
}
Example #4
0
// Remove and return display number from DISPLAY
string  read_disp_nr_str (string& display, GDBAgent *gdb)
{
    switch (gdb->type())
    {
    case GDB:
    case PYDB:
    case DBG:
    {
#if RUNTIME_REGEX
	static regex rxgdb_disp_nr("[1-9][0-9]*");
#endif

	string disp_nr = display.through (rxgdb_disp_nr);
	display = display.after (": ");
	return disp_nr;
    }
    case DBX:
	return read_disp_name(display, gdb);

    case XDB:
    case JDB:
    case PERL:
    case BASH:
	return "";		// FIXME
    }

    return "";
}
Example #5
0
void BreakPoint::process_jdb(string& info_output)
{
    int colon = info_output.index(':');
    if (colon >= 0)
    {
	string class_name = info_output.before(colon);
	int line_no = get_positive_nr(info_output.after(colon));
	if (line_no >= 0 && !class_name.empty())
	{
	    // Strip JDB 1.2 info like `breakpoint', etc.
	    strip_space(class_name);
	    int last_space = class_name.index(" ", -1);
	    if (last_space > 0)
		class_name = class_name.after(last_space);

	    myfile_name = class_name;
	    myline_nr   = line_no;

	    // Kill this line
	    int beginning_of_line = colon;
	    while (beginning_of_line >= 0 && 
		   info_output[beginning_of_line] != '\n')
		beginning_of_line--;
	    beginning_of_line++;

	    int next_nl = info_output.index('\n', colon);
	    if (next_nl >= 0)
		info_output = info_output.before(beginning_of_line)
		    + info_output.from(next_nl);
	    else
		info_output = info_output.before(beginning_of_line);
	}
    }
}
// Return 1 if the signal specified in PROGRAM_STATE is passed to the
// program; 0 if not, -1 if undecided.
static int passed_to_program(const string& program_state)
{
    string signal = program_state.from("SIG");
    signal = signal.through(rxalpha);

    if (!signal.empty())
    {
	string signal_description = program_state.after(signal);
	signal_description = signal_description.after(rxwhite);

	if (signal_description.empty())
	    signal_description = signal;
	
	defineConversionMacro("SIGNAL", signal.chars());
	defineConversionMacro("SIGNAL_DESCRIPTION", signal_description.chars());

	string ans = gdb_question("info handle " + signal);

	// `info handle SIGINT' output has the form
	// "Signal        Stop\tPrint\tPass to program\tDescription\n"
	// "SIGINT        Yes\tYes\tNo\t\tInterrupt\n"

	ans.downcase();
	string header = ans.before("pass ");
	int tabs_before_pass = header.freq('\t');
	string info = ans.after('\n');
	while (tabs_before_pass--)
	    info = info.after('\t');
	if (info.contains('y', 0))
	    return 1;
	if (info.contains('n', 0))
	    return 0;
    }
    return -1;
}
Example #7
0
string set_history_filter(const string& cmd)
{
    string arg;

    if (cmd.contains(" = "))
	arg = cmd.after(" = ");
    else if (cmd.contains(" := "))
	arg = cmd.after(" := ");

    if (!arg.empty())
    {
	strip_space(arg);
	return arg;
    }

    return "";
}
Example #8
0
static bool try_arg(const string& cmd, const string& prefix_, string& arg)
{
    if (prefix_.empty())
	return false;		// No such command
    string prefix( prefix_ );
    if (!prefix.contains(" ", -1))
	prefix += " ";

    if (cmd.contains(prefix, 0))
    {
	arg = cmd.after(prefix);
	strip_space(arg);

	// Strip format stuff
	while (arg.contains('/', 0))
	    arg = arg.after(' ');

	if (arg.contains("'", 0))
	{
	    // Quoted arg -- add as unquoted
	    arg = unquote(arg);
	    return true;
	}
	else if (is_file_pos(arg))
	{
	    // FILE:LINE arg -- ignore
	    return false;
	}
	else if (arg.matches(rxint))
	{
	    // LINE arg -- ignore
	    return false;
	}
	else
	{
	    // Other arg -- add unchanged
	    return true;
	}
    }

    // Bad prefix -- ignore
    return false;
}
Example #9
0
// Remove and return "NR: " from DISPLAY.
string get_info_disp_str (string& display_info, GDBAgent *gdb)
{
    switch (gdb->type())
    {
    case GDB:
    case PYDB:
	return display_info.after (":   ");

    case DBX:
	return display_info.after (") ");

    case XDB:
    case JDB:
    case PERL:
	return "";		// FIXME
    }

    return "";
}
Example #10
0
static void gdbEditOutputHP(Agent *, void *, void *call_data)
{
    DataLength *input = (DataLength *)call_data;
    output_buffer += string(input->data, input->length);
    while (output_buffer.contains('\n'))
    {
	set_status(output_buffer.before('\n'));
	output_buffer = output_buffer.after('\n');
    }
    if (output_buffer != "")
	set_status(output_buffer);
}
Example #11
0
// In FORTRAN mode, GDB issues last dimensions first.  Insert new
// dimension before first dimension and convert to FORTRAN
// multi-dimension syntax.
string DispValue::add_member_name(const string& base, 
				  const string& member_name)
{
    if (gdb->program_language() == LANGUAGE_FORTRAN && 
	member_name.contains('(', 0) &&	base.contains('('))
    {
	return base.before('(') + member_name.before(')') + ", " + 
	    base.after('(');
    }

    return base + member_name;
}
Example #12
0
bool add_running_arguments(string& cmd, Widget origin)
{
    if (cmd == "run")
	cmd = gdb->rerun_command();

    if (gdb->type() != JDB)
	return true;		// Ok, perform the command

    if (!is_run_cmd(cmd))
	return true;		// Ok, perform the command

    strip_leading_space(cmd);
    string args = cmd.after(rxwhite);

    ProgramInfo info;

    if (args.empty() && gdb->has_debug_command())
    {
	// JDB 1.1 requires at least a class name after the `run' command.
	cmd += " " + info.file;
    }

    if (info.running && !gdb->has_debug_command())
    {
	// JDB 1.2 cannot rerun a program after it has been started.
	// Offer to restart JDB instead.
	static Widget restart_jdb = 0;
	static string saved_run_command;

	if (restart_jdb == 0)
	{
	    restart_jdb = 
		verify(XmCreateQuestionDialog(find_shell(origin),
				 XMST("confirm_restart_gdb_dialog"), 
				 ArgList(0), 0));
	    Delay::register_shell(restart_jdb);
	    XtAddCallback(restart_jdb, XmNhelpCallback,   
			  ImmediateHelpCB, XtPointer(0));
	    XtAddCallback(restart_jdb, XmNokCallback,     
			  RestartAndRunCB, (XtPointer)&saved_run_command);
	}

	saved_run_command = cmd;
	XtManageChild(restart_jdb);

	return false;		// Don't perform the command yet
    }

    return true;
}
Example #13
0
// Return next display from DISPLAYS ("" if none); remove it from
// DISPLAYS
string read_next_display (string& displays, GDBAgent *gdb)
{
    string next_display;
    strip_leading_space(displays);

    // string old_displays = displays;
    // std::clog << "read_next_display(" << quote(old_displays) << ")...\n";

    if (is_disabling(displays, gdb))
    {
	// After a `disabling' message, `display' output finishes
	next_display = displays;
	displays = "";
    }
    else
    {
	for (;;)
	{
	    next_display += read_token(displays);

	    if (displays.empty())
		break;		// All done

	    if (next_display.contains(":()", -1))
	    {
		// AIX DBX gives weird `members' like
		// "pcg =     OM_PCGDownCasters:()\n(_root = 0x2004c248 ..."
		// Be sure to continue such displays.
		continue;
	    }

	    if (next_is_nl(displays))
		break;		// At end of display
	}
    }

    displays = displays.after('\n');
    strip_leading_space(displays);

    // std::clog << "read_next_display(" << quote(old_displays) << ") = "
    //           << quote(next_display) << "\n";
    return next_display;
}
Example #14
0
// Return the Nth component from NAME, or DEFAULT_VALUE if none
static string component(string name, FontComponent n)
{
    // If name does not begin with `-', assume it's a font family
    if (!name.contains('-', 0))
	name.prepend("-*-");

    // Let I point to the Nth occurrence of `-'
    int i = -1;
    while (n >= Foundry && (i = name.index('-', i + 1)) >= 0)
	n--;

    string w;
    if (i >= 0)
    {
	w = name.after(i);
	if (w.contains('-'))
	    w = w.before('-');
    }

    return w;
}
Example #15
0
// Filter all lines from ANSWER beginning with LINE.  This is required
// to suppress the line number output after a `stopping in' message.
void PosBuffer::filter_line(string& answer) const
{
    if (already_read != PosComplete)
	return;

    string line_s = pos_buffer;
    if (line_s.contains(':'))
	line_s = line_s.after(':');
    int line = atoi(line_s.chars());
    if (line <= 0)
	return;

    int pos = 0;
    do {
	if (atoi(answer.chars() + pos) == line)
	{
	    answer = answer.before(pos) + answer.after('\n', pos);
	    break;
	}
	pos = answer.index('\n', pos) + 1;
    } while (pos > 0);
}
Example #16
0
string display_history_filter(const string& cmd)
{
    if (cmd.contains("graph display ", 0))
    {
	string arg = cmd.after("graph display ");
	if (arg.contains("dependent on"))
	    arg = arg.before("dependent on");
	if (arg.contains("now or"))
	    arg = arg.before("now or");
	if (arg.contains("when in"))
	    arg = arg.before("when in");

	strip_space(arg);

	// Strip format stuff
	while (arg.contains('/', 0))
	    arg = arg.after(' ');

	strip_space(arg);
	return arg;
    }

    return "";
}
Example #17
0
// Handle incremental searches; return true if processed
static bool do_isearch(Widget, XmTextVerifyCallbackStruct *change)
{
    if (isearch_state == ISEARCH_NONE)
	return false;

    string saved_isearch_string = isearch_string;
    bool processed = false;

    if (change->startPos == change->endPos)
    {
	// Character insertion
	string input = string(change->text->ptr, change->text->length);
	if (!input.contains('\n', -1))
	{
	    // Add to current search string
	    isearch_string += input;
	    processed = true;
	}
    }
    else if (change->endPos - change->startPos == 1)
    {
	// Backspace - remove last character from search string
	if (!isearch_string.empty())
	    isearch_string.after(int(isearch_string.length()) - 2) = "";
	else
	    clear_isearch(true, false);

	processed = true;
    }

    if (processed)
    {
	int history = -1;
	if (isearch_string.empty() || current_line().contains(isearch_string))
	{
	    // Search string found in current line
	    history = -1;
	}
	else
	{
	    history = search_history(isearch_string, int(isearch_state));
	    if (history < 0)
	    {
		// Search string not found in history
		if (change->event != 0)
		    XtCallActionProc(gdb_w, "beep", change->event, 0, 0);
		isearch_string = saved_isearch_string;
	    }
	}

	// Make this a no-op
	if (!have_isearch_line)
	{
	    isearch_line = current_line();
	    have_isearch_line = true;
	}

	// Redraw current line with appropriate prompt.
	XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 0, 
			isearch_done, XtPointer(history));

	// Upon the next call to gdbMotionCB(), clear ISearch mode,
	// unless it immediately follows this one.
	isearch_motion_ok = true;
	XtAppAddTimeOut(XtWidgetToApplicationContext(gdb_w), 10,
			set_isearch_motion_ok, XtPointer(false));
    }

    return processed;
}
Example #18
0
// Set history file name
void process_history_filename(string answer)
{
    answer = answer.after('"');
    answer = answer.before('"');
    set_gdb_history_file(answer);
}
Example #19
0
void BreakPoint::process_perl(string& info_output)
{
    // Format: [FILE:]
    //          LINE_NO: LINE
    //           INFO 1
    //           INFO 2 ...

    if (!info_output.contains(' ', 0))
    {
	const string first_line = info_output.before('\n');
	if (first_line.contains(':', -1))
	{
	    // Get leading file name
	    myfile_name = first_line.before(':');
	    info_output = info_output.after('\n');
	}
    }

    static const StringArray empty;
    mycommands = empty;
    myline_nr = atoi(info_output.chars());
    info_output = info_output.after('\n');
    bool break_seen = false;
    while (info_output.contains("  ", 0))
    {
	string info = info_output.before('\n');
	info_output = info_output.after('\n');

	strip_space(info);
	if (info.contains("break if ", 0))
	{
	    string cond = info.after(" if ");
	    while (cond.contains('(', 0) && cond.contains(')', -1))
		cond = unquote(cond);
	    if (cond == "1")
		cond = "";
	    mycondition = cond;
	    break_seen = true;
	}
	else if (info.contains("action: ", 0))
	{
	    string commands = info.after(':');
	    strip_space(commands);

	    if (commands.contains("d " + itostring(line_nr())))
		mydispo = BPDEL; // Temporary breakpoint

	    string command = "";
	    while (!commands.empty())
	    {
		const string token = read_token(commands);
		if (token != ";")
		    command += token;

		if (token == ";" || commands.empty())
		{
		    strip_space(command);
		    if (!command.empty())
		    {
			mycommands += command;
			command = "";
		    }
		}
	    }
	}
	else
	{
	    myinfos += info + '\n';
	}
    }

    if (!break_seen)
	mytype = ACTIONPOINT;
}
Example #20
0
void BreakPoint::process_dbx(string& info_output)
{
    if (info_output.contains("PC==", 0) ||
	info_output.contains("stop ", 0) ||
	info_output.contains("stopped ", 0))
    {
	// Breakpoint

	info_output = info_output.after(rxblanks_or_tabs);
	strip_leading_space (info_output);

	if (info_output.contains ("at ", 0))
	{
	    info_output = info_output.after(rxblanks_or_tabs);
	    string file_name;
	    if (info_output.contains('"', 0))
	    {
		// `stop at "FILE":LINE'
		file_name = unquote(info_output.before(":"));
		info_output = info_output.after (":");
	    }
	    else if (info_output.contains('[', 0))
	    {
		// `stop at [file:line ...]'
		file_name = info_output.before(":");
		file_name = file_name.after('[');
		info_output = info_output.after (":");
	    }
	    else
	    {
		// `stop at LINE'
		file_name = "";
	    }

	    int new_line_nr = 0;
	    if (!info_output.empty() && isdigit(info_output[0]))
		new_line_nr = get_positive_nr(info_output);

	    if (!file_name.empty())
		myfile_name = file_name;

	    if (new_line_nr != 0)
		myline_nr = new_line_nr;

	    // DBX issues either locations or functions
	    myfunc = "";
	}
	else if (info_output.contains ("in ", 0))
	{
	    string line = info_output.after("in ");
	    if (line.contains('\n'))
		line = line.before('\n');

	    if (line.contains("\":"))
	    {
		// Ladebug output:
		// `PC==x in TYPE FUNC(ARGS...) "FILE":LINE { COMMANDS }

		myfile_name = line.after("\"");
		myfile_name = myfile_name.before("\"");
		myline_nr   = get_positive_nr(line.after("\":"));
		myfunc      = line.before("\"");
		strip_space(myfunc);

		// Be sure to remove TYPE
		while (myfunc.contains(" "))
		    myfunc = myfunc.after(" ");
	    }
	    else
	    {
		// DBX output:
		// `stop in FUNC'
		myfunc = line.before(rxblanks_or_tabs);
		strip_space(myfunc);

		myfile_name = "";
		myline_nr = 0;

		// Attempt to get exact position of FUNC
		const string pos = dbx_lookup(myfunc);
		if (!pos.empty())
		{
		    const string file_name = pos.before(":");
		    const string line_s    = pos.after(":");
		    int new_line_nr  = get_positive_nr(line_s);

		    myfile_name = file_name;
		    if (new_line_nr != 0)
			myline_nr = new_line_nr;
		}
	    }
	}
	else
	{
	    // `stop VAR'
	    mytype       = WATCHPOINT;
	    mywatch_mode = WATCH_CHANGE;

	    string expr = info_output;
	    if (expr.contains('\n'))
		expr = expr.before('\n');
	    if (expr.contains(rxblanks_or_tabs))
		expr = expr.before(rxblanks_or_tabs);

	    myexpr = expr;
	}

	// Sun DBX 3.0 issues extra characters like 
	// (2) stop in main -count 0/10
	// [3] stop in main -disable
	string options;
	if (info_output.contains('\n'))
	    options = info_output.before('\n');
	else
	    options = info_output;
	bool new_enabled = !options.contains(" -disable");
	myenabled = new_enabled;

	myinfos = "";
	if (options.contains(" -count "))
	{
	    string count = options.after(" -count ");
	    strip_leading_space(count);
	    if (count.contains(' '))
		count = count.before(' ');

	    myinfos = "count " + count;
	    if (count.contains('/'))
		count = count.after('/');
	    myignore_count = atoi(count.chars());
	}

	if (options.contains(" if ") || options.contains(" -if "))
	{
	    string cond = options.after("if ");
	    if (!myinfos.empty())
		myinfos += '\n';
	    myinfos += "stop only if " + cond;
	    mycondition = cond;
	}
    }

    info_output = info_output.after('\n');
}
Example #21
0
void BreakPoint::process_xdb(string& info_output)
{
    // Strip leading `:'.
    // Bob Wiegand <*****@*****.**>
    if (info_output.contains(':', 0))
	info_output = info_output.after(0);

    strip_leading_space(info_output);

    // Skip `count: N'
    if (info_output.contains("count:", 0))
    {
	info_output = info_output.after("count:");
	strip_leading_space(info_output);
	string count = info_output.before(rxblanks_or_tabs);
	info_output = info_output.after(rxblanks_or_tabs);

	myignore_count = atoi(count.chars());
    }
	    
    // Check for `Active' or `Suspended' and strip them
    // Bob Wiegand <*****@*****.**>
    if (info_output.contains("Active", 0))
    {
	info_output = info_output.after("Active");
	myenabled   = true;
    }
    else if (info_output.contains("Suspended", 0))
    {
	info_output = info_output.after("Suspended");
	myenabled   = false;
    }

    // Get function name and position
    info_output = info_output.after(rxblanks_or_tabs);
    myfunc = info_output.before(": ");

    const string pos = dbx_lookup(myfunc);
    if (!pos.empty())
    {
	myfile_name = pos.before(":");
    }

    info_output = info_output.after(": ");
    myline_nr = get_positive_nr(info_output);

    info_output = info_output.after('\n');

    // Examine commands for condition
    string commands = info_output;
    strip_leading_space(commands);
    if (commands.contains('{', 0))
    {
	// A condition has the form `{if COND {} {Q; c}}'.
	if (commands.contains("{if ", 0))
	{
	    string cond = commands.after("{if ");
	    cond = cond.before('{');
	    strip_space(cond);
	    mycondition = cond;
	}

	// Skip this line, too
	info_output = info_output.after('\n');
    }
}
Example #22
0
// Return commands to restore this breakpoint, using the dummy number
// NR.  If AS_DUMMY is set, delete the breakpoint immediately in order
// to increase the breakpoint number.  If ADDR is set, use ADDR as
// (fake) address.  If COND is set, use COND as (fake) condition.
// Return true iff successful.
bool BreakPoint::get_state(std::ostream& os, int nr, bool as_dummy,
			   string pos, string cond)
{
    if (pos.empty())
    { 
	if (line_nr() > 0)
	    pos = file_name() + ":" + itostring(line_nr());
	else
	    pos = string('*') + address();
    }

    if (cond == char(-1))
	cond = real_condition();

    const string num = "@" + itostring(nr) + "@";

    switch (gdb->type())
    {
    case BASH:
    case GDB:
    case MAKE:
    case PYDB:
    case DBG:
    {
	switch (type())
	{
	case BREAKPOINT:
	{
	    switch (dispo())
	    {
	    case BPKEEP:
	    case BPDIS:
		os << "break " << pos << "\n";
		break;

	    case BPDEL:
		os << "tbreak " << pos << "\n";
		break;
	    }
	    break;
	}

	case WATCHPOINT:
	{
	    os << gdb->watch_command(expr(), watch_mode()) << "\n";
	    break;
	}

	case TRACEPOINT:
	case ACTIONPOINT:
	{
	    // Not handled - FIXME
	    break;
	}
	}

	if (!as_dummy)
	{
	    // Extra infos
	    if (!enabled() && gdb->has_disable_command())
		os << gdb->disable_command(num) << "\n";
	    int ignore = ignore_count();
	    if (ignore > 0 && gdb->has_ignore_command())
		os << gdb->ignore_command(num, ignore) << "\n";
	    if (!cond.empty() && gdb->has_condition_command())
		os << gdb->condition_command(num, cond) << "\n";
	    if (commands().size() != 0)
	    {
		os << "commands " << num << "\n";
		for (int i = 0; i < commands().size(); i++)
		    os << commands()[i] << "\n";
		os << "end\n";
	    }
	}
	break;
    }

    case DBX:
    {
	string cond_suffix = "";
	if (!cond.empty())
	{
	    if (gdb->has_handler_command())
		cond_suffix = " -if " + cond;
	    else
		cond_suffix = " if " + cond;
	}

	switch (type())
	{
	case BREAKPOINT:
	    if (!func().empty())
	    {
		os << "stop in " << func() << "\n";
	    }
	    else if (pos.contains('*', 0))
	    {
		os << "stop at " << pos.after('*') << cond_suffix << '\n';
	    }
	    else
	    {
		os << "file "    << pos.before(':') << "\n";
		os << "stop at " << pos.after(':')  << cond_suffix << "\n";
	    }
	    break;

	case WATCHPOINT:
	    os << "stop " << expr() << cond_suffix << '\n';
	    break;

	case TRACEPOINT:
	case ACTIONPOINT:
	{
	    // Not handled - FIXME
	    break;
	}
	}

	if (!as_dummy)
	{
	    // Extra infos
	    if (!enabled() && gdb->has_disable_command())
		os << gdb->disable_command(num) << "\n";
	    int ignore = ignore_count();
	    if (ignore > 0 && gdb->has_ignore_command())
		os << gdb->ignore_command(num, ignore) << "\n";
	}
	break;
    }

    case JDB:
    {
	os << "stop at " << pos << "\n";
	break;
    }

    case XDB:
    {
	string cond_suffix;
	if (!cond.empty() && !gdb->has_condition_command())
	    cond_suffix = " {if " + cond + " {} {Q;c}}";

	if (pos.contains('*', 0))
	    os << "ba " << pos.after('*') << cond_suffix << '\n';
	else
	    os << "b " << pos << cond_suffix << "\n";

	if (!as_dummy)
	{
	    // Extra infos
	    if (!enabled() && gdb->has_disable_command())
		os << gdb->disable_command(num) << "\n";
	    int ignore = ignore_count();
	    if (ignore > 0 && gdb->has_ignore_command())
		os << gdb->ignore_command(num, ignore) << "\n";
	}
	break;
    }

    case PERL:
    {
	string cond_suffix;
	if (!cond.empty())
	    cond_suffix = " " + cond;

	os << "f " << pos.before(':') << "\n";

	if (type() == BREAKPOINT)
	    os << "b " << pos.after(':')  << cond_suffix << "\n";

	if (commands().size() != 0)
	{
	    os << "a " << pos.after(':') << " ";
	    for (int i = 0; i < commands().size(); i++)
		os << commands()[i] << ";";
	    os << "\n";
	}

	break;
    }
    }

    if (as_dummy && gdb->has_delete_command())
    {
	// Delete the breakpoint just created
	os << gdb->delete_command(num) << "\n";
    }

    return true;
}
Example #23
0
void BreakPoint::process_gdb(string& info_output)
{
    // Read type (`breakpoint' or `watchpoint')
    // The type may be prefixed by `hw ' or other details.
    const string word1 = info_output.before('\n');
    const string word2 = word1.after(rxblanks_or_tabs);

    if (word1.contains("watchpoint", 0) || 
	word2.contains("watchpoint", 0))
    {
	mytype = WATCHPOINT;

	// Fetch breakpoint mode detail (`acc' or `read')
	if (word1.contains("acc ", 0))
	    mywatch_mode = WATCH_ACCESS;
	else if (word1.contains("read ", 0))
	    mywatch_mode = WATCH_READ;
	else
	    mywatch_mode = WATCH_CHANGE;
    }
    else if (word1.contains("breakpoint", 0) || 
	     word2.contains("breakpoint", 0))
    {
	mytype = BREAKPOINT;
    }
    info_output = info_output.after("point");
    info_output = info_output.after(rxblanks_or_tabs);

    // Read disposition (`dis', `del', or `keep')
    if (info_output.contains("dis", 0))
    {
	mydispo = BPDIS;
    }
    else if (info_output.contains("del", 0))
    {
	mydispo = BPDEL;
    }
    else if (info_output.contains("keep", 0))
    {
	mydispo = BPKEEP;
    }
    info_output = info_output.after(rxblanks_or_tabs);

    // Read enabled flag (`y' or `n')
    if (info_output.contains('y', 0))
    {
	myenabled = true;
    }
    else if (info_output.contains('n', 0))
    {
	myenabled = false;
    }
    info_output = info_output.after(rxblanks_or_tabs);

    string new_info = "";
    if (mytype == BREAKPOINT) 
    {
        if (MAKE != gdb->type() && BASH != gdb->type())
	{
	    // Read address
	    myaddress = info_output.through(rxalphanum);
	  
	    info_output = info_output.after(myaddress);
	    strip_leading_space(info_output);
	    
	}
	  
        if (BASH != gdb->type()) {
	  if (info_output.contains("in ", 0))
	  {
	      // Function name
	      string func = info_output.after("in ");
	      if (func.contains('\n'))
		  func = func.before('\n');
	      if (func.contains(" at "))
		  func = func.before(" at ");
	      strip_space(func);

	      myfunc = func;
	  }
	}

	// Location
 	string remainder = info_output.through('\n');
	info_output = info_output.after('\n');

	// GDB 5.0 may issue an (indented) file name in the following line
	if (!remainder.contains(rxname_colon_int_nl))
	{
	    remainder += info_output.through('\n');
	    if (remainder.contains(rxname_colon_int_nl))
		info_output = info_output.after('\n');
	}

 	remainder = remainder.from(rxname_colon_int_nl);
 	myfile_name = remainder.before(":");

 	remainder = remainder.after(":");
 	if (!remainder.empty() && isdigit(remainder[0]))
 	    myline_nr = get_positive_nr(remainder);
    }
    else if (mytype == WATCHPOINT)
    {
	// Read watched expression
	myexpr = info_output.before('\n');
	info_output = info_output.after('\n');
    }

    int ignore_count = 0;
    string cond      = "";
    StringArray commands;

    if (!info_output.empty() && !isdigit(info_output[0]))
    {
	// Extra info follows
	int next_nl = index(info_output, rxnl_int, "\n");
	if (next_nl == -1)
	{
	    new_info += info_output;
	    info_output = "";
	}
	else
	{
	    new_info += info_output.through(next_nl);
	    info_output = info_output.after(next_nl);
	}

	int n = new_info.freq('\n');
	string *lines = new string[n + 1];
	split(new_info, lines, n + 1, '\n');
	string newer_info = "";

	for (int i = 0; i < n; i++)
	{
	    bool save_info = true;

	    string line = lines[i];
	    bool starts_with_space = (!line.empty() && isspace(line[0]));
	    strip_leading_space(line);

	    if (line.contains("ignore next ", 0))
	    {
		// Fetch ignore count
		string count = line.after("ignore next ");
		count = count.before(" hits");
		ignore_count = atoi(count.chars());
	    }
	    else if (line.contains("stop only if ", 0))
	    {
		// Fetch condition
		cond = line.after("stop only if ");
	    }
	    else if (line.contains("stop ", 0))
	    {
		// Any info (no GDB command starts with `stop')
	    }
	    else if (line.contains("breakpoint ", 0))
	    {
		// Any info (no GDB command starts with `breakpoint')
	    }
	    else if (starts_with_space)
	    {
		// A command (GDB indents all commands)
		commands += line;
		save_info = false;
	    }
	    else
	    {
		// Some other info
	    }

	    if (save_info)
		newer_info += line + '\n';
	}

	new_info = newer_info;
	delete[] lines;
    }

    myinfos = new_info;
    myignore_count = ignore_count;
    mycondition = cond;
    mycommands = commands;
}
Example #24
0
void PosBuffer::filter_dbx(string& answer)
{
    string file;		// File name found
    string line;		// Line number found

    // When reaching a breakpoint, DBX issues the breakpoint
    // number before the status line.  Check for this and
    // initialize defaults from breakpoint position.
    strip_leading_space(answer);
    if (answer.contains('(', 0) || answer.contains('[', 0))
    {
	// Get breakpoint position
	string ans = answer;
	int num = read_positive_nr(ans);
	string pos = source_view->bp_pos(num);
	if (!pos.empty())
	{
	    file = pos.before(':');
	    line = pos.after(':');
	}
    }

    // DEC DBX way issue warnings like
    // `warning: "./cxxtest.C":157 has no code associated with it'
    // right within the position info.

    int start_of_warning = answer.index("\nwarning");
    if (start_of_warning >= 0)
    {
	int open_bracket  = answer.index('[');
	int close_bracket = answer.index(']');
	if (open_bracket >= 0 && open_bracket < start_of_warning &&
	    close_bracket >= 0 && close_bracket > start_of_warning)
	{
	    // Remove warning

	    int end_of_warning = answer.index('\n', start_of_warning + 1);
	    while (end_of_warning < int(answer.length()) && 
		   answer[end_of_warning] == '\n')
		end_of_warning++;

	    while (start_of_warning > 0 && 
		   answer[start_of_warning - 1] == '\n')
		start_of_warning--;

	    int warning_length = end_of_warning - start_of_warning;
	    answer.at(start_of_warning, warning_length) = "";
	}
    }

#if RUNTIME_REGEX
    static regex rxdbxfunc2(
	".*line  *[1-9][0-9]*  *in  *(file  *)?\"[^\"]*\"\n.*");
#endif
    if (already_read != PosComplete && answer.matches(rxdbxfunc2))
    {
	// AIX DBX issues `up', `down' and `func' output
	// in the format `FUNCTION(ARGS), line LINE in "FILE"'.
	// SUN DBX uses `line LINE in file "FILE"' instead.
	// We check for the `line LINE' part.

	line = answer.after(" line ");
	line = line.through(rxint);

	file = answer.after('\"');
	file = file.before('\"');

	if (!line.empty())
	{
	    already_read = PosComplete;
	    // answer = answer.after("\n");
	}
    }

#if RUNTIME_REGEX
    static regex rxdbxpos("[[][^]]*:[1-9][0-9]*[^]]*[]].*");
#endif
    int dbxpos_index = -1;
    if (already_read != PosComplete && 
	(dbxpos_index = index(answer, rxdbxpos, "[")) >= 0)
    {
	// DEC DBX issues breakpoint lines in the format
	// "[new_tree:113 ,0x400858] \ttree->right = NULL;"
		
	line = answer.from(dbxpos_index);
	if (line.contains("[#", 0))
	{
	    // This is a Ladebug breakpoint, no position info.
	}
	else
	{
	    // Note that the function name may contain "::" sequences.
	    while (line.contains("::"))
		line = line.after("::");
	    line = line.after(":");
	    line = line.through(rxint);
	    if (!line.empty())
	    {
		if (answer.index('\n', dbxpos_index) >= 0)
		{
		    already_read = PosComplete;

		    // Strip position info and line
		    strip_leading_space(answer);
		    if (answer.contains('[', 0))
			answer = answer.after("\n");
		}
		else
		{
		    // Wait for `\n' such that we can delete the line
		    answer_buffer = answer;
		    answer = "";
		    already_read = PosPart;
		    return;
		}
	    }
	}
    }

    if (already_read != PosComplete && 
	(answer.contains("stopped in ") || 
	 answer.contains("stopped at ")))
    {
	int stopped_index = answer.index("stopped");
	assert(stopped_index >= 0);

	// Stop reached
	// AIX DBX issues lines like
	// `[4] stopped in unnamed block $b382 at line 4259 in file
	//      "/msdev/sms/ms7/riosqa/src/tffi/fi2tofu.c" ($t1)'
	int in_file_index = answer.index("in file ", stopped_index);
	int bracket_index = answer.index("[", stopped_index);

	if (in_file_index >= 0)
	{
	    // File name given
	    file = answer.from(in_file_index);
	    file = file.after("in file ");
	    if (file.contains('\n'))
		file = file.before('\n');
	    if (file.contains('"', 0))
	    {
		file = file.after('"');
		file = file.before('"');
	    }
	}
	else if (bracket_index >= 0)
	{
	    // DEC DBX and SGI DBX output format:
	    // `[3] Process  1852 (cxxtest) 
	    // stopped at [::main:266 ,0x1000a028]'
	    line = answer.after(bracket_index);
	    func_buffer = line;
	    while (line.contains("::"))
		line = line.after("::");
	    line = line.from(":");
	    func_buffer = func_buffer.before(line);
	    line = line.after(":");
	    line = line.through(rxint);
	    // answer = answer.after("\n");
	}
	else
	{
	    // Function name given
	    string func = answer.after(stopped_index);
	    func = func.after("stopped");
	    if (func.contains(" at "))
		func = func.before(" at ");
	    func_buffer = func;
	}

	if (!func_buffer.empty())
	{
	    // With DEC's `ladebug', the function name is fully qualified,
	    // as in `stopped at [void tree_test(void):277 0x120003f44]'
	    // We use only the base name (`tree_test' in this case).

	    // (We could avoid this if `ladebug' offered a way to look
	    // up fully qualified names.  Does it? - AZ)
	    if (func_buffer.contains('('))
		func_buffer = func_buffer.before('(');
	    while (func_buffer.contains(' '))
		func_buffer = func_buffer.after(' ');
	}

	if (line.empty())
	{
	    line = answer.after("at line ", stopped_index);
	    line = line.through(rxint);
	    if ((!file.empty() || !func_buffer.empty()) &&
		!answer.contains("at line "))
		line = "0";
	}

	if (!line.empty())
	    already_read = PosComplete;
    }

#if RUNTIME_REGEX
    static regex rxdbxfunc("[a-zA-Z_][^[]*: *[1-9][0-9]*  *.*");
#endif
    if (already_read != PosComplete && answer.matches(rxdbxfunc))
    {
	// DEC DBX issues `up', `down' and `func' output
	// in the format `FUNCTION: LINE  TEXT'
		
	// Note that the function name may contain "::" sequences.
	line = answer;
	while (line.contains("::"))
	    line = line.after("::");

	line = line.after(":");
	strip_leading_space(line);
	if (line.contains(rxint, 0))
	{
	    line = line.through(rxint);
	    if (!line.empty())
	    {
		if (answer.contains('\n'))
		{
		    // Got it!
		    already_read = PosComplete;
		    answer = answer.after("\n");
		}
		else
		{
		    // Wait for `\n' such that we can delete the line
		    answer_buffer = answer;
		    answer = "";
		    already_read = PosPart;
		    return;
		}
	    }
	}
    }

    if (already_read != PosComplete && 
	answer.contains("Current function is "))
    {
	// Up/Down command entered
	string nr = answer.after("\n");
	if (!nr.empty())
	{
	    line = itostring(atoi(nr.chars()));
	    already_read = PosComplete;
		    
	    // Show current function only
	    answer = answer.from("Current function is ");
	    answer = answer.through("\n");
	    func_buffer = answer.after("function is ");
	    func_buffer = func_buffer.before("\n");
	}
	else
	{
	    answer_buffer = answer;
	    answer = "";
	    already_read = PosPart;
	    return;
	}
    }

    if (already_read != PosComplete && 
	(!answer.contains('\n') ||
	 (answer.contains('[') && !answer.contains(']'))))
    {
	// Position info is incomplete
	answer_buffer = answer;
	answer = "";
	already_read = PosPart;
	return;
    }

    if (already_read == PosComplete && !line.empty())
    {
	if (!file.empty())
	    pos_buffer = file + ":" + line;
	else
	    pos_buffer = line;
    }

    if (already_read == PosComplete && pos_buffer.empty())
	already_read = Null;
}
Example #25
0
void PosBuffer::filter_gdb(string& answer)
{
    // Try to find out current PC even for non-existent source

    if (check_pc && pc_buffer.empty())
    {
	// `$pc = ADDRESS'
#if RUNTIME_REGEX
	static regex rxpc("\\$pc  *=  *" RXADDRESS);
#endif
	int pc_index = index(answer, rxpc, "$pc ");
	if (pc_index >= 0)
	{
	    int addr_index = answer.index('=');
	    fetch_address(answer, addr_index, pc_buffer);
		    
	    // Strip this line from ANSWER
	    int end_line = answer.index('\n', pc_index);
	    int start_line = pc_index;
	    while (start_line > 0 
		   && answer[start_line - 1] != '\n')
		start_line--;
		    
	    if (end_line < 0)
		answer.from(start_line) = "";
	    else
		answer.at(start_line, end_line - start_line + 1) 
		    = "";
	}
    }
	    
    if (check_pc && pc_buffer.empty() || 
	check_func && func_buffer.empty())
    {
	// `Breakpoint N, ADDRESS in FUNCTION (ARGS...)'
#if RUNTIME_REGEX
	static regex rxstopped_addr("Breakpoint  *[1-9][0-9]*,  *"
				    RXADDRESS);
#endif
	int pc_index = index(answer, rxstopped_addr, "Breakpoint");
	if (pc_index >= 0)
	{
	    annotate("stopped");
	    pc_index = answer.index(',');
	    fetch_address(answer, pc_index, pc_buffer);
	    fetch_in_function(answer, pc_index, func_buffer);
	}
    }
	    
    if (check_pc && pc_buffer.empty() || 
	check_func && func_buffer.empty())
    {
	// `#FRAME ADDRESS in FUNCTION (ARGS...)'
#if RUNTIME_REGEX
	static regex rxframe_addr("#[0-9][0-9]*  *" RXADDRESS);
#endif
		
	int pc_index = index(answer, rxframe_addr, "#");
	if (pc_index == 0
	    || pc_index > 0 && answer[pc_index - 1] == '\n')
	{
	    pc_index = answer.index(' ');
	    fetch_address(answer, pc_index, pc_buffer);
	    fetch_in_function(answer, pc_index, func_buffer);
	}
    }
	    
    if (check_pc && pc_buffer.empty() || 
	check_func && func_buffer.empty())
    {
	// `No line number available for 
	// address ADDRESS <FUNCTION>'
#if RUNTIME_REGEX
	static regex rxaddr("address  *" RXADDRESS);
#endif
		
	int pc_index = index(answer, rxaddr, "address ");
	if (pc_index >= 0)
	{
	    pc_index = answer.index(' ');
	    fetch_address(answer, pc_index, pc_buffer);
	    if (func_buffer.empty())
	    {
		string line = answer.from(pc_index);
		line = line.after('<');
		line = line.before('>');
		if (!line.empty())
		    func_buffer = line;
	    }
	}
    }

    if (check_pc && pc_buffer.empty() && !answer.empty())
    {
	// `ADDRESS in FUNCTION'
#if RUNTIME_REGEX
	static regex rxaddress_in(RXADDRESS " in ");
#endif
	int pc_index = -1;
	if (is_address_start(answer[0]) 
	    && answer.contains(rxaddress_in, 0))
	{
	    pc_index = 0;
	}
	else
	{
#if RUNTIME_REGEX
	    static regex rxnladdress_in("\n" RXADDRESS " in ");
#endif
	    pc_index = index(answer, rxnladdress_in, "\n");
	}
		
	if (pc_index >= 0)
	{
	    fetch_address(answer, pc_index, pc_buffer);
	    fetch_in_function(answer, pc_index, func_buffer);
	}
    }

    // Try to find out current function name, even for
    // non-existing addresses
    if (check_func && func_buffer.empty())
    {
	// `Breakpoint N, FUNCTION (ARGS...)'
	// This regex used for PYDB as well.
#if RUNTIME_REGEX
	static regex rxstopped_func("Breakpoint  *[1-9][0-9]*,  *");
#endif
	int bp_index = index(answer, rxstopped_func, "Breakpoint");
	if (bp_index >= 0)
	    fetch_function(answer, bp_index, func_buffer);
    }

    if (check_func && func_buffer.empty())
    {
	// `#FRAME FUNCTION'
#if RUNTIME_REGEX
	static regex rxframe_func("#[0-9][0-9]*  *[a-zA-Z_].*[(]");
#endif
	int frame_index = index(answer, rxframe_addr, "#");
	if (frame_index == 0
	    || frame_index > 0 && answer[frame_index - 1] == '\n')
	{
	    fetch_function(answer, frame_index, func_buffer);
	}
    }

    if (check_func && func_buffer.empty())
    {
	// FUNCTION (ARGS...) at FILE:POS
	int at_index = answer.index(" at ");
	if (at_index > 0)
	{
	    int nl_index = 
		answer.index('\n', at_index - answer.length() - 1) + 1;
	    fetch_function(answer, nl_index, func_buffer);

	    // Try to construct position from `at FILE:POS' (vxworks)
	    string file = answer.after(" at ");
	    file = file.before('\n');

	    if (file.contains(rxaddress, 0))
	    {
		// This is `at ADDRESS' (GDB output)
	    }
	    else if (file.contains(":") && !file.contains(": "))
	    {
		pos_buffer = file;
		already_read = PosComplete;
		return;
	    }
		
	}
    }
	    
    // Look for regular source info
    // (GDB's annotations are prefixed with "^Z^Z")
    int index1 = answer.index ("\032\032");
	    
    if (index1 < 0) 
    {
	int index_p = answer.index ("\032");
	if (index_p >= 0 && index_p == int(answer.length()) - 1)
	{
	    // Possible begin of position info at end of ANSWER
	    answer_buffer = "\032";
	    answer = answer.before (index_p);
	    already_read = PosPart;
	    return;
	}
		
	// Handle erroneous `info line' output like
	// `Line number 10 is out of range for "t1.f".'
	// At least get the file name.
#if RUNTIME_REGEX
	static regex rxout_of_range(
	    "Line number [0-9]+ is out of range for ");
#endif
	index_p = index(answer, rxout_of_range, "Line number");
	if (index_p >= 0)
	{
	    string file = answer.after('\"', index_p);
	    file = file.before('\"');
	    pos_buffer = file + ":1";
	    already_read = PosComplete;
	    return;
	}

	// Try to construct position from `Line xxxx of "filename"' (vxworks)
	// which is the output of an 'info line' command
	string line = answer.after("Line ");
	string file = answer.after('\"');
	if (!line.empty() && !file.empty())
	{
	    line = line.before(" of");
	    file = file.before('\"') + ":" + line;
	    if (!line.empty() && !file.empty())
	    {
		pos_buffer = file;
		already_read = PosComplete;
		return;
	    }
	}
	// Try FUNCTION (ARGS...) at FILE:POS
	// here to properly handle up/down commands 
	int at_index = answer.index(" at ");
	int br_index = answer.index("Break");
	if ( (at_index > 0) && (br_index < 0) )
	{
	    int nl_index = 
		answer.index('\n', at_index - answer.length() - 1) + 1;
	    fetch_function(answer, nl_index, func_buffer);

	    // Try to construct position from `at FILE:POS' (vxworks)
	    string file = answer.after(" at ");
	    file = file.before('\n');
	    if (!file.empty())
	    {
		pos_buffer = file;
		already_read = PosComplete;
		return;
	    }
		
	}
	
	// Nothing found
	return;
    }
	    
    // ANSWER contains position info
    int index2 = answer.index ("\n", index1);

    if (index2 == -1)
    {
	// Position info is incomplete
	answer_buffer = answer.from (index1);
	answer = answer.before (index1);
	already_read = PosPart;
	return;
    }

    assert (index1 < index2);

    // Position info is complete
    pos_buffer = answer.at(index1 + 2, index2 - (index1 + 2));

    if (pos_buffer.contains("source ", 0))
    {
	// This happens with GDB in annotation level 2
	pos_buffer = pos_buffer.after("source ");
    }

    int last_colon = pos_buffer.index(':', -1);
    pc_buffer = pos_buffer.after(last_colon);
    if (!pc_buffer.contains(rxaddress_start, 0))
	pc_buffer = "0x" + pc_buffer;
    pc_buffer = pc_buffer.through(rxaddress);

    answer.at(index1, index2 - index1 + 1) = "";
    if (!pos_buffer.empty())
	already_read = PosComplete;
}
Example #26
0
int line_of_listing(string& listing, bool silent)
{
    string message;
    while (!listing.empty()
	   && !listing.contains('>', 0) 
	   && !listing.contains('*', 1) 
	   && atoi(listing.chars()) == 0)
    {
	message += listing.through('\n');
	listing = listing.after('\n');
    }

    if (!silent)
	post_gdb_message(message);

    int idx = -1;

    if (idx < 0 && gdb->type() == JDB)
    {
	// JDB issues `=>' in the listed line
	int idx = listing.index("\t=> \t");
	while (idx > 0 && listing[idx - 1] != '\n')
	    idx--;
    }

    if (idx < 0 && gdb->type() == DBX)
    {
	// SGI DBX issues `*' in column 2 before the `list'ed line.
	// Quite useful.
#if RUNTIME_REGEX
	static regex rxnlstar("\n.[*]");
#endif
	int idx = index(listing, rxnlstar, "\n");
	if (idx < 0 && listing.contains('*', 1))
	    idx = 1;
    }

    if (idx < 0 && gdb->type() == DBX)
    {
	// DEC and SGI DBX issue `>' in column 1 before the current
	// execution line.  Quite useful.
	int idx = listing.index("\n>");
	if (idx < 0 && listing.contains('>', 0))
	    idx = 0;
    }

    // Use the first number found.
    int num_idx = listing.index(rxint, max(idx, 0));
    int line = 0;
    if (num_idx >= 0)
	line = atoi(listing.chars() + num_idx);

    if (line == 0)
    {
	// Weird.  No source?
    }
    else if (idx < 0)
    {
	// No indicator found - 
	// the position we are looking for is in the middle
	line += (listing.freq('\n') + 1) / 2 - 1;
    }

    return line;
}
Example #27
0
// Fetch position from GDB output ANSWER.
void PosBuffer::filter (string& answer)
{
    if (answer.length() == 0)
	return;

    // Check program state
    switch (gdb->type())
    {
    case BASH:
    {
 	if (has_prefix(answer, "Reading "))
 	    started = true;
	break;
    }

    case GDB:
    {
	// If GDB prints a "Current function" line, it overrides whatever
	// came before (e.g. "stopped in").
	if (has_prefix(answer, "Current function is "))
	    already_read= Null;

	// Check program state
	if (has_prefix(answer, "Starting program: "))
	    started = true;

	if (has_prefix(answer, "The program no longer exists"))
	    terminated = true;

	if (has_prefix(answer, "Program received signal"))
	    signaled = true;

	if (has_prefix(answer, "Program terminated with signal"))
	    signaled = terminated = true;

	if (answer.contains("has changed; re-reading symbols"))
	    recompiled = true;

	if (has_prefix(answer, "Current language: "))
	    gdb->program_language(answer);

	if (has_prefix(answer, "The current source language is "))
	    gdb->program_language(answer);

	if (terminated)
	    annotate("exited");
	if (signaled)
	    annotate("signalled");
    }
    break;

    case DBG:
    {
 	// Check program state
 	if (has_prefix(answer, "Starting program: "))
 	    started = true;
    }
    break;

    case DBX:
    {
	if (has_prefix(answer, "Running: "))
	    started = true;

	if (answer.contains("has been recompiled"))
	    recompiled = true;

	if (has_prefix(answer, "signal "))
	    signaled = true;
    }
    break;

    case MAKE:
    {
 	if (has_prefix(answer, "Reading makefiles..."))
 	    started = true;
	break;
    }

    case PERL:
    {
	if (has_prefix(answer, "Loading DB routines from perl5db.pl"))
	  recompiled = true;
    }
    break;

    case XDB:
    case JDB:
    case PYDB:
	break;			// Nothing special
    }

    // Check for terminated program
    int i = -1;
    while ((i = answer.index("rogram", i + 1)) > 0)
    {
	int j = i;
	while (j > 0 && answer[j - 1] != '\n')
	    j--;
	
#if RUNTIME_REGEX
	static regex rxterminated("([Tt]he )?[Pp]rogram "
				  "(exited|terminated"
				  "|is not being run|no longer exists).*");
#endif
	if (answer.matches(rxterminated, j))
	    terminated = true;
    }

    if (answer.contains("no active process") 
	|| answer.contains("execution completed")
	|| answer.contains("application exited"))
	terminated = true;

    // Check for auto command
    if (app_data.auto_commands)
    {
	answer.prepend(auto_cmd_part);
	auto_cmd_part = "";

	string pfx = app_data.auto_command_prefix;

	if (!auto_cmd_buffer.empty() && !auto_cmd_buffer.contains('\n', -1))
	{
	    // Complete pending auto command
	    if (answer.contains('\n'))
	    {
		auto_cmd_buffer += answer.through('\n');
		answer = answer.after('\n');
	    }
	    else
	    {
		auto_cmd_buffer += answer;
		answer = "";
	    }
	}

	int index;
	while ((index = answer.index(pfx)) >= 0)
	{
	    string cmd = answer.from(index);
	    if (cmd.contains('\n'))
		cmd = cmd.through('\n');
	    answer = 
		answer.before(index) + answer.from(int(index + cmd.length()));
	    cmd = cmd.after(pfx);
	    auto_cmd_buffer += cmd;
	}

	if (pfx.contains(answer, 0))
	{
	    auto_cmd_part = answer;
	    answer = "";
	}
    }

    // Fetch and store position info, return remainder
    switch (already_read)
    {
    case PosComplete:
	if (gdb->type() == GDB)
	    filter_gdb(answer);		// Slurp in the source annotation
	// Nothing more to filter - skip possible line number info
	filter_line(answer);
	break;

    case PosPart:
	answer.prepend (answer_buffer);
	answer_buffer = "";
	already_read = Null;
	// FALL THROUGH

    case Null:
    {
	// Now go for the actual position.
	switch (gdb->type())
	{
	case BASH:
	    filter_bash(answer);
	    break;
	
	case DBG:
	    filter_dbg(answer);
	    break;

	case DBX:
	    filter_dbx(answer);
	    break;

	case GDB:
	    filter_gdb(answer);
	    break;

	case JDB:
	    filter_jdb(answer);
	    break;

	case MAKE:
	    filter_make(answer);
	    break;

	case PERL:
	    filter_perl(answer);
	    break;

	case PYDB:
	    filter_pydb(answer);
	    break;

	case XDB:
	    filter_xdb(answer);
	    break;
	}

	filter_line(answer);
    }

    break;
    }
}
// Simulate a debugger via the DDD log LOGNAME.  If a command matches
// a DDD command in LOGNAME, issue the appropriate answer.
void logplayer(const string& logname)
{
    // All this is really ugly.  Works well as a hack for debugging DDD,
    // but not really worth anything else.

    static std::ifstream log(logname.chars());
    if (log.bad())
    {
	(void) fopen(logname.chars(), "r");
	perror(logname.chars());
	exit(EXIT_FAILURE);
    }

    put("[Playing " + quote(logname) + ".  Use `?' for help]\n");

    static string out;
    static string ddd_line;
    static string last_prompt;
    static bool initializing = true;
    static bool scanning = false;
    static bool out_seen = false;
    static bool wrapped = false;
    static bool echoing = false;
    static STREAMPOS scan_start, last_input;
    static string expecting;
    static int command_no = 0;
    static int command_no_start = 0;
    static bool ignore_next_input = false;

    signal(SIGINT, (SignalProc)intr);
    if (setjmp(main_loop_env) != 0)
    {
	put("Quit\n");

	scanning = false;
	wrapped  = false;
	log.clear();
	log.seekg(last_input);
	command_no = command_no_start;
	out = "";
	ddd_line = "";
	ignore_next_input = true;
    }

    for (;;)
    {
	STREAMPOS current = log.tellg();
	if (!scanning)
	{
	    scan_start = current;
	    command_no_start = command_no;
	}

	// Read line from log
	char buffer[65536];
	log.getline(buffer, sizeof buffer);
	if (!log.fail())
	{
	    string log_line(buffer);

	    if (out_seen && log_line.contains("   ", 0))
	    {
		// Continuation line
		out += unquote(log_line.from('"'));
	    }
	    else if (!out.empty())
	    {
		// Send out accumulated output
		if (!scanning)
		{
		    if (out.contains(ddd_line, 0))
			echoing = true;
		    put(out);
		}
		out = "";
	    }

	    if (log_line.contains("<- ", 0))
	    {
		assert(out.empty());

		// Output line
		out = unquote(log_line.from('"'));
		out_seen = true;
	    }

	    if (out_seen && log_line.contains("-> ", 0))
	    {
		// Handle input
		string in = unquote(log_line.from('"'));
		if (in.contains('\n', -1))
		    in = in.before('\n', -1);
		command_no++;

		if (ddd_line.contains('/', 0) || ddd_line.contains(':', 0))
		{
		    static string pattern;
		    char c = ddd_line[0];
		    string p = ddd_line.after(0);
		    if (!p.empty() || c == ':')
			pattern = p;
		    if (pattern.empty() ||
			(c == ':' && command_no == atoi(pattern.chars())) ||
			(c == '/' && (pattern.empty() || in.contains(pattern))))
		    {
			// Report line
			char buffer[256];
			sprintf(buffer, "%4d", command_no);
			std::ostringstream os;
			os << buffer << " " << in << "\n";
			put(os);

			if (c == '/' || !pattern.empty())
			{
			    // Stop here
			    scanning = false;
			    scan_start = current;
			    command_no_start = command_no - 1;
			}
		    }
		}

		if (!scanning)
		{
		    last_input = scan_start;
		    initializing = false;

		    // Read command from DDD
		    if (last_output.contains('\n'))
		    {
			string prompt = last_output.after('\n', -1);
			if (!prompt.empty() && !prompt.contains('\\', 0))
			{
			    if (prompt.contains('('))
				prompt = prompt.from('(', -1);

			    last_prompt = prompt;
			}
		    }

		    if (!last_output.contains(last_prompt, -1))
			put(last_prompt);

		    last_output = "";

		    char *s = fgets(buffer, sizeof buffer, stdin);
		    if (ignore_next_input)
		    {
			s = fgets(buffer, sizeof buffer, stdin);
			ignore_next_input = false;
		    }
		    if (s == 0)
			exit(EXIT_SUCCESS);

		    ddd_line = buffer;
		    if (ddd_line.contains('\n', -1))
			ddd_line = ddd_line.before('\n', -1);

		    if (echoing && !ddd_line.empty() && !isalpha(ddd_line[0]))
			put(ddd_line + "\r\n");

		    if (ddd_line.contains('q', 0))
			exit(EXIT_SUCCESS);

		    if ((ddd_line.contains("list ", 0) || 
			 ddd_line.contains("l ", 0)) && 
			(ddd_line.contains(" 1,") || 
			 ddd_line.contains(":1,") || 
			 ddd_line.contains(" 1-")))
		    {
			// Send the log file instead of a source
			if (echoing)
			    put(ddd_line + "\r\n");

			std::ifstream is(logname.chars());
			int line = 1;
			bool at_start_of_line = true;

			std::ostringstream os;
			for (;;)
			{
			    char c;
			    is.get(c);
			    if (is.eof())
				break;

			    if (at_start_of_line)
			    {
				os << line << '\t';
				at_start_of_line = false;
			    }

			    os << c;

			    if (c == '\n')
			    {
				line++;
				at_start_of_line = true;
			    }
			}

			put(string(os));
			scanning = false;
		    }
		}

		if (!scanning && ddd_line == ".")
		{
		    std::ostringstream os;
		    os << "Expecting " 
		       << command_no << " " << quote(in) << "\n";
		    put(os);
		    log.seekg(scan_start);
		    command_no = command_no_start;
		}
		else if (!scanning && ddd_line == "?")
		{
		    put(usage);
		    log.seekg(scan_start);
		    command_no = command_no_start;
		}
		else if (ddd_line == in || ddd_line == "!" || ddd_line.empty())
		{
		    // Okay, got it
		    scanning = false;
		}
		else if (!scanning)
		{
		    // Bad match: try to find this command in the log
		    expecting = in;
		    scanning = true;
		    wrapped = false;
		}
	    }
	}

	if (log.eof() || log.fail())
	{
	    if (scanning && wrapped)
	    {
		// Nothing found.  Don't reply.
		if (echoing && (ddd_line.empty() || isalpha(ddd_line[0])))
		    put(ddd_line + "\r\n");

		scanning = false;
		log.clear();
		log.seekg(scan_start);
		out = "";
		command_no = command_no_start;
	    }
	    else if (initializing)
	    {
		// No prompt found
		std::cerr << logname << ": invalid or incomplete log\n";
		exit(EXIT_FAILURE);
	    }
	    else
	    {
		// Try from the start
		wrapped = true;
		out_seen = false;
		log.clear();
		log.seekg(0);
		command_no = 0;
	    }
	}
    }
}
Example #29
0
// If LINE is an argument-setting command, add it to the list of arguments
void add_to_arguments(const string& line)
{
    if (is_set_args_cmd(line))
    {
	string args = line.after("args");
	args = args.after(rxwhite);
	add_argument(args, run_arguments, last_run_argument, 
		     run_arguments_updated);
    }
    else if (gdb->type() == PERL && line.contains("@ARGV = ", 0))
    {
	// @ARGV = ('arg1', 'arg2', )
	string args = line.after("('");
	args.gsub("', '", " ");
	args = args.before("', )");

	add_argument(args, run_arguments, last_run_argument, 
		     run_arguments_updated);
    }
    else if (is_run_cmd(line))
    {
	string args;
	if (gdb->type() == JDB)
	{
	    // `run CLASS ARGS...'
	    args = line.after(rxwhite);
	    args = args.after(rxwhite);
	}
	else if (gdb->type() == PERL && line.contains("exec ", 0))
	{
	    // `exec "perl -d PROGRAM ARGS..."'
	    args = line.after("exec ");
	    strip_leading_space(args);
	    if (args.contains('\"', 0) || args.contains('\'', 0))
		args = unquote(args);

	    args = args.after("-d ");
	    strip_leading_space(args);
	    args = args.after(rxwhite);
	}
	else
	{
	    // `run ARGS...'
	    args = line.after(rxwhite);
	}

	add_argument(args, run_arguments, last_run_argument, 
		     run_arguments_updated);
    }
    else if (is_make_cmd(line))
    {
	string args = line.after("make");
	args = args.after(rxwhite);
	add_argument(args, make_arguments, last_make_argument, 
		     make_arguments_updated);
    }
    else if (gdb->type() == PERL && line.contains("system 'make", 0))
    {
	string args = line.after("make");
	args = args.after(rxwhite);
	args = args.before("'");
	add_argument(args, make_arguments, last_make_argument, 
		     make_arguments_updated);
    }
    else if (is_cd_cmd(line))
    {
	string dir = line.after("cd");
	dir = dir.after(rxwhite);
	dir = source_view->full_path(dir);
	if (dir.contains('/', 0))
	    add_argument(dir, cd_arguments, last_cd_argument, 
			 cd_arguments_updated);
    }
    else if (gdb->type() == PERL && line.contains("chdir '", 0))
    {
	string dir = line.after("'");
	dir = dir.before("'");
	add_argument(dir, cd_arguments, last_cd_argument, 
		     cd_arguments_updated);
    }
    else if (gdb->type() == PERL && is_file_cmd(line, gdb))
    {
	string args = line.after(" -d ");
	args = args.after(rxwhite); // Skip file name
	args = args.before('\"');
	add_argument(args, run_arguments, last_run_argument, 
		     run_arguments_updated);
    }
}
Example #30
0
// Initialization
void DispValue::init(DispValue *parent, int depth, string& value,
		     DispValueType given_type)
{
#if LOG_CREATE_VALUES
    std::clog << "Building value from " << quote(value) << "\n";
#endif

    // Be sure the value is not changed in memory
    value.consuming(true);

    const char *initial_value = value.chars();

    static const DispValueArray empty(0);
    _children = empty;

    if (background(value.length()))
    {
	clear();

	mytype = Simple;
	_value = "(Aborted)";
	value  = "Aborted\n";
	return;
    }

    mytype = given_type;
    if (mytype == UnknownType && 
	(parent == 0 || parent->type() == List) && print_name.empty())
	mytype = Text;
    if (mytype == UnknownType && parent == 0 && is_user_command(print_name))
	mytype = List;
    if (mytype == UnknownType)
	mytype = determine_type(value);

    bool ignore_repeats = (parent != 0 && parent->type() == Array);

    char perl_type = '\0';

    switch (mytype)
    {

    case Simple:
    {
	_value = read_simple_value(value, depth, ignore_repeats);
#if LOG_CREATE_VALUES
	std::clog << mytype << ": " << quote(_value) << "\n";
#endif
	perl_type = '$';
	break;
    }

    case Text:
    {
	// Read in a line of text
	if (value.contains('\n'))
	    _value = value.through('\n');
	else
	    _value = value;
	value = value.after('\n');
#if LOG_CREATE_VALUES
	std::clog << mytype << ": " << quote(_value) << "\n";
#endif
	perl_type = '$';
	break;
    }

    case Pointer:
    {
	_value = read_pointer_value(value, ignore_repeats);
	_dereferenced = false;

#if LOG_CREATE_VALUES
	std::clog << mytype << ": " << quote(_value) << "\n";
#endif
	// Hide vtable pointers.
	if (_value.contains("virtual table") || _value.contains("vtable"))
	    myexpanded = false;
	perl_type = '$';

	// In Perl, pointers may be followed by indented `pointed to'
	// info.  Skip this.
	if (gdb->type() == PERL)
	{
	    while (value.contains("\n  ", 0))
	    {
		value = value.after("\n  ");
		value = value.from("\n");
	    }
	}		
	break;
    }

    case Array:
    {
	string base = normalize_base(myfull_name);

	_orientation = app_data.array_orientation;

#if LOG_CREATE_VALUES
	std::clog << mytype << ": " << "\n";
#endif

	read_array_begin(value, myaddr);

	// Check for `vtable entries' prefix.
	string vtable_entries = read_vtable_entries(value);
	if (!vtable_entries.empty())
	{
	    _children += parse_child(depth, vtable_entries, myfull_name);
	}

	// Read the array elements.  Assume that the type is the
	// same across all elements.
	DispValueType member_type = UnknownType;
	if (!_have_index_base)
	{
	    _index_base = index_base(base, depth);
	    _have_index_base = true;
	}
	int array_index = _index_base;

	// The array has at least one element.  Otherwise, GDB
	// would treat it as a pointer.
	do {
	    const char *repeated_value = value.chars();
	    string member_name = 
		gdb->index_expr("", itostring(array_index++));
	    DispValue *dv = parse_child(depth, value,
					add_member_name(base, member_name), 
					member_name, member_type);
	    member_type = dv->type();
	    _children += dv;

	    int repeats = read_repeats(value);

	    if (expand_repeated_values)
	    {
		// Create one value per repeat
		while (--repeats > 0)
		{
		    member_name = 
			gdb->index_expr("", itostring(array_index++));
		    string val = repeated_value;
		    DispValue *repeated_dv = 
			parse_child(depth, val, 
				    add_member_name(base, member_name),
				    member_name, member_type);
		    _children += repeated_dv;
		}
	    }
	    else
	    {
		// Show repetition in member
		if (repeats > 1)
		{
		    array_index--;

#if 0
		    // We use the GDB `artificial array' notation here,
		    // since repeat recognition is supported in GDB only.
		    member_name += "@" + itostring(repeats);

		    dv->full_name() = add_member_name(base, member_name);
		    dv->name()      = member_name;
#endif
		    dv->repeats()   = repeats;

		    array_index += repeats;
		}
	    }

	    if (background(value.length()))
	    {
		init(parent, depth, value);
		return;
	    }
	} while (read_array_next(value));
	read_array_end(value);

	// Expand only if at top-level.
	myexpanded = (depth == 0 || nchildren() <= 1);

#if LOG_CREATE_VALUES
	std::clog << mytype << " has " << nchildren() << " members\n";
#endif
	perl_type = '@';
	break;
    }

    case List:
	// Some DBXes issue the local variables via a frame line, just
	// like `set_date(d = 0x10003060, day_of_week = Sat, day = 24,
	// month = 12, year = 1994)'.  Make this more readable.
	munch_dump_line(value);

	// FALL THROUGH
    case Struct:
    {
	_orientation  = app_data.struct_orientation;
	_member_names = app_data.show_member_names;

	bool found_struct_begin   = false;
	bool read_multiple_values = false;
	
#if LOG_CREATE_VALUES
	std::clog << mytype << " " << quote(myfull_name) << "\n";
#endif
	string member_prefix = myfull_name;
	string member_suffix = "";
	if (mytype == List)
	{
	    member_prefix = "";
	    read_multiple_values = true;
	}
	else
	{
	    // In C and Java, `*' binds tighter than `.'
	    if (member_prefix.contains('*', 0))
	    {
		if (gdb->program_language() == LANGUAGE_C)
		{
		    // Use the C `->' operator instead
		    member_prefix.del("*");
		    if (member_prefix.contains('(', 0) &&
			member_prefix.contains(')', -1))
			member_prefix = unquote(member_prefix);

#if RUNTIME_REGEX
		    static regex rxchain("[-a-zA-Z0-9::_>.`]+");
#endif
		    if (member_prefix.matches(rxchain))
		    {
			// Simple chain of identifiers - prepend `->'
			member_prefix += "->";
		    }
		    else
		    {
			member_prefix.prepend("(");
			member_prefix += ")->";
		    }
		}
		else
		{
		    member_prefix.prepend("(");
		    member_prefix += ").";
		}
	    }
	    else if (gdb->program_language() == LANGUAGE_PERL)
	    {
		// In Perl, members of A are accessed as A{'MEMBER_NAME'}
		member_prefix = normalize_base(member_prefix) + "{'";
		member_suffix = "'}";
	    }
	    else if (gdb->program_language() == LANGUAGE_PHP)
	    {
		// In PHP, members of $A are accessed as $A['MEMBER_NAME']
		member_prefix = normalize_base(member_prefix) + "['";
		member_suffix = "']";
	    }
	    else if (gdb->program_language() == LANGUAGE_FORTRAN)
	    {
		// In Fortran, members of A are accessed as A%B
		member_prefix = normalize_base(member_prefix) + "%";
	    }
	    else
	    {
		// In all other languages, members are accessed as A.B
		member_prefix = normalize_base(member_prefix) + ".";
	    }

	    // In case we do not find a struct beginning, read only one value
	    found_struct_begin = read_struct_begin(value, myaddr);
	    read_multiple_values = found_struct_begin;
	}

	// Prepend base class in case of multiple inheritance
	// FIXME: This should be passed as an argument
	static string baseclass_prefix;
	member_prefix += baseclass_prefix;
	int base_classes = 0;

	bool more_values = true;
	while (more_values)
	{
	    // In a List, we may have `member' names like `(a + b)'.
	    // Don't be picky about this.
	    bool picky = (mytype == Struct);
	    string member_name = read_member_name(value, picky);

	    if (member_name.empty())
	    {
		// Some struct stuff that is not a member
		DispValue *dv = parse_child(depth, value, myfull_name, "");

		if (dv->type() == Struct)
		{
		    // What's this - a struct within a struct?  Just
		    // adopt the members.
		    // (This happens when we finally found the struct
		    // after having read all the AIX DBX base classes.)
		    for (int i = 0; i < dv->nchildren(); i++)
		    {
			DispValue *dv2 = dv->child(i)->link();
			_children += dv2;
		    }
		    dv->unlink();
		}
		else
		{
		    _children += dv;
		}

		more_values = read_multiple_values && read_struct_next(value);
	    }
	    else if (is_BaseClass_name(member_name))
	    {
		// Base class member
		string saved_baseclass_prefix = baseclass_prefix;
		base_classes++;

		if (base_classes > 1)
		{
		    // Multiple inheritance.  Be sure to
		    // reference further members unambiguously.
		    //
		    // Note: we don't do that for the first base class,
		    // because this might turn ambiguous again.
		    //
		    // Example:
		    //
		    //    Base
		    //    |   |
		    //    I1 I2
		    //     \ /
		    //      C
		    //
		    // Members of I1::Base are not prefixed, members
		    // of I2::Base get `I2::' as base class prefix.
		    // If we did this already for the first base class,
		    // members of both I1 and I2 would get `Base::' as
		    // base class prefix.

		    switch (gdb->program_language())
		    {
		    case LANGUAGE_C: // C++
			baseclass_prefix = unquote(member_name) + "::";
			break;

		    default:
			// Do nothing (yet)
			break;
		    }
		}

		DispValue *dv = 
		    parse_child(depth, value, myfull_name, member_name);
		_children += dv;

		baseclass_prefix = saved_baseclass_prefix;

		more_values = read_multiple_values && read_struct_next(value);

		// Skip a possible `members of CLASS:' prefix
		read_members_prefix(value);

		// AIX DBX does not place a separator between base
		// classes and the other members, so we always
		// continue reading after having found a base
		// class.  After all, the own class members are
		// still missing.
		if (mytype == Struct && !found_struct_begin)
		    more_values = true;
	    }
	    else
	    {
		// Ordinary member
		string full_name = "";

		if (member_name == " ")
		{
		    // Anonymous union
		    full_name = myfull_name;
		}
		
		if (member_name.contains('.'))
		{
		    if (gdb->has_quotes())
		    {
			// The member name contains `.' => quote it.  This
			// happens with vtable pointers on Linux (`_vptr.').
			full_name = member_prefix + quote(member_name, '\'') + 
			    member_suffix;
		    }
		    else
		    {
			// JDB (and others?) prepend the class name 
			// to inherited members.  Omit this.
			full_name = 
			    member_prefix + member_name.after('.', -1) + 
			    member_suffix;
		    }
		}
		
		if (full_name.empty())
		{
		    // Ordinary member
		    full_name = member_prefix + member_name + member_suffix;
		}

		DispValue *child = 
		    parse_child(depth, value, full_name, member_name);

		if (child->type() == Text)
		{
		    // Found a text as child - child value must be empty
		    string empty = "";
		    _children += 
			parse_child(depth, empty, full_name, member_name);

		    string v = child->value();
		    strip_space(v);
		    if (!v.empty())
			_children += child;
		}
		else
		{
		    _children += child;
		}

		more_values = read_multiple_values && read_struct_next(value);
	    }

	    if (background(value.length()))
	    {
		init(parent, depth, value);
		return;
	    }
	}

	if (mytype == List && !value.empty())
	{
	    // Add remaining value as text
	    _children += parse_child(depth, value, "");
	}

	if (found_struct_begin)
	{
	    // Skip the remainder
	    read_struct_end(value);
	}

	// Expand only if at top-level.
	myexpanded = (depth == 0 || nchildren() <= 1);

#if LOG_CREATE_VALUES
	std::clog << mytype << " "
		  << quote(myfull_name)
		  << " has " << nchildren() << " members\n";
#endif

	perl_type = '%';
	break;
    }

    case Reference:
    {
	myexpanded = true;

	int sep = value.index('@');
	sep = value.index(':', sep);

	string ref = value.before(sep);
	value = value.after(sep);

	string addr = gdb->address_expr(myfull_name);

	_children += parse_child(depth, ref, addr, myfull_name, Pointer);
	_children += parse_child(depth, value, myfull_name);

	if (background(value.length()))
	{
	    init(parent, depth, value);
	    return;
	}

	perl_type = '$';	// No such thing in Perl...
	break;
    }

    case Sequence:
    case UnknownType:
	assert(0);
	abort();
    }

    // Handle trailing stuff (`sequences')
    if (parent == 0 || parent->type() != Sequence)
    {
	bool need_clear = true;
	while (sequence_pending(value, parent))
	{
	    if (need_clear)
	    {
#if LOG_CREATE_VALUES
		std::clog << "Sequence detected at " << quote(value) << "\n";
#endif

		clear();
		value = initial_value;

		mytype = Sequence;

#if LOG_CREATE_VALUES
		std::clog << mytype << " " << quote(myfull_name) << "\n";
#endif

		need_clear = false;
	    }
	    
	    const char *old_value = value.chars();

	    DispValue *dv = parse_child(depth, value, myfull_name);

	    if (value == old_value)
	    {
		// Nothing consumed - stop here
		dv->unlink();
		break;
	    }
	    else if (dv->type() == Simple && dv->value().empty())
	    {
		// Empty value - ignore
		dv->unlink();
	    }
	    else
	    {
		_children += dv;
	    }
	}

#if LOG_CREATE_VALUES
	if (!need_clear)
	{
	    std::clog << mytype << " "
		      << quote(myfull_name)
		      << " has " << nchildren() << " members\n";
	}
#endif
    }

    if (gdb->program_language() == LANGUAGE_PERL && is_perl_prefix(perl_type))
    {
	// Set new type
	if (!myfull_name.empty() && is_perl_prefix(myfull_name[0]))
	    myfull_name[0] = perl_type;
    }

    background(value.length());
    changed = true;
}