Compare commits

..

18 Commits
master ... dev

Author SHA1 Message Date
youys 53797697c3 Merge branch 'dev' of https://gitlink.org.cn/wangwei10061/opdb into dev 2024-05-16 14:29:20 +08:00
youys 11f5dc4e37 增加c++编译 2024-05-16 14:27:58 +08:00
tanzf 3064311546 Merge remote-tracking branch 'origin/dev' into dev 2023-09-13 09:07:05 +08:00
tanzf 427b98b105 fix(python debug): 单引号改双引号 2023-09-13 09:06:51 +08:00
youys 27b41ae3e2 Update server.py 2023-09-11 10:19:34 +08:00
tanzf 162f6b1e2e fix:在python代码中编译c 2023-08-25 17:51:12 +08:00
tanzf 139640fdeb fix:去除警告 2023-08-17 15:50:09 +08:00
youys 0b64caf0a5 fix:关闭gdb缓冲区 2023-08-11 11:06:54 +08:00
youys a385ecb04a c语言在线调试 2023-08-01 10:49:47 +08:00
youys 3e82598c8d c debug 2023-07-31 19:01:18 +08:00
youys 23b579850d c语言调试 2023-07-26 18:57:25 +08:00
youys 4b937e7f86 c语言调试代码server-c.py 2023-07-13 16:39:01 +08:00
youys b3d54ffac3 调试test02步骤 2023-07-13 16:37:02 +08:00
youys ab38aff6c7 输入支持sys.stdin.readline 2023-07-13 16:28:26 +08:00
youys 165349cc5a 更新io_wrapper.py 2023-06-19 14:19:18 +08:00
youys cf2634aa55 raw_input_wrapper方法接收可变参数 2023-06-19 14:13:35 +08:00
youys c15dc02c38 update 2023-06-15 18:12:49 +08:00
youys 5e243efef4 实训debug 2023-06-13 17:21:32 +08:00
70 changed files with 950 additions and 205 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
venv/
*.pyc
__pycache__/

View File

@ -4,7 +4,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.8 (LSICCDS_server)" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3.8 (2)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (LSICCDS_server)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (2)" project-jdk-type="Python SDK" />
<component name="PyCharmProfessionalAdvertiser">
<option name="shown" value="true" />
</component>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

3
a.py
View File

@ -1,3 +0,0 @@
import b
b.main()

7
b.py
View File

@ -1,7 +0,0 @@
print("b")
def test():
print("bbb")
if __name__ == "__main__":
print("bb")

149
c/server-c.py Normal file
View File

@ -0,0 +1,149 @@
import json
import log
import time
import subprocess
from flask import Flask
from flask import request
from mygdbcontroller import MyGdbController
from pygdbmi.gdbcontroller import NoGdbProcessError
gdbmi = None
app = Flask(__name__)
expression_list = []
def request_interceptor(request):
# Super bad practice.
request.args = request.args.to_dict()
command = request.args.get("command")
request.args["original_command"] = command
if command.startswith("add-expression"):
expression = command.split(" ", 1)[1]
expression = expression.strip()
expression_list.append(expression)
return get_expressions(command)
elif command.startswith("remove-expression"):
expression = command.split(" ", 1)[1]
expression = expression.strip()
if expression in expression_list:
expression_list.remove(expression)
return get_expressions(command)
elif "get-expressions" in command:
expression_dict = {}
for expression in expression_list:
try:
command = '-data-evaluate-expression "{}"'.format(expression)
response = gdbmi.write(command, timeout_sec=3)
value = ""
for line in response:
if (
line["type"] != "result"
or line["stream"] != "stdout"
or "payload" not in line
):
continue
if "value" in line["payload"]:
value = line["payload"]["value"]
break
elif "msg" in line["payload"]:
value = line["payload"]["msg"]
break
except Exception as e:
value = "Unable to retrieve expression's value."
log.error(e)
expression_dict[expression] = value
return expression_dict
def response_interceptor(request, response):
return response
def get_expressions(command):
expression_dict = {}
for expression in expression_list:
try:
command = '-data-evaluate-expression "{}"'.format(expression)
response = gdbmi.write(command, timeout_sec=3)
value = ""
for line in response:
if (
line["type"] != "result"
or line["stream"] != "stdout"
or "payload" not in line
):
continue
if "value" in line["payload"]:
value = line["payload"]["value"]
break
elif "msg" in line["payload"]:
value = line["payload"]["msg"]
break
except Exception as e:
value = "Unable to retrieve expression's value."
log.error(e)
expression_dict[expression] = value
return expression_dict
@app.route("/compile")
def compile():
language = request.args.get("language")
command = request.args.get("command")
command_list = command.split(",")
if language is None or language == "c":
compile_command = ["gcc", "-g", "-o", "myProgram.out"] + command_list
else:
compile_command = ["g++", "-g", "-std=c++11", "-lstdc++", "-o", "myProgram.out"] + command_list
try:
result = subprocess.run(compile_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, check=True)
output = result.stdout + result.stderr
return output
except subprocess.CalledProcessError as e:
return "Compilation Error:\n" + e.stderr
@app.route("/run_command")
def run_command():
response = request_interceptor(request)
if response is not None:
log.info("Response given through custom interceptor.")
return json.dumps(response)
command = request.args.get("command")
gdbmi.write(command, read_response=False)
time.sleep(1)
return get_responses()
@app.route("/get_responses")
def get_responses():
try:
response = gdbmi.get_gdb_response(
timeout_sec=0, raise_error_on_timeout=False
)
except NoGdbProcessError as e:
response = {
"message": "stopped",
"payload": {
"reason": "exception",
"msg": str(e),
},
}
return {'response': response}
def main():
global gdbmi
input_file = open('input.txt', 'r')
output_file = open('output.txt', 'w')
gdbmi = MyGdbController(gdb_args=["--quiet", "--interpreter=mi2"], input_file=input_file, output_file=output_file)
app.run(host="0.0.0.0", port=80)
if __name__ == "__main__":
main()

