Commit a2d1ebaf890da03de850812cc8dbec2d56efb4e8

Authored by pbrook
1 parent 4046d913

GDB hosted syscalls.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2364 c046a42c-6fe2-441c-8c8c-71466251a162
arm-semi.c
@@ -61,7 +61,30 @@ @@ -61,7 +61,30 @@
61 #define O_BINARY 0 61 #define O_BINARY 0
62 #endif 62 #endif
63 63
64 -int open_modeflags[12] = { 64 +#define GDB_O_RDONLY 0x000
  65 +#define GDB_O_WRONLY 0x001
  66 +#define GDB_O_RDWR 0x002
  67 +#define GDB_O_APPEND 0x008
  68 +#define GDB_O_CREAT 0x200
  69 +#define GDB_O_TRUNC 0x400
  70 +#define GDB_O_BINARY 0
  71 +
  72 +static int gdb_open_modeflags[12] = {
  73 + GDB_O_RDONLY,
  74 + GDB_O_RDONLY | GDB_O_BINARY,
  75 + GDB_O_RDWR,
  76 + GDB_O_RDWR | GDB_O_BINARY,
  77 + GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
  78 + GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
  79 + GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
  80 + GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
  81 + GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
  82 + GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
  83 + GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
  84 + GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
  85 +};
  86 +
  87 +static int open_modeflags[12] = {
65 O_RDONLY, 88 O_RDONLY,
66 O_RDONLY | O_BINARY, 89 O_RDONLY | O_BINARY,
67 O_RDWR, 90 O_RDWR,
@@ -142,6 +165,35 @@ static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr, @@ -142,6 +165,35 @@ static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr,
142 #define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len) 165 #define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
143 #endif 166 #endif
144 167
  168 +static target_ulong arm_semi_syscall_len;
  169 +
  170 +static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
  171 +{
  172 +#ifdef CONFIG_USER_ONLY
  173 + TaskState *ts = env->opaque;
  174 +#endif
  175 + if (ret == (target_ulong)-1) {
  176 +#ifdef CONFIG_USER_ONLY
  177 + ts->swi_errno = err;
  178 +#endif
  179 + env->regs[0] = ret;
  180 + } else {
  181 + /* Fixup syscalls that use nonstardard return conventions. */
  182 + switch (env->regs[0]) {
  183 + case SYS_WRITE:
  184 + case SYS_READ:
  185 + env->regs[0] = arm_semi_syscall_len - ret;
  186 + break;
  187 + case SYS_SEEK:
  188 + env->regs[0] = 0;
  189 + break;
  190 + default:
  191 + env->regs[0] = ret;
  192 + break;
  193 + }
  194 + }
  195 +}
  196 +
145 #define ARG(n) tget32(args + (n) * 4) 197 #define ARG(n) tget32(args + (n) * 4)
146 #define SET_ARG(n, val) tput32(args + (n) * 4,val) 198 #define SET_ARG(n, val) tput32(args + (n) * 4,val)
147 uint32_t do_arm_semihosting(CPUState *env) 199 uint32_t do_arm_semihosting(CPUState *env)
@@ -170,52 +222,99 @@ uint32_t do_arm_semihosting(CPUState *env) @@ -170,52 +222,99 @@ uint32_t do_arm_semihosting(CPUState *env)
170 else 222 else
171 return STDOUT_FILENO; 223 return STDOUT_FILENO;
172 } 224 }
173 - ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644)); 225 + if (use_gdb_syscalls()) {
  226 + gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0), (int)ARG(2),
  227 + gdb_open_modeflags[ARG(1)]);
  228 + return env->regs[0];
  229 + } else {
  230 + ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
  231 + }
174 unlock_user(s, ARG(0), 0); 232 unlock_user(s, ARG(0), 0);
175 return ret; 233 return ret;
176 case SYS_CLOSE: 234 case SYS_CLOSE:
177 - return set_swi_errno(ts, close(ARG(0))); 235 + if (use_gdb_syscalls()) {
  236 + gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0));
  237 + return env->regs[0];
  238 + } else {
  239 + return set_swi_errno(ts, close(ARG(0)));
  240 + }
