11import { 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+
314export 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 }
0 commit comments