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