178 case SYS_WRITEC: 241 case SYS_WRITEC:
179 { 242 {
180 char c = tget8(args); 243 char c = tget8(args);
181 /* Write to debug console. stderr is near enough. */ 244 /* Write to debug console. stderr is near enough. */
182 - return write(STDERR_FILENO, &c, 1); 245 + if (use_gdb_syscalls()) {
  246 + gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
  247 + return env->regs[0];
  248 + } else {
  249 + return write(STDERR_FILENO, &c, 1);
  250 + }
183 } 251 }
184 case SYS_WRITE0: 252 case SYS_WRITE0:
185 s = lock_user_string(args); 253 s = lock_user_string(args);
186 - ret = write(STDERR_FILENO, s, strlen(s)); 254 + len = strlen(s);
  255 + if (use_gdb_syscalls()) {
  256 + gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
  257 + ret = env->regs[0];
  258 + } else {
  259 + ret = write(STDERR_FILENO, s, len);
  260 + }
187 unlock_user(s, args, 0); 261 unlock_user(s, args, 0);
188 return ret; 262 return ret;
189 case SYS_WRITE: 263 case SYS_WRITE:
190 len = ARG(2); 264 len = ARG(2);
191 - s = lock_user(ARG(1), len, 1);  
192 - ret = set_swi_errno(ts, write(ARG(0), s, len));  
193 - unlock_user(s, ARG(1), 0);  
194 - if (ret == (uint32_t)-1)  
195 - return -1;  
196 - return ARG(2) - ret; 265 + if (use_gdb_syscalls()) {
  266 + arm_semi_syscall_len = len;
  267 + gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len);
  268 + return env->regs[0];
  269 + } else {
  270 + s = lock_user(ARG(1), len, 1);
  271 + ret = set_swi_errno(ts, write(ARG(0), s, len));
  272 + unlock_user(s, ARG(1), 0);
  273 + if (ret == (uint32_t)-1)
  274 + return -1;
  275 + return len - ret;
  276 + }
197 case SYS_READ: 277 case SYS_READ:
198 len = ARG(2); 278 len = ARG(2);
199 - s = lock_user(ARG(1), len, 0);  
200 - do  
201 - ret = set_swi_errno(ts, read(ARG(0), s, len));  
202 - while (ret == -1 && errno == EINTR);  
203 - unlock_user(s, ARG(1), len);  
204 - if (ret == (uint32_t)-1)  
205 - return -1;  
206 - return ARG(2) - ret; 279 + if (use_gdb_syscalls()) {
  280 + arm_semi_syscall_len = len;
  281 + gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len);
  282 + return env->regs[0];
  283 + } else {
  284 + s = lock_user(ARG(1), len, 0);
  285 + do
  286 + ret = set_swi_errno(ts, read(ARG(0), s, len));
  287 + while (ret == -1 && errno == EINTR);
  288 + unlock_user(s, ARG(1), len);
  289 + if (ret == (uint32_t)-1)
  290 + return -1;
  291 + return len - ret;
  292 + }
207 case SYS_READC: 293 case SYS_READC:
208 /* XXX: Read from debug cosole. Not implemented. */ 294 /* XXX: Read from debug cosole. Not implemented. */
209 return 0; 295 return 0;
210 case SYS_ISTTY: 296 case SYS_ISTTY:
211 - return isatty(ARG(0)); 297 + if (use_gdb_syscalls()) {
  298 + gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0));
  299 + return env->regs[0];
  300 + } else {
  301 + return isatty(ARG(0));
  302 + }
212 case SYS_SEEK: 303 case SYS_SEEK:
213 - ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));  
214 - if (ret == (uint32_t)-1)  
215 - return -1;  
216 - return 0; 304 + if (use_gdb_syscalls()) {
  305 + gdb_do_syscall(arm_semi_cb, "fseek,%x,%x,0", ARG(0), ARG(1));
  306 + return env->regs[0];
  307 + } else {
  308 + ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
  309 + if (ret == (uint32_t)-1)
  310 + return -1;
  311 + return 0;
  312 + }
