summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rw-r--r--util/statetrace/arch/tracechild_sparc.cc172
-rw-r--r--util/statetrace/arch/tracechild_sparc.hh8
-rw-r--r--util/term/term.c283
-rwxr-xr-xutil/tracediff62
4 files changed, 316 insertions, 209 deletions
diff --git a/util/statetrace/arch/tracechild_sparc.cc b/util/statetrace/arch/tracechild_sparc.cc
index 378de0865..bad81b647 100644
--- a/util/statetrace/arch/tracechild_sparc.cc
+++ b/util/statetrace/arch/tracechild_sparc.cc
@@ -47,10 +47,10 @@ string SparcTraceChild::regNames[numregs] = {
//Input registers
"i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7",
//Floating point
- "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
- "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
- "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
- "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+ "f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14",
+ "f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30",
+ "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46",
+ "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",
//Miscelaneous
"fsr", "fprs", "pc", "npc", "y", "cwp", "pstate", "asi", "ccr"};
@@ -98,37 +98,37 @@ int64_t getRegs(regs & myregs, fpu & myfpu,
case SparcTraceChild::I7: return inputs[7];
//Floating point
case SparcTraceChild::F0: return myfpu.f_fpstatus.fpu_fr[0];
- case SparcTraceChild::F1: return myfpu.f_fpstatus.fpu_fr[1];
- case SparcTraceChild::F2: return myfpu.f_fpstatus.fpu_fr[2];
- case SparcTraceChild::F3: return myfpu.f_fpstatus.fpu_fr[3];
- case SparcTraceChild::F4: return myfpu.f_fpstatus.fpu_fr[4];
- case SparcTraceChild::F5: return myfpu.f_fpstatus.fpu_fr[5];
- case SparcTraceChild::F6: return myfpu.f_fpstatus.fpu_fr[6];
- case SparcTraceChild::F7: return myfpu.f_fpstatus.fpu_fr[7];
- case SparcTraceChild::F8: return myfpu.f_fpstatus.fpu_fr[8];
- case SparcTraceChild::F9: return myfpu.f_fpstatus.fpu_fr[9];
- case SparcTraceChild::F10: return myfpu.f_fpstatus.fpu_fr[10];
- case SparcTraceChild::F11: return myfpu.f_fpstatus.fpu_fr[11];
- case SparcTraceChild::F12: return myfpu.f_fpstatus.fpu_fr[12];
- case SparcTraceChild::F13: return myfpu.f_fpstatus.fpu_fr[13];
- case SparcTraceChild::F14: return myfpu.f_fpstatus.fpu_fr[14];
- case SparcTraceChild::F15: return myfpu.f_fpstatus.fpu_fr[15];
- case SparcTraceChild::F16: return myfpu.f_fpstatus.fpu_fr[16];
- case SparcTraceChild::F17: return myfpu.f_fpstatus.fpu_fr[17];
- case SparcTraceChild::F18: return myfpu.f_fpstatus.fpu_fr[18];
- case SparcTraceChild::F19: return myfpu.f_fpstatus.fpu_fr[19];
- case SparcTraceChild::F20: return myfpu.f_fpstatus.fpu_fr[20];
- case SparcTraceChild::F21: return myfpu.f_fpstatus.fpu_fr[21];
- case SparcTraceChild::F22: return myfpu.f_fpstatus.fpu_fr[22];
- case SparcTraceChild::F23: return myfpu.f_fpstatus.fpu_fr[23];
- case SparcTraceChild::F24: return myfpu.f_fpstatus.fpu_fr[24];
- case SparcTraceChild::F25: return myfpu.f_fpstatus.fpu_fr[25];
- case SparcTraceChild::F26: return myfpu.f_fpstatus.fpu_fr[26];
- case SparcTraceChild::F27: return myfpu.f_fpstatus.fpu_fr[27];
- case SparcTraceChild::F28: return myfpu.f_fpstatus.fpu_fr[28];
- case SparcTraceChild::F29: return myfpu.f_fpstatus.fpu_fr[29];
- case SparcTraceChild::F30: return myfpu.f_fpstatus.fpu_fr[30];
- case SparcTraceChild::F31: return myfpu.f_fpstatus.fpu_fr[31];
+ case SparcTraceChild::F2: return myfpu.f_fpstatus.fpu_fr[1];
+ case SparcTraceChild::F4: return myfpu.f_fpstatus.fpu_fr[2];
+ case SparcTraceChild::F6: return myfpu.f_fpstatus.fpu_fr[3];
+ case SparcTraceChild::F8: return myfpu.f_fpstatus.fpu_fr[4];
+ case SparcTraceChild::F10: return myfpu.f_fpstatus.fpu_fr[5];
+ case SparcTraceChild::F12: return myfpu.f_fpstatus.fpu_fr[6];
+ case SparcTraceChild::F14: return myfpu.f_fpstatus.fpu_fr[7];
+ case SparcTraceChild::F16: return myfpu.f_fpstatus.fpu_fr[8];
+ case SparcTraceChild::F18: return myfpu.f_fpstatus.fpu_fr[9];
+ case SparcTraceChild::F20: return myfpu.f_fpstatus.fpu_fr[10];
+ case SparcTraceChild::F22: return myfpu.f_fpstatus.fpu_fr[11];
+ case SparcTraceChild::F24: return myfpu.f_fpstatus.fpu_fr[12];
+ case SparcTraceChild::F26: return myfpu.f_fpstatus.fpu_fr[13];
+ case SparcTraceChild::F28: return myfpu.f_fpstatus.fpu_fr[14];
+ case SparcTraceChild::F30: return myfpu.f_fpstatus.fpu_fr[15];
+ case SparcTraceChild::F32: return myfpu.f_fpstatus.fpu_fr[16];
+ case SparcTraceChild::F34: return myfpu.f_fpstatus.fpu_fr[17];
+ case SparcTraceChild::F36: return myfpu.f_fpstatus.fpu_fr[18];
+ case SparcTraceChild::F38: return myfpu.f_fpstatus.fpu_fr[19];
+ case SparcTraceChild::F40: return myfpu.f_fpstatus.fpu_fr[20];
+ case SparcTraceChild::F42: return myfpu.f_fpstatus.fpu_fr[21];
+ case SparcTraceChild::F44: return myfpu.f_fpstatus.fpu_fr[22];
+ case SparcTraceChild::F46: return myfpu.f_fpstatus.fpu_fr[23];
+ case SparcTraceChild::F48: return myfpu.f_fpstatus.fpu_fr[24];
+ case SparcTraceChild::F50: return myfpu.f_fpstatus.fpu_fr[25];
+ case SparcTraceChild::F52: return myfpu.f_fpstatus.fpu_fr[26];
+ case SparcTraceChild::F54: return myfpu.f_fpstatus.fpu_fr[27];
+ case SparcTraceChild::F56: return myfpu.f_fpstatus.fpu_fr[28];
+ case SparcTraceChild::F58: return myfpu.f_fpstatus.fpu_fr[29];
+ case SparcTraceChild::F60: return myfpu.f_fpstatus.fpu_fr[30];
+ case SparcTraceChild::F62: return myfpu.f_fpstatus.fpu_fr[31];
//Miscelaneous
case SparcTraceChild::FSR: return myfpu.f_fpstatus.Fpu_fsr;
case SparcTraceChild::FPRS: return myregs.r_fprs;
@@ -188,46 +188,110 @@ bool SparcTraceChild::step()
//being breakpointed should be word (64bit) aligned, and that both the
//next instruction and the instruction after that need to be breakpointed
//so that annulled branches will still stop as well.
+
+ /*
+ * Useful constants
+ */
const static uint64_t breakInst = 0x91d02001;
const static uint64_t breakWord = breakInst | (breakInst << 32);
- const static uint64_t lowMask = (uint64_t)(0xFFFFFFFF);
+ const static uint64_t lowMask = 0xFFFFFFFFULL;
const static uint64_t highMask = lowMask << 32;
+
+ /*
+ * storage for the original contents of the child process's memory
+ */
uint64_t originalInst, originalAnnulInst;
+
+ /*
+ * Get information about where the process is and is headed next.
+ */
+ uint64_t currentPC = getRegVal(PC);
+ bool unalignedPC = currentPC & 7;
+ uint64_t alignedPC = currentPC & (~7);
uint64_t nextPC = getRegVal(NPC);
- bool unaligned = nextPC & 7;
- uint64_t alignedPC = nextPC & (~7);
- originalInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC, 0);
- if(unaligned)
+ bool unalignedNPC = nextPC & 7;
+ uint64_t alignedNPC = nextPC & (~7);
+
+ /*
+ * Store the original contents of the child process's memory
+ */
+ originalInst = ptrace(PTRACE_PEEKTEXT, pid, alignedNPC, 0);
+ //Save a ptrace call if we can
+ if(unalignedNPC)
{
- originalAnnulInst = ptrace(PTRACE_PEEKTEXT, pid, alignedPC+8, 0);
+ originalAnnulInst = ptrace(PTRACE_PEEKTEXT, pid, alignedNPC+8, 0);
}
- uint64_t newInst;
- if(unaligned)
+
+ /*
+ * Prepare breakpointed copies of child processes memory
+ */
+ uint64_t newInst, newAnnulInst;
+ //If the current instruction is in the same word as the npc
+ if(alignedPC == alignedNPC)
{
- newInst = (originalInst & highMask) | (breakInst << 0);
- if(ptrace(PTRACE_POKETEXT, pid, alignedPC, newInst) != 0)
- cerr << "Poke failed" << endl;
- newInst = (originalAnnulInst & lowMask) | (breakInst << 32);
- if(ptrace(PTRACE_POKETEXT, pid, alignedPC+8, newInst) != 0)
- cerr << "Poke failed" << endl;
+ //Make sure we only replace the other part
+ if(unalignedPC)
+ newInst = (originalInst & lowMask) | (breakWord & highMask);
+ else
+ newInst = (originalInst & highMask) | (breakWord & lowMask);
+ }
+ else
+ {
+ //otherwise replace the whole thing
+ newInst = breakWord;
+ }
+ //If the current instruction is in the same word as the word after
+ //the npc
+ if(alignedPC == alignedNPC+8)
+ {
+ //Make sure we only replace the other part
+ if(unalignedPC)
+ newAnnulInst = (originalAnnulInst & lowMask) | (breakWord & highMask);
+ else
+ newAnnulInst = (originalAnnulInst & highMask) | (breakWord & lowMask);
}
else
{
- if(ptrace(PTRACE_POKETEXT, pid, alignedPC, breakWord) != 0)
+ //otherwise replace the whole thing
+ newAnnulInst = breakWord;
+ }
+
+ /*
+ * Stuff the breakpoint instructions into the child's address space.
+ */
+ //Replace the word at npc
+ if(ptrace(PTRACE_POKETEXT, pid, alignedNPC, newInst) != 0)
+ cerr << "Poke failed" << endl;
+ //Replace the next word, if necessary
+ if(unalignedNPC)
+ {
+ if(ptrace(PTRACE_POKETEXT, pid, alignedNPC+8, newAnnulInst) != 0)
cerr << "Poke failed" << endl;
}
+
+ /*
+ * Restart the child process
+ */
//Note that the "addr" parameter is supposed to be ignored, but in at
//least one version of the kernel, it must be 1 or it will set what
//pc to continue from
- if(ptrace(PTRACE_CONT, pid, /*nextPC - 4*/ 1, 0) != 0)
+ if(ptrace(PTRACE_CONT, pid, 1, 0) != 0)
cerr << "Cont failed" << endl;
doWait();
+
+ /*
+ * Update our record of the child's state
+ */
update(pid);
- if(ptrace(PTRACE_POKETEXT, pid, alignedPC, originalInst) != 0)
+
+ /*
+ * Put back the original contents of the childs address space
+ */
+ if(ptrace(PTRACE_POKETEXT, pid, alignedNPC, originalInst) != 0)
cerr << "Repoke failed" << endl;
- if(unaligned)
+ if(unalignedNPC)
{
- if(ptrace(PTRACE_POKETEXT, pid, alignedPC+8, originalAnnulInst) != 0)
+ if(ptrace(PTRACE_POKETEXT, pid, alignedNPC+8, originalAnnulInst) != 0)
cerr << "Repoke failed" << endl;
}
return true;
diff --git a/util/statetrace/arch/tracechild_sparc.hh b/util/statetrace/arch/tracechild_sparc.hh
index d177d5941..80770211a 100644
--- a/util/statetrace/arch/tracechild_sparc.hh
+++ b/util/statetrace/arch/tracechild_sparc.hh
@@ -57,10 +57,10 @@ public:
//Input registers
I0, I1, I2, I3, I4, I5, I6, I7,
//Floating point
- F0, F1, F2, F3, F4, F5, F6, F7,
- F8, F9, F10, F11, F12, F13, F14, F15,
- F16, F17, F18, F19, F20, F21, F22, F23,
- F24, F25, F26, F27, F28, F29, F30, F31,
+ F0, F2, F4, F6, F8, F10, F12, F14,
+ F16, F18, F20, F22, F24, F26, F28, F30,
+ F32, F34, F36, F38, F40, F42, F44, F46,
+ F48, F50, F52, F54, F56, F58, F60, F62,
//Miscelaneous
FSR, FPRS, PC, NPC, Y, CWP, PSTATE, ASI, CCR,
numregs
diff --git a/util/term/term.c b/util/term/term.c
index 8a95480b1..597966159 100644
--- a/util/term/term.c
+++ b/util/term/term.c
@@ -60,46 +60,49 @@ void usage(int);
int
main(int argc, char *argv[])
{
- int ch, s, ret;
- char *host, *port, *endp;
- struct addrinfo hints;
- socklen_t len;
-
- ret = 1;
- s = 0;
- host = NULL;
- port = NULL;
- endp = NULL;
-
- strncpy(progname, argv[0], sizeof progname);
-
- /* Cruft to make sure options are clean, and used properly. */
- if (argc != 3 || !argv[1] || !argv[2])
- usage(1);
-
+ int ch, s, ret;
+ char *host, *port, *endp;
+ struct addrinfo hints;
+ socklen_t len;
+
+ ret = 1;
+ s = 0;
+ host = NULL;
+ port = NULL;
+ endp = NULL;
+
+ strncpy(progname, argv[0], sizeof progname);
+
+ /* Cruft to make sure options are clean, and used properly. */
+ if (argc == 2) {
+ host = "localhost";
+ port = argv[1];
+ } else if (argc == 3) {
host = argv[1];
port = argv[2];
+ } else {
+ usage(1);
+ }
+ if (!isatty(STDIN_FILENO))
+ errx(1, "not attached to a terminal");
- if (!isatty(STDIN_FILENO))
- errx(1, "not attached to a terminal");
+ raw_term();
- raw_term();
+ /* Initialize addrinfo structure */
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
- /* Initialize addrinfo structure */
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
+ s = remote_connect(host, port, hints);
+ ret = 0;
+ readwrite(s);
- s = remote_connect(host, port, hints);
- ret = 0;
- readwrite(s);
+ if (s)
+ close(s);
- if (s)
- close(s);
-
- exit(ret);
+ exit(ret);
}
/*
@@ -110,28 +113,28 @@ main(int argc, char *argv[])
int
remote_connect(char *host, char *port, struct addrinfo hints)
{
- struct addrinfo *res, *res0;
- int s, error;
+ struct addrinfo *res, *res0;
+ int s, error;
- if ((error = getaddrinfo(host, port, &hints, &res)))
- errx(1, "getaddrinfo: %s", gai_strerror(error));
+ if ((error = getaddrinfo(host, port, &hints, &res)))
+ errx(1, "getaddrinfo: %s", gai_strerror(error));
- res0 = res;
- do {
- if ((s = socket(res0->ai_family, res0->ai_socktype,
- res0->ai_protocol)) < 0)
- continue;
+ res0 = res;
+ do {
+ if ((s = socket(res0->ai_family, res0->ai_socktype,
+ res0->ai_protocol)) < 0)
+ continue;
- if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
- break;
+ if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
+ break;
- close(s);
- s = -1;
- } while ((res0 = res0->ai_next) != NULL);
+ close(s);
+ s = -1;
+ } while ((res0 = res0->ai_next) != NULL);
- freeaddrinfo(res);
+ freeaddrinfo(res);
- return (s);
+ return (s);
}
/*
@@ -141,79 +144,79 @@ remote_connect(char *host, char *port, struct addrinfo hints)
void
readwrite(int nfd)
{
- struct pollfd pfd[2];
- char buf[BUFSIZ];
- int wfd = fileno(stdin), n, ret;
- int lfd = fileno(stdout);
- int escape = 0;
-
- /* Setup Network FD */
- pfd[0].fd = nfd;
- pfd[0].events = POLLIN;
-
- /* Setup STDIN FD */
- pfd[1].fd = wfd;
- pfd[1].events = POLLIN;
-
- while (pfd[0].fd != -1) {
- if ((n = poll(pfd, 2, -1)) < 0) {
- close(nfd);
- err(1, "Polling Error");
- }
+ struct pollfd pfd[2];
+ char buf[BUFSIZ];
+ int wfd = fileno(stdin), n, ret;
+ int lfd = fileno(stdout);
+ int escape = 0;
+
+ /* Setup Network FD */
+ pfd[0].fd = nfd;
+ pfd[0].events = POLLIN;
+
+ /* Setup STDIN FD */
+ pfd[1].fd = wfd;
+ pfd[1].events = POLLIN;
+
+ while (pfd[0].fd != -1) {
+ if ((n = poll(pfd, 2, -1)) < 0) {
+ close(nfd);
+ err(1, "Polling Error");
+ }
- if (n == 0)
- return;
+ if (n == 0)
+ return;
+
+ if (pfd[0].revents & POLLIN) {
+ if ((n = read(nfd, buf, sizeof(buf))) < 0)
+ return;
+ else if (n == 0) {
+ shutdown(nfd, SHUT_RD);
+ pfd[0].fd = -1;
+ pfd[0].events = 0;
+ } else {
+ if ((ret = atomicio(write, lfd, buf, n)) != n)
+ return;
+ }
+ }
- if (pfd[0].revents & POLLIN) {
- if ((n = read(nfd, buf, sizeof(buf))) < 0)
- return;
- else if (n == 0) {
- shutdown(nfd, SHUT_RD);
- pfd[0].fd = -1;
- pfd[0].events = 0;
- } else {
- if ((ret = atomicio(write, lfd, buf, n)) != n)
- return;
- }
+ if (pfd[1].revents & POLLIN) {
+ if ((n = read(wfd, buf, sizeof(buf))) < 0)
+ return;
+ else if (n == 0) {
+ shutdown(nfd, SHUT_WR);
+ pfd[1].fd = -1;
+ pfd[1].events = 0;
+ } else {
+ if (escape) {
+ char buf2[] = "~";
+ if (*buf == '.') {
+ printf("quit!\n");
+ return;
+ }
+ escape = 0;
+ if (*buf != '~' &&
+ (ret = atomicio(write, nfd, buf2, 1)) != n)
+ return;
+ } else {
+ escape = (*buf == '~');
+ if (escape)
+ continue;
}
- if (pfd[1].revents & POLLIN) {
- if ((n = read(wfd, buf, sizeof(buf))) < 0)
- return;
- else if (n == 0) {
- shutdown(nfd, SHUT_WR);
- pfd[1].fd = -1;
- pfd[1].events = 0;
- } else {
- if (escape) {
- char buf2[] = "~";
- if (*buf == '.') {
- printf("quit!\n");
- return;
- }
- escape = 0;
- if (*buf != '~' &&
- (ret = atomicio(write, nfd, buf2, 1)) != n)
- return;
- } else {
- escape = (*buf == '~');
- if (escape)
- continue;
- }
-
- if ((ret = atomicio(write, nfd, buf, n)) != n)
- return;
- }
- }
+ if ((ret = atomicio(write, nfd, buf, n)) != n)
+ return;
+ }
}
+ }
}
void
usage(int ret)
{
- fprintf(stderr, "usage: %s hostname port\n", progname);
- if (ret)
- exit(1);
+ fprintf(stderr, "usage: %s hostname port\n", progname);
+ if (ret)
+ exit(1);
}
/*
@@ -247,22 +250,22 @@ usage(int ret)
ssize_t
atomicio(ssize_t (*f) (), int fd, void *_s, size_t n)
{
- char *s = _s;
- ssize_t res, pos = 0;
-
- while (n > pos) {
- res = (f) (fd, s + pos, n - pos);
- switch (res) {
- case -1:
- if (errno == EINTR || errno == EAGAIN)
- continue;
- case 0:
- return (res);
- default:
- pos += res;
- }
+ char *s = _s;
+ ssize_t res, pos = 0;
+
+ while (n > pos) {
+ res = (f) (fd, s + pos, n - pos);
+ switch (res) {
+ case -1:
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ case 0:
+ return (res);
+ default:
+ pos += res;
}
- return (pos);
+ }
+ return (pos);
}
/*
@@ -284,28 +287,28 @@ atomicio(ssize_t (*f) (), int fd, void *_s, size_t n)
void
raw_term()
{
- struct termios ios;
+ struct termios ios;
- if (tcgetattr(STDIN_FILENO, &ios) < 0)
- errx(1, "tcgetagttr\n");
+ if (tcgetattr(STDIN_FILENO, &ios) < 0)
+ errx(1, "tcgetagttr\n");
- memcpy(&saved_ios, &ios, sizeof(struct termios));
+ memcpy(&saved_ios, &ios, sizeof(struct termios));
- ios.c_iflag &= ~(ISTRIP|ICRNL|IGNCR|ICRNL|IXOFF|IXON);
- ios.c_oflag &= ~(OPOST);
- ios.c_oflag &= (ONLCR);
- ios.c_lflag &= ~(ISIG|ICANON|ECHO);
- ios.c_cc[VMIN] = 1;
- ios.c_cc[VTIME] = 0;
+ ios.c_iflag &= ~(ISTRIP|ICRNL|IGNCR|ICRNL|IXOFF|IXON);
+ ios.c_oflag &= ~(OPOST);
+ ios.c_oflag &= (ONLCR);
+ ios.c_lflag &= ~(ISIG|ICANON|ECHO);
+ ios.c_cc[VMIN] = 1;
+ ios.c_cc[VTIME] = 0;
- if (tcsetattr(STDIN_FILENO, TCSANOW, &ios) < 0)
- errx(1, "tcsetattr\n");
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &ios) < 0)
+ errx(1, "tcsetattr\n");
- atexit(restore_term);
+ atexit(restore_term);
}
void
restore_term()
{
- tcsetattr(STDIN_FILENO, TCSANOW, &saved_ios);
+ tcsetattr(STDIN_FILENO, TCSANOW, &saved_ios);
}
diff --git a/util/tracediff b/util/tracediff
index f2377a999..b25efe9b2 100755
--- a/util/tracediff
+++ b/util/tracediff
@@ -33,23 +33,63 @@
# ******Note that you need to enable some trace flags in the args in order
# to do anything useful!******
#
-# If you want to pass different arguments to the two instances of m5,
-# you can embed them in the simulator arguments like this:
+# Script arguments are handled uniformly as follows:
+# - If the argument does not contain a '|' character, it is appended
+# to both command lines.
+# - If the argument has a '|' character in it, the text on either side
+# of the '|' is appended to the respective command lines. Note that
+# you'll have to quote the arg or escape the '|' with a backslash
+# so that the shell doesn't think you're doing a pipe.
#
-# % tracediff "m5.opt --option1" "m5.opt --option2" [common args]
+# In other words, the arguments should look like the command line you
+# want to run, with "|" used to list the alternatives for the parts
+# that you want to differ between the two runs.
+#
+# For example:
+#
+# % tracediff m5.opt --opt1 "--opt2|--opt3" --opt4
+# would compare these two runs:
+# m5.opt --opt1 --opt2 --opt4
+# m5.opt --opt1 --opt3 --opt4
+#
+# If you want to compare two different simulator binaries, put a '|'
+# in the first script argument ("path1/m5.opt|path2/m5.opt"). If you
+# want to add arguments to one run only, just put a '|' in with text
+# only on one side ("--onlyOn1|"). You can do this with multiple
+# arguments together too ("|-a -b -c" adds three args to the second
+# run only).
#
if (@ARGV < 2) {
- die "Usage: tracediff sim1 sim2 [--root.trace.flags=X args...]\n";
+ die "Usage: tracediff \"sim1|sim2\" [common-arg \"arg1|arg2\" ...]\n";
+}
+
+foreach $arg (@ARGV) {
+ @pair = split('\|', $arg, -1); # -1 enables null trailing fields
+ if ($#pair > 0) {
+ push @cmd1, $pair[0];
+ push @cmd2, $pair[1];
+ } else {
+ push @cmd1, $arg;
+ push @cmd2, $arg;
+ }
}
# First two args are the two simulator binaries to compare
-$sim1 = shift;
-$sim2 = shift;
+$sim1 = shift @cmd1;
+$sim2 = shift @cmd2;
+
+# Everything else is a simulator arg.
+$args1 = join(' ', @cmd1);
+$args2 = join(' ', @cmd2);
-# Everything else on the command line is taken to be an m5 argument to
-# be given to both invocations
-$simargs = '"' . join('" "', @ARGV) . '"';
+# Common mistake: if you don't set any traceflags this often isn't
+# doing what you want.
+if ($args1 !~ /--trace-flags/) {
+ print "****\n";
+ print "**** WARNING: no trace flags set... you may not be diffing much!\n";
+ print "****\n";
+}
# Run individual invocations in separate dirs so output and intermediate
# files (particularly config.py and config.ini) don't conflict.
@@ -58,8 +98,8 @@ $dir2 = "tracediff-$$-2";
mkdir($dir1) or die "Can't create dir $dir1\n";
mkdir($dir2) or die "Can't create dir $dir2\n";
-$cmd1 = "$sim1 -d $dir1 $simargs 2>&1 |";
-$cmd2 = "$sim2 -d $dir2 $simargs 2>&1 |";
+$cmd1 = "$sim1 -d $dir1 $args1 2>&1 |";
+$cmd2 = "$sim2 -d $dir2 $args2 2>&1 |";
# This only works if you have rundiff in your path. I just edit it
# with an explicit path if necessary.