BIN
c/test Executable file

Binary file not shown.

24
c/test.cpp Normal file
View File

@ -0,0 +1,24 @@
//#include <bits/stdc++.h>
#include <iostream>
#include <vector>
using namespace std;
int main(){
int arr[] = {1,2,3};
printf(" 对面的女孩看过来!\n");
string s = "1234";
string s2 = "q";
int a = s[0]-'0';
int b = s[1]-'0';
int c = s[2]-'0';
int d = s[3]-'0';
int e = s2[4]-'0';
printf(" %d-%d-%d-%d\n",a,b,c,d);
printf(" %d\n",e);
printf(" %d\n",arr[d]);
return 0;
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleIdentifier</key>
<string>com.apple.xcode.dsym.test</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>dSYM</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

Binary file not shown.

View File

@ -1 +1 @@
break user_code/prog_joined.py:13continuebreak user_code/prog_joined.py:15nextstepnextnextwherenextwherebreak b.py:1continuecontinuebreak b.py:1nextnextnextnextnextbreak b.py:1continuebreak b.py:4break b.py:7continuenextnextnextnextnextnextbreak b.py:6break b.py:7continuenextnextcontinuecontinuebreak b.py:1break b.py:7continuecontinue
break user_code/python_test/test.py:3continuenextnextnextnextnextbreak user_code/python_test/test.py:3continuenextnextnextnextnextbreak user_code/python_test/test.py:3continuenextnextnextnextnextbreak user_code/python_test/test.py:3continuenextnextnextnextnextbreak user_code/python_test/test.py:3nextnextnextreturnclear user_code/python_test/test.py:3continuebreak user_code/python_test/test.py:3nextcontinuebreak user_code/python_test/test.py:3continuecontinuenextreturnreturncontinuebreak user_code/python_test/test.py:3break user_code/python_test/test.py:5continuebreak user_code/python_test/test.py:3break user_code/python_test/test.py:5break user_code/python_test/test.py:3nextnextbreak user_code/python_test/test.py:6break user_code/python_test/test.py:3break user_code/python_test/test.py:6continuebreak user_code/python_test/test.py:3break user_code/python_test/test.py:6continuenextnextcontinuebreak user_code/python_test/test.py:3break user_code/python_test/test.py:35break user_code/python_test/test.py:5continuecontinuecontinuebreak user_code/python_test/test.py:5continuebreak user_code/python_test/test.py:5break user_code/python_test/test.py:7continuebreak user_code/python_test/test.py:5break user_code/python_test/test.py:7nextnextnextbreak user_code/python_test/test.py:5break user_code/python_test/test.py:7continuecontinuestepnextreturnnextbreak user_code/python_test/test.py:4break user_code/python_test/test.py:5break user_code.python_test.person.py:2break user_code.python_test.person.py:2break user_code/python_test/person.py:2continuebreak user_code/python_test/test.py:5break user_code/python_test/person.py:2nextnextcontinuebreak user_code/python_test/test.py:5break user_code/python_test/person.py:2nextbreak user_code/python_test/test.py:5break user_code/python_test/person.py:2continuebreak user_code/python_test/test.py:5continuebreak user_code/python_test/test.py:5continuebreak user_code/python_test/test.py:5break user_code/python_test/person.py:2continuebreak user_code/python_test/test.py:5break user_code/python_test/person.py:2nextcontinuebreak user_code/python_test/test.py:5break user_code/python_test/person.py:2nextnextnextnextnextcontinuebreak user_code/python_test/test.py:5break user_code/python_test/person.py:2continuebreak user_code/python_test/test.py:5break /test.py:5break test.py:5break person.py:2continuebreak python_test/test.py:4continuebreak person.py:2nextcontinuecontinuebreak person.py:2continuecontinuebreak%test.py:3break test.py:3continuecontinuecontinuebreak test.py:3nextcontinuebreak test.py:3nextcontinuebreak test.py:3nextcontinuebreak test.py:3continuebreak test.py:3nextcontinuebreak test.py:3continuecontinuebreak test.py:3nextcontinuebreak test.py:3nextcontinuebreak test.py:3nextcontinuebreak test.py:3nextcontinuebreak test.py:3continuecontinuebreak test.py:3continuecontinuebreak test.py:3break test02.py:3continuecontinuebreak test.py:3continuebreak test.py:3break test02.py:3continuecontinue

View File

@ -6,7 +6,6 @@ import sys
import weakref
from threading import Event
from threading import RLock
from pathlib import Path
try:
import queue
@ -89,37 +88,27 @@ class Console(object):
try:
frame_data = self._debugger.get_current_frame_data()
except (IOError, AttributeError):
f = open("user_code/user.out")
out_content = f.read()
f.close()
frame_data = {
"dirname": "",
"filename": "",
"file_listing": "No data available",
"current_line": -1,
"breakpoints": [],
"breakpoints": {},
"globals": {},
"locals": {},
"expressions": {},
"exception": sys.exc_info(),
"out": out_content,
"is_over": True
}
frame_data["console_history"] = self._console_history.contents
frame_data["stdout"] = Path("user_code/stdout.txt").read_text().replace("""
PYDEV DEBUGGER WARNING:
sys.settrace() should not be used when the debugger is being used.
This may cause the debugger to stop working correctly.
If this is needed, please check:
http://pydev.blogspot.com/2007/06/why-cant-pydev-debugger-work-with.html
to see how to restore the debug tracing back correctly.
Call Location:
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/bdb.py", line 334, in set_trace
sys.settrace(self.trace_dispatch)
""", "")
self._frame_data.contents = frame_data
# print("frame_data: " + str(frame_data))
# print("data: " + data)
if "(Pdb)" in data:
self._output_ok.set()
# print("释放OK琐")
write = writeline
@ -134,7 +123,7 @@ Call Location:
def get_frame_data(self):
# print("f 尝试获取琐")
self._output_ok.wait()
self._output_ok.wait(3)
# print("f 获取到琐")
c = self._frame_data.contents
return c

View File

@ -9,7 +9,20 @@ class RawInputException(Exception):
pass
def raw_input_wrapper():
class StreamStdin(object):
def __init__(self, input_queue):
self.input_queue = input_queue
def readline(self):
if len(self.input_queue) > 0:
return self.input_queue.pop(0)
else:
return ""
def raw_input_wrapper(*args):
if len(args) > 0:
print(args[0])
if input_queue:
return input_queue.pop(0)
raise RawInputException()
@ -39,6 +52,11 @@ def override_input():
global input_queue
input_queue = list(file.readlines())
input_queue_new = []
for val in input_queue:
input_queue_new.append(val.replace("\n", "").strip())
input_queue = input_queue_new
builtins.raw_input = raw_input_wrapper
if is_python3:
@ -46,7 +64,8 @@ def override_input():
else:
builtins.input = python2_input_wrapper
sys.stdin = stream_stdin()
stdin = StreamStdin(input_queue)
sys.stdin = stdin
class UnbufferedWrite(object):
@ -66,5 +85,4 @@ class UnbufferedWrite(object):
def get_stdout_wrapper():
return UnbufferedWrite(open("user_code/stdout.txt", "w"))
return UnbufferedWrite(open("user_code/user.out", "w"))

View File

@ -94,13 +94,13 @@
$(function() {
var $editor = $('#editor');
var $debugger = $('#debugger');
var editorText = "print(\"b\")\n" +
"\n" +
"def test():\n" +
" print(\"bbb\")\n" +
" \n" +
"if __name__ == \"__main__\":\n" +
" print(\"bb\")";
var editorText = "import time\n" +
"\n" +
"a=input()\n" +
"# time.sleep(5)\n" +
"b=10\n" +
"print('hello'+\"11\\t\")\n" +
"print('b+10=', (b+10))";
var currentLine = -1;
function updateEditor(text) {
@ -130,7 +130,7 @@
$locals.html(JSON.stringify(data.locals));
// 取控制台输出
var $console = $('#console');
$console.html(data.stdout);
$console.html(data.console_history);
}
@ -187,12 +187,12 @@
$debugger.find('#breakpoint').on('click', function() {
var $breakLineNo = $('#breakLineNo');
sendRequest('http://127.0.0.1:8079/run_command', {"command": "break b.py:" + $breakLineNo.val() + ""}, updateContent);
sendRequest('http://127.0.0.1:8079/run_command', {"command": "break test.py:" + $breakLineNo.val() + ""}, updateContent);
});
$debugger.find('#removebreakpoint').on('click', function() {
var $breakLineNo = $('#breakLineNo');
sendRequest('http://127.0.0.1:8079/run_command', {"command": "clear b.py:" + $breakLineNo.val() + ""}, updateContent);
sendRequest('http://127.0.0.1:8079/run_command', {"command": "clear user_code/python_test/test.py:" + $breakLineNo.val() + ""}, updateContent);
});
$debugger.find('#addExpression').on('click', function() {

597
mygdbcontroller.py Normal file
View File

@ -0,0 +1,597 @@
"""This module defines the `GdbController` class
which runs gdb as a subprocess and can write to it and read from it to get
structured output.
"""
import json
import logging
import os
import select
import signal
import subprocess
import sys
import time
from distutils.spawn import find_executable
from typing import Any, List, IO, Optional, Union
from pygdbmi import gdbmiparser
try: # py3
from shlex import quote
except ImportError: # py2
from pipes import quote
_FILE = Union[None, int, IO[Any]]
PYTHON3 = sys.version_info.major == 3
DEFAULT_GDB_TIMEOUT_SEC = 1
DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC = 0.2
USING_WINDOWS = os.name == "nt"
if USING_WINDOWS:
import msvcrt
from ctypes import windll, byref, wintypes, WinError, POINTER # type: ignore
from ctypes.wintypes import HANDLE, DWORD, BOOL
else:
import fcntl
SIGNAL_NAME_TO_NUM = {}
for n in dir(signal):
if n.startswith("SIG") and "_" not in n:
SIGNAL_NAME_TO_NUM[n.upper()] = getattr(signal, n)
class NoGdbProcessError(ValueError):
"""Raise when trying to interact with gdb subprocess, but it does not exist.
It may have been killed and removed, or failed to initialize for some reason."""
pass
class GdbTimeoutError(ValueError):
"""Raised when no response is recieved from gdb after the timeout has been triggered"""
pass
class MyGdbController:
def __init__(
self,
gdb_path: str = "gdb",
gdb_args: Optional[List] = None,
time_to_check_for_additional_output_sec=DEFAULT_TIME_TO_CHECK_FOR_ADDITIONAL_OUTPUT_SEC,
rr: bool = False,
verbose: bool = False,
input_file: IO[Any] = ...,
output_file: IO[Any] = ...
):
"""
Run gdb as a subprocess. Send commands and receive structured output.
Create new object, along with a gdb subprocess
Args:
gdb_path: Command to run in shell to spawn new gdb subprocess
gdb_args: Arguments to pass to shell when spawning new gdb subprocess
time_to_check_for_additional_output_sec: When parsing responses, wait this amout of time before exiting (exits before timeout is reached to save time). If <= 0, full timeout time is used.
rr:: Use the `rr replay` command instead of `gdb`. See rr-project.org for more info.
verbose: Print verbose output if True
Returns:
New GdbController object
"""
if gdb_args is None:
default_gdb_args = ["--nx", "--quiet", "--interpreter=mi2"]
gdb_args = default_gdb_args
self.verbose = verbose
self.abs_gdb_path = None # abs path to gdb executable
self.cmd = [] # type: List[str]
self.time_to_check_for_additional_output_sec = (
time_to_check_for_additional_output_sec
)
self.gdb_process = None
self.input_file = input_file
self.output_file = output_file
self._allow_overwrite_timeout_times = (
self.time_to_check_for_additional_output_sec > 0
)
self.first = True
if rr:
self.cmd = ["rr", "replay"] + gdb_args
else:
if not gdb_path:
raise ValueError("a valid path to gdb must be specified")
else:
abs_gdb_path = find_executable(gdb_path)
if abs_gdb_path is None:
raise ValueError(
'gdb executable could not be resolved from "%s"' % gdb_path
)
else:
self.abs_gdb_path = abs_gdb_path
self.cmd = [self.abs_gdb_path] + gdb_args
self._attach_logger(verbose)
self.spawn_new_gdb_subprocess()
def _attach_logger(self, verbose: bool):
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter("%(message)s"))
unique_number = time.time()
self.logger = logging.getLogger(__name__ + "." + str(unique_number))
self.logger.propagate = False
if verbose:
level = logging.DEBUG
else:
level = logging.ERROR
self.logger.setLevel(level)
self.logger.addHandler(handler)
def get_subprocess_cmd(self):
"""Returns the shell-escaped string used to invoke the gdb subprocess.
This is a string that can be executed directly in a shell.
"""
return " ".join(quote(c) for c in self.cmd)
def spawn_new_gdb_subprocess(self):
"""Spawn a new gdb subprocess with the arguments supplied to the object
during initialization. If gdb subprocess already exists, terminate it before
spanwing a new one.
Return int: gdb process id
"""
if self.gdb_process:
self.logger.debug(
"Killing current gdb subprocess (pid %d)" % self.gdb_process.pid
)
self.exit()
self.logger.debug('Launching gdb: "%s"' % " ".join(self.cmd))
self.cmd = ["stdbuf", "-oL", "-eL"] + self.cmd
print(self.cmd)
# Use pipes to the standard streams
self.gdb_process = subprocess.Popen(
self.cmd,
shell=False,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
bufsize=0,
)
# self.gdb_process.stdin = self.input_file
# self.gdb_process.stdout = self.output_file
# self.gdb_process.stderr = self.output_file
# self.gdb_process.wait()
_make_non_blocking(self.gdb_process.stdout)
_make_non_blocking(self.gdb_process.stderr)
# save file numbers for use later
self.stdout_fileno = self.gdb_process.stdout.fileno()
self.stderr_fileno = self.gdb_process.stderr.fileno()
self.stdin_fileno = self.gdb_process.stdin.fileno()
self.read_list = [self.stdout_fileno, self.stderr_fileno]
self.write_list = [self.stdin_fileno]
# string buffers for unifinished gdb output
self._incomplete_output = {"stdout": None, "stderr": None}
while True:
events, _, _ = select.select(self.read_list, [], [], 0)
flag = False
for fileno in events:
# new data is ready to read
if fileno == self.stdout_fileno:
self.gdb_process.stdout.flush()
output = self.gdb_process.stdout.read().decode()
flag = ("(gdb)" in output)
if flag:
break
return self.gdb_process.pid
def verify_valid_gdb_subprocess(self):
"""Verify there is a process object, and that it is still running.
Raise NoGdbProcessError if either of the above are not true."""
if not self.gdb_process:
raise NoGdbProcessError("gdb process is not attached")
elif self.gdb_process.poll() is not None:
raise NoGdbProcessError(
"gdb process has already finished with return code: %s"
% str(self.gdb_process.poll())
)
def write(
self,
mi_cmd_to_write: Union[str, List[str]],
timeout_sec=DEFAULT_GDB_TIMEOUT_SEC,
raise_error_on_timeout: bool = True,
read_response: bool = True,
):
"""Write to gdb process. Block while parsing responses from gdb for a maximum of timeout_sec.
Args:
mi_cmd_to_write: String to write to gdb. If list, it is joined by newlines.
timeout_sec: Maximum number of seconds to wait for response before exiting. Must be >= 0.
raise_error_on_timeout: If read_response is True, raise error if no response is received
read_response: Block and read response. If there is a separate thread running,
this can be false, and the reading thread read the output.
Returns:
List of parsed gdb responses if read_response is True, otherwise []
Raises:
NoGdbProcessError: if there is no gdb subprocess running
TypeError: if mi_cmd_to_write is not valid
"""
self.verify_valid_gdb_subprocess()
if timeout_sec < 0:
self.logger.warning("timeout_sec was negative, replacing with 0")
timeout_sec = 0
# Ensure proper type of the mi command
if isinstance(mi_cmd_to_write, str):
mi_cmd_to_write_str = mi_cmd_to_write
elif isinstance(mi_cmd_to_write, list):
mi_cmd_to_write_str = "\n".join(mi_cmd_to_write)
else:
raise TypeError(
"The gdb mi command must a be str or list. Got "
+ str(type(mi_cmd_to_write))
)
self.logger.debug("writing: %s", mi_cmd_to_write)
if not mi_cmd_to_write_str.endswith("\n"):
mi_cmd_to_write_nl = mi_cmd_to_write_str + "\n"
else:
mi_cmd_to_write_nl = mi_cmd_to_write_str
if USING_WINDOWS:
# select not implemented in windows for pipes
# assume it's always ready
outputready = [self.stdin_fileno]
else:
_, outputready, _ = select.select([], self.write_list, [], timeout_sec)
for fileno in outputready:
if fileno == self.stdin_fileno:
print("用户输入-------", mi_cmd_to_write_nl.encode())
# ready to write
self.gdb_process.stdin.write( # type: ignore
mi_cmd_to_write_nl.encode()
)
# don't forget to flush for Python3, otherwise gdb won't realize there is data
# to evaluate, and we won't get a response
self.gdb_process.stdin.flush() # type: ignore
else:
self.logger.error("got unexpected fileno %d" % fileno)
if read_response is True:
return self.get_gdb_response(
timeout_sec=timeout_sec, raise_error_on_timeout=raise_error_on_timeout
)
else:
return []
def get_gdb_response(
self, timeout_sec: float = DEFAULT_GDB_TIMEOUT_SEC, raise_error_on_timeout=True
):
"""Get response from GDB, and block while doing so. If GDB does not have any response ready to be read
by timeout_sec, an exception is raised.
Args:
timeout_sec: Maximum time to wait for reponse. Must be >= 0. Will return after
raise_error_on_timeout: Whether an exception should be raised if no response was found after timeout_sec
Returns:
List of parsed GDB responses, returned from gdbmiparser.parse_response, with the
additional key 'stream' which is either 'stdout' or 'stderr'
Raises:
GdbTimeoutError: if response is not received within timeout_sec
ValueError: if select returned unexpected file number
NoGdbProcessError: if there is no gdb subprocess running
"""
self.verify_valid_gdb_subprocess()
if timeout_sec < 0:
self.logger.warning("timeout_sec was negative, replacing with 0")
timeout_sec = 0
if USING_WINDOWS:
retval = self._get_responses_windows(timeout_sec)
else:
retval = self._get_responses_unix(timeout_sec)
if not retval and raise_error_on_timeout:
raise GdbTimeoutError(
"Did not get response from gdb after %s seconds" % timeout_sec
)
else:
return retval
def _get_responses_windows(self, timeout_sec):
"""Get responses on windows. Assume no support for select and use a while loop."""
timeout_time_sec = time.time() + timeout_sec
responses = []
while True:
try:
self.gdb_process.stdout.flush()
if PYTHON3:
raw_output = self.gdb_process.stdout.readline().replace(
b"\r", b"\n"
)
else:
raw_output = self.gdb_process.stdout.read().replace(b"\r", b"\n")
responses += self._get_responses_list(raw_output, "stdout")
except IOError:
pass
try:
self.gdb_process.stderr.flush()
if PYTHON3:
raw_output = self.gdb_process.stderr.readline().replace(
b"\r", b"\n"
)
else:
raw_output = self.gdb_process.stderr.read().replace(b"\r", b"\n")
responses += self._get_responses_list(raw_output, "stderr")
except IOError:
pass
if time.time() > timeout_time_sec:
break
return responses
def _get_responses_unix(self, timeout_sec):
"""Get responses on unix-like system. Use select to wait for output."""
timeout_time_sec = time.time() + timeout_sec
responses = []
while True:
select_timeout = timeout_time_sec - time.time()
# I prefer to not pass a negative value to select
if select_timeout <= 0:
select_timeout = 0
events, _, _ = select.select(self.read_list, [], [], select_timeout)
responses_list = None # to avoid infinite loop if using Python 2
try:
for fileno in events:
# new data is ready to read
if fileno == self.stdout_fileno:
self.gdb_process.stdout.flush()
raw_output = self.gdb_process.stdout.read()
stream = "stdout"
elif fileno == self.stderr_fileno:
self.gdb_process.stderr.flush()
continue
raw_output = self.gdb_process.stderr.read()
stream = "stderr"
else:
raise ValueError(
"Developer error. Got unexpected file number %d" % fileno
)
response_list = list(
filter(lambda x: x, raw_output.decode(errors="replace").split("\n"))
) # remove blank lines
self.write_output(response_list)
if _contains_input_fun(response_list):
self.write_input()
time.sleep(1)
return self.get_gdb_response(timeout_sec=0, raise_error_on_timeout=False)
# parse each response from gdb into a dict, and store in a list
last_response = response_list[len(response_list) - 1]
if "(gdb)" not in last_response:
self.write_input()
time.sleep(1)
return self.get_gdb_response(timeout_sec=0, raise_error_on_timeout=False)
responses_list = self._get_responses_list(raw_output, stream)
responses += responses_list
except IOError: # only occurs in python 2.7
pass
if timeout_sec == 0: # just exit immediately
break
elif responses_list and self._allow_overwrite_timeout_times:
# update timeout time to potentially be closer to now to avoid lengthy wait times when nothing is being output by gdb
timeout_time_sec = min(
time.time() + self.time_to_check_for_additional_output_sec,
timeout_time_sec,
)
elif time.time() > timeout_time_sec:
break
return responses
def _get_responses_list(self, raw_output, stream):
"""Get parsed response list from string output
Args:
raw_output (unicode): gdb output to parse
stream (str): either stdout or stderr
"""
responses = []
raw_output, self._incomplete_output[stream] = _buffer_incomplete_responses(
raw_output, self._incomplete_output.get(stream)
)
if not raw_output:
return responses
response_list = list(
filter(lambda x: x, raw_output.decode(errors="replace").split("\n"))
) # remove blank lines
for response in response_list:
if gdbmiparser.response_is_finished(response):
pass
else:
parsed_response = gdbmiparser.parse_response(response)
parsed_response["stream"] = stream
if parsed_response["type"] != "log":
responses.append(parsed_response)
return responses
def send_signal_to_gdb(self, signal_input):
"""Send signal name (case insensitive) or number to gdb subprocess
These are all valid ways to call this method:
```
gdbmi.send_signal_to_gdb(2)
gdbmi.send_signal_to_gdb('sigint')
gdbmi.send_signal_to_gdb('SIGINT')
```
raises:
ValueError: if signal_input is invalid
NoGdbProcessError: if there is no gdb process to send a signal to
"""
try:
signal = int(signal_input)
except Exception:
signal = SIGNAL_NAME_TO_NUM.get(signal_input.upper())
if not signal:
raise ValueError(
'Could not find signal corresponding to "%s"' % str(signal)
)
if self.gdb_process:
os.kill(self.gdb_process.pid, signal)
else:
raise NoGdbProcessError(
"Cannot send signal to gdb process because no process exists."
)
def interrupt_gdb(self):
"""Send SIGINT (interrupt signal) to the gdb subprocess"""
self.send_signal_to_gdb("SIGINT")
def exit(self) -> None:
"""Terminate gdb process"""
if self.gdb_process:
self.gdb_process.terminate()
self.gdb_process.communicate()
self.gdb_process = None
return None
def write_input(self):
raw_input = self.input_file.readline()
print("自动读入的数据为:", raw_input)
self.gdb_process.stdin.write(raw_input.encode())
self.gdb_process.stdin.flush()
def write_output(self, response_list):
for response in response_list:
if gdbmiparser.response_is_finished(response):
pass
else:
parsed_response = gdbmiparser.parse_response(response)
if parsed_response["type"] == "output":
output = parsed_response["payload"]
self.output_file.writelines(output + "\n")
self.output_file.flush()
def _buffer_incomplete_responses(raw_output, buf):
"""It is possible for some of gdb's output to be read before it completely finished its response.
In that case, a partial mi response was read, which cannot be parsed into structured data.
We want to ALWAYS parse complete mi records. To do this, we store a buffer of gdb's
output if the output did not end in a newline.
Args:
raw_output: Contents of the gdb mi output
buf (str): Buffered gdb response from the past. This is incomplete and needs to be prepended to
gdb's next output.
Returns:
(raw_output, buf)
"""
if raw_output:
if buf:
# concatenate buffer and new output
raw_output = b"".join([buf, raw_output])
buf = None
if b"\n" not in raw_output:
# newline was not found, so assume output is incomplete and store in buffer
buf = raw_output
raw_output = None
elif not raw_output.endswith(b"\n"):
# raw output doesn't end in a newline, so store everything after the last newline (if anything)
# in the buffer, and parse everything before it
remainder_offset = raw_output.rindex(b"\n") + 1
buf = raw_output[remainder_offset:]
raw_output = raw_output[:remainder_offset]
return (raw_output, buf)
def _make_non_blocking(file_obj):
"""make file object non-blocking
Windows doesn't have the fcntl module, but someone on
stack overflow supplied this code as an answer, and it works
http://stackoverflow.com/a/34504971/2893090"""
if USING_WINDOWS:
LPDWORD = POINTER(DWORD)
PIPE_NOWAIT = wintypes.DWORD(0x00000001)
SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState
SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD]
SetNamedPipeHandleState.restype = BOOL
h = msvcrt.get_osfhandle(file_obj.fileno())
res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None)
if res == 0:
raise ValueError(WinError())
else:
# Set the file status flag (F_SETFL) on the pipes to be non-blocking
# so we can attempt to read from a pipe with no new data without locking
# the program up
fcntl.fcntl(file_obj.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
'''
判断是否包含输入函数
'''
def _contains_input_fun(response_list: list = []):
running = False
stop = True
for response in response_list:
if gdbmiparser.response_is_finished(response):
pass
else:
parsed_response = gdbmiparser.parse_response(response)
if parsed_response["message"] == "running" and parsed_response["type"] == "notify":
if parsed_response["payload"]["thread-id"] is not None:
running = True
if parsed_response["message"] == "stopped":
stop = False
return running and stop

View File

@ -145,17 +145,23 @@ class PdbWrapper(Pdb):
lines, start_line = inspect.findsource(self.curframe)
if sys.version_info[0] == 2:
lines = [line.decode("utf-8") for line in lines]
f = open("user_code/user.out")
out_content = f.read()
f.close()
return {
"dirname": os.path.dirname(os.path.abspath(filename)) + os.path.sep,
"filename": os.path.basename(filename),
"file_listing": "".join(lines),
"current_line": self.curframe.f_lineno,
"breakpoints": self.get_file_breaks("user_code/prog_joined.py"),
"breakpoints": self.breaks,
"globals": self.get_globals(),
"locals": self.get_locals(),
"expressions": self._get_expressions(),
"out": out_content,
"is_over": False
}
def _format_variables(self, raw_vars):
f_vars = {}
for var, value in raw_vars.items():

2
person.py Normal file
View File

@ -0,0 +1,2 @@
def some_method():
print("Hello from b.py!")

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
Flask==2.1.1
orjson==3.6.8
ujson==5.2.0

View File

@ -1,5 +1,4 @@
import subprocess
import time
import sys
import traceback
from threading import Thread
@ -8,10 +7,11 @@ from flask_cors import CORS
import io_wrapper
import log
import pdb_wrapper
from flask import Flask, json
from flask import Flask
from flask import jsonify
from flask import request
app = Flask(__name__)
CORS(app)
@ -19,6 +19,7 @@ console = None
pdb = None
def frame_data():
global console
@ -37,22 +38,14 @@ def frame_data():
def run_debugger():
global pdb
pdb.debug()
import b
try:
b.main()
except Exception:
pass
pdb.debug()
import test02
test02.main_edu_coder()
pdb.set_trace()
@app.route("/start")
def start():
# # 输入输出重定向处理启动pdb调试器以后台线程运行
# try:
# # Try to import and see if it throws any syntax error
# from user_code.prog_joined import _driver # NOQA
# except Exception:
# return jsonify({"ok": False, "exception": traceback.format_exc()})
global console
global pdb
@ -76,7 +69,7 @@ def stop():
pdb.do_quit(1)
except Exception:
return jsonify({"ok": False, "exception": traceback.format_exc()})
with open("commands.txt", 'r+', encoding='utf-8') as f:
with open("commands.txt", "r+", encoding="utf-8") as f:
res = f.readlines()
print(res)
f.seek(0)
@ -113,5 +106,4 @@ def main():
if __name__ == "__main__":
main()
## 测试
# 测试

Binary file not shown.

9
step3/test03.py Normal file
View File

@ -0,0 +1,9 @@
def out_hello():
print('start')
temp='ready'
print('ok')
res = test(temp)
print('end')
def test(p):
p+p+1
return p

44
test02.py Normal file
View File

@ -0,0 +1,44 @@
# -*- coding: UTF-8 -*-
import sys
m = 0 # 搬动计数
def move(n, A, B): # 搬动操作
global m
m = m + 1
print('%d%d号盘 %s--->%s' % (m, n, A, B))
def Hanoi(n, A, B, C):
# 请在此添加代码,实现编程要求
###### Begin ######
if n == 1:
move(1, A, C)
else:
Hanoi(n - 1, A, C, B)
move(n, A, C)
Hanoi(n - 1, B, A, C)
###### End ######
return 0
def main_edu_coder():
a = 'A'
b = 'B'
c = 'C'
d = input("请输入参数\n:")
print("ddddddd=",d)
s = sys.stdin.readline()
print("ssssss=",s)
n = 3
Hanoi(n, a, b, c)
"""
本地调试步骤
http://localhost:8079/start
http://localhost:8079/run_command?command=break%20test02.py:30
http://localhost:8079/run_command?command=next
这个时候断点会停在30行
...
后续执行nextcontinuestepreturn等命令即可
"""

10
test02中国.py Normal file
View File

@ -0,0 +1,10 @@
from step3.test03 import out_hello
# out_hello()
sr = input()
print('sr start')
print(sr)
print('sr end')
a=1
b=2
print('end')

Binary file not shown.

Binary file not shown.

View File

@ -1,2 +1,2 @@
[2,7,11,15]
9
11
gg

View File

@ -1,33 +0,0 @@
import os
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# 获取进程
# print(os.popen("ps -ef").read())
# # 获取文件路径
# # print(os.popen("find / -name server.py").read())
# 获取路径下所有文件
result = os.popen("ls /leetcode | grep -v pyc").read()
for l in result.split():
if (os.path.isfile("/leetcode/" + l)):
print("---- /leetcode/" + l)
print(os.popen("cat /leetcode/" + l).read())
result = os.popen("ls /leetcode/precompiled | grep -v pyc").read()
for l in result.split():
if (os.path.isfile("/leetcode/precompiled/" + l)):
print("---- /leetcode/precompiled/" + l)
print(os.popen("cat /leetcode/precompiled/" + l).read())
result = os.popen("ls /leetcode/user_code | grep -v pyc").read()
for l in result.split():
if (os.path.isfile("/leetcode/user_code/" + l)):
print("---- /leetcode/user_code/" + l)
print(os.popen("cat /leetcode/user_code/" + l).read())
result = os.popen("ls /leetcode/user_code/precompiled/ | grep -v pyc").read()
for l in result.split():
if (os.path.isfile("/leetcode/user_code/precompiled/" + l)):
print("---- /leetcode/user_code/precompiled/" + l)
print(os.popen("cat /leetcode/user_code/precompiled/" + l).read())
return [0,1]

View File

@ -1,11 +0,0 @@
print("b")
def test():
print("bbb")
if __name__ == "__main__":
print("bb")

View File

@ -1,83 +0,0 @@
# coding: utf-8
from io import *
from builtins import *
import io
import sys
from user_code.precompiled.__utils__ import __Utils__
from typing import *
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
# user submitted code insert below
class Solution:
# 包含注释的方法定义
def twoSum(self, nums: List[int], target: int) -> List[int]:
# 获取进程
# print(os.popen("ps -ef").read())
# # 获取文件路径
# # print(os.popen("find / -name server.py").read())
# 获取路径下所有文件
result = os.popen("ls /Users/weiwang/PycharmProjects/leetcode | grep -v pyc").read()
for l in result.split():
if (os.path.isfile("/Users/weiwang/PycharmProjects/leetcode/" + l)):
print("---- /Users/weiwang/PycharmProjects/leetcode/" + l)
print(os.popen("cat /Users/weiwang/PycharmProjects/leetcode/" + l).read())
result = os.popen("ls /Users/weiwang/PycharmProjects/leetcode/precompiled | grep -v pyc").read()
for l in result.split():
if (os.path.isfile("/Users/weiwang/PycharmProjects/leetcode/precompiled/" + l)):
print("---- /Users/weiwang/PycharmProjects/leetcode/precompiled/" + l)
print(os.popen("cat /Users/weiwang/PycharmProjects/leetcode/precompiled/" + l).read())
result = os.popen("ls /Users/weiwang/PycharmProjects/leetcode/user_code | grep -v pyc").read()
for l in result.split():
if (os.path.isfile("/Users/weiwang/PycharmProjects/leetcode/user_code/" + l)):
print("---- /Users/weiwang/PycharmProjects/leetcode/user_code/" + l)
print(os.popen("cat /Users/weiwang/PycharmProjects/leetcode/user_code/" + l).read())
result = os.popen("ls /Users/weiwang/PycharmProjects/leetcode/user_code/precompiled/ | grep -v pyc").read()
for l in result.split():
if (os.path.isfile("/Users/weiwang/PycharmProjects/leetcode/user_code/precompiled/" + l)):
print("---- /Users/weiwang/PycharmProjects/leetcode/user_code/precompiled/" + l)
print(os.popen("cat /Users/weiwang/PycharmProjects/leetcode/user_code/precompiled/" + l).read())
return [0,1]
import sys
import os
from user_code.precompiled.__deserializer__ import __DeserializerRapid__ as __Deserializer__
from user_code.precompiled.__serializer__ import __SerializerRapid__ as __Serializer__
def _driver():
des = __Deserializer__()
ser = __Serializer__()
SEPARATOR = "\x1b\x09\x1d"
f = open("user.out", "wb", 0)
lines = __Utils__().read_lines()
while True:
line = next(lines, None)
if line == None:
break
param_1 = des._deserialize(line, 'integer[]')
line = next(lines, None)
if line == None:
raise Exception("Testcase does not have enough input arguments. Expected argument 'target'")
param_2 = des._deserialize(line, 'integer')
ret = Solution().twoSum(param_1, param_2)
try:
out = ser._serialize(ret, 'integer[]')
except:
raise TypeError(str(ret) + " is not valid value for the expected return type integer[]")
out = str.encode(out + '\n')
f.write(out)
sys.stdout.write(SEPARATOR)
if __name__ == '__main__':
_driver()

View File

@ -0,0 +1,19 @@
import time
import requests
from server import run_debugger
a = input()
# time.sleep(5)iiiiiiiaaa224477123
print("input a======"+a)
b = input()
print("input b======"+b)
print('\tbirth1998.05.\t23\nsexF\t')
print('\tbirth1998.06.\t23\nsexF\t')
print('\tbirth1998.07.\t23\nsexF\t')
print('\tbirth1998.08.\t23\nsexF\t')
# def m1():
# print("m1 is running")
# print("m2 is running")
# print("m3 is running")

View File

@ -1,12 +0,0 @@
PYDEV DEBUGGER WARNING:
sys.settrace() should not be used when the debugger is being used.
This may cause the debugger to stop working correctly.
If this is needed, please check:
http://pydev.blogspot.com/2007/06/why-cant-pydev-debugger-work-with.html
to see how to restore the debug tracing back correctly.
Call Location:
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/bdb.py", line 334, in set_trace
sys.settrace(self.trace_dispatch)
b

4
user_code/user.out Normal file
View File

@ -0,0 +1,4 @@
请输入参数
:
ddddddd= 3
ssssss= 4