source: patches/grub-0.97-use_mmap-2.patch @ 4cc665a

clfs-1.2clfs-2.1clfs-3.0.0-systemdclfs-3.0.0-sysvinitsystemdsysvinit
Last change on this file since 4cc665a was a1811b6, checked in by Joe Ciccone <jciccone@…>, 14 years ago

Update the grub patches.

  • Property mode set to 100644
File size: 19.1 KB
RevLine 
[a1811b6]1Submitted By: Jim Gifford <clfs at cross-lfs dot org>
2Date: 07-15-2009
3Initial Package Version: 0.97
4Upstream Status: Unknown
5Origin: Grub Bug Report - http://savannah.gnu.org/bugs/?func=detailitem&item_id=11312
6Description: This patch fixes the following issues on x86_64
7        1) malloc'd pages seem to lack the execute bit on x86_64;
8        2) grub seems to use some stack pointer diversion to malloc'd pages;
9        3) nested functions execute data on the stack;
10        4) this causes a segfault (at least on my machine)
11
12diff -Naur grub-0.97.orig/grub/asmstub.c grub-0.97/grub/asmstub.c
13--- grub-0.97.orig/grub/asmstub.c       2005-02-16 12:45:14.000000000 -0800
14+++ grub-0.97/grub/asmstub.c    2009-07-05 23:32:43.000000000 -0700
15@@ -42,6 +42,7 @@
16 #include <sys/time.h>
17 #include <termios.h>
18 #include <signal.h>
19+#include <sys/mman.h>
20 
21 #ifdef __linux__
22 # include <sys/ioctl.h>                /* ioctl */
23@@ -79,7 +80,7 @@
24 struct apm_info apm_bios_info;
25 
26 /* Emulation requirements. */
27-char *grub_scratch_mem = 0;
28+void *grub_scratch_mem = 0;
29 
30 struct geometry *disks = 0;
31 
32@@ -103,14 +104,62 @@
33 static unsigned int serial_speed;
34 #endif /* SIMULATE_SLOWNESS_OF_SERIAL */
35 
36+/* This allocates page-aligned storage of the specified size, which must be
37+ * a multiple of the page size as determined by calling sysconf(_SC_PAGESIZE)
38+ */
39+#ifdef __linux__
40+static void *
41+grub_mmap_alloc(size_t len)
42+{
43+  int mmap_flags = MAP_ANONYMOUS|MAP_PRIVATE;
44+
45+#ifdef MAP_32BIT
46+  mmap_flags |= MAP_32BIT;
47+#endif
48+  /* Mark the simulated stack executable, as GCC uses stack trampolines
49+   * to implement nested functions. */
50+  return mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC, mmap_flags, -1, 0);
51+}
52+#else /* !defined(__linux__) */
53+static void *
54+grub_mmap_alloc(size_t len)
55+{
56+  int fd = 0, offset = 0, ret = 0;
57+  void *pa = MAP_FAILED;
58+  char template[] = "/tmp/grub_mmap_alloc_XXXXXX";
59+  int e;
60+
61+  fd = mkstemp(template);
62+  if (fd < 0)
63+    return pa;
64+
65+  unlink(template);
66+
67+  ret = ftruncate(fd, len);
68+  if (ret < 0)
69+    return pa;
70+
71+  /* Mark the simulated stack executable, as GCC uses stack trampolines
72+   * to implement nested functions. */
73+  pa = mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC,
74+                  MAP_PRIVATE, fd, offset);
75+
76+  e = errno;
77+  close(fd);
78+  errno = e;
79+  return pa;
80+}
81+#endif /* defined(__linux__) */
82+
83 /* The main entry point into this mess. */
84 int
85 grub_stage2 (void)
86 {
87   /* These need to be static, because they survive our stack transitions. */
88   static int status = 0;
89-  static char *realstack;
90-  char *scratch, *simstack;
91+  static void *realstack;
92+  void *simstack_alloc_base, *simstack;
93+  size_t simstack_size, page_size;
94   int i;
95 
96   auto void doit (void);
97@@ -142,9 +191,35 @@
98     }
99 
100   assert (grub_scratch_mem == 0);
101-  scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15);
102-  assert (scratch);
103-  grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4);
104+
105+  /* Allocate enough pages for 0x100000 + EXTENDED_SIZE + 15, and
106+   * make sure the memory is aligned to a multiple of the system's
107+   * page size */
108+  page_size = sysconf (_SC_PAGESIZE);
109+  simstack_size = ( 0x100000 + EXTENDED_MEMSIZE + 15);
110+  if (simstack_size % page_size)
111+    {
112+      /* If we're not on a page_size boundary, round up to the next one */
113+      simstack_size &= ~(page_size-1);
114+      simstack_size += page_size;
115+    }
116+
117+  /* Add one for a PROT_NONE boundary page at each end. */
118+  simstack_size += 2 * page_size;
119+
120+  simstack_alloc_base = grub_mmap_alloc(simstack_size);
121+  assert (simstack_alloc_base != MAP_FAILED);
122+
123+  /* mark pages above and below our simstack area as innaccessable.
124+   * If the implementation we're using doesn't support that, then the
125+   * new protection modes are undefined.  It's safe to just ignore
126+   * them, though.  It'd be nice if we knew that we'd get a SEGV for
127+   * touching the area, but that's all.  it'd be nice to have. */
128+  mprotect (simstack_alloc_base, page_size, PROT_NONE);
129+  mprotect ((void *)((unsigned long)simstack_alloc_base +
130+                         simstack_size - page_size),  page_size, PROT_NONE);
131+
132+  grub_scratch_mem = (void *)((unsigned long)simstack_alloc_base + page_size);
133 
134   /* FIXME: simulate the memory holes using mprot, if available. */
135 
136@@ -217,7 +292,7 @@
137   device_map = 0;
138   free (disks);
139   disks = 0;
140-  free (scratch);
141+  munmap(simstack_alloc_base, simstack_size);
142   grub_scratch_mem = 0;
143 
144   if (serial_device)
145diff -Naur grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c
146--- grub-0.97.orig/stage2/builtins.c    2005-02-15 13:58:23.000000000 -0800
147+++ grub-0.97/stage2/builtins.c 2009-07-05 23:42:45.000000000 -0700
148@@ -130,63 +130,97 @@
149   grub_printf ("[%d,%d,%d]", sector, offset, length);
150 }
151 
152-
153+/* blocklist_read_helper nee disk_read_blocklist_func was a nested
154+ * function, to which pointers were taken and exposed globally.  Even
155+ * in the GNU-C nested functions extension, they have local linkage,
156+ * and aren't guaranteed to be accessable *at all* outside of their
157+ * containing scope.
158+ *
159+ * Above and beyond all of that, the variables within blocklist_func_context
160+ * are originally local variables, with local (not even static) linkage,
161+ * from within blocklist_func.  These were each referenced by
162+ * disk_read_blocklist_func, which is only called from other functions
163+ * through a globally scoped pointer.
164+ *
165+ * The documentation in GCC actually uses the words "all hell will break
166+ * loose" to describe this scenario.
167+ *
168+ * Also, "start_sector" was also used uninitialized, but gcc doesn't warn
169+ * about it (possibly because of the scoping madness?)
170+ */
171+   
172+static struct {
173+       int start_sector;
174+       int num_sectors;
175+       int num_entries;
176+       int last_length;
177+} blocklist_func_context = {
178+       .start_sector = 0,
179+       .num_sectors = 0,
180+       .num_entries = 0,
181+       .last_length = 0
182+};
183+
184+/* Collect contiguous blocks into one entry as many as possible,
185+   and print the blocklist notation on the screen.  */
186+static void
187+blocklist_read_helper (int sector, int offset, int length)
188+{
189+  int *start_sector = &blocklist_func_context.start_sector;
190+  int *num_sectors = &blocklist_func_context.num_sectors;
191+  int *num_entries = &blocklist_func_context.num_entries;
192+  int *last_length = &blocklist_func_context.last_length;
193+
194+  if (*num_sectors > 0)
195+  {
196+    if (*start_sector + *num_sectors == sector
197+      && offset == 0 && *last_length == SECTOR_SIZE)
198+    {
199+      *num_sectors++;
200+      *last_length = length;
201+      return;
202+    }
203+    else
204+    {
205+      if (*last_length == SECTOR_SIZE)
206+        grub_printf ("%s%d+%d", *num_entries ? "," : "",
207+          *start_sector - part_start, *num_sectors);
208+      else if (*num_sectors > 1)
209+        grub_printf ("%s%d+%d,%d[0-%d]", *num_entries ? "," : "",
210+          *start_sector - part_start, *num_sectors-1,
211+          *start_sector + *num_sectors-1 - part_start,
212+          *last_length);
213+      else
214+        grub_printf ("%s%d[0-%d]", *num_entries ? "," : "",
215+          *start_sector - part_start, *last_length);
216+      *num_entries++;
217+      *num_sectors = 0;
218+    }
219+  }
220+
221+  if (offset > 0)
222+  {
223+    grub_printf("%s%d[%d-%d]", *num_entries ? "," : "",
224+          sector-part_start, offset, offset+length);
225+    *num_entries++;
226+  }
227+  else
228+  {
229+    *start_sector = sector;
230+    *num_sectors = 1;
231+    *last_length = length;
232+  }
233+}
234+
235 /* blocklist */
236 static int
237 blocklist_func (char *arg, int flags)
238 {
239   char *dummy = (char *) RAW_ADDR (0x100000);
240-  int start_sector;
241-  int num_sectors = 0;
242-  int num_entries = 0;
243-  int last_length = 0;
244 
245-  auto void disk_read_blocklist_func (int sector, int offset, int length);
246
247-  /* Collect contiguous blocks into one entry as many as possible,
248-     and print the blocklist notation on the screen.  */
249-  auto void disk_read_blocklist_func (int sector, int offset, int length)
250-    {
251-      if (num_sectors > 0)
252-       {
253-         if (start_sector + num_sectors == sector
254-             && offset == 0 && last_length == SECTOR_SIZE)
255-           {
256-             num_sectors++;
257-             last_length = length;
258-             return;
259-           }
260-         else
261-           {
262-             if (last_length == SECTOR_SIZE)
263-               grub_printf ("%s%d+%d", num_entries ? "," : "",
264-                            start_sector - part_start, num_sectors);
265-             else if (num_sectors > 1)
266-               grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "",
267-                            start_sector - part_start, num_sectors-1,
268-                            start_sector + num_sectors-1 - part_start,
269-                            last_length);
270-             else
271-               grub_printf ("%s%d[0-%d]", num_entries ? "," : "",
272-                            start_sector - part_start, last_length);
273-             num_entries++;
274-             num_sectors = 0;
275-           }
276-       }
277-
278-      if (offset > 0)
279-       {
280-         grub_printf("%s%d[%d-%d]", num_entries ? "," : "",
281-                     sector-part_start, offset, offset+length);
282-         num_entries++;
283-       }
284-      else
285-       {
286-         start_sector = sector;
287-         num_sectors = 1;
288-         last_length = length;
289-       }
290-    }
291+  int *start_sector = &blocklist_func_context.start_sector;
292+  int *num_sectors = &blocklist_func_context.num_sectors;
293+  int *num_entries = &blocklist_func_context.num_entries;
294 
295   /* Open the file.  */
296   if (! grub_open (arg))
297@@ -206,15 +240,15 @@
298   grub_printf (")");
299 
300   /* Read in the whole file to DUMMY.  */
301-  disk_read_hook = disk_read_blocklist_func;
302+  disk_read_hook = blocklist_read_helper;
303   if (! grub_read (dummy, -1))
304     goto fail;
305 
306   /* The last entry may not be printed yet.  Don't check if it is a
307    * full sector, since it doesn't matter if we read too much. */
308-  if (num_sectors > 0)
309-    grub_printf ("%s%d+%d", num_entries ? "," : "",
310-                start_sector - part_start, num_sectors);
311+  if (*num_sectors > 0)
312+       grub_printf ("%s%d+%d", *num_entries ? "," : "",
313+                *start_sector - part_start, *num_sectors);
314 
315   grub_printf ("\n");
316   
317@@ -1740,6 +1774,77 @@
318 
319 
320 /* install */
321+static struct {
322+       int saved_sector;
323+       int installaddr;
324+       int installlist;
325+       char *stage2_first_buffer;
326+} install_func_context = {
327+       .saved_sector = 0,
328+       .installaddr = 0,
329+       .installlist = 0,
330+       .stage2_first_buffer = NULL,
331+};
332+
333+/* Save the first sector of Stage2 in STAGE2_SECT.  */
334+/* Formerly disk_read_savesect_func with local scope inside install_func */
335+static void
336+install_savesect_helper(int sector, int offset, int length)
337+{
338+  if (debug)
339+    printf ("[%d]", sector);
340+
341+  /* ReiserFS has files which sometimes contain data not aligned
342+     on sector boundaries.  Returning an error is better than
343+     silently failing. */
344+  if (offset != 0 || length != SECTOR_SIZE)
345+    errnum = ERR_UNALIGNED;
346+
347+  install_func_context.saved_sector = sector;
348+}
349+
350+/* Write SECTOR to INSTALLLIST, and update INSTALLADDR and  INSTALLSECT.  */
351+/* Formerly disk_read_blocklist_func with local scope inside install_func */
352+static void
353+install_blocklist_helper (int sector, int offset, int length)
354+{
355+  int *installaddr = &install_func_context.installaddr;
356+  int *installlist = &install_func_context.installlist;
357+  char **stage2_first_buffer = &install_func_context.stage2_first_buffer;
358+  /* Was the last sector full? */
359+  static int last_length = SECTOR_SIZE;
360+
361+  if (debug)
362+    printf("[%d]", sector);
363+
364+  if (offset != 0 || last_length != SECTOR_SIZE)
365+    {
366+      /* We found a non-sector-aligned data block. */
367+      errnum = ERR_UNALIGNED;
368+      return;
369+    }
370+
371+  last_length = length;
372+
373+  if (*((unsigned long *) (*installlist - 4))
374+      + *((unsigned short *) *installlist) != sector
375+      || *installlist == (int) *stage2_first_buffer + SECTOR_SIZE + 4)
376+    {
377+      *installlist -= 8;
378+
379+      if (*((unsigned long *) (*installlist - 8)))
380+        errnum = ERR_WONT_FIT;
381+      else
382+        {
383+          *((unsigned short *) (*installlist + 2)) = (*installaddr >> 4);
384+          *((unsigned long *) (*installlist - 4)) = sector;
385+        }
386+    }
387+
388+  *((unsigned short *) *installlist) += 1;
389+  *installaddr += 512;
390+}
391+
392 static int
393 install_func (char *arg, int flags)
394 {
395@@ -1747,8 +1852,12 @@
396   char *stage1_buffer = (char *) RAW_ADDR (0x100000);
397   char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
398   char *old_sect = stage2_buffer + SECTOR_SIZE;
399-  char *stage2_first_buffer = old_sect + SECTOR_SIZE;
400-  char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
401+  /* stage2_first_buffer used to be defined as:
402+   * char *stage2_first_buffer = old_sect + SECTOR_SIZE;  */
403+  char **stage2_first_buffer = &install_func_context.stage2_first_buffer;
404+  /* and stage2_second_buffer was:
405+   * char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE; */
406+  char *stage2_second_buffer = old_sect + SECTOR_SIZE + SECTOR_SIZE;
407   /* XXX: Probably SECTOR_SIZE is reasonable.  */
408   char *config_filename = stage2_second_buffer + SECTOR_SIZE;
409   char *dummy = config_filename + SECTOR_SIZE;
410@@ -1757,10 +1866,11 @@
411   int src_drive, src_partition, src_part_start;
412   int i;
413   struct geometry dest_geom, src_geom;
414-  int saved_sector;
415+  int *saved_sector = &install_func_context.saved_sector;
416   int stage2_first_sector, stage2_second_sector;
417   char *ptr;
418-  int installaddr, installlist;
419+  int *installaddr = &install_func_context.installaddr;
420+  int *installlist = &install_func_context.installlist;
421   /* Point to the location of the name of a configuration file in Stage 2.  */
422   char *config_file_location;
423   /* If FILE is a Stage 1.5?  */
424@@ -1769,67 +1879,13 @@
425   int is_open = 0;
426   /* If LBA is forced?  */
427   int is_force_lba = 0;
428-  /* Was the last sector full? */
429-  int last_length = SECTOR_SIZE;
430
431+
432+  *stage2_first_buffer = old_sect + SECTOR_SIZE;
433 #ifdef GRUB_UTIL
434   /* If the Stage 2 is in a partition mounted by an OS, this will store
435      the filename under the OS.  */
436   char *stage2_os_file = 0;
437 #endif /* GRUB_UTIL */
438
439-  auto void disk_read_savesect_func (int sector, int offset, int length);
440-  auto void disk_read_blocklist_func (int sector, int offset, int length);
441
442-  /* Save the first sector of Stage2 in STAGE2_SECT.  */
443-  auto void disk_read_savesect_func (int sector, int offset, int length)
444-    {
445-      if (debug)
446-       printf ("[%d]", sector);
447-
448-      /* ReiserFS has files which sometimes contain data not aligned
449-         on sector boundaries.  Returning an error is better than
450-         silently failing. */
451-      if (offset != 0 || length != SECTOR_SIZE)
452-       errnum = ERR_UNALIGNED;
453-
454-      saved_sector = sector;
455-    }
456-
457-  /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
458-     INSTALLSECT.  */
459-  auto void disk_read_blocklist_func (int sector, int offset, int length)
460-    {
461-      if (debug)
462-       printf("[%d]", sector);
463-
464-      if (offset != 0 || last_length != SECTOR_SIZE)
465-       {
466-         /* We found a non-sector-aligned data block. */
467-         errnum = ERR_UNALIGNED;
468-         return;
469-       }
470-
471-      last_length = length;
472-
473-      if (*((unsigned long *) (installlist - 4))
474-         + *((unsigned short *) installlist) != sector
475-         || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4)
476-       {
477-         installlist -= 8;
478-
479-         if (*((unsigned long *) (installlist - 8)))
480-           errnum = ERR_WONT_FIT;
481-         else
482-           {
483-             *((unsigned short *) (installlist + 2)) = (installaddr >> 4);
484-             *((unsigned long *) (installlist - 4)) = sector;
485-           }
486-       }
487-
488-      *((unsigned short *) installlist) += 1;
489-      installaddr += 512;
490-    }
491 
492   /* First, check the GNU-style long option.  */
493   while (1)
494@@ -1862,10 +1918,10 @@
495   addr = skip_to (0, file);
496 
497   /* Get the installation address.  */
498-  if (! safe_parse_maxint (&addr, &installaddr))
499+  if (! safe_parse_maxint (&addr, installaddr))
500     {
501       /* ADDR is not specified.  */
502-      installaddr = 0;
503+      *installaddr = 0;
504       ptr = addr;
505       errnum = 0;
506     }
507@@ -1961,17 +2017,17 @@
508       = 0x9090;
509   
510   /* Read the first sector of Stage 2.  */
511-  disk_read_hook = disk_read_savesect_func;
512-  if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
513+  disk_read_hook = install_savesect_helper;
514+  if (grub_read (*stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
515     goto fail;
516 
517-  stage2_first_sector = saved_sector;
518+  stage2_first_sector = *saved_sector;
519   
520   /* Read the second sector of Stage 2.  */
521   if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
522     goto fail;
523 
524-  stage2_second_sector = saved_sector;
525+  stage2_second_sector = *saved_sector;
526   
527   /* Check for the version of Stage 2.  */
528   if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
529@@ -1987,27 +2043,27 @@
530 
531   /* If INSTALLADDR is not specified explicitly in the command-line,
532      determine it by the Stage 2 id.  */
533-  if (! installaddr)
534+  if (! *installaddr)
535     {
536       if (! is_stage1_5)
537        /* Stage 2.  */
538-       installaddr = 0x8000;
539+       *installaddr = 0x8000;
540       else
541        /* Stage 1.5.  */
542-       installaddr = 0x2000;
543+       *installaddr = 0x2000;
544     }
545 
546   *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
547     = stage2_first_sector;
548   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
549-    = installaddr;
550+    = *installaddr;
551   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
552-    = installaddr >> 4;
553+    = *installaddr >> 4;
554 
555-  i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
556+  i = (int) *stage2_first_buffer + SECTOR_SIZE - 4;
557   while (*((unsigned long *) i))
558     {
559-      if (i < (int) stage2_first_buffer
560+      if (i < (int) *stage2_first_buffer
561          || (*((int *) (i - 4)) & 0x80000000)
562          || *((unsigned short *) i) >= 0xA00
563          || *((short *) (i + 2)) == 0)
564@@ -2021,13 +2077,13 @@
565       i -= 8;
566     }
567 
568-  installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
569-  installaddr += SECTOR_SIZE;
570+  *installlist = (int) *stage2_first_buffer + SECTOR_SIZE + 4;
571+  *installaddr += SECTOR_SIZE;
572   
573   /* Read the whole of Stage2 except for the first sector.  */
574   grub_seek (SECTOR_SIZE);
575 
576-  disk_read_hook = disk_read_blocklist_func;
577+  disk_read_hook = install_blocklist_helper;
578   if (! grub_read (dummy, -1))
579     goto fail;
580   
581@@ -2110,7 +2166,7 @@
582          /* Skip the first sector.  */
583          grub_seek (SECTOR_SIZE);
584         
585-         disk_read_hook = disk_read_savesect_func;
586+         disk_read_hook = install_savesect_helper;
587          if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
588            goto fail;
589         
590@@ -2180,7 +2236,7 @@
591          else
592 #endif /* GRUB_UTIL */
593            {
594-             if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
595+             if (! devwrite (*saved_sector - part_start, 1, stage2_buffer))
596                goto fail;
597            }
598        }
599@@ -2202,7 +2258,7 @@
600          goto fail;
601        }
602 
603-      if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
604+      if (fwrite (*stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
605        {
606          fclose (fp);
607          errnum = ERR_WRITE;
608@@ -2229,7 +2285,7 @@
609        goto fail;
610 
611       if (! devwrite (stage2_first_sector - src_part_start, 1,
612-                     stage2_first_buffer))
613+                     *stage2_first_buffer))
614        goto fail;
615 
616       if (! devwrite (stage2_second_sector - src_part_start, 1,
617diff -Naur grub-0.97.orig/stage2/shared.h grub-0.97/stage2/shared.h
618--- grub-0.97.orig/stage2/shared.h      2004-06-19 09:40:09.000000000 -0700
619+++ grub-0.97/stage2/shared.h   2009-07-05 23:32:43.000000000 -0700
620@@ -36,8 +36,8 @@
621 
622 /* Maybe redirect memory requests through grub_scratch_mem. */
623 #ifdef GRUB_UTIL
624-extern char *grub_scratch_mem;
625-# define RAW_ADDR(x) ((x) + (int) grub_scratch_mem)
626+extern void *grub_scratch_mem;
627+# define RAW_ADDR(x) ((x) + (unsigned long) grub_scratch_mem)
628 # define RAW_SEG(x) (RAW_ADDR ((x) << 4) >> 4)
629 #else
630 # define RAW_ADDR(x) (x)
Note: See TracBrowser for help on using the repository browser.