update copyright year range in GDB files
[external/binutils.git] / gdb / testsuite / gdb.trace / tfile.c
1 /* This testcase is part of GDB, the GNU debugger.
2
3    Copyright 2010-2017 Free Software Foundation, Inc.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 /* This program does two things; it generates valid trace files, and
19    it can also be traced so as to test trace file creation from
20    GDB.  */
21
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <stdint.h>
28
29 char spbuf[200];
30
31 char trbuf[1000];
32 char *trptr;
33 char *tfsizeptr;
34
35 /* These globals are put in the trace buffer.  */
36
37 int testglob = 31415;
38
39 int testglob2 = 271828;
40
41 /* But these below are not.  */
42
43 const int constglob = 10000;
44
45 int nonconstglob = 14124;
46
47 int
48 start_trace_file (char *filename)
49 {
50   int fd;
51   mode_t mode = S_IRUSR | S_IWUSR;
52
53 #ifdef S_IRGRP
54   mode |= S_IRGRP;
55 #endif
56
57 #ifdef S_IROTH
58   mode |= S_IROTH;
59 #endif
60
61   fd = open (filename, O_WRONLY|O_CREAT|O_APPEND, mode);
62
63   if (fd < 0)
64     return fd;
65
66   /* Write a file header, with a high-bit-set char to indicate a
67      binary file, plus a hint as what this file is, and a version
68      number in case of future needs.  */
69   write (fd, "\x7fTRACE0\n", 8);
70
71   return fd;
72 }
73
74 void
75 finish_trace_file (int fd)
76 {
77   close (fd);
78 }
79
80 static void
81 tfile_write_64 (uint64_t value)
82 {
83   memcpy (trptr, &value, sizeof (uint64_t));
84   trptr += sizeof (uint64_t);
85 }
86
87 static void
88 tfile_write_16 (uint16_t value)
89 {
90   memcpy (trptr, &value, sizeof (uint16_t));
91   trptr += sizeof (uint16_t);
92 }
93
94 static void
95 tfile_write_8 (uint8_t value)
96 {
97   memcpy (trptr, &value, sizeof (uint8_t));
98   trptr += sizeof (uint8_t);
99 }
100
101 static void
102 tfile_write_addr (char *addr)
103 {
104   tfile_write_64 ((uint64_t) (uintptr_t) addr);
105 }
106
107 static void
108 tfile_write_buf (const void *addr, size_t size)
109 {
110   memcpy (trptr, addr, size);
111   trptr += size;
112 }
113
114 void
115 add_memory_block (char *addr, int size)
116 {
117   tfile_write_8 ('M');
118   tfile_write_addr (addr);
119   tfile_write_16 (size);
120   tfile_write_buf (addr, size);
121 }
122
123 /* Adjust a function's address to account for architectural
124    particularities.  */
125
126 static uintptr_t
127 adjust_function_address (uintptr_t func_addr)
128 {
129 #if defined(__thumb__) || defined(__thumb2__)
130   /* Although Thumb functions are two-byte aligned, function
131      pointers have the Thumb bit set.  Clear it.  */
132   return func_addr & ~1;
133 #elif defined __powerpc64__ && _CALL_ELF != 2
134   /* Get function address from function descriptor.  */
135   return *(uintptr_t *) func_addr;
136 #else
137   return func_addr;
138 #endif
139 }
140
141 /* Get a function's address as an integer.  */
142
143 #define FUNCTION_ADDRESS(FUN) adjust_function_address ((uintptr_t) &FUN)
144
145 void
146 write_basic_trace_file (void)
147 {
148   int fd, int_x;
149   unsigned long long func_addr;
150
151   fd = start_trace_file (TFILE_DIR "tfile-basic.tf");
152
153   /* The next part of the file consists of newline-separated lines
154      defining status, tracepoints, etc.  The section is terminated by
155      an empty line.  */
156
157   /* Dump the size of the R (register) blocks in traceframes.  */
158   snprintf (spbuf, sizeof spbuf, "R %x\n", 500 /* FIXME get from arch */);
159   write (fd, spbuf, strlen (spbuf));
160
161   /* Dump trace status, in the general form of the qTstatus reply.  */
162   snprintf (spbuf, sizeof spbuf, "status 0;tstop:0;tframes:1;tcreated:1;tfree:100;tsize:1000\n");
163   write (fd, spbuf, strlen (spbuf));
164
165   /* Dump tracepoint definitions, in syntax similar to that used
166      for reconnection uploads.  */
167   func_addr = FUNCTION_ADDRESS (write_basic_trace_file);
168
169   snprintf (spbuf, sizeof spbuf, "tp T1:%llx:E:0:0\n", func_addr);
170   write (fd, spbuf, strlen (spbuf));
171   /* (Note that we would only need actions defined if we wanted to
172      test tdump.) */
173
174   /* Empty line marks the end of the definition section.  */
175   write (fd, "\n", 1);
176
177   /* Make up a simulated trace buffer.  */
178   /* (Encapsulate better if we're going to do lots of this; note that
179      buffer endianness is the target program's enddianness.) */
180   trptr = trbuf;
181   tfile_write_16 (1);
182
183   tfsizeptr = trptr;
184   trptr += 4;
185   add_memory_block ((char *) &testglob, sizeof (testglob));
186   /* Divide a variable between two separate memory blocks.  */
187   add_memory_block ((char *) &testglob2, 1);
188   add_memory_block (((char*) &testglob2) + 1, sizeof (testglob2) - 1);
189   /* Go back and patch in the frame size.  */
190   int_x = trptr - tfsizeptr - sizeof (int);
191   memcpy (tfsizeptr, &int_x, 4);
192
193   /* Write end of tracebuffer marker.  */
194   memset (trptr, 0, 6);
195   trptr += 6;
196
197   write (fd, trbuf, trptr - trbuf);
198
199   finish_trace_file (fd);
200 }
201
202 /* Convert number NIB to a hex digit.  */
203
204 static int
205 tohex (int nib)
206 {
207   if (nib < 10)
208     return '0' + nib;
209   else
210     return 'a' + nib - 10;
211 }
212
213 int
214 bin2hex (const char *bin, char *hex, int count)
215 {
216   int i;
217
218   for (i = 0; i < count; i++)
219     {
220       *hex++ = tohex ((*bin >> 4) & 0xf);
221       *hex++ = tohex (*bin++ & 0xf);
222     }
223   *hex = 0;
224   return i;
225 }
226
227 void
228 write_error_trace_file (void)
229 {
230   int fd;
231   const char made_up[] = "made-up error";
232   char hex[(sizeof (made_up) - 1) * 2 + 1];
233   int len = sizeof (made_up) - 1;
234
235   fd = start_trace_file (TFILE_DIR "tfile-error.tf");
236
237   /* The next part of the file consists of newline-separated lines
238      defining status, tracepoints, etc.  The section is terminated by
239      an empty line.  */
240
241   /* Dump the size of the R (register) blocks in traceframes.  */
242   snprintf (spbuf, sizeof spbuf, "R %x\n", 500 /* FIXME get from arch */);
243   write (fd, spbuf, strlen (spbuf));
244
245   bin2hex (made_up, hex, len);
246
247   /* Dump trace status, in the general form of the qTstatus reply.  */
248   snprintf (spbuf, sizeof spbuf,
249             "status 0;"
250             "terror:%s:1;"
251             "tframes:0;tcreated:0;tfree:100;tsize:1000\n",
252             hex);
253   write (fd, spbuf, strlen (spbuf));
254
255   /* Dump tracepoint definitions, in syntax similar to that used
256      for reconnection uploads.  */
257   snprintf (spbuf, sizeof spbuf, "tp T1:%llx:E:0:0\n",
258             (unsigned long long) FUNCTION_ADDRESS (write_basic_trace_file));
259   write (fd, spbuf, strlen (spbuf));
260   /* (Note that we would only need actions defined if we wanted to
261      test tdump.) */
262
263   /* Empty line marks the end of the definition section.  */
264   write (fd, "\n", 1);
265
266   trptr = trbuf;
267
268   /* Write end of tracebuffer marker.  */
269   memset (trptr, 0, 6);
270   trptr += 6;
271
272   write (fd, trbuf, trptr - trbuf);
273
274   finish_trace_file (fd);
275 }
276
277 void
278 done_making_trace_files (void)
279 {
280 }
281
282 int
283 main (void)
284 {
285   write_basic_trace_file ();
286
287   write_error_trace_file ();
288
289   done_making_trace_files ();
290
291   return 0;
292 }
293