Skip to content

Commit

Permalink
fix for BYTEMAN-205 c/o James Livingstone's patch -- slightly modified
Browse files Browse the repository at this point in the history
  • Loading branch information
adinn committed May 29, 2012
1 parent 78c99c2 commit 9d0a745
Show file tree
Hide file tree
Showing 5 changed files with 369 additions and 23 deletions.
261 changes: 245 additions & 16 deletions agent/src/main/java/org/jboss/byteman/rule/helper/Helper.java
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,7 @@ public void traceStack(String prefix)
}

/**
* print a stack trace to System.out by calling traceStack(prefix, key, 0)
* print a stack trace to the trace stream identified by key by calling traceStack(prefix, key, 0)
*/
public void traceStack(String prefix, Object key)
{
Expand Down Expand Up @@ -1325,6 +1325,119 @@ public void traceStack(String prefix, Object key, int maxFrames)
trace(key, stackTrace);
}

// tracing frames of all stacks

/**
* print trace of all threads' stacks to System.out by calling traceAllStacks(null)
*/
public void traceAllStacks()
{
traceAllStacks(null);
}

/**
* print trace of all threads' stacks to System.out by calling traceAllStacks(prefix, "out")
*/
public void traceAllStacks(String prefix)
{
traceAllStacks(prefix, "out");
}

/**
* print trace of all threads' stacks to the trace stream identified by key by calling traceAllStacks(prefix, key, 0)
*/
public void traceAllStacks(String prefix, Object key)
{
traceAllStacks(prefix, key, 0);
}

/**
* print trace of all threads' stacks to System.out by calling traceAllStacks(null, maxFrames)
*/
public void traceAllStacks(int maxFrames)
{
traceAllStacks(null, maxFrames);
}

/**
* print trace of all threads' stacks to System.out by calling traceAllStacks(prefix, "out", maxFrames)
*/
public void traceAllStacks(String prefix, int maxFrames)
{
traceAllStacks(prefix, "out", maxFrames);
}

/**
* print trace of all threads' stacks to the trace stream identified by key
*
* @param prefix a String to be printed once before printing each line of stack trace. if supplied as null
* then the prefix "Stack trace for thread " + Thread.currentThread().getName() + "\n" is used
* @param key an object identifying the trace stream to which output should be generated
* @param maxFrames the maximum number of frames to print or 0 if no limit should apply
*/
public void traceAllStacks(String prefix, Object key, int maxFrames)
{
trace(key, formatAllStacks(prefix, maxFrames));
}


// trace stack of a specific thread

/**
* print a stack trace of a specific thread to System.out by calling traceThreadStack(threadName, null)
*/
public void traceThreadStack(String threadName)
{
traceThreadStack(threadName, null);
}

/**
* print a stack trace of a specific thread to System.out by calling traceThreadStack(threadName, prefix, "out")
*/
public void traceThreadStack(String threadName, String prefix)
{
traceThreadStack(threadName, prefix, "out");
}

/**
* print a stack trace of a specific thread to the trace stream identified by key by calling traceThreadStack(threadName, prefix, key, 0)
*/
public void traceThreadStack(String threadName, String prefix, Object key)
{
traceThreadStack(threadName, prefix, key, 0);
}

/**
* print a stack trace of a specific thread to System.out by calling traceThreadStack(threadName, null, maxFrames)
*/
public void traceThreadStack(String threadName, int maxFrames)
{
traceThreadStack(threadName, null, maxFrames);
}

/**
* print a stack trace of a specific thread of a specific thread to System.out by calling traceThreadStack(threadName, prefix, "out", maxFrames)
*/
public void traceThreadStack(String threadName, String prefix, int maxFrames)
{
traceThreadStack(threadName, prefix, "out", maxFrames);
}

/**
* print a stack trace to the trace stream identified by key
*
* @param prefix a String to be printed once before printing each line of stack trace. if supplied as null
* then the prefix "Stack trace for thread " + threadName + "\n" is used
* @param key an object identifying the trace stream to which output should be generated
* @param maxFrames the maximum number of frames to print or 0 if no limit should apply
*/
public void traceThreadStack(String threadName, String prefix, Object key, int maxFrames)
{
String stackTrace = formatThreadStack(threadName, prefix, maxFrames);
trace(key, stackTrace);
}


/**
* print all stack frames which match pattern to System.out by calling traceStackMatching(pattern, null)
*/
Expand Down Expand Up @@ -1671,23 +1784,141 @@ public String formatStack(int maxFrames)
public String formatStack(String prefix, int maxFrames)
{
StringBuffer buffer = new StringBuffer();
StackTraceElement[] stack = getStack();
appendStack(buffer, prefix, maxFrames, Thread.currentThread(), getStack());
return buffer.toString();
}


//
// retrieving frames for all threads

/**
* return all stack traces by calling formatAllStacks(null)
*/
public String formatAllStacks()
{
return formatAllStacks(null);
}

/**
* return all stack traces by calling formatAllStacks(prefix, 0)
*/
public String formatAllStacks(String prefix)
{
return formatAllStacks(prefix, 0);
}

/**
* return all stack traces by calling formatAllStacks(null, maxFrames)
*/
public String formatAllStacks(int maxFrames)
{
return formatAllStacks(null, maxFrames);
}

