parent
2e636b0a2e
commit
99217775cf
5 changed files with 139 additions and 8 deletions
36
README.md
36
README.md
|
|
@ -18,9 +18,9 @@ Now you need to change `target` to the application you want to debug relative
|
||||||
to the cwd. (Which is the workspace root by default)
|
to the cwd. (Which is the workspace root by default)
|
||||||
|
|
||||||
Before debugging you need to compile your application first, then you can run it using
|
Before debugging you need to compile your application first, then you can run it using
|
||||||
the green start button in the debug sidebar. Multithreading and removing breakpoints
|
the green start button in the debug sidebar. Multithreading and adding breakpoints
|
||||||
while running does not work at the time of writing. Also stopping the program sometimes
|
while running does not work at the time of writing. However you can add/remove breakpoints
|
||||||
does not work properly.
|
as you wish while the program is paused.
|
||||||
|
|
||||||
Extending variables is very limited as it does not support child values of variables.
|
Extending variables is very limited as it does not support child values of variables.
|
||||||
Watching expressions works partially but the result does not get properly parsed and
|
Watching expressions works partially but the result does not get properly parsed and
|
||||||
|
|
@ -34,4 +34,34 @@ in `stdout` for the application, `stderr` for errors and `log` for GDB log messa
|
||||||
Some exceptions/signals like segmentation faults will be catched and displayed but
|
Some exceptions/signals like segmentation faults will be catched and displayed but
|
||||||
it does not support for example most D exceptions.
|
it does not support for example most D exceptions.
|
||||||
|
|
||||||
|
### Attaching to existing processes
|
||||||
|
|
||||||
|
Attaching to existing processes currently only works by specifying the PID in the
|
||||||
|
`launch.json` and setting `request` to `"attach"`. You also need to specify the executable
|
||||||
|
path for GDB to find the debug symbols.
|
||||||
|
|
||||||
|
```
|
||||||
|
"request": "attach",
|
||||||
|
"executable": "./bin/executable",
|
||||||
|
"target": "4285"
|
||||||
|
```
|
||||||
|
|
||||||
|
This will attach to PID 4285 which should already run. GDB will pause the program on entering.
|
||||||
|
|
||||||
|
### Using `gdbserver` for remote debugging
|
||||||
|
|
||||||
|
You can also connect to a gdbserver instance and debug using that. For that modify the
|
||||||
|
`launch.json` by setting `request` to `"attach"` and `remote` to `true` and specifing the
|
||||||
|
port and optionally hostname in `target`.
|
||||||
|
|
||||||
|
```
|
||||||
|
"request": "attach",
|
||||||
|
"executable": "./bin/executable",
|
||||||
|
"target": ":2345",
|
||||||
|
"remote": true
|
||||||
|
```
|
||||||
|
|
||||||
|
This will attach to the running process managed by gdbserver on localhost:2345. You might
|
||||||
|
need to hit the start button in the debug bar at the top first to start the program.
|
||||||
|
|
||||||
## [Issues](https://github.com/WebFreak001/code-debug)
|
## [Issues](https://github.com/WebFreak001/code-debug)
|
||||||
24
package.json
24
package.json
|
|
@ -49,6 +49,30 @@
|
||||||
"description": "Path of project"
|
"description": "Path of project"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"attach": {
|
||||||
|
"required": [
|
||||||
|
"target"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"target": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "PID of running program or program name or connection arguments (eg :2345) if remote is true"
|
||||||
|
},
|
||||||
|
"remote": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "If true this will connect to a gdbserver instead of attaching to a PID",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"executable": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path of executable for debugging symbols"
|
||||||
|
},
|
||||||
|
"cwd": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path of project"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"initialConfigurations": [
|
"initialConfigurations": [
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,11 @@ export interface Stack {
|
||||||
|
|
||||||
export interface IBackend {
|
export interface IBackend {
|
||||||
load(cwd: string, target: string): Thenable<any>;
|
load(cwd: string, target: string): Thenable<any>;
|
||||||
|
attach(cwd: string, executable: string, target: string): Thenable<any>;
|
||||||
|
connect(cwd: string, executable: string, target: string): Thenable<any>;
|
||||||
start(): Thenable<boolean>;
|
start(): Thenable<boolean>;
|
||||||
stop();
|
stop();
|
||||||
|
detach();
|
||||||
interrupt(): Thenable<boolean>;
|
interrupt(): Thenable<boolean>;
|
||||||
continue(): Thenable<boolean>;
|
continue(): Thenable<boolean>;
|
||||||
next(): Thenable<boolean>;
|
next(): Thenable<boolean>;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ export class MI2 extends EventEmitter implements IBackend {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.process = ChildProcess.spawn(this.application, this.preargs.concat([target]), { cwd: cwd });
|
this.process = ChildProcess.spawn(this.application, this.preargs.concat([target]), { cwd: cwd });
|
||||||
this.process.stdout.on("data", this.stdout.bind(this));
|
this.process.stdout.on("data", this.stdout.bind(this));
|
||||||
|
this.process.stderr.on("data", this.stdout.bind(this));
|
||||||
this.process.on("exit", (() => { this.emit("quit"); }).bind(this));
|
this.process.on("exit", (() => { this.emit("quit"); }).bind(this));
|
||||||
Promise.all([
|
Promise.all([
|
||||||
this.sendCommand("environment-directory \"" + cwd + "\"")
|
this.sendCommand("environment-directory \"" + cwd + "\"")
|
||||||
|
|
@ -19,6 +20,40 @@ export class MI2 extends EventEmitter implements IBackend {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attach(cwd: string, executable: string, target: string): Thenable<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let args = [];
|
||||||
|
if (!executable)
|
||||||
|
executable = "-p";
|
||||||
|
args = args.concat([executable, target], this.preargs);
|
||||||
|
this.process = ChildProcess.spawn(this.application, args, { cwd: cwd });
|
||||||
|
this.process.stdout.on("data", this.stdout.bind(this));
|
||||||
|
this.process.stderr.on("data", this.stdout.bind(this));
|
||||||
|
this.process.on("exit", (() => { this.emit("quit"); }).bind(this));
|
||||||
|
Promise.all([
|
||||||
|
this.sendCommand("environment-directory \"" + cwd + "\"")
|
||||||
|
]).then(resolve, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(cwd: string, executable: string, target: string): Thenable<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let args = [];
|
||||||
|
if (executable)
|
||||||
|
args = args.concat([executable], this.preargs);
|
||||||
|
else
|
||||||
|
args = this.preargs;
|
||||||
|
this.process = ChildProcess.spawn(this.application, args, { cwd: cwd });
|
||||||
|
this.process.stdout.on("data", this.stdout.bind(this));
|
||||||
|
this.process.stderr.on("data", this.stdout.bind(this));
|
||||||
|
this.process.on("exit", (() => { this.emit("quit"); }).bind(this));
|
||||||
|
Promise.all([
|
||||||
|
this.sendCommand("environment-directory \"" + cwd + "\""),
|
||||||
|
this.sendCommand("target-select remote " + target)
|
||||||
|
]).then(resolve, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
stdout(data) {
|
stdout(data) {
|
||||||
this.buffer += data.toString("utf8");
|
this.buffer += data.toString("utf8");
|
||||||
let end = this.buffer.lastIndexOf('\n');
|
let end = this.buffer.lastIndexOf('\n');
|
||||||
|
|
@ -88,13 +123,24 @@ export class MI2 extends EventEmitter implements IBackend {
|
||||||
stop() {
|
stop() {
|
||||||
let proc = this.process;
|
let proc = this.process;
|
||||||
let to = setTimeout(() => {
|
let to = setTimeout(() => {
|
||||||
proc.kill();
|
process.kill(-proc.pid);
|
||||||
}, 2222);
|
}, 1000);
|
||||||
this.process.on("exit", function(code) {
|
this.process.on("exit", function(code) {
|
||||||
clearTimeout(to);
|
clearTimeout(to);
|
||||||
});
|
});
|
||||||
this.sendRaw("-gdb-exit");
|
this.sendRaw("-gdb-exit");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detach() {
|
||||||
|
let proc = this.process;
|
||||||
|
let to = setTimeout(() => {
|
||||||
|
process.kill(-proc.pid);
|
||||||
|
}, 1000);
|
||||||
|
this.process.on("exit", function(code) {
|
||||||
|
clearTimeout(to);
|
||||||
|
});
|
||||||
|
this.sendRaw("-target-detach");
|
||||||
|
}
|
||||||
|
|
||||||
interrupt(): Thenable<boolean> {
|
interrupt(): Thenable<boolean> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
|
||||||
34
src/gdb.ts
34
src/gdb.ts
|
|
@ -10,11 +10,19 @@ export interface LaunchRequestArguments {
|
||||||
target: string;
|
target: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AttachRequestArguments {
|
||||||
|
cwd: string;
|
||||||
|
target: string;
|
||||||
|
executable: string;
|
||||||
|
remote: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
class MI2DebugSession extends DebugSession {
|
class MI2DebugSession extends DebugSession {
|
||||||
private static THREAD_ID = 1;
|
private static THREAD_ID = 1;
|
||||||
private gdbDebugger: MI2;
|
private gdbDebugger: MI2;
|
||||||
private variableHandles = new Handles<any>();
|
private variableHandles = new Handles<any>();
|
||||||
private quit: boolean;
|
private quit: boolean;
|
||||||
|
private attached: boolean;
|
||||||
|
|
||||||
public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) {
|
public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) {
|
||||||
super(debuggerLinesStartAt1, isServer);
|
super(debuggerLinesStartAt1, isServer);
|
||||||
|
|
@ -43,9 +51,9 @@ class MI2DebugSession extends DebugSession {
|
||||||
private handleBreak(info: MINode) {
|
private handleBreak(info: MINode) {
|
||||||
this.sendEvent(new StoppedEvent("step", MI2DebugSession.THREAD_ID));
|
this.sendEvent(new StoppedEvent("step", MI2DebugSession.THREAD_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
private stopEvent(info: MINode) {
|
private stopEvent(info: MINode) {
|
||||||
if(!this.quit)
|
if (!this.quit)
|
||||||
this.sendEvent(new StoppedEvent("exception", MI2DebugSession.THREAD_ID));
|
this.sendEvent(new StoppedEvent("exception", MI2DebugSession.THREAD_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,6 +63,8 @@ class MI2DebugSession extends DebugSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void {
|
protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void {
|
||||||
|
this.quit = false;
|
||||||
|
this.attached = false;
|
||||||
this.gdbDebugger.load(args.cwd, args.target).then(() => {
|
this.gdbDebugger.load(args.cwd, args.target).then(() => {
|
||||||
this.gdbDebugger.start().then(() => {
|
this.gdbDebugger.start().then(() => {
|
||||||
this.sendResponse(response);
|
this.sendResponse(response);
|
||||||
|
|
@ -62,8 +72,26 @@ class MI2DebugSession extends DebugSession {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void {
|
||||||
|
this.quit = false;
|
||||||
|
this.attached = !args.remote;
|
||||||
|
if (args.remote) {
|
||||||
|
this.gdbDebugger.connect(args.cwd, args.executable, args.target).then(() => {
|
||||||
|
this.sendResponse(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.gdbDebugger.attach(args.cwd, args.executable, args.target).then(() => {
|
||||||
|
this.sendResponse(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected disconnectRequest(response: DebugProtocol.DisconnectResponse, args: DebugProtocol.DisconnectArguments): void {
|
protected disconnectRequest(response: DebugProtocol.DisconnectResponse, args: DebugProtocol.DisconnectArguments): void {
|
||||||
this.gdbDebugger.stop();
|
if (this.attached)
|
||||||
|
this.gdbDebugger.detach();
|
||||||
|
else
|
||||||
|
this.gdbDebugger.stop();
|
||||||
this.sendResponse(response);
|
this.sendResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue