1#
2# Copyright 2014, General Dynamics C4 Systems
3#
4# This software may be distributed and modified according to the terms of
5# the GNU General Public License version 2. Note that NO WARRANTY is provided.
6# See "LICENSE_GPLv2.txt" for details.
7#
8# @TAG(GD_GPL)
9#
10
11#GDB macros for displaying seL4 data structures. Currently a work in progress.
12#TODO: macros for examining an address space
13
14set print pretty on
15
16define sel4
17end
18
19document sel4
20  This is a set of macros to interpret sel4 data structures. Available commands:
21
22  runqueues
23  currthread 
24  sched_action
25  current_lookup_fault
26  current_fault
27  current_syscall_error
28  resolve_cap
29  resolve_cap_current
30  currthread_cnode
31  disp_cap
32  disp_ep
33  disp_ep_queue
34  dump_cnode
35  dump_currthread_cnode
36  get_thread_vspace
37  get_thread_cspace
38  get_thread_reply_slot
39  get_thread_most_recent_ipc_sender
40  get_thread_ipc_buffer
41  dump_thread_info
42
43  Type help <command> for more information on a specific command
44end
45
46define runqueues
47  set $found=0
48  while($found<255)
49    set $queue = ksReadyQueues[$found]
50    if($queue.head != 0x0)
51      set $current = $queue.head
52      while($current != $queue->end)
53        print *$current
54        set $current = $current->tcbSchedNext
55      end
56      print *$current
57    end
58    set $found++
59  end
60end
61
62document runqueues
63  Print TCBs of all runnable threads
64end
65
66define runqueues_c
67  set $found=0
68  while($found<255)
69    set $queue = ksReadyQueues[$found]
70    if($queue.head != 0x0)
71      set $current = $queue.head
72      while($current != $queue->end)
73        print_condensed_tcb $current
74        set $current = $current->tcbSchedNext
75      end
76      print_condensed_tcb $current
77    end
78    set $found++
79  end
80end
81
82define print_condensed_tcb
83  printf "%d\n", $arg0->tcbPriority
84end
85
86define currthread
87  print *ksCurThread
88end
89
90document currthread
91  Print TCB of current thread
92end
93
94define sched_action
95  if(ksSchedulerAction == 0x0)
96    printf "ResumeCurrentThread\n"
97  else 
98    if (ksSchedulerAction == ~0x0)
99      printf "ChooseNewThread\n"
100    else
101      printf "SwitchToThread:\n"
102      print *ksSchedulerAction
103    end
104  end
105end
106
107document sched_action
108  Print the next scheduler action
109end
110
111define current_lookup_fault
112#print current_lookup_fault
113  if((current_lookup_fault.words[0] & 0x3)==lookup_fault_invalid_root)
114    printf "invalid root\n"
115  else
116    if((current_lookup_fault.words[0] & 0x3)==lookup_fault_missing_capability)
117      printf "missing capability\n"
118    else
119      if ((current_lookup_fault.words[0] & 0x3)==lookup_fault_depth_mismatch)
120        printf "depth mismatch\n"
121      else 
122        if((current_lookup_fault.words[0] & 0x3)==lookup_fault_guard_mismatch)
123          printf "guard mismatch\n"
124        else
125          printf "unknown lookup fault\n"
126        end
127      end
128    end
129  end
130end
131
132document current_lookup_fault
133  Decodes the current_lookup_fault variable to determine what went wrong with the last lookup
134end
135
136define current_fault
137  print current_fault
138end
139
140document current_fault
141  Prints the last fault
142end
143
144define current_syscall_error
145  print current_syscall_error
146end
147
148document current_syscall_error
149  Prints the last syscall error
150end
151
152define cap_type
153  return ($arg1.words[0]>>28) & 0xf
154end
155
156define mask
157  ((1<< $arg0)-1)
158end
159
160define currthread_cnode
161  set $cnode = ((cte_t *)((unsigned int)ksCurThread&~((1<<9)-1)))
162  print $cnode->cap
163end
164
165document currthread_cnode
166  Prints the root CNode of the current thread
167end
168
169define cnode_for_thread
170  set $cnode = ((cte_t *)((unsigned int)($arg0)&~((1<<9)-1)))
171  print $cnode->cap
172end
173
174define disp_ep
175  set $ep = *(endpoint_t *)$arg0
176  printf "Queue head: %x\n", ($ep.words[1] & 0xfffffff0)
177  printf "Queue tail: %x\n", ($ep.words[0] & 0xfffffff0)
178  print ((enum endpoint_state)($ep.words[0] & 0x3))
179end
180
181document disp_ep
182  Display basic information about an endpoint. arg0: pointer to an endpoint data structure in-kernel memory. This can be obtained from resolve_cap.
183end
184
185define disp_ep_queue
186  set $ep = *(endpoint_t *)$arg0
187  set $current = (tcb_t *)($ep.words[1] & 0xfffffff0)
188  set $tail = (tcb_t *)($ep.words[0] & 0xfffffff0)
189  if( $current == 0)
190    printf "empty\n"
191  else
192    while( $current != $tail)
193      print *$current
194      set $current = $current->tcbEPNext
195    end
196    print *$current
197  end
198end
199
200document disp_ep_queue
201  Display all TCBs in an endpoint's queue. arg0: pointer to an endpoint data structure in kernel memory. This can be obtained from resolve_cap.
202end
203
204define disp_cap
205  set $cap = $arg0
206  set $type = (cap_tag_t)(($cap.words[0] >> 28) & 0xf)
207
208  if( $type == cap_null_cap )
209    printf "Type: cap_null_cap\n"
210  end
211
212  if( $type == cap_untyped_cap )
213    printf "Type: cap_untyped_cap\n"
214    printf "blocksize: %x\n", $cap.words[1] & 0x1f
215    printf "capPtr: %x\n", ($cap.words[0]>>28) & 0xf
216  end
217
218  if( $type == cap_endpoint_cap )
219    printf "Type: cap_endpoint_cap\n"
220    printf "badge: %x\n", ($cap.words[1] & 0xfffffff8) >> 3
221    printf "EPPtr: %x\n", ($cap.words[0] & 0xfffffff) << 4
222  end
223
224  if( $type == cap_notification_cap )
225    printf "Type: cap_notification_cap\n"
226    printf "badge: %x\n", ($cap.words[1] & 0xfffffff8) >> 3
227    printf "AEPPtr: %x\n", ($cap.words[0] & 0xfffffff) << 4
228  end
229
230  if( $type == cap_reply_cap )
231    printf "Type: cap_reply_cap\n"
232  end
233
234  if( $type == cap_cnode_cap)
235    printf "Type: cap_cnode_cap\n"
236    printf "Radix: %x\n", ($cap.words[1] & 0xf800000) >> 23
237    printf "Guard size: %x\n", ($cap.words[1] & 0x7c0000) >> 18
238    printf "Guard: %x\n", ($cap.words[1] & 0x3ffff) >> 0
239    printf "CNode ptr: %x\n", ($cap.words[0] & 0x7ffffff) << 5
240  end
241
242  if( $type == cap_thread_cap)
243    printf "Type: cap_thread_cap\n"
244    printf "TCBPtr: %x\n", ($cap.words[0] & 0xfffffff) << 4
245  end
246
247  if( $type == cap_irq_handler_cap )
248    printf "Type: cap_irq_handler_cap\n"
249    printf "capIRQ: %x\n", ($cap.words[1] & 0xff) >> 0
250  end
251
252  if( $type == cap_irq_control_cap )
253    printf "Type: cap_irq_control_cap\n"
254    printf "not implemented\n"
255  end
256
257  if( $type == cap_zombie_cap )
258    printf "Type: cap_zombie_cap\n"
259  end
260
261  if( $type == cap_subtype_cap )
262    printf "Type: cap_subtype_cap\n"
263
264    set $subtype = (subcap_tag_t)(($cap.words[0] & 0xf000000) >> 24)
265
266    if( $subtype == subcap_asid_control_cap )
267      printf "Subtype: subcap_asid_control_cap\n"
268    end
269
270    if( $subtype == subcap_asid_pool_cap )
271      printf "Subtype: subcap_asid_pool_cap\n"
272      printf "capASIDBase: %x\n", $cap.words[1] & 0xffff
273      printf "capType: %x\n", ($cap.words[0] >> 28) & 0xf
274      printf "capASIDPool %x\n", ($cap.words[0] << 12)
275    end
276
277    if( $subtype == subcap_io_port_cap )
278      printf "Subtype: subcap_io_port_cap\n"
279      printf "capType: %x\n", ($cap.words[0] >> 28) & 0xf
280    end
281
282    if( $subtype == subcap_io_space_cap )
283      printf "Subtype: subcap_io_space_cap\n"
284    end
285
286    if( $subtype == subcap_io_page_table_cap )
287      printf "Subtype: subcap_io_page_table_cap\n"
288    end
289
290  end
291
292  if( $type == cap_frame_cap )
293    printf "Type: cap_frame_cap\n"
294    printf "FMappedAddress: %x\n", ($cap.words[1] & 0xfffff) << 12
295    printf "FBasePtr: %x\n", ($cap.words[0] & 0xfffff) << 12
296    printf "FMappedASIDLow: %x\n", ($cap.words[1] & 0x3ff00000) >> 20
297    printf "FMappedASIDHigh: %x\n", ($cap.words[0] & 0xfc00000) >> 22
298    printf "Frame size: %x\n", ($cap.words[1] & 0x80000000) >> 31
299  end
300
301  if( $type == cap_page_table_cap )
302    printf "Type: cap_page_table_cap\n"
303    printf "not implemented\n"
304  end
305
306  if( $type == cap_page_directory_cap )
307    printf "Type: cap_page_directory_cap\n"
308    printf "Is mapped: %x\n", ($cap.words[1] & 0x10000) >> 16
309    printf "ASID: %x\n", ($cap->words[1] & 0xffff) >> 0
310    printf "CapPDBasePTR: %x\n", $cap->words[1] << 12
311  end
312
313  print $cap
314end
315
316document disp_cap
317  Determines the type of a cap and prints relevant information. arg0: a kernel capability data structure (not a pointer). This can be obtained from resolve_cap.
318end
319
320define get_thread_cap
321  set $result = ((cte_t *)(((unsigned int) $arg0 )&~((1<<10)-1))) + $arg1
322  set $result = $result->cap
323end
324
325document get_thread_cap
326  Gets one of the caps associated with a TCB e.g. root CNode, VSpace, ipc_buffer. arg0: pointer to tcb struct, arg1: index of cap
327end
328
329define get_thread_cspace
330  get_thread_cap $arg0 0
331end
332
333document get_thread_cspace
334  Get the CTE for the root CNode of a thread. arg0: the in-kernel data structure representing the thread cap
335end
336
337define get_thread_vspace
338  get_thread_cap $arg0 1
339end
340
341document get_thread_vspace
342  Get the CTE for the vspace of a thread. arg0: the in-kernel data structure representing the thread cap
343end
344
345define get_thread_reply_slot
346  get_thread_cap $arg0 2
347end
348
349document get_thread_reply_slot
350  Get the CTE for the reply slot of a thread. arg0: the in-kernel data structure representing the thread cap
351end
352
353define get_thread_most_recent_ipc_sender
354  get_thread_cap $arg0 3
355end
356
357document get_thread_most_recent_ipc_sender
358  Get the CTE for the most recent IPC sender of a thread. arg0: the in-kernel data structure representing the thread cap
359end
360
361define get_thread_ipc_buffer
362  get_thread_cap $arg0 4
363end
364
365document get_thread_ipc_buffer
366  Get the CTE for the IPC buffer of a thread. arg0: the in-kernel data structure representing the thread cap
367end
368
369define dump_thread_info
370  set $tcbptr = $arg0
371  printf "\nCSpace:\n"
372  get_thread_cspace $tcbptr
373  disp_cap $result
374  printf "\nVSpace:\n"
375  get_thread_vspace $tcbptr
376  disp_cap $result
377  printf "\nReply slot:\n"
378  get_thread_reply_slot $tcbptr
379  disp_cap $result
380  printf "\nMost recent IPC sender:\n"
381  get_thread_most_recent_ipc_sender $tcbptr
382  disp_cap $result
383  printf "\nIPC buffer:\n"
384  get_thread_ipc_buffer $tcbptr
385  disp_cap $result
386end
387
388document dump_thread_info
389  Dump the extra caps associated with a thread (root CNode, VSpace etc). arg0: the in-kernel data structure representing the thread cap
390end
391
392define pd_for_asid
393  set $asid = $arg0
394  set $poolPtr = ia32KSASIDTable[$asid >> asidLowBits];
395  set $pd = poolPtr->array[$asid & ((1<<asidLowBits)-1)];
396  if( !$asid || !$poolPtr )
397    printf "Something went wrong\n"
398  else
399    print $pd
400  end
401end
402
403define resolve_cap
404  set $nodeCap = $arg0
405  set $capptr = (int)$arg1
406  set $n_bits = (int)$arg2
407
408  while(1) 
409#printf "loop: remaining: %d\n", $n_bits
410    #test cap type
411    if((( $nodeCap.words[0]>>28)&0xf) != cap_cnode_cap)
412      printf "Error: not a CNode\n"
413      loop_break
414    end
415    set $radixBits = ($nodeCap.words[1] & 0xf800000) >> 23
416    set $guardBits = ($nodeCap.words[1] & 0x7c0000) >> 18
417    set $levelBits = $radixBits + $guardBits
418    set $capGuard = ($nodeCap.words[1] & 0x3ffff) >> 0
419
420    set $guard = ($capptr >> ($n_bits - $guardBits)) & ((1<<$guardBits)-1)
421    
422    if( ($guardBits > $n_bits) || ($guard != $capGuard))
423      printf "levelbits: %d, radixbits: %d, guardbits: %d, n_bits: %d\n", $levelBits, $radixBits, $guardBits, $n_bits
424      printf "guard: %x, capguard: %x", $guard, $capGuard
425      printf "lookup fault guard mismatch\n"
426      loop_break
427    end
428
429    if( $levelBits > $n_bits )
430      printf "lookup fault depth mismatch\n"
431      loop_break
432    end
433
434    set $offset = ($capptr >> ($n_bits - $levelBits)) & ((1<<$radixBits)-1)
435    set $slot = ((cte_t *)(($nodeCap.words[0] & 0x7ffffff) << 5)) + $offset
436
437    if( $n_bits <= $levelBits)
438      disp_cap $slot->cap
439      loop_break
440    end
441
442    set $n_bits -= $levelBits
443    set $nodeCap = $slot->cap
444
445    #test cap type
446    if((( $nodeCap.words[0]>>28)&0xf) != cap_cnode_cap)
447      printf "warning: terminating because node is not a CNode, not because all bits were resolved\n"
448      disp_cap $nodeCap
449      loop_break
450    end
451
452  end
453
454end
455
456document resolve_cap
457  Resolve a capPtr and print its contents using disp_cap. arg0: CNode to start resolving at, arg1: the cap to resolve (an integer), arg2: the depth to resolve to (an integer). The currthread_cnode macro may be useful to obtain the first argument.
458end
459
460define resolve_cap_current
461  currthread_cnode
462  resolve_cap $cnode->cap $arg0 $arg1
463end
464
465document resolve_cap_current
466  Resolve a capPtr and print its contents. Caps are resolved relative to root CNode of current thread. arg1: the cap to resolve, arg2: the depth.
467end
468
469define dump_cnode
470  set $nodeCap = $arg0
471
472  if((( $nodeCap.words[0]>>28)&0xf) != cap_cnode_cap)
473    printf "Error: not a CNode\n"
474  end
475
476  set $radixBits = ($nodeCap.words[1] & 0xf800000) >> 23
477  set $guardBits = ($nodeCap.words[1] & 0x7c0000) >> 18
478  set $levelBits = $radixBits + $guardBits
479
480  set $count = 0
481
482  while( $count < (1<<$radixBits))
483    set $slot = ((cte_t *)(($nodeCap.words[0] & 0x7ffffff) << 5)) + $count
484    if((($slot->cap.words[0]>>28)&0xf) != cap_null_cap)
485      printf "offset: %d\n", $count
486      disp_cap $slot->cap 
487      printf "\n"
488    end
489    set $count = $count+1
490  end
491end
492
493document dump_cnode
494  Dump the contents of a CNode. arg1: the CNode to dump
495end
496
497define dump_currthread_cnode
498  printf "Top level CNode: \n"
499  currthread_cnode
500  printf "\n\n"
501  dump_cnode $cnode->cap
502end
503
504document dump_currthread_cnode
505  Dump the contents of the root CNode of the current thread. No arguments.
506end
507
508define irq_handler
509  set $slot = intStateIRQNode + $arg0
510  set $cap = $slot->cap
511  if((cap_tag_t)(($cap.words[0] >> 28) & 0xf) != cap_notification_cap)
512    printf "no handler\n"
513  else
514    set $cap = (async_endpoint_t *)(($cap.words[0] & 0xfffffff) << 4)
515    disp_ep *$cap
516    disp_ep_queue *$cap
517  end
518end
519
520document irq_handler
521  Print the endpoints and handling threads for an IRQ. arg0: the IRQ number
522end
523
524define wombat_current
525  print ((struct thread_info *)per_cpu___l4_current_tinfo)->task
526end
527
528define finish_irq
529  set $current_sel4_thread = ksCurThread
530#set $current = ((struct thread_info *)per_cpu___l4_current_tinfo)->task
531  tbreak *0xf012102a if (ksCurThread==$current_sel4_thread)  
532  continue
533  stepi
534end
535
536document finish_irq
537  Run until the end of the IRQ handler. This is useful if you are stepping through userland code and an interrupt occurs and control moves to the kernel. As far as I know there is no way to disable interrupts in qemu to avoid this.
538end
539
540define n2
541  next
542  if $eip>0xf0000000
543    printf "IRQ happened\n"
544    finish_irq
545  end
546end
547
548document n2
549  Like next but if it detects that an IRQ happens it executes that and returns.
550end
551
552define vtd_root
553  print ia32KSvtdRootTable
554end
555
556define decode_vtd_root_entry
557  set $vtd_root_entry = (vtd_root_entry_t)$arg0
558  set $vtd_re_ctp = ($vtd_root_entry.words[0] & 0xfffff000)
559  set $vtd_re_present = ($vtd_root_entry.words[0] & 0x1)
560end
561
562document decode_vtd_root_entry
563  "Decodes the vtd root entry into its component parts"
564end
565
566define print_vtd_root_entry
567  printf "ctp: %x\n", $vtd_re_ctp
568  printf "present: %x\n", $vtd_re_present
569end
570
571document print_vtd_root_entry
572  "Print the fields of an earlier decoded vtd root entry"
573end
574
575define print_vtd_root_table 
576  set $vtd_root_entry_ptr = ia32KSvtdRootTable
577  set $count = 0
578  while($count < 256)
579    decode_vtd_root_entry $vtd_root_entry_ptr[$count] 
580    if($vtd_re_present)
581      printf "Index: %x\n", $count
582      print_vtd_root_entry 
583    end
584    set $count++
585  end
586end
587
588document print_vtd_root_table
589  "Prints all of the entries in the vtd root table. There is one entry for each PCI bus"
590end
591
592define decode_vtd_context_entry
593  set $vtd_context_entry = (vtd_context_entry_t)$arg0
594  set $vtd_ce_did = ($vtd_context_entry.words[2] & 0xffff00) >> 8
595  set $vtd_ce_aw = ($vtd_context_entry.words[2] & 0x7)
596  set $vtd_ce_asr = ($vtd_context_entry.words[0] & 0xfffff000)
597  set $vtd_ce_present = ($vtd_context_entry.words[0] & 0x1)
598end
599
600document decode_vtd_context_entry
601  "Decodes a vtd context entry into its component parts. arg0: pointer to the entry"
602end
603
604define print_vtd_context_entry
605  printf "did: %x\n", $vtd_ce_did
606  printf "aw: %x\n", $vtd_ce_aw
607  printf "asr: %x\n", $vtd_ce_asr
608  printf "present: %x\n", $vtd_ce_present
609end
610
611document print_vtd_context_entry 
612  "Print the fields of an earlier decoded vtd context entry"
613end
614
615define print_vtd_context_table
616  set $vtd_context_entry_ptr = (vtd_context_entry_t *)$arg0
617  set $count = 0
618  while($count < 256)
619    decode_vtd_context_entry $vtd_context_entry_ptr[$count]
620    if($vtd_ce_present)
621      printf "index %x\n", $count
622      print_vtd_context_entry
623    end
624    set $count++
625  end
626end
627
628document print_vtd_context_table
629  "Prints all of the fields in a vtd context table. There is one entry for each (dev, fn) in the bus. arg0: a pointer to the context table"
630end
631
632define decode_vtd_page_table_entry
633  set $vtd_page_table_entry = (vtd_pte_t)$arg0
634  set $vtd_pte_addr =  ($vtd_page_table_entry.words[0] & 0xfffff000)
635  set $vtd_pte_write = ($vtd_page_table_entry.words[0] & 0x2) >> 1
636  set $vtd_pte_read = ($vtd_page_table_entry.words[0] & 0x1)
637end
638
639document decode_vtd_page_table_entry
640  "Decodes a vtd PTE info its component parts. arg0: pointer to the entry"
641end
642
643define print_vtd_page_table_entry
644  printf "addr: %x\n", $vtd_pte_addr
645  printf "write: %x\n", $vtd_pte_write
646  printf "read: %x\n", $vtd_pte_read
647end
648
649document print_vtd_page_table_entry 
650  "Print the fields of an earlier decoded vtd page table entry"
651end
652
653define print_vtd_page_table
654  set $vtd_pte_ptr = (vtd_pte_t *)$arg0
655  set $count = 0
656  while($count < 256)
657    decode_vtd_page_table_entry $vtd_pte_ptr[$count]
658    if($vtd_pte_read || $vtd_pte_write)
659      printf "index: %x\n", $count
660      print_vtd_page_table_entry 
661    end
662    set $count++
663  end
664end
665
666document print_vtd_page_table
667  "Prints all of the fields in a vtd page table. arg0: a pointer to the page table"
668end
669
670define paddr_to_vaddr
671  set $var = (unsigned int)$arg0
672  set $vaddr = ($var + 0xf0000000)
673end
674
675document paddr_to_vaddr
676  "Convert a physical address to the locaction to which it is mapped in the kernel"
677end
678
679define vaddr_to_paddr
680  set $paddr = ($arg0 - 0xf0000000)
681end
682
683document vaddr_to_paddr
684  "Convert a virtual address in the kernel to a physical address"
685end
686
687define lookup_vtd_address
688  set $bus = $arg0
689  set $devfn = $arg1
690  set $address = $arg2
691
692  set $vtd_root_entry_ptr = ia32KSvtdRootTable
693  decode_vtd_root_entry $vtd_root_entry_ptr[$bus]
694  if($vtd_re_present)
695    printf "Root entry: \n"
696    print_vtd_root_entry
697    paddr_to_vaddr $vtd_re_ctp
698    set $vtd_context_entry_ptr = (vtd_context_entry_t *)$vaddr
699    decode_vtd_context_entry $vtd_context_entry_ptr[$devfn]
700    if($vtd_ce_present)
701      printf "Context entry: \n"
702      print_vtd_context_entry
703      walk_vtd_pgtables $vtd_ce_asr $address
704    else
705      printf "Error: context entry not present\n"
706    end
707  else
708    printf "Error: root entry not present\n"
709  end
710end
711
712document lookup_vtd_address
713  "Looks up an address in the address space of a given PCI device. arg0: PCI bus number, arg1: PCI devfn number, arg2: virtual address to look up"
714end
715
716define walk_vtd_pgtables
717  set $pg_tab = (vtd_pte_t *)$arg0
718  set $address = (unsigned long long int)$arg1
719  set $count=0
720  if(($address & 0xffffff8000000000) == 0x0)
721    set $address = $address << 25
722    while(1)
723      set $index = ($address & 0xff80000000000000) >> (64-9)
724      printf "index: %x\n", $index
725      set $address = ($address << 9)
726      paddr_to_vaddr $pg_tab
727      set $pg_tab = (vtd_pte_t *)$vaddr
728      decode_vtd_page_table_entry $pg_tab[$index]
729      if($vtd_pte_read || $vtd_pte_write)
730        printf "Page table entry: \n"
731        print_vtd_page_table_entry
732#TODO check for superpages
733        set $count++
734        if($count==3)
735          printf "Translation complete. Physical address: %llx\n", $vtd_pte_addr 
736          loop_break
737        else
738          set $pg_tab = (vtd_pte_t *)$vtd_pte_addr
739        end
740      else 
741        printf "Error: Page table entry not present\n"
742        printf "Page table: "
743        print_vtd_page_table_entry 
744        loop_break
745      end
746    end
747  else
748    printf "Error: bits 63:39 must be 0\n"
749  end
750end
751
752document walk_vtd_pgtables
753  "Walks the IOMMU page table to resolve a virtual address starting at the given page table. arg0: pointer to page table (in seL4 virtual memory), arg1: virtual address to resolve"
754end
755
756define decode_pte
757  set $pte_addr = $arg0 & 0xfffff000
758  set $pte_present = $arg0 & 1
759  set $pte_rw = ($arg0 >> 1) & 1
760  set $pte_usr = ($arg0 >> 2) & 1
761  set $pte_pwt = ($arg0 >> 3) & 1
762  set $pte_pcd = ($arg0 >> 4) & 1
763  set $pte_accessed = ($arg0 >> 5) & 1
764  set $pte_dirty = ($arg0 >> 6) & 1
765  set $pte_pse = ($arg0 >> 7) & 1
766  set $pte_pat = ($arg0 >> 12) & 1
767  set $pte_avl = ($arg0 >> 9) & 7
768  set $pte_global = ($arg0 >> 8) & 1
769end
770
771document decode_pte
772 Decode an IA32 page table leaf entry into its component parts.
773 If the PRESENT bit is 0 then the rest of the bits can be anything
774 (OSs typically reuse them for swap housekeeping)
775end
776
777define maybe_print
778  if $arg0
779    printf $arg1
780  else
781    printf $arg2
782  end
783end
784
785document maybe_print
786 If arg0 is non-zero print arg1 otherwise print arg2.
787end
788
789# Can't use the obvious printf formulation for this because gdb tries
790# to call malloc in the target --- which doesn't work in SeL4
791define print_pte
792  printf "Address 0x%x ", $pte_addr
793  printf "  attributes: "
794  maybe_print $pte_present "P" "-"
795  maybe_print $pte_rw  "w"  "r"
796  maybe_print $pte_usr  "U"  "S"
797  maybe_print $pte_pwt " WT "  " WB "
798  maybe_print $pte_pcd "NC "  "C "
799  maybe_print $pte_accessed  "A"  "-"
800  maybe_print $pte_dirty  "d"  "-"
801  maybe_print $pte_pse  "4M"  "4k"
802  maybe_print $pte_pat " PAT " ""
803  maybe_print $pte_global "g" ""
804
805  printf "AVL%x\n", $pte_avl
806end
807
808document print_pte
809  Print the PTE parts split out by decode_pte.
810  You must invoke decode_pte before invoking this function.
811end
812
813define pgd
814  set $idx = 0
815  set $pgdptr = $arg0
816  while ($idx < 1024)
817    set $pte = *(long *)$pgdptr
818#printf "PGD@0x%x is 0x%x\n", $pgdptr, $pte
819    decode_pte $pte
820    set $mapped_addr =  $idx * (4 * 1024 * 1024)
821    set $idx = $idx + 1
822    set $pgdptr = $pgdptr + 4
823    if (! $pte_present)
824       loop_continue
825    end
826    if $pte_pse
827       printf "HUGE (4G) V 0x%x ", $mapped_addr
828       print_pte
829    else
830      set $pteptr = (long)$pte_addr + 0xe0000000
831      set $n = 0
832      while ($n < 1024)
833        set $pte = *(long *)$pteptr
834        decode_pte $pte
835        if $pte_present
836          printf  "V:%08x ", $mapped_addr
837          print_pte
838        end
839        set $pteptr = $pteptr + 4
840        set $mapped_addr = $mapped_addr + 4096
841        set $n = $n + 1
842      end
843    end
844  end
845end
846
847document pgd
848  Print a page table, starting at the page global directory.
849  Assumes 2-level (non-PAE) page tables,
850end
851