/**
* return all stack traces
*
* @param prefix a String to be printed once before printing each line of stack trace. if supplied as null
* then the prefix "Stack trace for thread " + Thread.currentThread().getName() + "\n" is used
* @param maxFrames the maximum number of frames to print or 0 if no limit should apply
*/

public String formatAllStacks(String prefix, int maxFrames)
{
StringBuffer buffer = new StringBuffer();

Map<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces();
for (Map.Entry<Thread, StackTraceElement[]> entry : stacks.entrySet()) {
appendStack(buffer, prefix, maxFrames, entry.getKey(), entry.getValue());
buffer.append('\n');
}

return buffer.toString();
}

//
// retrieving frames for all threads

/**
* return stack traces of a specific thread by calling formatThreadStack(threadName, null)
*/
public String formatThreadStack(String threadName)
{
return formatThreadStack(threadName, null);
}

/**
* return all stack traces by calling formatThreadStack(threadName, prefix, 0)
*/
public String formatThreadStack(String threadName, String prefix)
{
return formatThreadStack(threadName, prefix, 0);
}

/**
* return all stack traces by calling formatThreadStack(threadName, null, maxFrames)
*/
public String formatThreadStack(String threadName, int maxFrames)
{
return formatThreadStack(threadName, null, maxFrames);
}

/**
* return all stack traces
*
* @param prefix a String to be printed once before printing each line of stack trace. if supplied as null
* then the prefix "Stack trace for thread " + threadName + "\n" is used
* @param maxFrames the maximum number of frames to print or 0 if no limit should apply
*/

public String formatThreadStack(String threadName, String prefix, int maxFrames)
{
StringBuffer buffer = new StringBuffer();
Map<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces();

boolean found = false;

for (Map.Entry<Thread, StackTraceElement[]> entry : stacks.entrySet()) {
Thread thread = entry.getKey();
if (thread.getName().equals(threadName)) {
appendStack(buffer, prefix, maxFrames, thread, entry.getValue());
found = true;
}
}

if (!found) {
buffer.append("Thread ");
buffer.append(threadName);
buffer.append(" not found\n");
}

return buffer.toString();
}

private void appendStack(StringBuffer buffer, String prefix, int maxFrames, Thread thread, StackTraceElement[] stack) {
int l = stack.length;
int i = triggerIndex(stack);
int i;

if (i < 0) {
return "";
}
if (thread == Thread.currentThread()) {
// trim off the byteman trigger parts
i = triggerIndex(stack);
if (i < 0) {
return;
}
} else {
i = 0;
}

if (prefix != null) {
buffer.append(prefix);
} else {
buffer.append("Stack trace for thread ");
buffer.append(thread.getName());
buffer.append('\n');
}

if (prefix != null) {
buffer.append(prefix);
} else {
buffer.append("Stack trace for thread ");
buffer.append(Thread.currentThread().getName());
buffer.append('\n');
}
boolean dotdotdot = false;

if (maxFrames > 0 && (i + maxFrames) < l) {
l = i + maxFrames;
dotdotdot = true;
Expand All @@ -1699,8 +1930,6 @@ public String formatStack(String prefix, int maxFrames)
if (dotdotdot) {
buffer.append(" . . .\n");
}

return buffer.toString();
}

// retrieving caller frames which match a regular expression
Expand Down
39 changes: 39 additions & 0 deletions agent/src/test/java/org/jboss/byteman/tests/Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,45 @@ public void checkOutput(boolean reset)
}
}

// variant of method checkOutput which ensures that all expected
// lines occur in the correct order in the actual output but
// tolerates extra lines in output which are not present in
// expected.
public void checkOutputPartial(boolean reset)
{
String output = getOutput();
String expected = getExpected();
String[] outputLines = output.split("\n");
String[] expectedLines = expected.split("\n");
int outlen = outputLines.length;
int explen = expectedLines.length;
int outidx = 0;
int expidx = 0;
while (expidx < explen) {
boolean matched = false;
while (outidx < outlen && !matched) {
if (outputLines[outidx++].equals(expectedLines[expidx])) {
matched = true;
}
}
if (matched) {
expidx++;
} else {
break;
}
}

if (expidx < explen) {
fail("Test " + name + "failure\n" + "\n<expectedPartial>\n" + expected + "</expectedPartial>\n\n<log>\n" + output +"</log>\n");
} else {
System.out.println("Test " + name + " success");
}

if (reset) {
this.output = new StringBuffer();
this.expected = new StringBuffer();
}
}
public String getOutput()
{
return output.toString();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.jboss.byteman.tests.helpers;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

import org.jboss.byteman.tests.helpertests.TestStackTrace;


public class TestThread extends Thread {
private static CyclicBarrier barrier = new CyclicBarrier(2);

private final boolean trigger;
private final TestStackTrace inner;

public TestThread(TestStackTrace inner, boolean trigger) {
super("TestThread-" + trigger);
this.trigger = trigger;
this.inner = inner;
}

public void run() {
sync();
if (trigger)
fire();
sync();
}

private void sync() {
try {
barrier.await();
} catch (InterruptedException ex) {
return;
} catch (BrokenBarrierException ex) {
return;
}
}

private void fire() {
}
}
Loading

0 comments on commit 9d0a745

Please sign in to comment.