/* This program does two things; it generates valid trace files, and it can also be traced so as to test trace file creation from GDB. */ #include #include #include #include char spbuf[200]; char trbuf[1000]; char *trptr; char *tfsizeptr; int testglob = 31415; int testglob2 = 271828; const int constglob = 10000; int start_trace_file (char *filename) { int fd; fd = open (filename, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (fd < 0) return fd; /* Write a file header, with a high-bit-set char to indicate a binary file, plus a hint as what this file is, and a version number in case of future needs. */ write (fd, "\x7fTRACE0\n", 8); return fd; } void finish_trace_file (int fd) { close (fd); } void add_memory_block (char *addr, int size) { short short_x; unsigned long long ll_x; *((char *) trptr) = 'M'; trptr += 1; ll_x = (unsigned long) addr; memcpy (trptr, &ll_x, sizeof (unsigned long long)); trptr += sizeof (unsigned long long); short_x = size; memcpy (trptr, &short_x, 2); trptr += 2; memcpy (trptr, addr, size); trptr += size; } void write_basic_trace_file (void) { int fd, int_x; short short_x; fd = start_trace_file ("basic.tf"); /* The next part of the file consists of newline-separated lines defining status, tracepoints, etc. The section is terminated by an empty line. */ /* Dump the size of the R (register) blocks in traceframes. */ snprintf (spbuf, sizeof spbuf, "R %x\n", 500 /* FIXME get from arch */); write (fd, spbuf, strlen (spbuf)); /* Dump trace status, in the general form of the qTstatus reply. */ snprintf (spbuf, sizeof spbuf, "status 0;tstop:0;tframes:1;tcreated:1;tfree:100;tsize:1000\n"); write (fd, spbuf, strlen (spbuf)); /* Dump tracepoint definitions, in syntax similar to that used for reconnection uploads. */ /* FIXME need a portable way to print function address in hex */ snprintf (spbuf, sizeof spbuf, "tp T1:%lx:E:0:0\n", (long) &write_basic_trace_file); write (fd, spbuf, strlen (spbuf)); /* (Note that we would only need actions defined if we wanted to test tdump.) */ /* Empty line marks the end of the definition section. */ write (fd, "\n", 1); /* Make up a simulated trace buffer. */ /* (Encapsulate better if we're going to do lots of this; note that buffer endianness is the target program's enddianness.) */ trptr = trbuf; short_x = 1; memcpy (trptr, &short_x, 2); trptr += 2; tfsizeptr = trptr; trptr += 4; add_memory_block (&testglob, sizeof (testglob)); /* Divide a variable between two separate memory blocks. */ add_memory_block (&testglob2, 1); add_memory_block (((char*) &testglob2) + 1, sizeof (testglob2) - 1); /* Go back and patch in the frame size. */ int_x = trptr - tfsizeptr - sizeof (int); memcpy (tfsizeptr, &int_x, 4); /* Write end of tracebuffer marker. */ memset (trptr, 0, 6); trptr += 6; write (fd, trbuf, trptr - trbuf); finish_trace_file (fd); } /* Convert number NIB to a hex digit. */ static int tohex (int nib) { if (nib < 10) return '0' + nib; else return 'a' + nib - 10; } int bin2hex (const char *bin, char *hex, int count) { int i; for (i = 0; i < count; i++) { *hex++ = tohex ((*bin >> 4) & 0xf); *hex++ = tohex (*bin++ & 0xf); } *hex = 0; return i; } void write_error_trace_file (void) { int fd; const char made_up[] = "made-up error"; int len = sizeof (made_up) - 1; char *hex = alloca (len * 2 + 1); fd = start_trace_file ("error.tf"); /* The next part of the file consists of newline-separated lines defining status, tracepoints, etc. The section is terminated by an empty line. */ /* Dump the size of the R (register) blocks in traceframes. */ snprintf (spbuf, sizeof spbuf, "R %x\n", 500 /* FIXME get from arch */); write (fd, spbuf, strlen (spbuf)); bin2hex (made_up, hex, len); /* Dump trace status, in the general form of the qTstatus reply. */ snprintf (spbuf, sizeof spbuf, "status 0;" "terror:%s:1;" "tframes:0;tcreated:0;tfree:100;tsize:1000\n", hex); write (fd, spbuf, strlen (spbuf)); /* Dump tracepoint definitions, in syntax similar to that used for reconnection uploads. */ /* FIXME need a portable way to print function address in hex */ snprintf (spbuf, sizeof spbuf, "tp T1:%lx:E:0:0\n", (long) &write_basic_trace_file); write (fd, spbuf, strlen (spbuf)); /* (Note that we would only need actions defined if we wanted to test tdump.) */ /* Empty line marks the end of the definition section. */ write (fd, "\n", 1); trptr = trbuf; /* Write end of tracebuffer marker. */ memset (trptr, 0, 6); trptr += 6; write (fd, trbuf, trptr - trbuf); finish_trace_file (fd); } void done_making_trace_files (void) { } int main (int argc, char **argv, char **envp) { write_basic_trace_file (); write_error_trace_file (); done_making_trace_files (); return 0; }