This is the mail archive of the frysk@sources.redhat.com mailing list for the frysk project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

One frysk-core patch to add breakpoint support in PPC64.


hi,

Based on the codes submitted by Mark, we do one patch to add the
breakpoint support in PPC64. At the meanwhile, we find some attributes
in Breakpoint.java are dependent on ISA, so we do some modifications on
Breakpoint.java and TaskState.java.

2006-08-22  Yong Zheng  <zhengyo@cn.ibm.com>

	* frysk/proc/Isa.java (getBpInstruction): New method to get the
	instruction to replace the original instruction for breakpoint.
	(getBreakpointAddress): New method to get the breakpoint's
	address after hitting the breakpoint.
	* frysk/proc/IsaIA32.java (getBpInstruction): New method to
	implement the Isa interface.
	(getBreakpointAddress): New method to implement the Isa
	interface.
	(BREAKPOINT_INSTRUCTION): New attribute to store the breakpoint
	instruction on IA32.
	* frysk/proc/IsaEMT64.java (getBpInstruction): New method to
	implement the Isa interface.
	(getBreakpointAddress): New method to implement the Isa
	interface.
	(BREAKPOINT_INSTRUCTION): New attribute to store the breakpoint
	instruction on EMT64.
	* frysk/proc/IsaPPC.java (getBpInstruction): New method to
	implement the Isa interface.
	(getBreakpointAddress): New method to implement the Isa
	interface.
	* frysk/proc/IsaPPC64.java (getBpInstruction): New method to
	implement the Isa interface.
	(getBreakpointAddress): New method to implement the Isa
	interface.
	(BREAKPOINT_INSTRUCTION): New attribute to store the breakpoint
	instruction on PPC64.

	* frysk/proc/Breakpoint.java (TRAP): Move it to
	BREAKPOINT_INSTRUCTION in specific ISA.
	(origInstruction): Renamed from orig.
	(set): Replace the original instruction with breakpoint
	instruction got from ISA. 
	(reset): Restore the original instruction.
	(prepareStep): Add support for PPC64.

	* frysk/proc/TaskState.java (Running.handleTrappedEvent): Get
	breakpoint address according to task's ISA.

	*frysk/pkglibexecdir/funit-breakpoint.c (main): Get the function
	address instead of address of function descriptor on PPC64.

Rebuild frysk on X86/X86-64/PPC64 based on the cvs head(08-22) and
tested. Please review and commit!  Thanks!

Best regards
Yong Zheng
Index: frysk-core/frysk/proc/Isa.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/Isa.java,v
retrieving revision 1.10
diff -u -r1.10 Isa.java
--- frysk-core/frysk/proc/Isa.java	8 Aug 2006 08:27:11 -0000	1.10
+++ frysk-core/frysk/proc/Isa.java	22 Aug 2006 03:19:06 -0000
@@ -57,7 +57,26 @@
 
   int getWordSize();
   ByteOrder getByteOrder();
-
+  
+  /**
+   * Get the breakpoint instruction.
+   * 
+   * @return bytes[] the instruction of the ISA.
+   */
+  byte[] getBpInstruction();
+ 
+  /**
+   * Get the true breakpoint address according to PC register after hitting 
+   * one breakpoint set in task. Different arch will take different action
+   * when it hit one breakpoint. In X86/X86-64, the length of the breakpoint
+   * instruction will be added to the PC register.However in PPC64, the PC 
+   * register's value will remain unchanged. 
+   * 
+   * The function will take different actions according to task's ISA.
+   * 
+   */
+  long getBreakpointAddress(Task task);
+  
   // int addressSize;
   // InstructionSet;
   // FloatingPointFormat;