217 case SYS_FLEN: 313 case SYS_FLEN:
218 - { 314 + if (use_gdb_syscalls()) {
  315 + /* TODO: Use stat syscall. */
  316 + return -1;
  317 + } else {
219 struct stat buf; 318 struct stat buf;
220 ret = set_swi_errno(ts, fstat(ARG(0), &buf)); 319 ret = set_swi_errno(ts, fstat(ARG(0), &buf));
221 if (ret == (uint32_t)-1) 320 if (ret == (uint32_t)-1)
@@ -226,12 +325,21 @@ uint32_t do_arm_semihosting(CPUState *env) @@ -226,12 +325,21 @@ uint32_t do_arm_semihosting(CPUState *env)
226 /* XXX: Not implemented. */ 325 /* XXX: Not implemented. */
227 return -1; 326 return -1;
228 case SYS_REMOVE: 327 case SYS_REMOVE:
229 - s = lock_user_string(ARG(0));  
230 - ret = set_swi_errno(ts, remove(s));  
231 - unlock_user(s, ARG(0), 0); 328 + if (use_gdb_syscalls()) {
  329 + gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1));
  330 + ret = env->regs[0];
  331 + } else {
  332 + s = lock_user_string(ARG(0));
  333 + ret = set_swi_errno(ts, remove(s));
  334 + unlock_user(s, ARG(0), 0);
  335 + }
232 return ret; 336 return ret;
233 case SYS_RENAME: 337 case SYS_RENAME:
234 - { 338 + if (use_gdb_syscalls()) {
  339 + gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
  340 + ARG(0), (int)ARG(1), ARG(2), (int)ARG(3));
  341 + return env->regs[0];
  342 + } else {
235 char *s2; 343 char *s2;
236 s = lock_user_string(ARG(0)); 344 s = lock_user_string(ARG(0));
237 s2 = lock_user_string(ARG(2)); 345 s2 = lock_user_string(ARG(2));
@@ -245,9 +353,14 @@ uint32_t do_arm_semihosting(CPUState *env) @@ -245,9 +353,14 @@ uint32_t do_arm_semihosting(CPUState *env)
245 case SYS_TIME: 353 case SYS_TIME:
246 return set_swi_errno(ts, time(NULL)); 354 return set_swi_errno(ts, time(NULL));
247 case SYS_SYSTEM: 355 case SYS_SYSTEM:
248 - s = lock_user_string(ARG(0));  
249 - ret = set_swi_errno(ts, system(s));  
250 - unlock_user(s, ARG(0), 0); 356 + if (use_gdb_syscalls()) {
  357 + gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1));
  358 + return env->regs[0];
  359 + } else {
  360 + s = lock_user_string(ARG(0));
  361 + ret = set_swi_errno(ts, system(s));
  362 + unlock_user(s, ARG(0), 0);
  363 + }
251 case SYS_ERRNO: 364 case SYS_ERRNO:
252 #ifdef CONFIG_USER_ONLY 365 #ifdef CONFIG_USER_ONLY
253 return ts->swi_errno; 366 return ts->swi_errno;
gdbstub.c
@@ -52,6 +52,7 @@ enum RSState { @@ -52,6 +52,7 @@ enum RSState {
52 RS_GETLINE, 52 RS_GETLINE,
53 RS_CHKSUM1, 53 RS_CHKSUM1,
54 RS_CHKSUM2, 54 RS_CHKSUM2,
  55 + RS_SYSCALL,
55 }; 56 };
56 typedef struct GDBState { 57 typedef struct GDBState {
57 CPUState *env; /* current CPU */ 58 CPUState *env; /* current CPU */
@@ -96,6 +97,27 @@ static int get_char(GDBState *s) @@ -96,6 +97,27 @@ static int get_char(GDBState *s)
96 } 97 }
97 #endif 98 #endif
98 99
  100 +/* GDB stub state for use by semihosting syscalls. */
  101 +static GDBState *gdb_syscall_state;
  102 +static gdb_syscall_complete_cb gdb_current_syscall_cb;
  103 +
  104 +enum {
  105 + GDB_SYS_UNKNOWN,
  106 + GDB_SYS_ENABLED,
  107 + GDB_SYS_DISABLED,
  108 +} gdb_syscall_mode;
  109 +
  110 +/* If gdb is connected when the first semihosting syscall occurs then use
  111 + remote gdb syscalls. Otherwise use native file IO. */
  112 +int use_gdb_syscalls(void)
  113 +{
  114 + if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
  115 + gdb_syscall_mode = (gdb_syscall_state ? GDB_SYS_ENABLED
  116 + : GDB_SYS_DISABLED);
  117 + }
  118 + return gdb_syscall_mode == GDB_SYS_ENABLED;
  119 +}
  120 +
