diff options
author | Nick Bofferding <bofferdn@us.ibm.com> | 2015-03-10 00:31:38 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2015-04-13 13:37:21 -0500 |
commit | 3b607d46875d6cd5d353d92be5bf261713e52a18 (patch) | |
tree | b3990c360c34d56a7bf5f73aa44f4de4ff980928 | |
parent | ad7b32c9fa4d4c0179f3974700016d7eaf4f89e8 (diff) | |
download | talos-hostboot-3b607d46875d6cd5d353d92be5bf261713e52a18.tar.gz talos-hostboot-3b607d46875d6cd5d353d92be5bf261713e52a18.zip |
Report stack traces in Hostboot Ps debug tool
- Added optional stack trace support to Ps tool
- Modified debug framework to find a symbol based on fuzzy address
- Added optional suppression of some traces in VMM framework
Change-Id: I2b08e8d1593e0ddc16581ad999fc38df4bab31e4
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/16258
Tested-by: Jenkins Server
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Reviewed-by: Jay M. Azurin <jmazurin@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
-rwxr-xr-x | src/build/debug/Hostboot/Ps.pm | 140 | ||||
-rwxr-xr-x | src/build/debug/Hostboot/_DebugFramework.pm | 54 | ||||
-rwxr-xr-x | src/build/debug/Hostboot/_DebugFrameworkVMM.pm | 12 |
3 files changed, 197 insertions, 9 deletions
diff --git a/src/build/debug/Hostboot/Ps.pm b/src/build/debug/Hostboot/Ps.pm index 4895a63f7..37bb47c20 100755 --- a/src/build/debug/Hostboot/Ps.pm +++ b/src/build/debug/Hostboot/Ps.pm @@ -6,7 +6,9 @@ # # OpenPOWER HostBoot Project # -# COPYRIGHT International Business Machines Corp. 2011,2014 +# Contributors Listed Below - COPYRIGHT 2011,2015 +# [+] International Business Machines Corp. +# # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,6 +25,8 @@ # IBM_PROLOG_END_TAG use strict; +use Hostboot::VirtToPhys; + package Hostboot::Ps; use Exporter; our @EXPORT_OK = ('main'); @@ -49,8 +53,18 @@ use constant PS_TRACKER_ENTRYPOINT_OFFSET => 8 + PS_TRACKER_WAITINFO_OFFSET; use constant PS_TASK_STATE_OFFSET => 8*43; use constant PS_TASK_STATEEXTRA_OFFSET => 8 + PS_TASK_STATE_OFFSET; +use bigint; + sub main { + my ($packName,$args) = @_; + + my $withBacktrace = 0; + if(defined $args->{"with-backtrace"}) + { + $withBacktrace = 1; + } + # Find symbol containing kernel list of task objects. # (Tasks who's parent is the kernel) my ($symAddr, $symSize) = ::findSymbolAddress(PS_TASKMGR_SYMBOLNAME); @@ -62,13 +76,119 @@ sub main # Pass address of list to 'displayList' function. $symAddr += PS_TASKMGR_TRACKER_LIST_OFFSET; - displayList($symAddr,0); + displayList($symAddr,0,$withBacktrace); +} + +# @sub displayStackTrace +# +# Displays a task's stack trace, including frame number, symbol, offset within +# symbol +# +# @param[in] i_taskAddr Task address +# @param[in] i_level Level of indent for stack trace +# +sub displayStackTrace +{ + my ( $i_taskAddr, $i_level ) = @_; + + my $off = 0; + + # Knobs for the VMM package + my $vmmDebug = 0; + my $vmmDisplaySPTE = 0; + my $vmmQuiet = 1; + + use constant FRAME_TO_LR_OFFSET => 16; + use constant MAX_STACK_FRAMES => 25; + + # Read in the task struct, which mirrors struct task_t in Hostboot + # d prefix means "display", i.e. "dstack_ptr" is the display version of + # "stack_ptr". d-prefixed values are not part of task_t + my %task = (); + $task{cpu} = ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{stack_ptr} = ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{dstack_ptr} = sprintf "0x%X", $task{context_t}{stack_ptr}; + $task{context_t}{nip} = ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{dnip} = sprintf "0x%X",$task{context_t}{nip}; + + foreach(my $gpr=0; $gpr<32; ++$gpr) + { + $task{context_t}{"gprs$gpr"} = + ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{"dgprs$gpr"} = + sprintf "0x%X",$task{context_t}{"gprs$gpr"}; + + # For now, only interpret gpr1 as a virtual address having to be + # converted to a physical address. This gives the frame pointer + if($gpr==1) + { + $task{context_t}{"pgprs$gpr"} + = Hostboot::_DebugFrameworkVMM::getPhysicalAddr( + $task{context_t}{"gprs$gpr"}, $vmmDebug, $vmmDisplaySPTE, + $vmmQuiet); + $task{context_t}{"dpgprs$gpr"} = + sprintf "0x%x",$task{context_t}{"pgprs$gpr"} ; + } + } + + $task{context_t}{lr} = ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{dlr} = sprintf "0x%X",$task{context_t}{lr} ; + $task{context_t}{cr} = ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{ctr} = ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{xer} = ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{msr_mask} = ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{fp_context} = ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{tid} = ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{affinity_pinned} = ::read64($i_taskAddr + $off); $off+=8; + $task{context_t}{state} = ::read8( $i_taskAddr + $off); $off+=1; + + # At this point we cached the whole task struct, for any later application. + # Now dump the stack trace + + my $curFrame = $task{context_t}{"pgprs1"} ; + my $curLinkReg = $task{context_t}{lr}; + my ($entryPointName, $symOff) = ::findSymbolWithinAddrRange($curLinkReg); + + my $prefix = makeTabs($i_level); + + print sprintf("%s F[%02d]: %s : 0x%08X\n", + $prefix, 0, $entryPointName,$symOff); + + for(my $i=0; $i<MAX_STACK_FRAMES; ++$i) + { + my $nextFrame = ::read64($curFrame); + my $linkReg = ::read64($curFrame + FRAME_TO_LR_OFFSET); + + $nextFrame = Hostboot::_DebugFrameworkVMM::getPhysicalAddr( + $nextFrame, $vmmDebug, $vmmDisplaySPTE,$vmmQuiet); + if ( ($nextFrame eq Hostboot::_DebugFrameworkVMM::NotFound) + || ($nextFrame eq Hostboot::_DebugFrameworkVMM::NotPresent)) + { + last; + } + + ($entryPointName,$symOff) = ::findSymbolWithinAddrRange($linkReg); + + if($i!=0) + { + if($entryPointName eq "UNKNOWN") + { + last; + } + print sprintf("%s F[%02d]: %s : 0x%08X\n", + $prefix, $i, $entryPointName,$symOff); + } + + $curFrame = $nextFrame; + } + + print $prefix . "\n"; } # Display a list of task objects. sub displayList { - my ($listAddr, $level) = @_; + my ($listAddr, $level, $withBacktrace) = @_; my $firstDisplayed = 0; @@ -86,7 +206,7 @@ sub displayList } # Display tracker object for this node. - displayTracker($node, $level); + displayTracker($node, $level, $withBacktrace); # Follow pointer to the next node. $node = ::read64(PS_TRACKER_PREV_OFFSET + $node); } @@ -94,7 +214,7 @@ sub displayList sub displayTracker { - my ($trackAddr, $level) = @_; + my ($trackAddr, $level, $withBacktrace) = @_; # Read TID. my $tid = ::read16(PS_TRACKER_TID_OFFSET + $trackAddr); @@ -148,6 +268,12 @@ sub displayTracker ::userDisplay makeTabs($level)."-+ TID $tid State: $state$stateExtra\n"; ::userDisplay makeTabs($level)." | $entryPointName [$moduleName]\n"; + # Display stack trace for each task if specifically requested + if($withBacktrace) + { + displayStackTrace($taskAddr, $level+1); + } + # Display list of children tasks. displayList($trackAddr + PS_TRACKER_CHILDREN_LIST_OFFSET, $level + 1); } @@ -171,5 +297,9 @@ sub helpInfo my %info = ( name => "Ps", intro => ["Displays a tree of all tasks and their current state."], + options => { + "with-backtrace" => ["Additionally display backtrace for", + "each task."], + }, ); } diff --git a/src/build/debug/Hostboot/_DebugFramework.pm b/src/build/debug/Hostboot/_DebugFramework.pm index 271f335e1..0c3de0257 100755 --- a/src/build/debug/Hostboot/_DebugFramework.pm +++ b/src/build/debug/Hostboot/_DebugFramework.pm @@ -6,7 +6,9 @@ # # OpenPOWER HostBoot Project # -# COPYRIGHT International Business Machines Corp. 2011,2014 +# Contributors Listed Below - COPYRIGHT 2011,2015 +# [+] International Business Machines Corp. +# # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -50,11 +52,12 @@ our @EXPORT = ( 'callToolModule', 'callToolModuleHelp', 'callToolModuleHelpInfo' 'read64', 'read32', 'read16', 'read8', 'readStr', 'write64', 'write32', 'write16', 'write8', 'translateHRMOR', - 'getIstepList' + 'getIstepList', + 'findSymbolWithinAddrRange', ); our ($parsedSymbolFile, %symbolAddress, %symbolTOC, - %addressSymbol, %symbolSize); + %addressSymbol, %symbolSize, %addrRangeHash); our ($parsedModuleFile, %moduleAddress); our (%toolOpts); @@ -64,6 +67,8 @@ BEGIN %symbolAddress = (); %symbolTOC = (); %addressSymbol = (); + %addrRangeHash = (); + %symbolSize = (); $parsedModuleFile = 0; @@ -283,6 +288,9 @@ sub parseSymbolFile $addressSymbol{$addr} = $name; $addressSymbol{$tocAddr} = $name; + $addrRangeHash{$addr}{name} = $name; + $addrRangeHash{$addr}{size} = $size; + # Use only the first definition of a symbol. # This is useful for constructors where we only want to call the # 'in-charge' version of the constructor. @@ -351,6 +359,46 @@ sub findSymbolByAddress return $addressSymbol{$addr}; } +# @sub findSymbolWithinAddrRange +# +# Searches a syms file for the symbol name for a given address that might not be +# the beginning of the symbol, and returns the symbol name and offset within +# symbol +# +# @param[in] i_addr Address to locate, within some symbol +# @return On success, string name of symbol + offset within symbol. On failure, +# UNKNOWN + 0 +# +sub findSymbolWithinAddrRange +{ + my $i_addr = shift; + + parseSymbolFile(); + + my $found = 0; + my $symName = undef; + my $symOff = 0; + foreach my $sym (sort { $a <=> $b } keys %addrRangeHash) + { + if( ($i_addr >= $sym) + && ($i_addr <= ($sym+$addrRangeHash{$sym}{size})) ) + { + $symName = $addrRangeHash{$sym}{name}; + $symOff = ($i_addr - $sym); + last; + } + + } + + if(!defined $symName) + { + $symName = "UNKNOWN"; + $symOff = 0; + } + + return ($symName , $symOff) ; +} + # @sub parseModuleFile <INTERNAL ONLY> # # Parses through a .modinfo file and populates a hash. diff --git a/src/build/debug/Hostboot/_DebugFrameworkVMM.pm b/src/build/debug/Hostboot/_DebugFrameworkVMM.pm index 1f0d3fdc9..e51e195a3 100755 --- a/src/build/debug/Hostboot/_DebugFrameworkVMM.pm +++ b/src/build/debug/Hostboot/_DebugFrameworkVMM.pm @@ -381,6 +381,13 @@ sub getPhysicalAddr my $vaddr = shift; my $debug = shift; my $displaySPTE = shift; + my $quiet = shift; + + # The quiet flag suppresses some annoying traces when used by other tools + if(!defined $quiet) + { + $quiet = 0; + } my $phyAddr = NotFound; @@ -629,7 +636,10 @@ sub getPhysicalAddr } else { - ::userDisplay (" \nVirtualToPhy: ERROR.. VA Address is out of range.\n"); + if(!$quiet) + { + ::userDisplay (" \nVirtualToPhy: ERROR.. VA Address is out of range.\n"); + } } if ($debug) |