Exemplo n.º 1
0
static void
callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
	struct callstack_element *elem, *prev;

	debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
		fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__);
		abort();
		return;
	}

	prev = &proc->callstack[proc->callstack_depth-1];
	elem = &proc->callstack[proc->callstack_depth];
	elem->is_syscall = 0;
	elem->c_un.libfunc = sym;

	elem->return_addr = proc->return_addr;
	if (elem->return_addr) {
		insert_breakpoint(proc, elem->return_addr, NULL, 1);
	}

	/* handle functions like atexit() on mips which have no return */
	if (elem->return_addr != prev->return_addr)
		proc->callstack_depth++;
	if (opt_T || options.summary) {
		struct timezone tz;
		gettimeofday(&elem->time_spent, &tz);
	}
}
Exemplo n.º 2
0
int
linkmap_init(Process *proc, struct ltelf *lte) {
	void *dbg_addr = NULL, *dyn_addr = GELF_ADDR_CAST(lte->dyn_addr);
	struct r_debug *rdbg = NULL;
	struct cb_data data;

	debug(DEBUG_FUNCTION, "linkmap_init()");

	if (find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, &dbg_addr) == -1) {
		debug(2, "Couldn't find debug structure!");
		return -1;
	}

	proc->debug = dbg_addr;

	if (!(rdbg = load_debug_struct(proc))) {
		debug(2, "No debug structure or no memory to allocate one!");
		return -1;
	}

	data.lte = lte;

	add_library_symbol(rdbg->r_brk, "", &library_symbols, LS_TOPLT_NONE, 0);
	insert_breakpoint(proc, sym2addr(proc, library_symbols),
			  library_symbols, 1);

	crawl_linkmap(proc, rdbg, hook_libdl_cb, &data);

	free(rdbg);
	return 0;
}
Exemplo n.º 3
0
int
linkmap_init(struct Process *proc, arch_addr_t dyn_addr)
{
	debug(DEBUG_FUNCTION, "linkmap_init(%d, dyn_addr=%p)", proc->pid, dyn_addr);

	if (arch_find_dl_debug(proc, dyn_addr, &proc->os.debug_addr) == -1) {
		debug(2, "Couldn't find debug structure!");
		return -1;
	}

	int status;
	struct lt_r_debug_64 rdbg;
	if ((status = load_debug_struct(proc, &rdbg)) < 0) {
		debug(2, "No debug structure or no memory to allocate one!");
		return status;
	}

	/* XXX The double cast should be removed when
	 * arch_addr_t becomes integral type.  */
	arch_addr_t addr = (arch_addr_t)(uintptr_t)rdbg.r_brk;
	if (arch_translate_address_dyn(proc, addr, &addr) < 0)
		return -1;

	struct breakpoint *rdebug_bp = insert_breakpoint(proc, addr, NULL);
	static struct bp_callbacks rdebug_callbacks = {
		.on_hit = rdebug_bp_on_hit,
	};
	rdebug_bp->cbs = &rdebug_callbacks;

	crawl_linkmap(proc, &rdbg);

	return 0;
}
Exemplo n.º 4
0
void
enable_all_breakpoints(Process *proc) {
	debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid);
	if (proc->breakpoints_enabled <= 0) {
#ifdef __powerpc__
		unsigned long a;

		/*
		 * PPC HACK! (XXX FIXME TODO)
		 * If the dynamic linker hasn't populated the PLT then
		 * dont enable the breakpoints
		 */
		if (options.libcalls) {
			a = ptrace(PTRACE_PEEKTEXT, proc->pid,
				   sym2addr(proc, proc->list_of_symbols),
				   0);
			if (a == 0x0)
				return;
		}
#endif

		debug(1, "Enabling breakpoints for pid %u...", proc->pid);
		if (proc->breakpoints) {
			dict_apply_to_all(proc->breakpoints, enable_bp_cb,
					  proc);
		}
#ifdef __mips__
		{
			/*
			 * I'm sure there is a nicer way to do this. We need to
			 * insert breakpoints _after_ the child has been started.
			 */
			struct library_symbol *sym;
			struct library_symbol *new_sym;
			sym=proc->list_of_symbols;
			while(sym){
				void *addr= sym2addr(proc,sym);
				if(!addr){
					sym=sym->next;
					continue;
				}
				if(dict_find_entry(proc->breakpoints,addr)){
					sym=sym->next;
					continue;
				}
				debug(2,"inserting bp %p %s",addr,sym->name);
				new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
				memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
				new_sym->next=proc->list_of_symbols;
				proc->list_of_symbols=new_sym;
				insert_breakpoint(proc, addr, new_sym);
				sym=sym->next;
			}
		}
#endif
	}
	proc->breakpoints_enabled = 1;
}
Exemplo n.º 5
0
static void
linkmap_add_cb(void *data) { //const char *lib_name, ElfW(Addr) addr) {
	size_t i = 0;
	struct cb_data *lm_add = data;
	struct ltelf lte;
	struct opt_x_t *xptr;

	debug(DEBUG_FUNCTION, "linkmap_add_cb");

	/*
		XXX
		iterate through library[i]'s to see if this lib is in the list.
		if not, add it
	 */
	for(;i < library_num;i++) {
		if (strcmp(library[i], lm_add->lib_name) == 0) {
			/* found it, so its not new */
			return;
		}
	}

	/* new library linked! */
	debug(2, "New libdl loaded library found: %s\n", lm_add->lib_name);

	if (library_num < MAX_LIBRARIES) {
		library[library_num++] = strdup(lm_add->lib_name);
		memset(&lte, 0, sizeof(struct ltelf));
		lte.base_addr = lm_add->addr;
		do_init_elf(&lte, library[library_num-1]);
		/* add bps */
		for (xptr = opt_x; xptr; xptr = xptr->next) {
			if (xptr->found)
				continue;

			GElf_Sym sym;
			GElf_Addr addr;

			if (in_load_libraries(xptr->name, &lte, 1, &sym)) {
				debug(2, "found symbol %s @ %#" PRIx64
						", adding it.",
						xptr->name, sym.st_value);
				addr = sym.st_value;
				add_library_symbol(addr, xptr->name, &library_symbols, LS_TOPLT_NONE, 0);
				xptr->found = 1;
				insert_breakpoint(lm_add->proc,
						  sym2addr(lm_add->proc,
							   library_symbols),
						  library_symbols, 1);
			}
		}
		do_close_elf(&lte);
	}
}
Exemplo n.º 6
0
void ScriptDebuggerRemote::_poll_events() {

	while(packet_peer_stream->get_available_packet_count()>0) {

		_get_output();

		//send over output_strings

		Variant var;
		Error err = packet_peer_stream->get_var(var);

		ERR_CONTINUE( err != OK);
		ERR_CONTINUE( var.get_type()!=Variant::ARRAY );

		Array cmd = var;

		ERR_CONTINUE( cmd.size()==0);
		ERR_CONTINUE( cmd[0].get_type()!=Variant::STRING );

		String command = cmd[0];
		//cmd.remove(0);

		if (command=="break") {

			if (get_break_language())
				debug(get_break_language());
		} else if (command=="request_scene_tree") {

			if (request_scene_tree)
				request_scene_tree(request_scene_tree_ud);
		} else if (command=="request_video_mem") {

			_send_video_memory();
		} else if (command=="breakpoint") {

			bool set = cmd[3];
			if (set)
				insert_breakpoint(cmd[2],cmd[1]);
			else
				remove_breakpoint(cmd[2],cmd[1]);
		} else {
			_parse_live_edit(cmd);
		}

	}

}
Exemplo n.º 7
0
void
breakpoints_init(Process *proc) {
	struct library_symbol *sym;

	debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid);
	if (proc->breakpoints) {	/* let's remove that struct */
		dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL);
		dict_clear(proc->breakpoints);
		proc->breakpoints = NULL;
	}
	proc->breakpoints = dict_init(dict_key2hash_int, dict_key_cmp_int);

	if (options.libcalls && proc->filename) {
		/* FIXME: memory leak when called by exec(): */
		proc->list_of_symbols = read_elf(proc);
		if (opt_e) {
			struct library_symbol **tmp1 = &(proc->list_of_symbols);
			while (*tmp1) {
				struct opt_e_t *tmp2 = opt_e;
				int keep = !opt_e_enable;

				while (tmp2) {
					if (!strcmp((*tmp1)->name, tmp2->name)) {
						keep = opt_e_enable;
					}
					tmp2 = tmp2->next;
				}
				if (!keep) {
					*tmp1 = (*tmp1)->next;
				} else {
					tmp1 = &((*tmp1)->next);
				}
			}
		}
	} else {
		proc->list_of_symbols = NULL;
	}
	for (sym = proc->list_of_symbols; sym; sym = sym->next) {
		/* proc->pid==0 delays enabling. */
		insert_breakpoint(proc, sym2addr(proc, sym), sym);
	}
	proc->callstack_depth = 0;
	proc->breakpoints_enabled = -1;
}
Exemplo n.º 8
0
void
reinitialize_breakpoints(Process *proc) {
	struct library_symbol *sym;

	debug(DEBUG_FUNCTION, "reinitialize_breakpoints(pid=%d)", proc->pid);

	sym = proc->list_of_symbols;

	while (sym) {
		if (sym->needs_init) {
			insert_breakpoint(proc, sym2addr(proc, sym),
					  sym);
			if (sym->needs_init && !sym->is_weak) {
				fprintf(stderr,
					"could not re-initialize breakpoint for \"%s\" in file \"%s\"\n",
					sym->name, proc->filename);
				exit(1);
			}
		}
		sym = sym->next;
	}
}
Exemplo n.º 9
0
void ScriptDebuggerRemote::_poll_events() {

	//this si called from ::idle_poll, happens only when running the game,
	//does not get called while on debug break

	while (packet_peer_stream->get_available_packet_count() > 0) {

		_get_output();

		//send over output_strings

		Variant var;
		Error err = packet_peer_stream->get_var(var);

		ERR_CONTINUE(err != OK);
		ERR_CONTINUE(var.get_type() != Variant::ARRAY);

		Array cmd = var;

		ERR_CONTINUE(cmd.size() == 0);
		ERR_CONTINUE(cmd[0].get_type() != Variant::STRING);

		String command = cmd[0];
		//cmd.remove(0);

		if (command == "break") {

			if (get_break_language())
				debug(get_break_language());
		} else if (command == "request_scene_tree") {

			if (request_scene_tree)
				request_scene_tree(request_scene_tree_ud);
		} else if (command == "request_video_mem") {

			_send_video_memory();
		} else if (command == "inspect_object") {

			ObjectID id = cmd[1];
			_send_object_id(id);
		} else if (command == "set_object_property") {

			_set_object_property(cmd[1], cmd[2], cmd[3]);

		} else if (command == "start_profiling") {

			for (int i = 0; i < ScriptServer::get_language_count(); i++) {
				ScriptServer::get_language(i)->profiling_start();
			}

			max_frame_functions = cmd[1];
			profiler_function_signature_map.clear();
			profiling = true;
			frame_time = 0;
			idle_time = 0;
			fixed_time = 0;
			fixed_frame_time = 0;

			print_line("PROFILING ALRIGHT!");

		} else if (command == "stop_profiling") {

			for (int i = 0; i < ScriptServer::get_language_count(); i++) {
				ScriptServer::get_language(i)->profiling_stop();
			}
			profiling = false;
			_send_profiling_data(false);
			print_line("PROFILING END!");
		} else if (command == "reload_scripts") {
			reload_all_scripts = true;
		} else if (command == "breakpoint") {

			bool set = cmd[3];
			if (set)
				insert_breakpoint(cmd[2], cmd[1]);
			else
				remove_breakpoint(cmd[2], cmd[1]);
		} else {
			_parse_live_edit(cmd);
		}
	}
}
Exemplo n.º 10
0
void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) {

	//this function is called when there is a debugger break (bug on script)
	//or when execution is paused from editor

	if (!tcp_client->is_connected_to_host()) {
		ERR_EXPLAIN("Script Debugger failed to connect, but being used anyway.");
		ERR_FAIL();
	}

	packet_peer_stream->put_var("debug_enter");
	packet_peer_stream->put_var(2);
	packet_peer_stream->put_var(p_can_continue);
	packet_peer_stream->put_var(p_script->debug_get_error());

	skip_profile_frame = true; // to avoid super long frame time for the frame

	Input::MouseMode mouse_mode = Input::get_singleton()->get_mouse_mode();
	if (mouse_mode != Input::MOUSE_MODE_VISIBLE)
		Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);

	while (true) {

		_get_output();

		if (packet_peer_stream->get_available_packet_count() > 0) {

			Variant var;
			Error err = packet_peer_stream->get_var(var);
			ERR_CONTINUE(err != OK);
			ERR_CONTINUE(var.get_type() != Variant::ARRAY);

			Array cmd = var;

			ERR_CONTINUE(cmd.size() == 0);
			ERR_CONTINUE(cmd[0].get_type() != Variant::STRING);

			String command = cmd[0];

			if (command == "get_stack_dump") {

				packet_peer_stream->put_var("stack_dump");
				int slc = p_script->debug_get_stack_level_count();
				packet_peer_stream->put_var(slc);

				for (int i = 0; i < slc; i++) {

					Dictionary d;
					d["file"] = p_script->debug_get_stack_level_source(i);
					d["line"] = p_script->debug_get_stack_level_line(i);
					d["function"] = p_script->debug_get_stack_level_function(i);
					//d["id"]=p_script->debug_get_stack_level_
					d["id"] = 0;

					packet_peer_stream->put_var(d);
				}

			} else if (command == "get_stack_frame_vars") {

				cmd.remove(0);
				ERR_CONTINUE(cmd.size() != 1);
				int lv = cmd[0];

				List<String> members;
				List<Variant> member_vals;

				p_script->debug_get_stack_level_members(lv, &members, &member_vals);

				ERR_CONTINUE(members.size() != member_vals.size());

				List<String> locals;
				List<Variant> local_vals;

				p_script->debug_get_stack_level_locals(lv, &locals, &local_vals);

				ERR_CONTINUE(locals.size() != local_vals.size());

				packet_peer_stream->put_var("stack_frame_vars");
				packet_peer_stream->put_var(2 + locals.size() * 2 + members.size() * 2);

				{ //members
					packet_peer_stream->put_var(members.size());

					List<String>::Element *E = members.front();
					List<Variant>::Element *F = member_vals.front();

					while (E) {

						_put_variable(E->get(), F->get());

						E = E->next();
						F = F->next();
					}
				}

				{ //locals
					packet_peer_stream->put_var(locals.size());

					List<String>::Element *E = locals.front();
					List<Variant>::Element *F = local_vals.front();

					while (E) {
						_put_variable(E->get(), F->get());

						E = E->next();
						F = F->next();
					}
				}

			} else if (command == "step") {

				set_depth(-1);
				set_lines_left(1);
				break;
			} else if (command == "next") {

				set_depth(0);
				set_lines_left(1);
				break;

			} else if (command == "continue") {

				set_depth(-1);
				set_lines_left(-1);
				OS::get_singleton()->move_window_to_foreground();
				break;
			} else if (command == "break") {
				ERR_PRINT("Got break when already broke!");
				break;
			} else if (command == "request_scene_tree") {

				if (request_scene_tree)
					request_scene_tree(request_scene_tree_ud);

			} else if (command == "request_video_mem") {

				_send_video_memory();
			} else if (command == "inspect_object") {

				ObjectID id = cmd[1];
				_send_object_id(id);
			} else if (command == "set_object_property") {

				_set_object_property(cmd[1], cmd[2], cmd[3]);

			} else if (command == "reload_scripts") {
				reload_all_scripts = true;
			} else if (command == "breakpoint") {

				bool set = cmd[3];
				if (set)
					insert_breakpoint(cmd[2], cmd[1]);
				else
					remove_breakpoint(cmd[2], cmd[1]);

			} else {
				_parse_live_edit(cmd);
			}

		} else {
			OS::get_singleton()->delay_usec(10000);
		}
	}

	packet_peer_stream->put_var("debug_exit");
	packet_peer_stream->put_var(0);

	if (mouse_mode != Input::MOUSE_MODE_VISIBLE)
		Input::get_singleton()->set_mouse_mode(mouse_mode);
}
Exemplo n.º 11
0
static void
handle_breakpoint(Event *event) {
	int i, j;
	Breakpoint *sbp;
	Process *leader = event->proc->leader;

	/* The leader has terminated.  */
	if (leader == NULL) {
		continue_process(event->proc->pid);
		return;
	}

	debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr);
	debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);