Index: frysk-core/frysk/proc/TaskState.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/TaskState.java,v
retrieving revision 1.102
diff -u -r1.102 TaskState.java
--- frysk-core/frysk/proc/TaskState.java	15 Aug 2006 17:16:58 -0000	1.102
+++ frysk-core/frysk/proc/TaskState.java	22 Aug 2006 03:19:56 -0000
@@ -1031,7 +1031,7 @@
 	long address;
 	try
 	  {
-	    address = task.getIsa().pc(task) - 1;
+	    address = task.getIsa().getBreakpointAddress(task);
 	  }
 	catch (TaskException tte)
 	  {
Index: frysk-core/frysk/proc/Breakpoint.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/Breakpoint.java,v
retrieving revision 1.1
diff -u -r1.1 Breakpoint.java
--- frysk-core/frysk/proc/Breakpoint.java	15 Aug 2006 17:16:58 -0000	1.1
+++ frysk-core/frysk/proc/Breakpoint.java	22 Aug 2006 03:20:37 -0000
@@ -60,13 +60,8 @@
   // Static cache of installed break points.
   private static HashMap installed = new HashMap();
 
-  // The instruction that will generate a trap signal.  Happens to be
-  // the same for x86 and x86_64, but will depend on the Isa in use
-  // for other architectures.
-  private static final byte TRAP = (byte) 0xcc;
-
-  // The original instruction at the location we replaced with TRAP.
-  private byte orig;
+  // The original instruction at the location we replaced with BREAKPOINT_INSTRUCTION.
+  private byte[] origInstruction;
 
   /**
    * Private constructor called by create to record address and
@@ -115,20 +110,61 @@
 	  throw new IllegalStateException("Already installed: " + this);
 
 	installed.put(this, this);
-	set(task);
+    
+        try
+          {
+            set(task);
+          }
+	catch (TaskException e)
+          {
+            // Throw RuntimeException for the following two reasons:
+            // 1st) TaskException is thrown out by Task.getIsa() in set(), if the
+            //      frysk works well, the exception shouldnot be thrown out. If we
+            //      get one, it mean some runtime exception occurs.
+            // 2nd) This method will be called in TaskState.Running.handleStoppedEvent().
+            //      There's no exception hanling there. So we have to throw one Runtime-
+            //      Exception here.
+            throw new RuntimeException(e);
+          }
       }
   }
 
   /**
    * Actually sets the breakpoint.
    */
-  private void set(Task task)
+  private void set(Task task) throws TaskException
   {
-    ByteBuffer buffer = task.memory;
+    int len = 0;
+    ByteBuffer buffer = null;
+    byte[] bpInstruction = null;
+    
+    if (null == task)
+      return;
+    
+    buffer = task.memory;
     buffer.position(address);
-    orig = buffer.getByte();
+    
+    try
+      {
+        bpInstruction = task.getIsa().getBpInstruction();
+      }
+    catch (TaskException e)
+      {
+        throw e;
+      }
+    
+    len = bpInstruction.length;
+    if (len <= 0)
+      throw new IllegalStateException("Breakpoint instruction is invalid: " + 
+                                      this);
+    
+    origInstruction = new byte[len];
+    for (int index = 0; index < len; index++)
+      origInstruction[index] = buffer.getByte();
+    
     buffer.position(address);
-    buffer.putByte(TRAP);
+    for (int index = 0; index < len; index++)
+      buffer.putByte(bpInstruction[index]);
   }
 
   /**
@@ -151,9 +187,18 @@
    */
   private void reset(Task task)
   {
-    ByteBuffer buffer = task.memory;
+    int len = 0;
+    ByteBuffer buffer = null;
+    
+    if (null == task)
+      return;
+    
+    buffer = task.memory;
     buffer.position(address);
-    buffer.putByte(orig);
+    
+    len = origInstruction.length;
+    for (int index = 0; index < len; index++)
+      buffer.putByte(origInstruction[index]);
   }
 
   // XXX Prepare step and step done are not multi-task safe.
@@ -176,6 +221,8 @@
       pc = isa.getRegisterByName("eip");
     else if (isa instanceof LinuxEMT64)
       pc = isa.getRegisterByName("rip");
+    else if (isa instanceof LinuxPPC64)
+      pc = isa.getRegisterByName("nip");
     else
       throw new RuntimeException("unsupported architecture: " + isa);
     pc.put(task, address);
@@ -192,8 +239,23 @@
   {
     if (! stepping)
       throw new IllegalStateException("Not stepping");
-
-    set(task);
+          
+    try
+      {
+        set(task);
+      }
+    catch (TaskException e)
+      {
+        // Throw RuntimeException for the following two reasons:
+        // 1st) TaskException is thrown out by Task.getIsa() in set(), if the
+        //      frysk works well, the exception shouldnot be thrown out. If we
+        //      get one, it mean some runtime exception occurs.
+        // 2nd) setDone() will be called in TaskState.Running.handleTrappedEvent().
+        //      There's no exception hanling there. So we have to throw one Runtime-
+        //      Exception here.
+        throw new RuntimeException(e);
+      }
+    
     stepping = false;
   }
 
Index: frysk-core/frysk/proc/IsaIA32.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/IsaIA32.java,v
retrieving revision 1.2
diff -u -r1.2 IsaIA32.java
--- frysk-core/frysk/proc/IsaIA32.java	8 Aug 2006 08:27:11 -0000	1.2
+++ frysk-core/frysk/proc/IsaIA32.java	22 Aug 2006 03:21:42 -0000
@@ -48,6 +48,8 @@
   static final int I387_OFFSET = 18*4;
   static final int DBG_OFFSET = 63 * 4;
 
+  private static final byte[] BREAKPOINT_INSTRUCTION = { (byte)0xcc };
+  
   static class IA32Register extends Register
   {
     IA32Register(String name, int wordOffset)
@@ -121,6 +123,46 @@
   {
     return ByteOrder.LITTLE_ENDIAN;
   }
+  
+  /**
+   * Get the breakpoint instruction.
+   * 
+   * @return bytes[] the instruction of the ISA or null if TRAP is not 
+   *         initialized.
+   */
+  public final byte[] getBpInstruction()
+  {
+    byte[] instruction = null;
+    
+    if (null == IsaIA32.BREAKPOINT_INSTRUCTION)
+      return null;
+    
+    instruction = new byte[IsaIA32.BREAKPOINT_INSTRUCTION.length];
+    
+    System.arraycopy(IsaIA32.BREAKPOINT_INSTRUCTION, 0, 
+                     instruction, 0, IsaIA32.BREAKPOINT_INSTRUCTION.length);
+    
+    return instruction;
+  }
+  
+  /**
+   * Get the true breakpoint address according to PC register after hitting 
+   * one breakpoint set in task. In X86, the length of breakpoint instruction
+   * will be added to the PC register's value. So the true breakpoint address
+   * is the PC register's value minus the length of breakpoint. 
+   */
+  public long getBreakpointAddress(Task task)
+  {
+    long pcValue = 0;
+    
+    if (null == task)
+      return pcValue;
+    
+    pcValue = this.pc(task);
+    pcValue = pcValue - IsaIA32.BREAKPOINT_INSTRUCTION.length;
+    
+    return pcValue;
+  }
 }
 
     
Index: frysk-core/frysk/proc/IsaEMT64.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/IsaEMT64.java,v
retrieving revision 1.2
diff -u -r1.2 IsaEMT64.java
--- frysk-core/frysk/proc/IsaEMT64.java	8 Aug 2006 08:27:11 -0000	1.2
+++ frysk-core/frysk/proc/IsaEMT64.java	22 Aug 2006 03:22:15 -0000
@@ -48,6 +48,8 @@
   static final int FPREGS_OFFSET = 28 * 8;
   static final int DBG_OFFSET = 32 * 8;
 
+  private static final byte[] BREAKPOINT_INSTRUCTION = { (byte)0xcc };
+  
   static class EMT64Register extends Register
   {
     EMT64Register(String name, int wordOffset)
@@ -117,4 +119,44 @@
   {
     return ByteOrder.LITTLE_ENDIAN;
   }
+  
+  /**
+   * Get the breakpoint instruction of the specific ISA.
+   * 
+   * @return bytes[] the instruction of the ISA or null if TRAP is not 
+   *         initialized.
+   */
+  public final byte[] getBpInstruction()
+  {
+    byte[] instruction = null;
+    
+    if (null == IsaEMT64.BREAKPOINT_INSTRUCTION)
+      return null;
+    
+    instruction = new byte[IsaEMT64.BREAKPOINT_INSTRUCTION.length];
+    
+    System.arraycopy(IsaEMT64.BREAKPOINT_INSTRUCTION, 0, 
+                     instruction, 0, IsaEMT64.BREAKPOINT_INSTRUCTION.length);
+    
+    return instruction;
+  }
+  
+  /**
+   * Get the true breakpoint address according to PC register after hitting 
+   * one breakpoint set in task. In X86-64, the length of breakpoint instruction
+   * will be added to the PC register's value. So the true breakpoint address
+   * is the PC register's value minus the length of breakpoint. 
+   */
+  public long getBreakpointAddress(Task task)
+  {
+    long pcValue = 0;
+    
+    if (null == task)
+      return pcValue;
+
+    pcValue = this.pc(task);
+    pcValue = pcValue - IsaEMT64.BREAKPOINT_INSTRUCTION.length;
+    
+    return pcValue;
+  }
 }
Index: frysk-core/frysk/proc/IsaPPC64.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/IsaPPC64.java,v
retrieving revision 1.1
diff -u -r1.1 IsaPPC64.java
--- frysk-core/frysk/proc/IsaPPC64.java	4 Aug 2006 09:07:42 -0000	1.1
+++ frysk-core/frysk/proc/IsaPPC64.java	22 Aug 2006 03:23:07 -0000
@@ -46,6 +46,11 @@
 
   private LinkedHashMap registerMap = new LinkedHashMap();
 
+  // the illegal instruction for ppc64: 0x7d821008.
+  // the default order is BIG_ENDIAN
+  private static byte[] BREAKPOINT_INSTRUCTION = { (byte)0x7d, (byte)0x82, 
+                                                   (byte)0x10, (byte)0x08 };
+  
   IsaPPC64()
   {
     for (int i = 0; i < gpr.length; i++) 
@@ -91,4 +96,42 @@
   {
     return ByteOrder.BIG_ENDIAN;
   }
+  
+  /**
+   * Get the breakpoint instruction of the PPC64 platform.
+   * 
+   * @return bytes[] the breakpoint instruction
+   */
+  public final byte[] getBpInstruction()
+  {
+    byte[] instruction = null;
+    
+    if (null == IsaPPC64.BREAKPOINT_INSTRUCTION)
+      return null;
+    
+    instruction = new byte[IsaPPC64.BREAKPOINT_INSTRUCTION.length];
+    
+    System.arraycopy(IsaPPC64.BREAKPOINT_INSTRUCTION, 0, 
+                     instruction, 0, IsaPPC64.BREAKPOINT_INSTRUCTION.length);
+    
+    return instruction;
+  }
+  
+  /**
+   * Get the true breakpoint address according to PC register after hitting 
+   * one breakpoint set in task. In PPC64, the PC register's value will 
+   * remain unchanged. 
+   * 
+   */
+  public final long getBreakpointAddress(Task task)
+  {
+    long pcValue = 0;
+        
+    if (null == task)
+      return pcValue;
+
+    pcValue = this.pc(task);
+    
+    return pcValue;
+  }
 }
Index: frysk-core/frysk/proc/IsaPPC.java
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/proc/IsaPPC.java,v
retrieving revision 1.1
diff -u -r1.1 IsaPPC.java
--- frysk-core/frysk/proc/IsaPPC.java	4 Aug 2006 09:07:42 -0000	1.1
+++ frysk-core/frysk/proc/IsaPPC.java	22 Aug 2006 03:24:39 -0000
@@ -91,4 +91,22 @@
   {
     return ByteOrder.BIG_ENDIAN;
   }
+  
+  /**
+   * Not support now.
+   * 
+   * @return bytes[] the instruction of the ISA.
+   */
+  public byte[] getBpInstruction()
+  {
+    return null;
+  }
+  
+  /**
+   * Not support now.
+   */
+  public long getBreakpointAddress(Task task)
+  {
+   return 0; 
+  }
 }