99 static void put_buffer(GDBState *s, const uint8_t *buf, int len) 121 static void put_buffer(GDBState *s, const uint8_t *buf, int len)
100 { 122 {
101 #ifdef CONFIG_USER_ONLY 123 #ifdef CONFIG_USER_ONLY
@@ -755,6 +777,34 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) @@ -755,6 +777,34 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
755 vm_start(); 777 vm_start();
756 #endif 778 #endif
757 return RS_IDLE; 779 return RS_IDLE;
  780 + case 'F':
  781 + {
  782 + target_ulong ret;
  783 + target_ulong err;
  784 +
  785 + ret = strtoull(p, (char **)&p, 16);
  786 + if (*p == ',') {
  787 + p++;
  788 + err = strtoull(p, (char **)&p, 16);
  789 + } else {
  790 + err = 0;
  791 + }
  792 + if (*p == ',')
  793 + p++;
  794 + type = *p;
  795 + if (gdb_current_syscall_cb)
  796 + gdb_current_syscall_cb(s->env, ret, err);
  797 + if (type == 'C') {
  798 + put_packet(s, "T02");
  799 + } else {
  800 +#ifdef CONFIG_USER_ONLY
  801 + s->running_state = 1;
  802 +#else
  803 + vm_start();
  804 +#endif
  805 + }
  806 + }
  807 + break;
758 case 'g': 808 case 'g':
759 reg_size = cpu_gdb_read_registers(env, mem_buf); 809 reg_size = cpu_gdb_read_registers(env, mem_buf);
760 memtohex(buf, mem_buf, reg_size); 810 memtohex(buf, mem_buf, reg_size);
@@ -855,6 +905,9 @@ static void gdb_vm_stopped(void *opaque, int reason) @@ -855,6 +905,9 @@ static void gdb_vm_stopped(void *opaque, int reason)
855 char buf[256]; 905 char buf[256];
856 int ret; 906 int ret;
857 907
  908 + if (s->state == RS_SYSCALL)
  909 + return;
  910 +
858 /* disable single step if it was enable */ 911 /* disable single step if it was enable */
859 cpu_single_step(s->env, 0); 912 cpu_single_step(s->env, 0);
860 913
@@ -871,6 +924,60 @@ static void gdb_vm_stopped(void *opaque, int reason) @@ -871,6 +924,60 @@ static void gdb_vm_stopped(void *opaque, int reason)
871 } 924 }
872 #endif 925 #endif
873 926
  927 +/* Send a gdb syscall request.
  928 + This accepts limited printf-style format specifiers, specifically:
  929 + %x - target_ulong argument printed in hex.
  930 + %s - string pointer (target_ulong) and length (int) pair. */
  931 +void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...)
  932 +{
  933 + va_list va;
  934 + char buf[256];
  935 + char *p;
  936 + target_ulong addr;
  937 + GDBState *s;
  938 +
  939 + s = gdb_syscall_state;
  940 + if (!s)
  941 + return;
  942 + gdb_current_syscall_cb = cb;
  943 + s->state = RS_SYSCALL;
  944 +#ifndef CONFIG_USER_ONLY
  945 + vm_stop(EXCP_DEBUG);
  946 +#endif
  947 + s->state = RS_IDLE;
  948 + va_start(va, fmt);
  949 + p = buf;
  950 + *(p++) = 'F';
  951 + while (*fmt) {
  952 + if (*fmt == '%') {
  953 + fmt++;
  954 + switch (*fmt++) {
  955 + case 'x':
  956 + addr = va_arg(va, target_ulong);
  957 + p += sprintf(p, TARGET_FMT_lx, addr);
  958 + break;
  959 + case 's':
  960 + addr = va_arg(va, target_ulong);
  961 + p += sprintf(p, TARGET_FMT_lx "/%x", addr, va_arg(va, int));
  962 + break;
  963 + default:
  964 + fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n",
  965 + fmt - 1);
  966 + break;
  967 + }
  968 + } else {
  969 + *(p++) = *(fmt++);
  970 + }
  971 + }
  972 + va_end(va);
  973 + put_packet(s, buf);
  974 +#ifdef CONFIG_USER_ONLY
  975 + gdb_handlesig(s->env, 0);
  976 +#else
  977 + cpu_interrupt(s->env, CPU_INTERRUPT_EXIT);
  978 +#endif
  979 +}
  980 +
