763905a3ad
I see the following fails on powerpc64-linux, (gdb) target tfile tfile-basic.tf^M warning: Uploaded tracepoint 1 has no source location, using raw address^M Tracepoint 1 at 0x10012358^M Created tracepoint 1 for target's tracepoint 1 at 0x10012358.^M (gdb) PASS: gdb.trace/tfile.exp: target tfile tfile-basic.tf info trace^M Num Type Disp Enb Address What^M 1 tracepoint keep y 0x0000000010012358 <write_basic_trace_file>^M installed on target^M (gdb) FAIL: gdb.trace/tfile.exp: info tracepoints on trace file -target-select tfile tfile-basic.tf^M =thread-group-started,id="i1",pid="1"^M =thread-created,id="1",group-id="i1"^M &"warning: Uploaded tracepoint 1 has no source location, using raw address\n"^M =breakpoint-created,bkpt={number="1",type="tracepoint",disp="keep",enabled="y", addr="0x0000000010012358",at="<write_basic_trace_file>",thread-groups=["i1"], times="0",installed="y",original-location="*0x10012358"}^M ~"Created tracepoint 1 for target's tracepoint 1 at 0x10012358.\n"^M ^connected^M (gdb) ^M FAIL: gdb.trace/mi-traceframe-changed.exp: tfile: select trace file These fails are caused by writing function descriptor address into trace file instead of function address. This patch is to teach tfile.c to write function address on powerpc64 target. With this patch applied, fails in tfile.exp and mi-traceframe-changed.exp are fixed. Is it OK? gdb/testsuite: 2014-10-27 Yao Qi <yao@codesourcery.com> * gdb.trace/tfile.c (adjust_function_address) [__powerpc64__ && _CALL_ELF != 2]: Get function address from function descriptor.
293 lines
6.9 KiB
C
293 lines
6.9 KiB
C
/* This testcase is part of GDB, the GNU debugger.
|
|
|
|
Copyright 2010-2014 Free Software Foundation, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
/* 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 <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <stdint.h>
|
|
|
|
char spbuf[200];
|
|
|
|
char trbuf[1000];
|
|
char *trptr;
|
|
char *tfsizeptr;
|
|
|
|
/* These globals are put in the trace buffer. */
|
|
|
|
int testglob = 31415;
|
|
|
|
int testglob2 = 271828;
|
|
|
|
/* But these below are not. */
|
|
|
|
const int constglob = 10000;
|
|
|
|
int nonconstglob = 14124;
|
|
|
|
int
|
|
start_trace_file (char *filename)
|
|
{
|
|
int fd;
|
|
mode_t mode = S_IRUSR | S_IWUSR;
|
|
|
|
#ifdef S_IRGRP
|
|
mode |= S_IRGRP;
|
|
#endif
|
|
|
|
#ifdef S_IROTH
|
|
mode |= S_IROTH;
|
|
#endif
|
|
|
|
fd = open (filename, O_WRONLY|O_CREAT|O_APPEND, mode);
|
|
|
|
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);
|
|
}
|
|
|
|
static void
|
|
tfile_write_64 (uint64_t value)
|
|
{
|
|
memcpy (trptr, &value, sizeof (uint64_t));
|
|
trptr += sizeof (uint64_t);
|
|
}
|
|
|
|
static void
|
|
tfile_write_16 (uint16_t value)
|
|
{
|
|
memcpy (trptr, &value, sizeof (uint16_t));
|
|
trptr += sizeof (uint16_t);
|
|
}
|
|
|
|
static void
|
|
tfile_write_8 (uint8_t value)
|
|
{
|
|
memcpy (trptr, &value, sizeof (uint8_t));
|
|
trptr += sizeof (uint8_t);
|
|
}
|
|
|
|
static void
|
|
tfile_write_addr (char *addr)
|
|
{
|
|
tfile_write_64 ((uint64_t) (uintptr_t) addr);
|
|
}
|
|
|
|
static void
|
|
tfile_write_buf (const void *addr, size_t size)
|
|
{
|
|
memcpy (trptr, addr, size);
|
|
trptr += size;
|
|
}
|
|
|
|
void
|
|
add_memory_block (char *addr, int size)
|
|
{
|
|
tfile_write_8 ('M');
|
|
tfile_write_addr (addr);
|
|
tfile_write_16 (size);
|
|
tfile_write_buf (addr, size);
|
|
}
|
|
|
|
/* Adjust a function's address to account for architectural
|
|
particularities. */
|
|
|
|
static uintptr_t
|
|
adjust_function_address (uintptr_t func_addr)
|
|
{
|
|
#if defined(__thumb__) || defined(__thumb2__)
|
|
/* Although Thumb functions are two-byte aligned, function
|
|
pointers have the Thumb bit set. Clear it. */
|
|
return func_addr & ~1;
|
|
#elif defined __powerpc64__ && _CALL_ELF != 2
|
|
/* Get function address from function descriptor. */
|
|
return *(uintptr_t *) func_addr;
|
|
#else
|
|
return func_addr;
|
|
#endif
|
|
}
|
|
|
|
/* Get a function's address as an integer. */
|
|
|
|
#define FUNCTION_ADDRESS(FUN) adjust_function_address ((uintptr_t) &FUN)
|
|
|
|
void
|
|
write_basic_trace_file (void)
|
|
{
|
|
int fd, int_x;
|
|
unsigned long long func_addr;
|
|
|
|
fd = start_trace_file (TFILE_DIR "tfile-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. */
|
|
func_addr = FUNCTION_ADDRESS (write_basic_trace_file);
|
|
|
|
snprintf (spbuf, sizeof spbuf, "tp T1:%llx:E:0:0\n", func_addr);
|
|
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;
|
|
tfile_write_16 (1);
|
|
|
|
tfsizeptr = trptr;
|
|
trptr += 4;
|
|
add_memory_block ((char *) &testglob, sizeof (testglob));
|
|
/* Divide a variable between two separate memory blocks. */
|
|
add_memory_block ((char *) &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";
|
|
char hex[(sizeof (made_up) - 1) * 2 + 1];
|
|
int len = sizeof (made_up) - 1;
|
|
|
|
fd = start_trace_file (TFILE_DIR "tfile-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. */
|
|
snprintf (spbuf, sizeof spbuf, "tp T1:%llx:E:0:0\n",
|
|
(unsigned long long) FUNCTION_ADDRESS (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 (void)
|
|
{
|
|
write_basic_trace_file ();
|
|
|
|
write_error_trace_file ();
|
|
|
|
done_making_trace_files ();
|
|
|
|
return 0;
|
|
}
|
|
|