Index: frysk-core/frysk/pkglibexecdir/funit-breakpoints.c
===================================================================
RCS file: /cvs/frysk/frysk-core/frysk/pkglibexecdir/funit-breakpoints.c,v
retrieving revision 1.1
diff -u -r1.1 funit-breakpoints.c
--- frysk-core/frysk/pkglibexecdir/funit-breakpoints.c	15 Aug 2006 17:16:58 -0000	1.1
+++ frysk-core/frysk/pkglibexecdir/funit-breakpoints.c	22 Aug 2006 03:27:19 -0000
@@ -77,9 +77,18 @@
   bp2 = 0;
 
   // Tell the tester the addresses of the functions to put breakpoints on.
-  // XXX add ppc case
+  // There's great difference to get the addresses of one function between 
+  // PPC64 and other platform(such as X86/X86_64). What we get through the
+  // the form "&function_name" is the address of function descriptor but 
+  // not the true entry address of the function.
+#ifndef __powerpc64__
   printf("%p\n", &first_breakpoint_function);
   printf("%p\n", &second_breakpoint_function);
+#else
+  printf("%p\n", (void *)(*(long *)&first_breakpoint_function));
+  printf("%p\n", (void *) (*(long *)&second_breakpoint_function));
+#endif
+
   fflush(stdout);
 
   // Go round and round.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]