Skip to content

Commit 9031824

Browse files
author
Your Name
committed
Add breakpoint index to pseudo registers
1 parent 9c39eb9 commit 9031824

7 files changed

Lines changed: 111 additions & 123 deletions

File tree

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "frida-cshell",
3-
"version": "1.6.8",
3+
"version": "1.6.9",
44
"description": "Frida's CShell",
55
"scripts": {
66
"prepare": "npm run build && npm run version && npm run package && npm run copy",

src/breakpoints/bps.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ export class Bps {
2020
);
2121

2222
if (overlapping) {
23-
throw new Error(
24-
`breakpoint overlaps existing breakpoint:\n\t`,
25-
);
23+
throw new Error(`breakpoint overlaps existing breakpoint:\n\t`);
2624
}
2725
}
2826

src/breakpoints/code.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export abstract class BpCode extends Bp {
5252
Regs.setThreadId(threadId);
5353
Regs.setContext(ctx);
5454
Regs.setReturnAddress(returnAddress);
55+
Regs.setBreakpointId(this.index);
5556
if (retVal !== null) Regs.setRetVal(retVal);
5657

5758
try {

src/breakpoints/memory.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export abstract class BpMemory extends Bp {
9393

9494
Regs.setAddress(details.address);
9595
Regs.setPc(details.from);
96+
Regs.setBreakpointId(this.index);
9697

9798
try {
9899
if (this.runConditions()) {

src/breakpoints/regs.ts

Lines changed: 96 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,75 @@
11
import { Var } from '../vars/var.js';
22

3+
enum PseudoRegNames {
4+
TID = 'tid',
5+
RA = 'ra',
6+
ADDRESS = 'addr',
7+
BP = 'bp',
8+
}
9+
10+
type PseudoRegs = {
11+
[K in PseudoRegNames]: Var | null;
12+
};
13+
314
export class Regs {
4-
private static readonly THREAD_ID_NAME: string = 'tid';
5-
private static readonly RETURN_ADDRESS_NAME: string = 'ra';
6-
private static readonly ADDR_NAME: string = 'addr';
715
private static readonly PC_NAME: string = 'pc';
8-
private static readonly RETVAL_NAME: string = 'ret';
9-
10-
private static threadId: ThreadId | null = null;
16+
private static readonly RETVAL_NAME = 'ret';
1117
private static ctx: CpuContext | null = null;
12-
private static returnAddress: NativePointer | null = null;
13-
private static addr: NativePointer | null = null;
14-
private static pc: NativePointer | null = null;
18+
private static pc: Var | null = null;
1519
private static retVal: InvocationReturnValue | null = null;
1620

21+
private static pseudoRegs: PseudoRegs = {
22+
[PseudoRegNames.TID]: null,
23+
[PseudoRegNames.RA]: null,
24+
[PseudoRegNames.ADDRESS]: null,
25+
[PseudoRegNames.BP]: null,
26+
};
27+
1728
private constructor() {}
1829

30+
public static setPc(pc: NativePointer) {
31+
this.pc = new Var(uint64(pc.toString()), Regs.PC_NAME);
32+
}
33+
34+
public static setThreadId(threadId: ThreadId) {
35+
this.pseudoRegs[PseudoRegNames.TID] = new Var(
36+
uint64(threadId),
37+
PseudoRegNames.TID,
38+
);
39+
}
40+
41+
public static setReturnAddress(returnAddress: NativePointer) {
42+
this.pseudoRegs[PseudoRegNames.RA] = new Var(
43+
uint64(returnAddress.toString()),
44+
PseudoRegNames.RA,
45+
);
46+
}
47+
48+
public static setAddress(addr: NativePointer) {
49+
this.pseudoRegs[PseudoRegNames.ADDRESS] = new Var(
50+
uint64(addr.toString()),
51+
PseudoRegNames.ADDRESS,
52+
);
53+
}
54+
55+
public static setRetVal(retVal: InvocationReturnValue) {
56+
this.retVal = retVal;
57+
}
58+
59+
public static setBreakpointId(breakpointId: number) {
60+
this.pseudoRegs[PseudoRegNames.BP] = new Var(
61+
uint64(breakpointId.toString()),
62+
`#${breakpointId}`,
63+
);
64+
}
65+
1966
public static get(name: string): Var {
20-
if (name === Regs.THREAD_ID_NAME) {
21-
if (this.threadId === null)
22-
throw new Error('thread ID not available outside of a breakpoint');
23-
return new Var(uint64(this.threadId), Regs.THREAD_ID_NAME);
24-
} else if (name === Regs.RETURN_ADDRESS_NAME) {
25-
if (this.returnAddress === null)
26-
throw new Error('return address not available outside of a breakpoint');
27-
return new Var(
28-
uint64(this.returnAddress.toString()),
29-
Regs.RETURN_ADDRESS_NAME,
30-
);
31-
} else if (name === Regs.ADDR_NAME) {
32-
if (this.addr === null)
33-
throw new Error('addr not available outside of a breakpoint');
34-
return new Var(uint64(this.addr.toString()), Regs.ADDR_NAME);
67+
if (name in this.pseudoRegs) {
68+
const key = name as PseudoRegNames;
69+
const v = this.pseudoRegs[key];
70+
if (v === null)
71+
throw new Error(`${name} not available outside of a breakpoint`);
72+
return v;
3573
} else if (name === Regs.RETVAL_NAME) {
3674
if (this.retVal === null)
3775
throw new Error(
@@ -43,7 +81,7 @@ export class Regs {
4381
if (this.pc === null) {
4482
throw new Error('pc not available outside of a breakpoint');
4583
}
46-
return new Var(uint64(this.pc.toString()), Regs.PC_NAME);
84+
return this.pc;
4785
} else {
4886
throw new Error('registers not available outside of a breakpoint');
4987
}
@@ -56,6 +94,31 @@ export class Regs {
5694
}
5795
}
5896

97+
public static set(name: string, value: Var) {
98+
if (name in this.pseudoRegs) {
99+
throw new Error(`${name} cannot be set`);
100+
} else if (name === Regs.RETVAL_NAME) {
101+
if (this.retVal === null)
102+
throw new Error(
103+
'return Value not available outside of a function exit breakpoint',
104+
);
105+
const ptr = value.toPointer();
106+
this.retVal.replace(ptr);
107+
} else if (this.ctx === null) {
108+
if (name === Regs.PC_NAME) {
109+
throw new Error('pc cannot be set');
110+
} else {
111+
throw new Error('registers not available outside of a breakpoint');
112+
}
113+
} else {
114+
const regs = this.getRegs(this.ctx);
115+
if (!regs.has(name))
116+
throw new Error(`register name '${name}' is invalid`);
117+
regs.set(name, value);
118+
this.setRegs(this.ctx, regs);
119+
}
120+
}
121+
59122
public static getRegs(cpuContext: CpuContext): Map<string, Var> {
60123
switch (Process.arch) {
61124
case 'ia32': {
@@ -162,35 +225,6 @@ export class Regs {
162225
}
163226
}
164227

165-
public static set(name: string, value: Var) {
166-
if (name === Regs.THREAD_ID_NAME) {
167-
throw new Error('thread ID cannot be set');
168-
} else if (name === Regs.RETURN_ADDRESS_NAME) {
169-
throw new Error('return address cannot be set');
170-
} else if (name === Regs.ADDR_NAME) {
171-
throw new Error('addr cannot be set');
172-
} else if (name === Regs.RETVAL_NAME) {
173-
if (this.retVal === null)
174-
throw new Error(
175-
'return Value not available outside of a function exit breakpoint',
176-
);
177-
const ptr = value.toPointer();
178-
this.retVal.replace(ptr);
179-
} else if (this.ctx === null) {
180-
if (name === Regs.PC_NAME) {
181-
throw new Error('pc cannot be set');
182-
} else {
183-
throw new Error('registers not available outside of a breakpoint');
184-
}
185-
} else {
186-
const regs = this.getRegs(this.ctx);
187-
if (!regs.has(name))
188-
throw new Error(`register name '${name}' is invalid`);
189-
regs.set(name, value);
190-
this.setRegs(this.ctx, regs);
191-
}
192-
}
193-
194228
public static setRegs(cpuContext: CpuContext, regs: Map<string, Var>) {
195229
switch (Process.arch) {
196230
case 'ia32': {
@@ -310,60 +344,21 @@ export class Regs {
310344
regs.forEach(r => result.push(r));
311345
}
312346

313-
if (this.threadId !== null) {
314-
result.push([
315-
Regs.THREAD_ID_NAME,
316-
new Var(uint64(this.threadId), Regs.THREAD_ID_NAME),
317-
]);
318-
}
319-
320-
if (this.returnAddress !== null) {
321-
result.push([
322-
Regs.RETURN_ADDRESS_NAME,
323-
new Var(
324-
uint64(this.returnAddress.toString()),
325-
Regs.RETURN_ADDRESS_NAME,
326-
),
327-
]);
328-
}
329-
330-
if (this.addr !== null) {
331-
result.push([
332-
Regs.ADDR_NAME,
333-
new Var(uint64(this.addr.toString()), Regs.ADDR_NAME),
334-
]);
335-
}
336-
337-
if (this.retVal !== null) {
338-
result.push([
339-
Regs.RETVAL_NAME,
340-
new Var(uint64(this.retVal.toString()), Regs.RETVAL_NAME),
341-
]);
347+
for (const [k, v] of Object.entries(this.pseudoRegs)) {
348+
if (v === null) continue;
349+
result.push([k, v]);
342350
}
343351

344352
return result;
345353
}
346354

347355
private static isClear() {
348-
if (this.threadId !== null) return false;
349-
350356
if (this.ctx !== null) return false;
351-
352-
if (this.returnAddress !== null) return false;
353-
354-
if (this.addr !== null) return false;
355-
356357
if (this.pc !== null) return false;
357-
358-
if (this.retVal !== null) return false;
359-
358+
if (Object.values(this.pseudoRegs).some(v => v !== null)) return false;
360359
return true;
361360
}
362361

363-
public static setThreadId(threadId: ThreadId) {
364-
this.threadId = threadId;
365-
}
366-
367362
public static setContext(ctx: CpuContext) {
368363
this.ctx = ctx;
369364
}
@@ -372,27 +367,11 @@ export class Regs {
372367
return this.ctx;
373368
}
374369

375-
public static setReturnAddress(returnAddress: NativePointer) {
376-
this.returnAddress = returnAddress;
377-
}
378-
379-
public static setAddress(addr: NativePointer) {
380-
this.addr = addr;
381-
}
382-
383-
public static setPc(pc: NativePointer) {
384-
this.pc = pc;
385-
}
386-
387-
public static setRetVal(retVal: InvocationReturnValue) {
388-
this.retVal = retVal;
389-
}
390-
391370
public static clear() {
392-
this.threadId = null;
393-
this.ctx = null;
394-
this.returnAddress = null;
395-
this.addr = null;
371+
for (const name of Object.keys(this.pseudoRegs)) {
372+
const key = name as PseudoRegNames;
373+
this.pseudoRegs[key] = null;
374+
}
396375
this.pc = null;
397376
this.retVal = null;
398377
}

src/commands/cmdlet.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ export abstract class CmdLetBase implements CmdLet {
125125

126126
protected parseIndex(token: Token): number | null {
127127
const literal = token.getLiteral();
128+
if (literal.startsWith(CmdLetBase.NUM_CHAR))
129+
return CmdLetBase.parseIndexString(literal);
130+
131+
const v = token.toVar();
132+
if (v === null) return null;
133+
return CmdLetBase.parseIndexString(v.getLiteral());
134+
}
135+
136+
private static parseIndexString(literal: string): number | null {
128137
if (!literal.startsWith(CmdLetBase.NUM_CHAR)) return null;
129138

130139
const numStr = literal.slice(1);

0 commit comments

Comments
 (0)