7df5157e427842a5a6ac67bc10a26b17baac101f
[binutils-gdb.git] / gdb / gdbserver / low-linux.c
1 /* Low level interface to ptrace, for the remote server for GDB.
2 Copyright (C) 1995, 1996 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #include "defs.h"
22 #include <sys/wait.h>
23 #include "frame.h"
24 #include "inferior.h"
25
26 #include <stdio.h>
27 #include <sys/param.h>
28 #include <sys/dir.h>
29 #include <sys/ptrace.h>
30 #include <sys/user.h>
31 #include <signal.h>
32 #include <sys/ioctl.h>
33 #include <fcntl.h>
34
35 /***************Begin MY defs*********************/
36 int quit_flag = 0;
37 static char my_registers[REGISTER_BYTES];
38 char *registers = my_registers;
39
40 /* Index within `registers' of the first byte of the space for
41 register N. */
42
43
44 char buf2[MAX_REGISTER_RAW_SIZE];
45 /***************End MY defs*********************/
46
47 #ifdef HAVE_SYS_REG_H
48 #include <sys/reg.h>
49 #endif
50
51 /* Default the type of the ptrace transfer to int. */
52 #ifndef PTRACE_XFER_TYPE
53 #define PTRACE_XFER_TYPE int
54 #endif
55
56 extern char **environ;
57 extern int errno;
58 extern int inferior_pid;
59 void quit (), perror_with_name ();
60 int query ();
61
62 static void initialize_arch (void);
63
64 /* Start an inferior process and returns its pid.
65 ALLARGS is a vector of program-name and args.
66 ENV is the environment vector to pass. */
67
68 int
69 create_inferior (char *program, char **allargs)
70 {
71 int pid;
72
73 pid = fork ();
74 if (pid < 0)
75 perror_with_name ("fork");
76
77 if (pid == 0)
78 {
79 ptrace (PTRACE_TRACEME, 0, 0, 0);
80
81 execv (program, allargs);
82
83 fprintf (stderr, "Cannot exec %s: %s.\n", program,
84 errno < sys_nerr ? sys_errlist[errno] : "unknown error");
85 fflush (stderr);
86 _exit (0177);
87 }
88
89 return pid;
90 }
91
92 /* Kill the inferior process. Make us have no inferior. */
93
94 void
95 kill_inferior (void)
96 {
97 if (inferior_pid == 0)
98 return;
99 ptrace (PTRACE_KILL, inferior_pid, 0, 0);
100 wait (0);
101 /*************inferior_died ();****VK**************/
102 }
103
104 /* Return nonzero if the given thread is still alive. */
105 int
106 mythread_alive (int pid)
107 {
108 return 1;
109 }
110
111 /* Wait for process, returns status */
112
113 unsigned char
114 mywait (char *status)
115 {
116 int pid;
117 union wait w;
118
119 pid = wait (&w);
120 if (pid != inferior_pid)
121 perror_with_name ("wait");
122
123 if (WIFEXITED (w))
124 {
125 fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
126 *status = 'W';
127 return ((unsigned char) WEXITSTATUS (w));
128 }
129 else if (!WIFSTOPPED (w))
130 {
131 fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
132 *status = 'X';
133 return ((unsigned char) WTERMSIG (w));
134 }
135
136 fetch_inferior_registers (0);
137
138 *status = 'T';
139 return ((unsigned char) WSTOPSIG (w));
140 }
141
142 /* Resume execution of the inferior process.
143 If STEP is nonzero, single-step it.
144 If SIGNAL is nonzero, give it that signal. */
145
146 void
147 myresume (int step, int signal)
148 {
149 errno = 0;
150 ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal);
151 if (errno)
152 perror_with_name ("ptrace");
153 }
154
155
156 #if !defined (offsetof)
157 #define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
158 #endif
159
160 /* U_REGS_OFFSET is the offset of the registers within the u area. */
161 #if !defined (U_REGS_OFFSET)
162 #define U_REGS_OFFSET \
163 ptrace (PT_READ_U, inferior_pid, \
164 (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \
165 - KERNEL_U_ADDR
166 #endif
167
168 #ifdef I386_GNULINUX_TARGET
169 /* i386_register_raw_size[i] is the number of bytes of storage in the
170 actual machine representation for register i. */
171 int i386_register_raw_size[MAX_NUM_REGS] = {
172 4, 4, 4, 4,
173 4, 4, 4, 4,
174 4, 4, 4, 4,
175 4, 4, 4, 4,
176 10, 10, 10, 10,
177 10, 10, 10, 10,
178 4, 4, 4, 4,
179 4, 4, 4, 4,
180 16, 16, 16, 16,
181 16, 16, 16, 16,
182 4
183 };
184
185 int i386_register_byte[MAX_NUM_REGS];
186
187 static void
188 initialize_arch (void)
189 {
190 /* Initialize the table saying where each register starts in the
191 register file. */
192 {
193 int i, offset;
194
195 offset = 0;
196 for (i = 0; i < MAX_NUM_REGS; i++)
197 {
198 i386_register_byte[i] = offset;
199 offset += i386_register_raw_size[i];
200 }
201 }
202 }
203
204 /* this table must line up with REGISTER_NAMES in tm-i386v.h */
205 /* symbols like 'EAX' come from <sys/reg.h> */
206 static int regmap[] =
207 {
208 EAX, ECX, EDX, EBX,
209 UESP, EBP, ESI, EDI,
210 EIP, EFL, CS, SS,
211 DS, ES, FS, GS,
212 };
213
214 int
215 i386_register_u_addr (int blockend, int regnum)
216 {
217 #if 0
218 /* this will be needed if fp registers are reinstated */
219 /* for now, you can look at them with 'info float'
220 * sys5 wont let you change them with ptrace anyway
221 */
222 if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM)
223 {
224 int ubase, fpstate;
225 struct user u;
226 ubase = blockend + 4 * (SS + 1) - KSTKSZ;
227 fpstate = ubase + ((char *) &u.u_fpstate - (char *) &u);
228 return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
229 }
230 else
231 #endif
232 return (blockend + 4 * regmap[regnum]);
233
234 }
235 #elif defined(TARGET_M68K)
236 static void
237 initialize_arch (void)
238 {
239 return;
240 }
241
242 /* This table must line up with REGISTER_NAMES in tm-m68k.h */
243 static int regmap[] =
244 {
245 #ifdef PT_D0
246 PT_D0, PT_D1, PT_D2, PT_D3, PT_D4, PT_D5, PT_D6, PT_D7,
247 PT_A0, PT_A1, PT_A2, PT_A3, PT_A4, PT_A5, PT_A6, PT_USP,
248 PT_SR, PT_PC,
249 #else
250 14, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15,
251 17, 18,
252 #endif
253 #ifdef PT_FP0
254 PT_FP0, PT_FP1, PT_FP2, PT_FP3, PT_FP4, PT_FP5, PT_FP6, PT_FP7,
255 PT_FPCR, PT_FPSR, PT_FPIAR
256 #else
257 21, 24, 27, 30, 33, 36, 39, 42, 45, 46, 47
258 #endif
259 };
260
261 /* BLOCKEND is the value of u.u_ar0, and points to the place where GS
262 is stored. */
263
264 int
265 m68k_linux_register_u_addr (int blockend, int regnum)
266 {
267 return (blockend + 4 * regmap[regnum]);
268 }
269 #elif defined(IA64_GNULINUX_TARGET)
270 #undef NUM_FREGS
271 #define NUM_FREGS 0
272
273 #include <asm/ptrace_offsets.h>
274
275 static int u_offsets[] =
276 {
277 /* general registers */
278 -1, /* gr0 not available; i.e, it's always zero */
279 PT_R1,
280 PT_R2,
281 PT_R3,
282 PT_R4,
283 PT_R5,
284 PT_R6,
285 PT_R7,
286 PT_R8,
287 PT_R9,
288 PT_R10,
289 PT_R11,
290 PT_R12,
291 PT_R13,
292 PT_R14,
293 PT_R15,
294 PT_R16,
295 PT_R17,
296 PT_R18,
297 PT_R19,
298 PT_R20,
299 PT_R21,
300 PT_R22,
301 PT_R23,
302 PT_R24,
303 PT_R25,
304 PT_R26,
305 PT_R27,
306 PT_R28,
307 PT_R29,
308 PT_R30,
309 PT_R31,
310 /* gr32 through gr127 not directly available via the ptrace interface */
311 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
312 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
313 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
314 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
315 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
316 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
317 /* Floating point registers */
318 -1, -1, /* f0 and f1 not available (f0 is +0.0 and f1 is +1.0) */
319 PT_F2,
320 PT_F3,
321 PT_F4,
322 PT_F5,
323 PT_F6,
324 PT_F7,
325 PT_F8,
326 PT_F9,
327 PT_F10,
328 PT_F11,
329 PT_F12,
330 PT_F13,
331 PT_F14,
332 PT_F15,
333 PT_F16,
334 PT_F17,
335 PT_F18,
336 PT_F19,
337 PT_F20,
338 PT_F21,
339 PT_F22,
340 PT_F23,
341 PT_F24,
342 PT_F25,
343 PT_F26,
344 PT_F27,
345 PT_F28,
346 PT_F29,
347 PT_F30,
348 PT_F31,
349 PT_F32,
350 PT_F33,
351 PT_F34,
352 PT_F35,
353 PT_F36,
354 PT_F37,
355 PT_F38,
356 PT_F39,
357 PT_F40,
358 PT_F41,
359 PT_F42,
360 PT_F43,
361 PT_F44,
362 PT_F45,
363 PT_F46,
364 PT_F47,
365 PT_F48,
366 PT_F49,
367 PT_F50,
368 PT_F51,
369 PT_F52,
370 PT_F53,
371 PT_F54,
372 PT_F55,
373 PT_F56,
374 PT_F57,
375 PT_F58,
376 PT_F59,
377 PT_F60,
378 PT_F61,
379 PT_F62,
380 PT_F63,
381 PT_F64,
382 PT_F65,
383 PT_F66,
384 PT_F67,
385 PT_F68,
386 PT_F69,
387 PT_F70,
388 PT_F71,
389 PT_F72,
390 PT_F73,
391 PT_F74,
392 PT_F75,
393 PT_F76,
394 PT_F77,
395 PT_F78,
396 PT_F79,
397 PT_F80,
398 PT_F81,
399 PT_F82,
400 PT_F83,
401 PT_F84,
402 PT_F85,
403 PT_F86,
404 PT_F87,
405 PT_F88,
406 PT_F89,
407 PT_F90,
408 PT_F91,
409 PT_F92,
410 PT_F93,
411 PT_F94,
412 PT_F95,
413 PT_F96,
414 PT_F97,
415 PT_F98,
416 PT_F99,
417 PT_F100,
418 PT_F101,
419 PT_F102,
420 PT_F103,
421 PT_F104,
422 PT_F105,
423 PT_F106,
424 PT_F107,
425 PT_F108,
426 PT_F109,
427 PT_F110,
428 PT_F111,
429 PT_F112,
430 PT_F113,
431 PT_F114,
432 PT_F115,
433 PT_F116,
434 PT_F117,
435 PT_F118,
436 PT_F119,
437 PT_F120,
438 PT_F121,
439 PT_F122,
440 PT_F123,
441 PT_F124,
442 PT_F125,
443 PT_F126,
444 PT_F127,
445 /* predicate registers - we don't fetch these individually */
446 -1, -1, -1, -1, -1, -1, -1, -1,
447 -1, -1, -1, -1, -1, -1, -1, -1,
448 -1, -1, -1, -1, -1, -1, -1, -1,
449 -1, -1, -1, -1, -1, -1, -1, -1,
450 -1, -1, -1, -1, -1, -1, -1, -1,
451 -1, -1, -1, -1, -1, -1, -1, -1,
452 -1, -1, -1, -1, -1, -1, -1, -1,
453 -1, -1, -1, -1, -1, -1, -1, -1,
454 /* branch registers */
455 PT_B0,
456 PT_B1,
457 PT_B2,
458 PT_B3,
459 PT_B4,
460 PT_B5,
461 PT_B6,
462 PT_B7,
463 /* virtual frame pointer and virtual return address pointer */
464 -1, -1,
465 /* other registers */
466 PT_PR,
467 PT_CR_IIP, /* ip */
468 PT_CR_IPSR, /* psr */
469 PT_CFM, /* cfm */
470 /* kernel registers not visible via ptrace interface (?) */
471 -1, -1, -1, -1, -1, -1, -1, -1,
472 /* hole */
473 -1, -1, -1, -1, -1, -1, -1, -1,
474 PT_AR_RSC,
475 PT_AR_BSP,
476 PT_AR_BSPSTORE,
477 PT_AR_RNAT,
478 -1,
479 -1, /* Not available: FCR, IA32 floating control register */
480 -1, -1,
481 -1, /* Not available: EFLAG */
482 -1, /* Not available: CSD */
483 -1, /* Not available: SSD */
484 -1, /* Not available: CFLG */
485 -1, /* Not available: FSR */
486 -1, /* Not available: FIR */
487 -1, /* Not available: FDR */
488 -1,
489 PT_AR_CCV,
490 -1, -1, -1,
491 PT_AR_UNAT,
492 -1, -1, -1,
493 PT_AR_FPSR,
494 -1, -1, -1,
495 -1, /* Not available: ITC */
496 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
497 -1, -1, -1, -1, -1, -1, -1, -1, -1,
498 PT_AR_PFS,
499 PT_AR_LC,
500 -1, /* Not available: EC, the Epilog Count register */
501 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
502 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
503 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
504 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
505 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
506 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
507 -1,
508 /* nat bits - not fetched directly; instead we obtain these bits from
509 either rnat or unat or from memory. */
510 -1, -1, -1, -1, -1, -1, -1, -1,
511 -1, -1, -1, -1, -1, -1, -1, -1,
512 -1, -1, -1, -1, -1, -1, -1, -1,
513 -1, -1, -1, -1, -1, -1, -1, -1,
514 -1, -1, -1, -1, -1, -1, -1, -1,
515 -1, -1, -1, -1, -1, -1, -1, -1,
516 -1, -1, -1, -1, -1, -1, -1, -1,
517 -1, -1, -1, -1, -1, -1, -1, -1,
518 -1, -1, -1, -1, -1, -1, -1, -1,
519 -1, -1, -1, -1, -1, -1, -1, -1,
520 -1, -1, -1, -1, -1, -1, -1, -1,
521 -1, -1, -1, -1, -1, -1, -1, -1,
522 -1, -1, -1, -1, -1, -1, -1, -1,
523 -1, -1, -1, -1, -1, -1, -1, -1,
524 -1, -1, -1, -1, -1, -1, -1, -1,
525 -1, -1, -1, -1, -1, -1, -1, -1,
526 };
527
528 int
529 ia64_register_u_addr (int blockend, int regnum)
530 {
531 int addr;
532
533 if (regnum < 0 || regnum >= NUM_REGS)
534 error ("Invalid register number %d.", regnum);
535
536 addr = u_offsets[regnum];
537 if (addr == -1)
538 addr = 0;
539
540 return addr;
541 }
542
543 static void
544 initialize_arch (void)
545 {
546 return;
547 }
548 #endif
549
550 CORE_ADDR
551 register_addr (int regno, CORE_ADDR blockend)
552 {
553 CORE_ADDR addr;
554
555 if (regno < 0 || regno >= ARCH_NUM_REGS)
556 error ("Invalid register number %d.", regno);
557
558 REGISTER_U_ADDR (addr, blockend, regno);
559
560 return addr;
561 }
562
563 /* Fetch one register. */
564
565 static void
566 fetch_register (int regno)
567 {
568 CORE_ADDR regaddr;
569 register int i;
570
571 /* Offset of registers within the u area. */
572 unsigned int offset;
573
574 offset = U_REGS_OFFSET;
575
576 regaddr = register_addr (regno, offset);
577 for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
578 {
579 errno = 0;
580 *(PTRACE_XFER_TYPE *) &registers[REGISTER_BYTE (regno) + i] =
581 ptrace (PTRACE_PEEKUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, 0);
582 regaddr += sizeof (PTRACE_XFER_TYPE);
583 if (errno != 0)
584 {
585 /* Warning, not error, in case we are attached; sometimes the
586 kernel doesn't let us at the registers. */
587 char *err = strerror (errno);
588 char *msg = alloca (strlen (err) + 128);
589 sprintf (msg, "reading register %d: %s", regno, err);
590 error (msg);
591 goto error_exit;
592 }
593 }
594 error_exit:;
595 }
596
597 /* Fetch all registers, or just one, from the child process. */
598
599 void
600 fetch_inferior_registers (int regno)
601 {
602 if (regno == -1 || regno == 0)
603 for (regno = 0; regno < NUM_REGS - NUM_FREGS; regno++)
604 fetch_register (regno);
605 else
606 fetch_register (regno);
607 }
608
609 /* Store our register values back into the inferior.
610 If REGNO is -1, do this for all registers.
611 Otherwise, REGNO specifies which register (so we can save time). */
612
613 void
614 store_inferior_registers (int regno)
615 {
616 CORE_ADDR regaddr;
617 int i;
618 unsigned int offset = U_REGS_OFFSET;
619
620 if (regno >= 0)
621 {
622 #if 0
623 if (CANNOT_STORE_REGISTER (regno))
624 return;
625 #endif
626 regaddr = register_addr (regno, offset);
627 errno = 0;
628 #if 0
629 if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM)
630 {
631 scratch = *(int *) &registers[REGISTER_BYTE (regno)] | 0x3;
632 ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
633 scratch, 0);
634 if (errno != 0)
635 {
636 /* Error, even if attached. Failing to write these two
637 registers is pretty serious. */
638 sprintf (buf, "writing register number %d", regno);
639 perror_with_name (buf);
640 }
641 }
642 else
643 #endif
644 for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
645 {
646 errno = 0;
647 ptrace (PTRACE_POKEUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
648 *(int *) &registers[REGISTER_BYTE (regno) + i]);
649 if (errno != 0)
650 {
651 /* Warning, not error, in case we are attached; sometimes the
652 kernel doesn't let us at the registers. */
653 char *err = strerror (errno);
654 char *msg = alloca (strlen (err) + 128);
655 sprintf (msg, "writing register %d: %s",
656 regno, err);
657 error (msg);
658 return;
659 }
660 regaddr += sizeof (int);
661 }
662 }
663 else
664 for (regno = 0; regno < NUM_REGS - NUM_FREGS; regno++)
665 store_inferior_registers (regno);
666 }
667
668 /* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
669 in the NEW_SUN_PTRACE case.
670 It ought to be straightforward. But it appears that writing did
671 not write the data that I specified. I cannot understand where
672 it got the data that it actually did write. */
673
674 /* Copy LEN bytes from inferior's memory starting at MEMADDR
675 to debugger memory starting at MYADDR. */
676
677 void
678 read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
679 {
680 register int i;
681 /* Round starting address down to longword boundary. */
682 register CORE_ADDR addr = memaddr & -sizeof (PTRACE_XFER_TYPE);
683 /* Round ending address up; get number of longwords that makes. */
684 register int count
685 = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
686 / sizeof (PTRACE_XFER_TYPE);
687 /* Allocate buffer of that many longwords. */
688 register PTRACE_XFER_TYPE *buffer
689 = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
690
691 /* Read all the longwords */
692 for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
693 {
694 buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid, addr, 0);
695 }
696
697 /* Copy appropriate bytes out of the buffer. */
698 memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len);
699 }
700
701 /* Copy LEN bytes of data from debugger memory at MYADDR
702 to inferior's memory at MEMADDR.
703 On failure (cannot write the inferior)
704 returns the value of errno. */
705
706 int
707 write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
708 {
709 register int i;
710 /* Round starting address down to longword boundary. */
711 register CORE_ADDR addr = memaddr & -sizeof (PTRACE_XFER_TYPE);
712 /* Round ending address up; get number of longwords that makes. */
713 register int count
714 = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE);
715 /* Allocate buffer of that many longwords. */
716 register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
717 extern int errno;
718
719 /* Fill start and end extra bytes of buffer with existing memory data. */
720
721 buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid, addr, 0);
722
723 if (count > 1)
724 {
725 buffer[count - 1]
726 = ptrace (PTRACE_PEEKTEXT, inferior_pid,
727 addr + (count - 1) * sizeof (PTRACE_XFER_TYPE), 0);
728 }
729
730 /* Copy data to be written over corresponding part of buffer */
731
732 memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), myaddr, len);
733
734 /* Write the entire buffer. */
735
736 for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
737 {
738 errno = 0;
739 ptrace (PTRACE_POKETEXT, inferior_pid, addr, buffer[i]);
740 if (errno)
741 return errno;
742 }
743
744 return 0;
745 }
746 \f
747 void
748 initialize_low (void)
749 {
750 initialize_arch ();
751 }