#ifdef __powerpc__
	/* Need to skip following NOP's to prevent a fake function from being stacked.  */
	long stub_addr = (long) get_count_register(event->proc);
	Breakpoint *stub_bp = NULL;
	char nop_instruction[] = PPC_NOP;

	stub_bp = address2bpstruct(leader, event->e_un.brk_addr);

	if (stub_bp) {
		unsigned char *bp_instruction = stub_bp->orig_value;

		if (memcmp(bp_instruction, nop_instruction,
			    PPC_NOP_LENGTH) == 0) {
			if (stub_addr != (long) event->e_un.brk_addr) {
				set_instruction_pointer (event->proc, event->e_un.brk_addr + 4);
				continue_process(event->proc->pid);
				return;
			}
		}
	}
#endif

	for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
		if (event->e_un.brk_addr ==
		    event->proc->callstack[i].return_addr) {
#ifdef __powerpc__
			/*
			 * PPC HACK! (XXX FIXME TODO)
			 * The PLT gets modified during the first call,
			 * so be sure to re-enable the breakpoint.
			 */
			unsigned long a;
			struct library_symbol *libsym =
			    event->proc->callstack[i].c_un.libfunc;
			void *addr = sym2addr(event->proc, libsym);

			if (libsym->plt_type != LS_TOPLT_POINT) {
				unsigned char break_insn[] = BREAKPOINT_VALUE;

				sbp = address2bpstruct(leader, addr);
				assert(sbp);
				a = ptrace(PTRACE_PEEKTEXT, event->proc->pid,
					   addr);

				if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) {
					sbp->enabled--;
					insert_breakpoint(event->proc, addr,
							  libsym, 1);
				}
			} else {
				sbp = dict_find_entry(leader->breakpoints, addr);
				/* On powerpc, the breakpoint address
				   may end up being actual entry point
				   of the library symbol, not the PLT
				   address we computed.  In that case,
				   sbp is NULL.  */
				if (sbp == NULL || addr != sbp->addr) {
					insert_breakpoint(event->proc, addr,
							  libsym, 1);
				}
			}
