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