Commit | Line | Data |
---|---|---|
14a1aa17 YQ |
1 | /* This testcase is part of GDB, the GNU debugger. |
2 | ||
61baf725 | 3 | Copyright 2010-2017 Free Software Foundation, Inc. |
14a1aa17 YQ |
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 | ||
00bf0b85 SS |
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> | |
1b5d0ab3 | 23 | #include <unistd.h> |
00bf0b85 SS |
24 | #include <string.h> |
25 | #include <fcntl.h> | |
26 | #include <sys/stat.h> | |
1b5d0ab3 | 27 | #include <stdint.h> |
00bf0b85 SS |
28 | |
29 | char spbuf[200]; | |
30 | ||
31 | char trbuf[1000]; | |
32 | char *trptr; | |
33 | char *tfsizeptr; | |
34 | ||
3f1175a9 PA |
35 | /* These globals are put in the trace buffer. */ |
36 | ||
00bf0b85 SS |
37 | int testglob = 31415; |
38 | ||
fce3c1f0 SS |
39 | int testglob2 = 271828; |
40 | ||
3f1175a9 PA |
41 | /* But these below are not. */ |
42 | ||
fce3c1f0 SS |
43 | const int constglob = 10000; |
44 | ||
3f1175a9 PA |
45 | int nonconstglob = 14124; |
46 | ||
00bf0b85 SS |
47 | int |
48 | start_trace_file (char *filename) | |
49 | { | |
50 | int fd; | |
1b5d0ab3 | 51 | mode_t mode = S_IRUSR | S_IWUSR; |
00bf0b85 | 52 | |
1b5d0ab3 PA |
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); | |
00bf0b85 SS |
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 | ||
1b5d0ab3 PA |
80 | static void |
81 | tfile_write_64 (uint64_t value) | |
82 | { | |
83 | memcpy (trptr, &value, sizeof (uint64_t)); | |
84 | trptr += sizeof (uint64_t); | |
85 | } | |
fce3c1f0 | 86 | |
1b5d0ab3 PA |
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) | |
fce3c1f0 | 109 | { |
fce3c1f0 SS |
110 | memcpy (trptr, addr, size); |
111 | trptr += size; | |
112 | } | |
113 | ||
1b5d0ab3 PA |
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; | |
763905a3 YQ |
133 | #elif defined __powerpc64__ && _CALL_ELF != 2 |
134 | /* Get function address from function descriptor. */ | |
135 | return *(uintptr_t *) func_addr; | |
1b5d0ab3 PA |
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 | ||
00bf0b85 | 145 | void |
6c28cbf2 | 146 | write_basic_trace_file (void) |
00bf0b85 | 147 | { |
6c28cbf2 | 148 | int fd, int_x; |
1b5d0ab3 | 149 | unsigned long long func_addr; |
00bf0b85 | 150 | |
32cfb09d | 151 | fd = start_trace_file (TFILE_DIR "tfile-basic.tf"); |
00bf0b85 SS |
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. */ | |
1b5d0ab3 | 167 | func_addr = FUNCTION_ADDRESS (write_basic_trace_file); |
2d6f0de6 | 168 | |
1b5d0ab3 | 169 | snprintf (spbuf, sizeof spbuf, "tp T1:%llx:E:0:0\n", func_addr); |
00bf0b85 SS |
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. */ | |
6c28cbf2 SS |
178 | /* (Encapsulate better if we're going to do lots of this; note that |
179 | buffer endianness is the target program's enddianness.) */ | |
00bf0b85 | 180 | trptr = trbuf; |
1b5d0ab3 PA |
181 | tfile_write_16 (1); |
182 | ||
00bf0b85 | 183 | tfsizeptr = trptr; |
6c28cbf2 | 184 | trptr += 4; |
1b5d0ab3 | 185 | add_memory_block ((char *) &testglob, sizeof (testglob)); |
fce3c1f0 | 186 | /* Divide a variable between two separate memory blocks. */ |
1b5d0ab3 | 187 | add_memory_block ((char *) &testglob2, 1); |
fce3c1f0 | 188 | add_memory_block (((char*) &testglob2) + 1, sizeof (testglob2) - 1); |
00bf0b85 | 189 | /* Go back and patch in the frame size. */ |
6c28cbf2 SS |
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 | ||
610197fd PA |
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 | ||
6c28cbf2 SS |
227 | void |
228 | write_error_trace_file (void) | |
229 | { | |
230 | int fd; | |
610197fd | 231 | const char made_up[] = "made-up error"; |
1b5d0ab3 | 232 | char hex[(sizeof (made_up) - 1) * 2 + 1]; |
610197fd | 233 | int len = sizeof (made_up) - 1; |
6c28cbf2 | 234 | |
32cfb09d | 235 | fd = start_trace_file (TFILE_DIR "tfile-error.tf"); |
6c28cbf2 SS |
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 | ||
610197fd PA |
245 | bin2hex (made_up, hex, len); |
246 | ||
6c28cbf2 | 247 | /* Dump trace status, in the general form of the qTstatus reply. */ |
610197fd PA |
248 | snprintf (spbuf, sizeof spbuf, |
249 | "status 0;" | |
250 | "terror:%s:1;" | |
251 | "tframes:0;tcreated:0;tfree:100;tsize:1000\n", | |
252 | hex); | |
6c28cbf2 SS |
253 | write (fd, spbuf, strlen (spbuf)); |
254 | ||
255 | /* Dump tracepoint definitions, in syntax similar to that used | |
256 | for reconnection uploads. */ | |
1b5d0ab3 PA |
257 | snprintf (spbuf, sizeof spbuf, "tp T1:%llx:E:0:0\n", |
258 | (unsigned long long) FUNCTION_ADDRESS (write_basic_trace_file)); | |
6c28cbf2 SS |
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; | |
00bf0b85 SS |
267 | |
268 | /* Write end of tracebuffer marker. */ | |
6c28cbf2 SS |
269 | memset (trptr, 0, 6); |
270 | trptr += 6; | |
00bf0b85 SS |
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 | |
1b5d0ab3 | 283 | main (void) |
00bf0b85 SS |
284 | { |
285 | write_basic_trace_file (); | |
286 | ||
6c28cbf2 SS |
287 | write_error_trace_file (); |
288 | ||
00bf0b85 SS |
289 | done_making_trace_files (); |
290 | ||
291 | return 0; | |
292 | } | |
293 |