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