Fix up previous commit.
[deliverable/binutils-gdb.git] / gdb / infptrace.c
CommitLineData
c906108c 1/* Low level Unix child interface to ptrace, for GDB when running under Unix.
0a65a603 2 Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
2689df5a 3 1998, 1999, 2000, 2001, 2002, 2004
c906108c
SS
4 Free Software Foundation, Inc.
5
c5aa993b 6 This file is part of GDB.
c906108c 7
c5aa993b
JM
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
c906108c 12
c5aa993b
JM
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
c906108c 17
c5aa993b
JM
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
c906108c
SS
22
23#include "defs.h"
8cbba7c8 24#include "command.h"
c906108c 25#include "frame.h"
8cbba7c8 26#include "gdbcore.h"
c906108c 27#include "inferior.h"
4e052eda 28#include "regcache.h"
8cbba7c8 29#include "target.h"
ed9a39eb 30
8cbba7c8 31#include "gdb_assert.h"
03f2053f 32#include "gdb_wait.h"
8cbba7c8 33#include "gdb_string.h"
c906108c 34
c906108c 35#include <sys/param.h>
4b14d3e4 36#include "gdb_dirent.h"
c906108c
SS
37#include <signal.h>
38#include <sys/ioctl.h>
39
11003ae3 40#include "gdb_ptrace.h"
c906108c 41
c0ccb908 42#ifdef HAVE_SYS_FILE_H
c906108c
SS
43#include <sys/file.h>
44#endif
652fc137 45
c906108c
SS
46#if !defined (FETCH_INFERIOR_REGISTERS)
47#include <sys/user.h> /* Probably need to poke the user structure */
c906108c
SS
48#endif /* !FETCH_INFERIOR_REGISTERS */
49
50#if !defined (CHILD_XFER_MEMORY)
a14ed312 51static void udot_info (char *, int);
c906108c
SS
52#endif
53
a14ed312 54void _initialize_infptrace (void);
c906108c 55\f
c5aa993b 56
c906108c
SS
57/* This function simply calls ptrace with the given arguments.
58 It exists so that all calls to ptrace are isolated in this
59 machine-dependent file. */
60int
f8707cac 61call_ptrace (int request, int pid, PTRACE_ARG3_TYPE addr, int data)
c906108c
SS
62{
63 int pt_status = 0;
64
65#if 0
66 int saved_errno;
67
68 printf ("call_ptrace(request=%d, pid=%d, addr=0x%x, data=0x%x)",
69 request, pid, addr, data);
70#endif
71#if defined(PT_SETTRC)
72 /* If the parent can be told to attach to us, try to do it. */
c5aa993b
JM
73 if (request == PT_SETTRC)
74 {
75 errno = 0;
daa98270 76#ifndef PTRACE_TYPE_ARG5
ed9a39eb
JM
77 pt_status = ptrace (PT_SETTRC, pid, addr, data);
78#else
c5aa993b
JM
79 /* Deal with HPUX 8.0 braindamage. We never use the
80 calls which require the fifth argument. */
ed9a39eb 81 pt_status = ptrace (PT_SETTRC, pid, addr, data, 0);
c906108c 82#endif
c5aa993b
JM
83 if (errno)
84 perror_with_name ("ptrace");
c906108c 85#if 0
c5aa993b 86 printf (" = %d\n", pt_status);
c906108c 87#endif
c5aa993b
JM
88 if (pt_status < 0)
89 return pt_status;
90 else
91 return parent_attach_all (pid, addr, data);
92 }
c906108c
SS
93#endif
94
95#if defined(PT_CONTIN1)
96 /* On HPUX, PT_CONTIN1 is a form of continue that preserves pending
97 signals. If it's available, use it. */
98 if (request == PT_CONTINUE)
99 request = PT_CONTIN1;
100#endif
101
102#if defined(PT_SINGLE1)
103 /* On HPUX, PT_SINGLE1 is a form of step that preserves pending
104 signals. If it's available, use it. */
105 if (request == PT_STEP)
106 request = PT_SINGLE1;
107#endif
108
109#if 0
110 saved_errno = errno;
111 errno = 0;
112#endif
daa98270 113#ifndef PTRACE_TYPE_ARG5
ed9a39eb
JM
114 pt_status = ptrace (request, pid, addr, data);
115#else
c5aa993b
JM
116 /* Deal with HPUX 8.0 braindamage. We never use the
117 calls which require the fifth argument. */
ed9a39eb 118 pt_status = ptrace (request, pid, addr, data, 0);
c906108c 119#endif
ed9a39eb 120
c906108c
SS
121#if 0
122 if (errno)
123 printf (" [errno = %d]", errno);
124
125 errno = saved_errno;
126 printf (" = 0x%x\n", pt_status);
127#endif
128 return pt_status;
129}
130
131
daa98270 132#if defined (DEBUG_PTRACE) || defined (PTRACE_TYPE_ARG5)
c906108c
SS
133/* For the rest of the file, use an extra level of indirection */
134/* This lets us breakpoint usefully on call_ptrace. */
135#define ptrace call_ptrace
136#endif
137
138/* Wait for a process to finish, possibly running a target-specific
139 hook before returning. */
140
141int
39f77062 142ptrace_wait (ptid_t ptid, int *status)
c906108c
SS
143{
144 int wstate;
145
146 wstate = wait (status);
39f77062 147 target_post_wait (pid_to_ptid (wstate), *status);
c906108c
SS
148 return wstate;
149}
150
adbef1f0
AC
151#ifndef DEPRECATED_KILL_INFERIOR
152/* NOTE: cagney/2004-09-12: Instead of definining this macro, code
153 should call inf_ptrace_target to get a basic ptrace target and then
154 locally update any necessary methods. See ppcnbsd-nat.c. */
155
c906108c 156void
fba45db2 157kill_inferior (void)
c906108c
SS
158{
159 int status;
39f77062 160 int pid = PIDGET (inferior_ptid);
c906108c 161
39f77062 162 if (pid == 0)
c906108c
SS
163 return;
164
165 /* This once used to call "kill" to kill the inferior just in case
166 the inferior was still running. As others have noted in the past
167 (kingdon) there shouldn't be any way to get here if the inferior
168 is still running -- else there's a major problem elsewere in gdb
169 and it needs to be fixed.
170
171 The kill call causes problems under hpux10, so it's been removed;
172 if this causes problems we'll deal with them as they arise. */
655c5466 173 ptrace (PT_KILL, pid, (PTRACE_TYPE_ARG3) 0, 0);
39f77062 174 ptrace_wait (null_ptid, &status);
c906108c
SS
175 target_mourn_inferior ();
176}
adbef1f0 177#endif /* DEPRECATED_KILL_INFERIOR */
c906108c 178
adbef1f0
AC
179#ifndef DEPRECATED_CHILD_RESUME
180/* NOTE: cagney/2004-09-12: Instead of definining this macro, code
181 should call inf_ptrace_target to get a basic ptrace target and then
182 locally update any necessary methods. See ppcnbsd-nat.c. */
c906108c
SS
183
184/* Resume execution of the inferior process.
185 If STEP is nonzero, single-step it.
186 If SIGNAL is nonzero, give it that signal. */
187
188void
39f77062 189child_resume (ptid_t ptid, int step, enum target_signal signal)
c906108c 190{
8cbba7c8 191 int request = PT_CONTINUE;
39f77062
KB
192 int pid = PIDGET (ptid);
193
c906108c
SS
194 if (pid == -1)
195 /* Resume all threads. */
196 /* I think this only gets used in the non-threaded case, where "resume
39f77062
KB
197 all threads" and "resume inferior_ptid" are the same. */
198 pid = PIDGET (inferior_ptid);
c906108c 199
c906108c
SS
200 if (step)
201 {
8cbba7c8
MK
202 /* If this system does not support PT_STEP, a higher level
203 function will have called single_step() to transmute the step
204 request into a continue request (by setting breakpoints on
205 all possible successor instructions), so we don't have to
206 worry about that here. */
207
208 gdb_assert (!SOFTWARE_SINGLE_STEP_P ());
209 request = PT_STEP;
c906108c 210 }
c906108c 211
8cbba7c8
MK
212 /* An address of (PTRACE_TYPE_ARG3)1 tells ptrace to continue from
213 where it was. If GDB wanted it to start some other way, we have
214 already written a new PC value to the child. */
215
216 errno = 0;
217 ptrace (request, pid, (PTRACE_TYPE_ARG3)1, target_signal_to_host (signal));
218 if (errno != 0)
219 perror_with_name ("ptrace");
c906108c 220}
adbef1f0 221#endif /* DEPRECATED_CHILD_RESUME */
c906108c 222\f
8cbba7c8 223
c906108c 224/* Start debugging the process whose number is PID. */
8cbba7c8 225
c906108c 226int
fba45db2 227attach (int pid)
c906108c 228{
d966f0cb 229#ifdef PT_ATTACH
11003ae3 230 errno = 0;
655c5466 231 ptrace (PT_ATTACH, pid, (PTRACE_TYPE_ARG3) 0, 0);
8cbba7c8 232 if (errno != 0)
c906108c
SS
233 perror_with_name ("ptrace");
234 attach_flag = 1;
235 return pid;
d966f0cb
AC
236#else
237 error ("This system does not support attaching to a process");
238#endif
c906108c
SS
239}
240
8cbba7c8
MK
241/* Stop debugging the process whose number is PID and continue it with
242 signal number SIGNAL. SIGNAL = 0 means just continue it. */
c906108c
SS
243
244void
fba45db2 245detach (int signal)
c906108c 246{
d966f0cb 247#ifdef PT_DETACH
8cbba7c8
MK
248 int pid = PIDGET (inferior_ptid);
249
11003ae3 250 errno = 0;
8cbba7c8
MK
251 ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3) 1, signal);
252 if (errno != 0)
253 perror_with_name ("ptrace");
c906108c 254 attach_flag = 0;
d966f0cb
AC
255#else
256 error ("This system does not support detaching from a process");
257#endif
c906108c 258}
c906108c 259\f
c906108c 260
652fc137 261#ifndef FETCH_INFERIOR_REGISTERS
c906108c 262
652fc137
MK
263/* U_REGS_OFFSET is the offset of the registers within the u area. */
264#ifndef U_REGS_OFFSET
265
266#ifndef offsetof
c906108c
SS
267#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
268#endif
269
c906108c 270#define U_REGS_OFFSET \
39f77062 271 ptrace (PT_READ_U, PIDGET (inferior_ptid), \
655c5466 272 (PTRACE_TYPE_ARG3) (offsetof (struct user, u_ar0)), 0) \
c906108c
SS
273 - KERNEL_U_ADDR
274#endif
275
652fc137 276/* Fetch register REGNUM from the inferior. */
c906108c
SS
277
278static void
652fc137 279fetch_register (int regnum)
c906108c 280{
652fc137
MK
281 CORE_ADDR addr;
282 size_t size;
283 PTRACE_TYPE_RET *buf;
284 int tid, i;
285
286 if (CANNOT_FETCH_REGISTER (regnum))
c906108c 287 {
652fc137 288 regcache_raw_supply (current_regcache, regnum, NULL);
c906108c
SS
289 return;
290 }
291
652fc137
MK
292 /* GNU/Linux LWP ID's are process ID's. */
293 tid = TIDGET (inferior_ptid);
294 if (tid == 0)
295 tid = PIDGET (inferior_ptid); /* Not a threaded program. */
296
297 /* This isn't really an address. But ptrace thinks of it as one. */
298 addr = register_addr (regnum, U_REGS_OFFSET);
299 size = register_size (current_gdbarch, regnum);
ed9a39eb 300
652fc137
MK
301 gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
302 buf = alloca (size);
c906108c 303
652fc137
MK
304 /* Read the register contents from the inferior a chuck at the time. */
305 for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
c906108c
SS
306 {
307 errno = 0;
652fc137 308 buf[i] = ptrace (PT_READ_U, tid, (PTRACE_TYPE_ARG3) addr, 0);
c906108c 309 if (errno != 0)
652fc137
MK
310 error ("Couldn't read register %s (#%d): %s.", REGISTER_NAME (regnum),
311 regnum, safe_strerror (errno));
312
313 addr += sizeof (PTRACE_TYPE_RET);
c906108c 314 }
652fc137 315 regcache_raw_supply (current_regcache, regnum, buf);
c906108c
SS
316}
317
652fc137
MK
318/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
319 for all registers. */
c906108c
SS
320
321void
652fc137 322fetch_inferior_registers (int regnum)
c906108c 323{
652fc137
MK
324 if (regnum == -1)
325 for (regnum = 0; regnum < NUM_REGS; regnum++)
326 fetch_register (regnum);
c906108c 327 else
652fc137 328 fetch_register (regnum);
c906108c
SS
329}
330
652fc137 331/* Store register REGNUM into the inferior. */
c906108c
SS
332
333static void
652fc137 334store_register (int regnum)
c906108c 335{
652fc137
MK
336 CORE_ADDR addr;
337 size_t size;
338 PTRACE_TYPE_RET *buf;
339 int tid, i;
c906108c 340
652fc137
MK
341 if (CANNOT_STORE_REGISTER (regnum))
342 return;
ed9a39eb 343
652fc137
MK
344 /* GNU/Linux LWP ID's are process ID's. */
345 tid = TIDGET (inferior_ptid);
346 if (tid == 0)
347 tid = PIDGET (inferior_ptid); /* Not a threaded program. */
c906108c 348
652fc137
MK
349 /* This isn't really an address. But ptrace thinks of it as one. */
350 addr = register_addr (regnum, U_REGS_OFFSET);
351 size = register_size (current_gdbarch, regnum);
8b6f1f3a 352
652fc137
MK
353 gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
354 buf = alloca (size);
8b6f1f3a 355
652fc137
MK
356 /* Write the register contents into the inferior a chunk at the time. */
357 regcache_raw_collect (current_regcache, regnum, buf);
358 for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
c906108c
SS
359 {
360 errno = 0;
652fc137 361 ptrace (PT_WRITE_U, tid, (PTRACE_TYPE_ARG3) addr, buf[i]);
c906108c 362 if (errno != 0)
652fc137
MK
363 error ("Couldn't write register %s (#%d): %s.", REGISTER_NAME (regnum),
364 regnum, safe_strerror (errno));
365
366 addr += sizeof (PTRACE_TYPE_RET);
c906108c
SS
367 }
368}
369
652fc137
MK
370/* Store register REGNUM back into the inferior. If REGNUM is -1, do
371 this for all registers (including the floating point registers). */
c906108c
SS
372
373void
652fc137 374store_inferior_registers (int regnum)
c906108c 375{
652fc137
MK
376 if (regnum == -1)
377 for (regnum = 0; regnum < NUM_REGS; regnum++)
378 store_register (regnum);
c906108c 379 else
652fc137 380 store_register (regnum);
c906108c 381}
652fc137
MK
382
383#endif /* not FETCH_INFERIOR_REGISTERS. */
c906108c
SS
384\f
385
94cd915f
MS
386/* Set an upper limit on alloca. */
387#ifndef GDB_MAX_ALLOCA
388#define GDB_MAX_ALLOCA 0x1000
389#endif
390
c906108c
SS
391#if !defined (CHILD_XFER_MEMORY)
392/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
3c2fb7bd
MK
393 in the NEW_SUN_PTRACE case. It ought to be straightforward. But
394 it appears that writing did not write the data that I specified. I
395 cannot understand where it got the data that it actually did write. */
c906108c 396
3c2fb7bd
MK
397/* Copy LEN bytes to or from inferior's memory starting at MEMADDR to
398 debugger memory starting at MYADDR. Copy to inferior if WRITE is
399 nonzero. TARGET is ignored.
c5aa993b 400
3c2fb7bd
MK
401 Returns the length copied, which is either the LEN argument or
402 zero. This xfer function does not do partial moves, since
403 child_ops doesn't allow memory operations to cross below us in the
404 target stack anyway. */
c906108c
SS
405
406int
73186089 407child_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
0a65a603 408 struct mem_attrib *attrib, struct target_ops *target)
c906108c 409{
3c2fb7bd 410 int i;
c906108c 411 /* Round starting address down to longword boundary. */
88800403 412 CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_TYPE_RET);
c906108c 413 /* Round ending address up; get number of longwords that makes. */
88800403
MK
414 int count = ((((memaddr + len) - addr) + sizeof (PTRACE_TYPE_RET) - 1)
415 / sizeof (PTRACE_TYPE_RET));
416 int alloc = count * sizeof (PTRACE_TYPE_RET);
417 PTRACE_TYPE_RET *buffer;
94cd915f
MS
418 struct cleanup *old_chain = NULL;
419
371a6e84
MK
420#ifdef PT_IO
421 /* OpenBSD 3.1, NetBSD 1.6 and FreeBSD 5.0 have a new PT_IO request
422 that promises to be much more efficient in reading and writing
423 data in the traced process's address space. */
424
425 {
426 struct ptrace_io_desc piod;
427
428 /* NOTE: We assume that there are no distinct address spaces for
429 instruction and data. */
430 piod.piod_op = write ? PIOD_WRITE_D : PIOD_READ_D;
431 piod.piod_offs = (void *) memaddr;
432 piod.piod_addr = myaddr;
433 piod.piod_len = len;
434
435 if (ptrace (PT_IO, PIDGET (inferior_ptid), (caddr_t) &piod, 0) == -1)
436 {
437 /* If the PT_IO request is somehow not supported, fallback on
438 using PT_WRITE_D/PT_READ_D. Otherwise we will return zero
439 to indicate failure. */
440 if (errno != EINVAL)
441 return 0;
442 }
443 else
444 {
445 /* Return the actual number of bytes read or written. */
446 return piod.piod_len;
447 }
448 }
449#endif
450
c906108c 451 /* Allocate buffer of that many longwords. */
94cd915f
MS
452 if (len < GDB_MAX_ALLOCA)
453 {
88800403 454 buffer = (PTRACE_TYPE_RET *) alloca (alloc);
94cd915f
MS
455 }
456 else
457 {
88800403 458 buffer = (PTRACE_TYPE_RET *) xmalloc (alloc);
94cd915f
MS
459 old_chain = make_cleanup (xfree, buffer);
460 }
c906108c
SS
461
462 if (write)
463 {
3c2fb7bd
MK
464 /* Fill start and end extra bytes of buffer with existing memory
465 data. */
88800403 466 if (addr != memaddr || len < (int) sizeof (PTRACE_TYPE_RET))
c5aa993b
JM
467 {
468 /* Need part of initial word -- fetch it. */
39f77062 469 buffer[0] = ptrace (PT_READ_I, PIDGET (inferior_ptid),
655c5466 470 (PTRACE_TYPE_ARG3) addr, 0);
c5aa993b 471 }
c906108c 472
3c2fb7bd 473 if (count > 1) /* FIXME, avoid if even boundary. */
c906108c 474 {
3c2fb7bd
MK
475 buffer[count - 1] =
476 ptrace (PT_READ_I, PIDGET (inferior_ptid),
655c5466 477 ((PTRACE_TYPE_ARG3)
88800403 478 (addr + (count - 1) * sizeof (PTRACE_TYPE_RET))), 0);
c906108c
SS
479 }
480
3c2fb7bd 481 /* Copy data to be written over corresponding part of buffer. */
88800403 482 memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_TYPE_RET) - 1)),
3c2fb7bd 483 myaddr, len);
c906108c
SS
484
485 /* Write the entire buffer. */
88800403 486 for (i = 0; i < count; i++, addr += sizeof (PTRACE_TYPE_RET))
c906108c
SS
487 {
488 errno = 0;
39f77062 489 ptrace (PT_WRITE_D, PIDGET (inferior_ptid),
655c5466 490 (PTRACE_TYPE_ARG3) addr, buffer[i]);
c906108c 491 if (errno)
c5aa993b 492 {
c906108c 493 /* Using the appropriate one (I or D) is necessary for
c5aa993b 494 Gould NP1, at least. */
c906108c 495 errno = 0;
39f77062 496 ptrace (PT_WRITE_I, PIDGET (inferior_ptid),
655c5466 497 (PTRACE_TYPE_ARG3) addr, buffer[i]);
c906108c
SS
498 }
499 if (errno)
500 return 0;
501 }
c906108c
SS
502 }
503 else
504 {
3c2fb7bd 505 /* Read all the longwords. */
88800403 506 for (i = 0; i < count; i++, addr += sizeof (PTRACE_TYPE_RET))
c906108c
SS
507 {
508 errno = 0;
39f77062 509 buffer[i] = ptrace (PT_READ_I, PIDGET (inferior_ptid),
655c5466 510 (PTRACE_TYPE_ARG3) addr, 0);
c906108c
SS
511 if (errno)
512 return 0;
513 QUIT;
514 }
515
516 /* Copy appropriate bytes out of the buffer. */
517 memcpy (myaddr,
88800403 518 (char *) buffer + (memaddr & (sizeof (PTRACE_TYPE_RET) - 1)),
c906108c
SS
519 len);
520 }
3c2fb7bd 521
94cd915f
MS
522 if (old_chain != NULL)
523 do_cleanups (old_chain);
c906108c
SS
524 return len;
525}
c906108c 526\f
c5aa993b 527
c906108c 528static void
fba45db2 529udot_info (char *dummy1, int dummy2)
c906108c
SS
530{
531#if defined (KERNEL_U_SIZE)
7343d46a 532 long udot_off; /* Offset into user struct */
c5aa993b
JM
533 int udot_val; /* Value from user struct at udot_off */
534 char mess[128]; /* For messages */
c906108c
SS
535#endif
536
c5aa993b
JM
537 if (!target_has_execution)
538 {
539 error ("The program is not being run.");
540 }
c906108c
SS
541
542#if !defined (KERNEL_U_SIZE)
543
544 /* Adding support for this command is easy. Typically you just add a
545 routine, called "kernel_u_size" that returns the size of the user
546 struct, to the appropriate *-nat.c file and then add to the native
547 config file "#define KERNEL_U_SIZE kernel_u_size()" */
548 error ("Don't know how large ``struct user'' is in this version of gdb.");
549
550#else
551
552 for (udot_off = 0; udot_off < KERNEL_U_SIZE; udot_off += sizeof (udot_val))
553 {
554 if ((udot_off % 24) == 0)
555 {
556 if (udot_off > 0)
557 {
558 printf_filtered ("\n");
559 }
7343d46a 560 printf_filtered ("%s:", paddr (udot_off));
c906108c 561 }
655c5466 562 udot_val = ptrace (PT_READ_U, PIDGET (inferior_ptid), (PTRACE_TYPE_ARG3) udot_off, 0);
c906108c
SS
563 if (errno != 0)
564 {
7343d46a
AC
565 sprintf (mess, "\nreading user struct at offset 0x%s",
566 paddr_nz (udot_off));
c906108c
SS
567 perror_with_name (mess);
568 }
569 /* Avoid using nonportable (?) "*" in print specs */
570 printf_filtered (sizeof (int) == 4 ? " 0x%08x" : " 0x%16x", udot_val);
571 }
572 printf_filtered ("\n");
573
574#endif
575}
576#endif /* !defined (CHILD_XFER_MEMORY). */
c906108c 577\f
c5aa993b 578
c906108c 579void
fba45db2 580_initialize_infptrace (void)
c906108c
SS
581{
582#if !defined (CHILD_XFER_MEMORY)
583 add_info ("udot", udot_info,
584 "Print contents of kernel ``struct user'' for current child.");
585#endif
586}
This page took 0.430329 seconds and 4 git commands to generate.