#elif defined(__mips__)
			void *addr = NULL;
			struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
			struct library_symbol *new_sym;
			assert(sym);
			addr = sym2addr(event->proc, sym);
			sbp = dict_find_entry(leader->breakpoints, addr);
			if (sbp) {
				if (addr != sbp->addr) {
					insert_breakpoint(event->proc, addr, sym, 1);
				}
			} else {
				new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
				memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
				new_sym->next = leader->list_of_symbols;
				leader->list_of_symbols = new_sym;
				insert_breakpoint(event->proc, addr, new_sym, 1);
			}
#endif
			for (j = event->proc->callstack_depth - 1; j > i; j--) {
				callstack_pop(event->proc);
			}
			if (event->proc->state != STATE_IGNORED) {
				if (opt_T || options.summary) {
					calc_time_spent(event->proc);
				}
			}
			event->proc->return_addr = event->e_un.brk_addr;
			if (event->proc->state != STATE_IGNORED) {
				mock_return(LT_TOF_FUNCTIONR, event->proc,
						event->proc->callstack[i].c_un.libfunc->name);
				output_right(LT_TOF_FUNCTIONR, event->proc,
						event->proc->callstack[i].c_un.libfunc->name);
			}
			callstack_pop(event->proc);
			sbp = address2bpstruct(leader, event->e_un.brk_addr);
			continue_after_breakpoint(event->proc, sbp);
			return;
		}
	}

	if ((sbp = address2bpstruct(leader, event->e_un.brk_addr))) {
		if (sbp->libsym == NULL) {
			continue_after_breakpoint(event->proc, sbp);
			return;
		}

		if (strcmp(sbp->libsym->name, "") == 0) {
			debug(DEBUG_PROCESS, "Hit _dl_debug_state breakpoint!\n");
			arch_check_dbg(leader);
		}

		if (event->proc->state != STATE_IGNORED) {
			event->proc->stack_pointer = get_stack_pointer(event->proc);
			event->proc->return_addr =
				get_return_addr(event->proc, event->proc->stack_pointer);
			callstack_push_symfunc(event->proc, sbp->libsym);
			output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
		}
#ifdef PLT_REINITALISATION_BP
		if (event->proc->need_to_reinitialize_breakpoints
		    && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) ==
			0))
			reinitialize_breakpoints(leader);
