summaryrefslogtreecommitdiffstats
path: root/src/build/debug
diff options
context:
space:
mode:
authorPatrick Williams <iawillia@us.ibm.com>2011-11-21 15:44:52 -0600
committerA. Patrick Williams III <iawillia@us.ibm.com>2011-12-06 16:11:44 -0600
commit7799749ee2db86f4fb66c4a7a69fb9fb0b46334e (patch)
treef50027f990e1db0ea79fabb1b8a9afa1a172dfd1 /src/build/debug
parentc761a76534988071d0988daa77b8c51526e2d9f4 (diff)
downloadtalos-hostboot-7799749ee2db86f4fb66c4a7a69fb9fb0b46334e.tar.gz
talos-hostboot-7799749ee2db86f4fb66c4a7a69fb9fb0b46334e.zip
Interactive debug tool.
- Modify debug fw to support writing data. - Modify debug fw to support clocking model forward. - Add simics environment support for both. - Kernel support to start a task when directed. - Write debug tool to modify kernel structure for debug. Change-Id: Ic001dfd45f91392aefbc9d5096c5344018d5190e Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/518 Tested-by: Jenkins Server Reviewed-by: Andrew J. Geissler <andrewg@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/build/debug')
-rw-r--r--src/build/debug/Hostboot/CallFunc.pm159
-rwxr-xr-xsrc/build/debug/Hostboot/_DebugFramework.pm149
-rwxr-xr-xsrc/build/debug/simics-debug-framework.pl37
-rwxr-xr-xsrc/build/debug/simics-debug-framework.py52
4 files changed, 382 insertions, 15 deletions
diff --git a/src/build/debug/Hostboot/CallFunc.pm b/src/build/debug/Hostboot/CallFunc.pm
new file mode 100644
index 000000000..69cf0130b
--- /dev/null
+++ b/src/build/debug/Hostboot/CallFunc.pm
@@ -0,0 +1,159 @@
+use strict;
+
+package Hostboot::CallFunc;
+use Exporter;
+our @EXPORT_OK = ('main');
+
+use constant CALLFUNC_DEBUG_READY_OFFSET => 0;
+use constant CALLFUNC_DEBUG_RUNNING_OFFSET => CALLFUNC_DEBUG_READY_OFFSET + 1;
+use constant CALLFUNC_DEBUG_COMPLETE_OFFSET => CALLFUNC_DEBUG_READY_OFFSET + 2;
+use constant CALLFUNC_DEBUG_ENTRY_OFFSET => CALLFUNC_DEBUG_READY_OFFSET + 8;
+use constant CALLFUNC_DEBUG_RETVAL_OFFSET => CALLFUNC_DEBUG_ENTRY_OFFSET + 8;
+use constant CALLFUNC_DEBUG_PARMS_OFFSET => CALLFUNC_DEBUG_RETVAL_OFFSET + 8;
+use constant CALLFUNC_DEBUG_PARMS => 8;
+sub main
+{
+ my ($packName,$args) = @_;
+
+ # Parse 'debug' option.
+ my $debug = 0;
+ if (defined $args->{"debug"})
+ {
+ $debug = 1;
+ }
+
+ # Parse function name from options.
+ my $function = "";
+ if (defined $args->{"function"})
+ {
+ $function = $args->{"function"};
+ }
+ elsif (defined $args->{"func"})
+ {
+ $function = $args->{"func"};
+ }
+ else
+ {
+ ::userDisplay "Must give a function to execute.\n";
+ return;
+ }
+
+ # Parse function arguments from options.
+ my @parms = ();
+ my $parms_string = "";
+ if (defined $args->{"arguments"})
+ {
+ $parms_string = $args->{"arguments"}
+ }
+ elsif (defined $args->{"args"})
+ {
+ $parms_string = $args->{"args"};
+ }
+ elsif (defined $args->{"parameters"})
+ {
+ $parms_string = $args->{"parameters"};
+ }
+ elsif (defined $args->{"parms"})
+ {
+ $parms_string = $args->{"parms"};
+ }
+ @parms = map eval, split /,/, $parms_string;
+
+ # Parse 'force' argument.
+ my $force = 0;
+ if (defined $args->{"force"})
+ {
+ $force = 1;
+ }
+
+
+ # Ensure environment is in the proper state for running instructions.
+ if (!::readyForInstructions())
+ {
+ ::userDisplay "Cannot execute while unable to run instructions.\n";
+ return;
+ }
+
+ # Find symbol's TOC address.
+ my $toc = ::findSymbolTOCAddress($function);
+ if ($debug)
+ {
+ ::userDisplay("Symbol $function TOC at $toc.\n");
+ }
+
+ # Find interactive debug structure in the kernel.
+ my $address = (::findSymbolAddress("CpuManager::cv_interactive_debug"))[0];
+
+ if ((not defined $toc) || (not defined $address))
+ {
+ ::userDisplay "Cannot find symbol to execute $function.\n";
+ return;
+ }
+
+ # Verify kernel isn't busy with an outstanding request.
+ if ((0 != ::read16 ($address + CALLFUNC_DEBUG_READY_OFFSET)) &&
+ (0 == $force))
+ {
+ ::userDisplay "Another command is still pending.\n";
+ return;
+ }
+
+ # Write entry point (function TOC) and parameters into debug structure.
+ ::write64(($address + CALLFUNC_DEBUG_ENTRY_OFFSET), $toc);
+ while(($#parms + 1) != CALLFUNC_DEBUG_PARMS)
+ {
+ push @parms, 0x0;
+ }
+ my $i = 0;
+ while ($i != CALLFUNC_DEBUG_PARMS)
+ {
+ if ($debug)
+ {
+ ::userDisplay "Param $i = ".$parms[$i]."\n";
+ }
+ ::write64(($address + CALLFUNC_DEBUG_PARMS_OFFSET + 8*$i), $parms[$i]);
+ $i = $i + 1;
+ }
+
+ # Set ready state.
+ ::write32(($address + CALLFUNC_DEBUG_READY_OFFSET), 0x01000000);
+
+ # Clock forward until kernel marks 'complete' state.
+ my $i = 0;
+ while((0 != ::read16($address + CALLFUNC_DEBUG_READY_OFFSET)) &&
+ (0 == ::read8($address + CALLFUNC_DEBUG_COMPLETE_OFFSET)) &&
+ ($i < 50))
+ {
+ ::executeInstrCycles(100000);
+ $i = $i + 1;
+ if ($debug)
+ {
+ ::userDisplay("Loop $i.\n");
+ }
+ }
+
+ # Verify successful execution ('complete' state set).
+ if (0 == ::read8($address + CALLFUNC_DEBUG_COMPLETE_OFFSET))
+ {
+ ::userDisplay "Command failed to complete.\n";
+ return;
+ }
+
+ # Display return value.
+ ::userDisplay ::read64($address + CALLFUNC_DEBUG_RETVAL_OFFSET)."\n";
+}
+
+sub help
+{
+ ::userDisplay "Tool: CallFunc\n";
+ ::userDisplay "\tInteractively execute a function.\n";
+ ::userDisplay "\n Options:\n";
+ ::userDisplay "\tfunction='function name' - Function to execute.\n";
+ ::userDisplay "\targuments=arg0,arg1... - List of arguments to pass.\n";
+ ::userDisplay "\tforce - Run command even if state doesn't not appear ".
+ "correct.\n";
+ ::userDisplay "\n\tfunc can be used as a short-name for 'function'.\n";
+ ::userDisplay "\targs, parameters, or parms can be used as a short-name ";
+ ::userDisplay "for arguments.\n";
+}
+
diff --git a/src/build/debug/Hostboot/_DebugFramework.pm b/src/build/debug/Hostboot/_DebugFramework.pm
index a55794ebc..fd62127bf 100755
--- a/src/build/debug/Hostboot/_DebugFramework.pm
+++ b/src/build/debug/Hostboot/_DebugFramework.pm
@@ -44,13 +44,16 @@ use Exporter 'import';
our @EXPORT = ( 'callToolModule', 'callToolModuleHelp',
'parseToolOpts', 'determineImagePath',
- 'findSymbolAddress', 'findSymbolByAddress',
+ 'findSymbolAddress', 'findSymbolTOCAddress',
+ 'findSymbolByAddress',
'findModuleByAddress',
'littleendian',
- 'read64', 'read32', 'read16', 'read8', 'readStr'
+ 'read64', 'read32', 'read16', 'read8', 'readStr',
+ 'write64', 'write32', 'write16', 'write8'
);
-our ($parsedSymbolFile, %symbolAddress, %addressSymbol, %symbolSize);
+our ($parsedSymbolFile, %symbolAddress, %symbolTOC,
+ %addressSymbol, %symbolSize);
our ($parsedModuleFile, %moduleAddress);
our (%toolOpts);
@@ -58,6 +61,7 @@ BEGIN
{
$parsedSymbolFile = 0;
%symbolAddress = ();
+ %symbolTOC = ();
%addressSymbol = ();
%symbolSize = ();
@@ -109,18 +113,50 @@ sub callToolModuleHelp
#
# Parses a space deliminated string of options for use by the tool.
#
+# Allows an option to contain spaces itself by wrapping the value in a
+# single quote.
+#
# @param string - Tool option list.
#
-# Example: "foo bar=/abcd/efg" --> { "foo" => 1 , "bar" => "/abcd/efg" }
+# Example:
+# "foo bar=/abcd/efg" --> { "foo" => 1 , "bar" => "/abcd/efg" }
+# "foo='bar nil'" --> { "foo" => "bar nil" }
#
sub parseToolOpts
{
my $toolOptions = shift;
+ my $partial = "";
foreach my $opt (split / /, $toolOptions)
{
+ # Search for a single-quoted word in the option string.
+ if (($opt =~ m/'/) and (not ($opt =~ m/'.*'/)))
+ {
+ # If partial is not empty, this single-quote terminates the string.
+ if ($partial ne "")
+ {
+ $opt = $partial." ".$opt;
+ $partial = "";
+ }
+ # Otherwise, append it to the partial string.
+ else
+ {
+ $partial = $opt;
+ next;
+ }
+ }
+ # Append a word to a partially completed string in progress.
+ elsif ($partial ne "")
+ {
+ $partial = $partial." ".$opt;
+ next;
+ }
+
+ # At this point "opt" is either a free-standing argument set or a
+ # fully complete single-quote deliminated string.
if ($opt =~ m/=/)
{
my ($name,$value) = split /=/, $opt;
+ $value =~ s/^'([^']*)'$/$1/; # Trim out the 's.
$toolOpts{$name} = $value;
}
else
@@ -185,11 +221,26 @@ sub parseSymbolFile
my $addr = hex $2;
my $tocAddr = hex $3;
my $size = hex $4;
+ my $type = $1;
- $symbolAddress{$name} = $addr;
- $symbolSize{$name} = $size;
$addressSymbol{$addr} = $name;
$addressSymbol{$tocAddr} = $name;
+
+ # 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.
+ if (defined $symbolAddress{$name})
+ {
+ next;
+ }
+
+ $symbolAddress{$name} = $addr;
+ if ($type eq "F")
+ {
+ $symbolTOC{$name} = $tocAddr;
+ }
+ $symbolSize{$name} = $size;
+
}
close(FILE);
@@ -212,6 +263,21 @@ sub findSymbolAddress
return ($symbolAddress{$name}, $symbolSize{$name} );
}
+# @sub findSymbolTOCAddress
+# Searches a syms file for the address of the TOC of a symbol.
+#
+# @param string - Symbol to search for.
+# @return TOC address or 'not-defined'.
+#
+sub findSymbolTOCAddress
+{
+ my $name = shift;
+
+ parseSymbolFile();
+
+ return $symbolTOC{$name};
+}
+
# @sub findSymbolByAddress
#
# Searchs a syms file for the symbol name at a particular address.
@@ -393,4 +459,75 @@ sub readStr
return $result;
}
+# @sub write64
+#
+# Write a 64-bit unsigned integer to an address.
+#
+# @param Address to write to.
+# @param Value to write
+#
+sub write64
+{
+ my $addr = shift;
+ my $value = shift;
+
+ $value = pack("Q", $value);
+ if (littleendian()) { $value = reverse($value); }
+
+ my $result = ::writeData($addr, 8, $value);
+}
+
+# @sub write32
+#
+# Write a 32-bit unsigned integer to an address.
+#
+# @param Address to write to.
+# @param Value to write
+#
+sub write32
+{
+ my $addr = shift;
+ my $value = shift;
+
+ $value = pack("L", $value);
+ if (littleendian()) { $value = reverse($value); }
+
+ my $result = ::writeData($addr, 4, $value);
+}
+
+# @sub write16
+#
+# Write a 16-bit unsigned integer to an address.
+#
+# @param Address to write to.
+# @param Value to write
+#
+sub write16
+{
+ my $addr = shift;
+ my $value = shift;
+
+ $value = pack("S", $value);
+ if (littleendian()) { $value = reverse($value); }
+
+ my $result = ::writeData($addr, 2, $value);
+}
+
+# @sub write8
+#
+# Write a 8-bit unsigned integer to an address.
+#
+# @param Address to write to.
+# @param Value to write
+#
+sub write8
+{
+ my $addr = shift;
+ my $value = shift;
+
+ $value = pack("C", $value);
+
+ my $result = ::writeData($addr, 1, $value);
+}
+
__END__
diff --git a/src/build/debug/simics-debug-framework.pl b/src/build/debug/simics-debug-framework.pl
index a255439a9..90a7822a9 100755
--- a/src/build/debug/simics-debug-framework.pl
+++ b/src/build/debug/simics-debug-framework.pl
@@ -106,6 +106,43 @@ sub readData
return "";
}
+# @sub writeData
+# @brief Send a 'write-data' type message to Python.
+sub writeData
+{
+ my $addr = shift;
+ my $size = shift;
+ my $value = shift;
+
+ my $value = unpack("H*", $value);
+ sendIPCMsg("write-data", "$addr,$size,$value");
+
+ return;
+}
+
+# @sub executeInstrCycles
+# @brief Send a 'execute-instrs' type message to Python.
+sub executeInstrCycles
+{
+ my $cycles = shift;
+ sendIPCMsg("execute-instrs", "$cycles");
+}
+
+# @sub readyForInstructions
+# @brief Send a 'ready-for-instr' type message to Python.
+# @returns 0 - Not ready or 1 - Ready
+sub readyForInstructions
+{
+ sendIPCMsg("ready-for-instr", "");
+
+ my ($type, $data) = recvIPCMsg();
+ if ("1" eq $data)
+ {
+ return 1;
+ }
+ return 0;
+}
+
# Image path global.
my $imgPath = "";
sub getImgPath
diff --git a/src/build/debug/simics-debug-framework.py b/src/build/debug/simics-debug-framework.py
index 9cbfe8090..dcd05cee1 100755
--- a/src/build/debug/simics-debug-framework.py
+++ b/src/build/debug/simics-debug-framework.py
@@ -86,17 +86,19 @@ class DebugFrameworkProcess:
process = ""; # subprocess object.
tool = ""; # string - tool module name.
toolOptions = ""; # string - tool options
- usage = None; # mode - Usage output instead of Execution.
+ outputToString = None; # mode - String output instead of STDOUT.
imgPath = "./"; # Image dir path override.
result = ""; # Result string for Usage-mode.
outputFile = None; # Output file for results in addition to STDOUT
def __init__(self, tool = "Printk", toolOptions = "",
- usage = None, imgPath = "./",outputFile = None):
+ outputToString = None, usage = None,
+ imgPath = "./",outputFile = None):
# Determine sub-process arguments.
process_args = ["./simics-debug-framework.pl"];
if (usage): # Pass --usage if Usage mode selected.
process_args = process_args + [ "--usage" ];
+ outputToString = True;
# Spawn sub-process
self.process = subprocess.Popen(process_args,
@@ -104,7 +106,7 @@ class DebugFrameworkProcess:
# Update instance variables.
self.tool = tool;
self.toolOptions = toolOptions;
- self.usage = usage;
+ self.outputToString = outputToString;
self.imgPath = imgPath;
self.outputFile = open(outputFile, 'w') if outputFile else None;
@@ -129,7 +131,7 @@ class DebugFrameworkProcess:
# Display string (or save to result in Usage mode).
def display(self,data):
- if (self.usage):
+ if (self.outputToString):
self.result += data
else:
print data,
@@ -137,10 +139,10 @@ class DebugFrameworkProcess:
print >>self.outputFile,data,
# Read data from memory.
- # This message has data of the format "0xADDRESS,0xSIZE".
+ # This message has data of the format "0dADDRESS,0dSIZE".
def read_data(self,data):
pattern = re.compile("([0-9]+),([0-9]+)")
- match = pattern.search(data);
+ match = pattern.search(data)
addr = int(match.group(1))
size = int(match.group(2))
@@ -148,6 +150,32 @@ class DebugFrameworkProcess:
data = "".join(map(chr, conf.phys_mem.memory[[addr , addr+size-1]]))
self.sendMsg("data-response", data)
+ # Write data to memory.
+ # This message has data of the format "0dADDR,0dSIZE,hDATA".
+ def write_data(self,data):
+ pattern = re.compile("([0-9]+),([0-9]+),([0-9A-Fa-f]+)")
+ match = pattern.search(data)
+
+ addr = int(match.group(1))
+ size = int(match.group(2))
+ data = map(ord, match.group(3).decode("hex"));
+
+ conf.phys_mem.memory[[addr, addr+size-1]] = data;
+
+ # Clock forward the model.
+ # This message had data of the format "0dCYCLES".
+ def execute_instrs(self,data):
+ pattern = re.compile("([0-9]+)")
+ match = pattern.search(data)
+
+ cycles = int(match.group(1))
+
+ if (not SIM_simics_is_running()):
+ SIM_continue(cycles)
+
+ def ready_for_instr(self,data):
+ self.sendMsg("data-response", "0" if SIM_simics_is_running() else "1")
+
# Get tool module name.
def get_tool(self,data):
self.sendMsg("data-response", self.tool)
@@ -168,15 +196,20 @@ class DebugFrameworkProcess:
# @param usage - Usage mode or Execute mode.
# @param imgPath - Image path override.
def run_hb_debug_framework(tool = "Printk", toolOpts = "",
- usage = None, imgPath = "./", outputFile = None):
+ outputToString = None, usage = None,
+ imgPath = "./", outputFile = None):
# Create debug sub-process.
- fp = DebugFrameworkProcess(tool,toolOpts,usage,imgPath,outputFile)
+ fp = DebugFrameworkProcess(tool,toolOpts,outputToString,
+ usage,imgPath,outputFile)
# Read / handle messages until there are no more.
msg = fp.recvMsg()
while msg[0] != "":
operations = { "display" : DebugFrameworkProcess.display,
"read-data" : DebugFrameworkProcess.read_data,
+ "write-data" : DebugFrameworkProcess.write_data,
+ "execute-instrs" : DebugFrameworkProcess.execute_instrs,
+ "ready-for-instr" : DebugFrameworkProcess.ready_for_instr,
"get-tool" : DebugFrameworkProcess.get_tool,
"get-tool-options" : DebugFrameworkProcess.get_tool_options,
"get-img-path" : DebugFrameworkProcess.get_img_path,
@@ -186,10 +219,11 @@ def run_hb_debug_framework(tool = "Printk", toolOpts = "",
msg = fp.recvMsg()
# If in Usage mode, return result string.
- if (usage):
+ if (usage or outputToString):
return fp.result
return None
+
# @fn register_hb_debug_framework_tools
# @brief Create a simics command wrapper for each debug tool module.
def register_hb_debug_framework_tools():
OpenPOWER on IntegriCloud