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 61 #define O_BINARY 0
62 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 88 O_RDONLY,
66 89 O_RDONLY | O_BINARY,
67 90 O_RDWR,
... ... @@ -142,6 +165,35 @@ static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr,
142 165 #define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
143 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 197 #define ARG(n) tget32(args + (n) * 4)
146 198 #define SET_ARG(n, val) tput32(args + (n) * 4,val)
147 199 uint32_t do_arm_semihosting(CPUState *env)
... ... @@ -170,52 +222,99 @@ uint32_t do_arm_semihosting(CPUState *env)
170 222 else
171 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 232 unlock_user(s, ARG(0), 0);
175 233 return ret;
176 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 241 case SYS_WRITEC:
179 242 {
180 243 char c = tget8(args);
181 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 252 case SYS_WRITE0:
185 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 261 unlock_user(s, args, 0);
188 262 return ret;
189 263 case SYS_WRITE:
190 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 277 case SYS_READ:
198 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 293 case SYS_READC:
208 294 /* XXX: Read from debug cosole. Not implemented. */
209 295 return 0;
210 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 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 313 case SYS_FLEN:
218   - {
  314 + if (use_gdb_syscalls()) {
  315 + /* TODO: Use stat syscall. */
  316 + return -1;
  317 + } else {
219 318 struct stat buf;
220 319 ret = set_swi_errno(ts, fstat(ARG(0), &buf));
221 320 if (ret == (uint32_t)-1)
... ... @@ -226,12 +325,21 @@ uint32_t do_arm_semihosting(CPUState *env)
226 325 /* XXX: Not implemented. */
227 326 return -1;
228 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 336 return ret;
233 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 343 char *s2;
236 344 s = lock_user_string(ARG(0));
237 345 s2 = lock_user_string(ARG(2));
... ... @@ -245,9 +353,14 @@ uint32_t do_arm_semihosting(CPUState *env)
245 353 case SYS_TIME:
246 354 return set_swi_errno(ts, time(NULL));
247 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 364 case SYS_ERRNO:
252 365 #ifdef CONFIG_USER_ONLY
253 366 return ts->swi_errno;
... ...
gdbstub.c
... ... @@ -52,6 +52,7 @@ enum RSState {
52 52 RS_GETLINE,
53 53 RS_CHKSUM1,
54 54 RS_CHKSUM2,
  55 + RS_SYSCALL,
55 56 };
56 57 typedef struct GDBState {
57 58 CPUState *env; /* current CPU */
... ... @@ -96,6 +97,27 @@ static int get_char(GDBState *s)
96 97 }
97 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 121 static void put_buffer(GDBState *s, const uint8_t *buf, int len)
100 122 {
101 123 #ifdef CONFIG_USER_ONLY
... ... @@ -755,6 +777,34 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
755 777 vm_start();
756 778 #endif
757 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 808 case 'g':
759 809 reg_size = cpu_gdb_read_registers(env, mem_buf);
760 810 memtohex(buf, mem_buf, reg_size);
... ... @@ -855,6 +905,9 @@ static void gdb_vm_stopped(void *opaque, int reason)
855 905 char buf[256];
856 906 int ret;
857 907  
  908 + if (s->state == RS_SYSCALL)
  909 + return;
  910 +
858 911 /* disable single step if it was enable */
859 912 cpu_single_step(s->env, 0);
860 913  
... ... @@ -871,6 +924,60 @@ static void gdb_vm_stopped(void *opaque, int reason)
871 924 }
872 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 981 static void gdb_read_byte(GDBState *s, int ch)
875 982 {
876 983 CPUState *env = s->env;
... ... @@ -942,6 +1049,8 @@ static void gdb_read_byte(GDBState *s, int ch)
942 1049 s->state = gdb_handle_packet(s, env, s->line_buf);
943 1050 }
944 1051 break;
  1052 + default:
  1053 + abort();
945 1054 }
946 1055 }
947 1056 }
... ... @@ -1034,6 +1143,8 @@ static void gdb_accept(void *opaque)
1034 1143 s->env = first_cpu; /* XXX: allow to change CPU */
1035 1144 s->fd = fd;
1036 1145  
  1146 + gdb_syscall_state = s;
  1147 +
1037 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 1209 switch (event) {
1099 1210 case CHR_EVENT_RESET:
1100 1211 vm_stop(EXCP_INTERRUPT);
  1212 + gdb_syscall_state = opaque;
1101 1213 break;
1102 1214 default:
1103 1215 break;
... ...
gdbstub.h
... ... @@ -3,6 +3,11 @@
3 3  
4 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 11 #ifdef CONFIG_USER_ONLY
7 12 int gdb_handlesig (CPUState *, int);
8 13 void gdb_exit(CPUState *, int);
... ...