1- import gdb
2-
31from .struct import TailQueue
4- from .cmd import UserCommand
2+ from .cmd import UserCommand , CommandDispatcher
53from .cpu import TLBLo
6- from .utils import TextTable , global_var , cast
4+ from .utils import TextTable , global_var , cast_ptr , get_arch
5+ from .proc import Process
76
87
98PM_NQUEUES = 16
109
1110
12- class PhysMap (UserCommand ):
13- """List active page entries in kernel pmap"""
11+ class VmInfo (CommandDispatcher ):
12+ """Examine virtual memory data structures."""
13+
1414 def __init__ (self ):
15- super ().__init__ ('pmap' )
15+ super ().__init__ ('vm' , [DumpPmap ('kernel' ),
16+ DumpPmap ('user' ),
17+ VmMapDump (),
18+ SegmentInfo ('' ),
19+ SegmentInfo ('proc' ),
20+ VmPhysSeg (),
21+ VmFreePages (),
22+ ])
23+
24+
25+ def _print_mips_pmap (pmap ):
26+ pdp = cast_ptr (pmap ['pde' ], 'pde_t' )
27+ table = TextTable (types = 'ttttt' , align = 'rrrrr' )
28+ table .header (['vpn' , 'pte0' , 'pte1' , 'pte2' , 'pte3' ])
29+ for i in range (1024 ):
30+ pde = TLBLo (pdp [i ])
31+ if not pde .valid :
32+ continue
33+ ptp = cast_ptr (pde .ppn , 'pte_t' )
34+ pte = [TLBLo (ptp [j ]) for j in range (1024 )]
35+ for j in range (0 , 1024 , 4 ):
36+ if not any (pte .valid for pte in pte [j :j + 4 ]):
37+ continue
38+ pte4 = [str (pte ) if pte .valid else '-' for pte in pte [j :j + 4 ]]
39+ table .add_row (['{:8x}' .format ((i << 22 ) + (j << 12 )),
40+ pte4 [0 ], pte4 [1 ], pte4 [2 ], pte4 [3 ]])
41+ print (table )
42+
43+
44+ class DumpPmap (UserCommand ):
45+ """List active page entries in user pmap"""
46+
47+ def __init__ (self , typ ):
48+ command = 'pmap_' + typ
49+ if command not in ('pmap_user' , 'pmap_kernel' ):
50+ print (f'{ command } command not supported' )
51+ return
52+ self .command = command
53+ super ().__init__ (command )
1654
1755 def __call__ (self , args ):
18- pdp = global_var ('kernel_pmap' )['pde' ]
19- table = TextTable (types = 'ttttt' , align = 'rrrrr' )
20- table .header (['vpn' , 'pte0' , 'pte1' , 'pte2' , 'pte3' ])
21- for i in range (1024 ):
22- pde = TLBLo (pdp [i ])
23- if not pde .valid :
24- continue
25- ptp = pde .ppn .cast (gdb .lookup_type ('pte_t' ).pointer ())
26- pte = [TLBLo (ptp [j ]) for j in range (1024 )]
27- for j in range (0 , 1024 , 4 ):
28- if not any (pte .valid for pte in pte [j :j + 4 ]):
29- continue
30- pte4 = [str (pte ) if pte .valid else '-' for pte in pte [j :j + 4 ]]
31- table .add_row (['{:8x}' .format ((i << 22 ) + (j << 12 )),
32- pte4 [0 ], pte4 [1 ], pte4 [2 ], pte4 [3 ]])
56+ if self .command == 'pmap_kernel' :
57+ pmap = global_var ('kernel_pmap' )
58+ else :
59+ args = args .split ()
60+ if len (args ) == 0 :
61+ proc = Process .from_current ()
62+ else :
63+ pid = int (args [0 ])
64+ proc = Process .find_by_pid (pid )
65+ if proc is None :
66+ print (f'Process { pid } not found' )
67+ return
68+ pmap = proc .p_uspace .pmap
69+
70+ arch = get_arch ()
71+ if arch == 'mips' :
72+ _print_mips_pmap (pmap )
73+ else :
74+ print (f"Can't print { arch } pmap" )
75+
76+
77+ class VmMapDump (UserCommand ):
78+ """List segments describing virtual address space"""
79+
80+ def __init__ (self ):
81+ super ().__init__ ('map' )
82+
83+ def __call__ (self , args ):
84+ args = args .split ()
85+ if len (args ) == 0 :
86+ proc = Process .from_current ()
87+ else :
88+ pid = int (args [0 ])
89+ proc = Process .find_by_pid (pid )
90+ if proc is None :
91+ print (f'Process { pid } not found' )
92+ return
93+
94+ entries = proc .p_uspace .get_entries ()
95+
96+ table = TextTable (types = 'ittttt' , align = 'rrrrrr' )
97+ table .header (['segment' , 'start' , 'end' , 'prot' , 'flags' , 'amap' ])
98+ for idx , seg in enumerate (entries ):
99+ table .add_row ([idx , hex (seg .start ), hex (seg .end ), seg .prot ,
100+ seg .flags , seg .aref ])
33101 print (table )
34102
35103
104+ class SegmentInfo (UserCommand ):
105+ """Show info about i-th segment in proc vm_map"""
106+
107+ def __init__ (self , typ ):
108+ command = f"segment{ '_' if typ != '' else '' } { typ } "
109+ if command not in ['segment' , 'segment_proc' ]:
110+ print (f'{ command } command not supported' )
111+ return
112+ self .command = command
113+ super ().__init__ (command )
114+
115+ def _print_segment (self , seg , pid , id ):
116+ print ('Segment {} in proc {}' .format (id , pid ))
117+ print ('Range: {:#08x}-{:#08x} ({:d} pages)' .format (seg .start ,
118+ seg .end ,
119+ seg .pages ))
120+ print ('Prot: {}' .format (seg .prot ))
121+ print ('Flags: {}' .format (seg .flags ))
122+ amap = seg .amap
123+ if amap :
124+ print ('Amap: {}' .format (seg .amap_ptr ))
125+ print ('Amap offset: {}' .format (seg .amap_offset ))
126+ print ('Amap slots: {}' .format (amap .slots ))
127+ print ('Amap refs: {}' .format (amap .ref_cnt ))
128+
129+ # TODO: show used pages/anons
130+ else :
131+ print ('Amap: NULL' )
132+
133+ def __call__ (self , args ):
134+ args = args .split ()
135+ if self .command == 'segment' :
136+ if len (args ) < 1 :
137+ print ('require argument (segment)' )
138+ return
139+ proc = Process .from_current ()
140+ else :
141+ if len (args ) < 2 :
142+ print ('require 2 arguments (pid and segment)' )
143+ return
144+
145+ pid = int (args [0 ])
146+ proc = Process .find_by_pid (pid )
147+ if proc is None :
148+ print (f'Process { pid } not found' )
149+ return
150+ args = args [1 :]
151+
152+ entries = proc .p_uspace .get_entries ()
153+
154+ segment = int (args [0 ], 0 )
155+
156+ if segment < 4096 :
157+ # Lookup by id
158+ if segment > len (entries ):
159+ print (f'Segment { segment } does not exist!' )
160+ return
161+ self ._print_segment (entries [segment ], proc .p_pid , segment )
162+ else :
163+ # Lookup by address
164+ addr = segment
165+ for idx , e in enumerate (entries ):
166+ if e .start <= addr and addr < e .end :
167+ self ._print_segment (e , proc .p_pid , idx )
168+ return
169+ print (f'Segment with address { addr } not found' )
170+
171+
36172class VmPhysSeg (UserCommand ):
37173 """List physical memory segments managed by vm subsystem"""
38174
39175 def __init__ (self ):
40- super ().__init__ ('vm_physseg ' )
176+ super ().__init__ ('physseg ' )
41177
42178 def __call__ (self , args ):
43179 table = TextTable (types = 'ittit' , align = 'rrrrr' )
@@ -53,7 +189,7 @@ class VmFreePages(UserCommand):
53189 """List free pages known to vm subsystem"""
54190
55191 def __init__ (self ):
56- super ().__init__ ('vm_freepages ' )
192+ super ().__init__ ('freepages ' )
57193
58194 def __call__ (self , args ):
59195 table = TextTable (align = 'rrl' , types = 'iit' )
@@ -71,24 +207,3 @@ def __call__(self, args):
71207 segments = TailQueue (global_var ('seglist' ), 'seglink' )
72208 pages = int (sum (seg ['npages' ] for seg in segments if not seg ['used' ]))
73209 print ('Used pages count: {}' .format (pages - free_pages ))
74-
75-
76- class VmMapSeg (UserCommand ):
77- """List segments describing virtual address space"""
78-
79- def __init__ (self ):
80- super ().__init__ ('vm_map' )
81-
82- def __call__ (self , args ):
83- vm_map = gdb .parse_and_eval ('vm_map_user()' )
84- if vm_map == 0 :
85- print ('No active user vm_map!' )
86- return
87- entries = vm_map ['entries' ]
88- table = TextTable (types = 'ittttt' , align = 'rrrrrr' )
89- table .header (['segment' , 'start' , 'end' , 'prot' , 'flags' , 'amap' ])
90- segments = TailQueue (entries , 'link' )
91- for idx , seg in enumerate (segments ):
92- table .add_row ([idx , seg ['start' ], seg ['end' ], seg ['prot' ],
93- seg ['flags' ], seg ['aref' ]])
94- print (table )
0 commit comments