#endif

		continue_after_breakpoint(event->proc, sbp);
		return;
	}

	if (event->proc->state != STATE_IGNORED && !options.no_plt) {
		output_line(event->proc, "unexpected breakpoint at %p",
				(void *)event->e_un.brk_addr);
	}
	continue_process(event->proc->pid);
}
Exemplo n.º 12
0
void ScriptDebuggerLocal::debug(ScriptLanguage *p_script, bool p_can_continue) {

	print_line("Debugger Break, Reason: '" + p_script->debug_get_error() + "'");
	print_line("*Frame " + itos(0) + " - " + p_script->debug_get_stack_level_source(0) + ":" + itos(p_script->debug_get_stack_level_line(0)) + " in function '" + p_script->debug_get_stack_level_function(0) + "'");
	print_line("Enter \"help\" for assistance.");
	int current_frame = 0;
	int total_frames = p_script->debug_get_stack_level_count();
	while (true) {

		OS::get_singleton()->print("debug> ");
		String line = OS::get_singleton()->get_stdin_string().strip_edges();

		if (line == "") {
			print_line("Debugger Break, Reason: '" + p_script->debug_get_error() + "'");
			print_line("*Frame " + itos(current_frame) + " - " + p_script->debug_get_stack_level_source(current_frame) + ":" + itos(p_script->debug_get_stack_level_line(current_frame)) + " in function '" + p_script->debug_get_stack_level_function(current_frame) + "'");
			print_line("Enter \"help\" for assistance.");
		} else if (line == "c" || line == "continue")
			break;
		else if (line == "bt" || line == "breakpoint") {

			for (int i = 0; i < total_frames; i++) {

				String cfi = (current_frame == i) ? "*" : " "; //current frame indicator
				print_line(cfi + "Frame " + itos(i) + " - " + p_script->debug_get_stack_level_source(i) + ":" + itos(p_script->debug_get_stack_level_line(i)) + " in function '" + p_script->debug_get_stack_level_function(i) + "'");
			}

		} else if (line.begins_with("fr") || line.begins_with("frame")) {

			if (line.get_slice_count(" ") == 1) {
				print_line("*Frame " + itos(current_frame) + " - " + p_script->debug_get_stack_level_source(current_frame) + ":" + itos(p_script->debug_get_stack_level_line(current_frame)) + " in function '" + p_script->debug_get_stack_level_function(current_frame) + "'");
			} else {
				int frame = line.get_slicec(' ', 1).to_int();
				if (frame < 0 || frame >= total_frames) {
					print_line("Error: Invalid frame.");
				} else {
					current_frame = frame;
					print_line("*Frame " + itos(frame) + " - " + p_script->debug_get_stack_level_source(frame) + ":" + itos(p_script->debug_get_stack_level_line(frame)) + " in function '" + p_script->debug_get_stack_level_function(frame) + "'");
				}
			}

		} else if (line == "lv" || line == "locals") {

			List<String> locals;
			List<Variant> values;
			p_script->debug_get_stack_level_locals(current_frame, &locals, &values);
			List<Variant>::Element *V = values.front();
			for (List<String>::Element *E = locals.front(); E; E = E->next()) {
				print_line(E->get() + ": " + String(V->get()));
				V = V->next();
			}

		} else if (line == "gv" || line == "globals") {

			List<String> locals;
			List<Variant> values;
			p_script->debug_get_globals(&locals, &values);
			List<Variant>::Element *V = values.front();
			for (List<String>::Element *E = locals.front(); E; E = E->next()) {
				print_line(E->get() + ": " + String(V->get()));
				V = V->next();
			}

		} else if (line == "mv" || line == "members") {

			List<String> locals;
			List<Variant> values;
			p_script->debug_get_stack_level_members(current_frame, &locals, &values);
			List<Variant>::Element *V = values.front();
			for (List<String>::Element *E = locals.front(); E; E = E->next()) {
				print_line(E->get() + ": " + String(V->get()));
				V = V->next();
			}

		} else if (line.begins_with("p") || line.begins_with("print")) {

			if (line.get_slice_count(" ") <= 1) {
				print_line("Usage: print <expre>");
			} else {

				String expr = line.get_slicec(' ', 2);
				String res = p_script->debug_parse_stack_level_expression(current_frame, expr);
				print_line(res);
			}

		} else if (line == "s" || line == "step") {

			set_depth(-1);
			set_lines_left(1);
			break;
		} else if (line.begins_with("n") || line.begins_with("next")) {

			set_depth(0);
			set_lines_left(1);
			break;
		} else if (line.begins_with("br") || line.begins_with("break")) {

			if (line.get_slice_count(" ") <= 1) {
				//show breakpoints
			} else {

				String bppos = line.get_slicec(' ', 1);
				String source = bppos.get_slicec(':', 0).strip_edges();
				int line = bppos.get_slicec(':', 1).strip_edges().to_int();

				source = breakpoint_find_source(source);

				insert_breakpoint(line, source);

				print_line("BreakPoint at " + source + ":" + itos(line));
			}

		} else if (line.begins_with("delete")) {

			if (line.get_slice_count(" ") <= 1) {
				clear_breakpoints();
			} else {

				String bppos = line.get_slicec(' ', 1);
				String source = bppos.get_slicec(':', 0).strip_edges();
				int line = bppos.get_slicec(':', 1).strip_edges().to_int();

				source = breakpoint_find_source(source);

				remove_breakpoint(line, source);

				print_line("Removed BreakPoint at " + source + ":" + itos(line));
			}

		} else if (line == "h" || line == "help") {

			print_line("Built-In Debugger command list:\n");
			print_line("\tc,continue :\t\t Continue execution.");
			print_line("\tbt,backtrace :\t\t Show stack trace (frames).");
			print_line("\tfr,frame <frame>:\t Change current frame.");
			print_line("\tlv,locals :\t\t Show local variables for current frame.");
			print_line("\tmv,members :\t\t Show member variables for \"this\" in frame.");
			print_line("\tgv,globals :\t\t Show global variables.");
			print_line("\tp,print <expr> :\t Execute and print variable in expression.");
			print_line("\ts,step :\t\t Step to next line.");
			print_line("\tn,next :\t\t Next line.");
			print_line("\tbr,break source:line :\t Place a breakpoint.");
			print_line("\tdelete [source:line]:\t\t Delete one/all breakpoints.");
		} else {
			print_line("Error: Invalid command, enter \"help\" for assistance.");
		}
	}
}
Exemplo n.º 13
0
void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) {

	if (!tcp_client->is_connected()) {
		ERR_EXPLAIN("Script Debugger failed to connect, but being used anyway.");
		ERR_FAIL();
	}

	packet_peer_stream->put_var("debug_enter");
	packet_peer_stream->put_var(2);
	packet_peer_stream->put_var(p_can_continue);
	packet_peer_stream->put_var(p_script->debug_get_error());


	while(true) {

		_get_output();

		if (packet_peer_stream->get_available_packet_count()>0) {

			Variant var;
			Error err = packet_peer_stream->get_var(var);
			ERR_CONTINUE( err != OK);
			ERR_CONTINUE( var.get_type()!=Variant::ARRAY );

			Array cmd = var;

			ERR_CONTINUE( cmd.size()==0);
			ERR_CONTINUE( cmd[0].get_type()!=Variant::STRING );

			String command = cmd[0];



			if (command=="get_stack_dump") {

				packet_peer_stream->put_var("stack_dump");
				int slc = p_script->debug_get_stack_level_count();
				packet_peer_stream->put_var( slc );

				for(int i=0;i<slc;i++) {

					Dictionary d;
					d["file"]=p_script->debug_get_stack_level_source(i);
					d["line"]=p_script->debug_get_stack_level_line(i);
					d["function"]=p_script->debug_get_stack_level_function(i);
					//d["id"]=p_script->debug_get_stack_level_
					d["id"]=0;

					packet_peer_stream->put_var( d );
				}

			} else if (command=="get_stack_frame_vars") {

				cmd.remove(0);
				ERR_CONTINUE( cmd.size()!=1 );
				int lv = cmd[0];

				List<String> members;
				List<Variant> member_vals;

				p_script->debug_get_stack_level_members(lv,&members,&member_vals);



				ERR_CONTINUE( members.size() !=member_vals.size() );

				List<String> locals;
				List<Variant> local_vals;

				p_script->debug_get_stack_level_locals(lv,&locals,&local_vals);

				ERR_CONTINUE( locals.size() !=local_vals.size() );

				packet_peer_stream->put_var("stack_frame_vars");
				packet_peer_stream->put_var(2+locals.size()*2+members.size()*2);

				{ //members
					packet_peer_stream->put_var(members.size());

					List<String>::Element *E=members.front();
					List<Variant>::Element *F=member_vals.front();

					while(E) {

						if (F->get().get_type()==Variant::OBJECT) {
							packet_peer_stream->put_var("*"+E->get());
							packet_peer_stream->put_var(safe_get_instance_id(F->get()));
						} else {
							packet_peer_stream->put_var(E->get());
							packet_peer_stream->put_var(F->get());
						}

						E=E->next();
						F=F->next();
					}

				}


				{ //locals
					packet_peer_stream->put_var(locals.size());

					List<String>::Element *E=locals.front();
					List<Variant>::Element *F=local_vals.front();

					while(E) {

						if (F->get().get_type()==Variant::OBJECT) {
							packet_peer_stream->put_var("*"+E->get());
							packet_peer_stream->put_var(safe_get_instance_id(F->get()));
						} else {
							packet_peer_stream->put_var(E->get());
							packet_peer_stream->put_var(F->get());
						}

						E=E->next();
						F=F->next();
					}

				}



			} else if (command=="step") {

				set_depth(-1);
				set_lines_left(1);
				break;
			} else if (command=="next") {

				set_depth(0);
				set_lines_left(1);
				break;

			} else if (command=="continue") {

				set_depth(-1);
				set_lines_left(-1);
				break;
			} else if (command=="break") {
				ERR_PRINT("Got break when already broke!");
				break;
			} else if (command=="request_scene_tree") {

				if (request_scene_tree)
					request_scene_tree(request_scene_tree_ud);

			} else if (command=="request_video_mem") {

				_send_video_memory();
			} else if (command=="breakpoint") {

				bool set = cmd[3];
				if (set)
					insert_breakpoint(cmd[2],cmd[1]);
				else
					remove_breakpoint(cmd[2],cmd[1]);

			} else {
				_parse_live_edit(cmd);
			}



		} else {
			OS::get_singleton()->delay_usec(10000);
		}

	}

	packet_peer_stream->put_var("debug_exit");
	packet_peer_stream->put_var(0);

}