1 /* This testcase is part of GDB, the GNU debugger. 2 3 Copyright 2010-2023 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 endianness.) */ 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 294