874 static void gdb_read_byte(GDBState *s, int ch) 981 static void gdb_read_byte(GDBState *s, int ch)
875 { 982 {
876 CPUState *env = s->env; 983 CPUState *env = s->env;
@@ -942,6 +1049,8 @@ static void gdb_read_byte(GDBState *s, int ch) @@ -942,6 +1049,8 @@ static void gdb_read_byte(GDBState *s, int ch)
942 s->state = gdb_handle_packet(s, env, s->line_buf); 1049 s->state = gdb_handle_packet(s, env, s->line_buf);
943 } 1050 }
944 break; 1051 break;
  1052 + default:
  1053 + abort();
945 } 1054 }
946 } 1055 }
947 } 1056 }
@@ -1034,6 +1143,8 @@ static void gdb_accept(void *opaque) @@ -1034,6 +1143,8 @@ static void gdb_accept(void *opaque)
1034 s->env = first_cpu; /* XXX: allow to change CPU */ 1143 s->env = first_cpu; /* XXX: allow to change CPU */
1035 s->fd = fd; 1144 s->fd = fd;
1036 1145
  1146 + gdb_syscall_state = s;
  1147 +
1037 fcntl(fd, F_SETFL, O_NONBLOCK); 1148 fcntl(fd, F_SETFL, O_NONBLOCK);
1038 } 1149 }
1039 1150
@@ -1098,6 +1209,7 @@ static void gdb_chr_event(void *opaque, int event) @@ -1098,6 +1209,7 @@ static void gdb_chr_event(void *opaque, int event)
1098 switch (event) { 1209 switch (event) {
1099 case CHR_EVENT_RESET: 1210 case CHR_EVENT_RESET:
1100 vm_stop(EXCP_INTERRUPT); 1211 vm_stop(EXCP_INTERRUPT);
  1212 + gdb_syscall_state = opaque;
1101 break; 1213 break;
1102 default: 1214 default:
1103 break; 1215 break;
gdbstub.h
@@ -3,6 +3,11 @@ @@ -3,6 +3,11 @@
3 3
4 #define DEFAULT_GDBSTUB_PORT 1234 4 #define DEFAULT_GDBSTUB_PORT 1234
5 5
  6 +typedef void (*gdb_syscall_complete_cb)(CPUState *env,
  7 + target_ulong ret, target_ulong err);
  8 +
  9 +void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...);
  10 +int use_gdb_syscalls(void);
6 #ifdef CONFIG_USER_ONLY 11 #ifdef CONFIG_USER_ONLY
7 int gdb_handlesig (CPUState *, int); 12 int gdb_handlesig (CPUState *, int);
8 void gdb_exit(CPUState *, int); 13 void gdb_exit(CPUState *, int);