Merge from emacs--rel--22
[bpt/emacs.git] / src / unexec.c
index d916445..2ca70b7 100644 (file)
@@ -1,10 +1,11 @@
-/* Copyright (C) 1985,86,87,88,92,93,94 Free Software Foundation, Inc.
+/* Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 2001, 2002, 2003,
+                 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -14,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 
 /*
@@ -75,14 +77,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 Define this if your system uses COFF for executables.
 
-* COFF_ENCAPSULATE
-
-Define this if you are using the GNU coff encapsulated a.out format.
-This is closer to a.out than COFF. You should *not* define COFF if
-you define COFF_ENCAPSULATE
-
-Otherwise we assume you use Berkeley format.
-
 * NO_REMAP
 
 Define this if you do not want to try to save Emacs's pure data areas
@@ -133,17 +127,12 @@ before writing it (above and beyond the number of bytes of actual
 program text).  HDR's standard fields are already correct, except that
 this adjustment to the `a_text' field has not yet been made;
 thus, the amount of offset can depend on the data in the file.
-  
+
 * A_TEXT_SEEK(HDR)
 
 If defined, this macro specifies the number of bytes to seek into the
 a.out file before starting to write the text segment.
 
-* EXEC_MAGIC
-
-For machines using COFF, this macro, if defined, is a value stored
-into the magic number field of the output file.
-
 * ADJUST_EXEC_HEADER
 
 This macro can be used to generate statements to adjust or
@@ -163,21 +152,20 @@ pointer looks like an int) but not on all machines.
 #ifndef emacs
 #define PERROR(arg) perror (arg); return -1
 #else
-#define IN_UNEXEC
 #include <config.h>
 #define PERROR(file) report_error (file, new)
 #endif
 
 #ifndef CANNOT_DUMP  /* all rest of file!  */
 
-#ifndef CANNOT_UNEXEC /* most of rest of file */
-
-#ifdef COFF_ENCAPSULATE
-int need_coff_header = 1;
-#include <coff-encap/a.out.encap.h> /* The location might be a poor assumption */
-#else
-#ifdef MSDOS
+#if defined(COFF) && defined(HAVE_COFF_H)
 #include <coff.h>
+#ifdef MSDOS
+#if __DJGPP__ > 1
+#include <fcntl.h>  /* for O_RDONLY, O_RDWR */
+#include <crt0.h>   /* for _crt0_startup_flags and its bits */
+static int save_djgpp_startup_flags;
+#endif /* __DJGPP__ > 1 */
 #define filehdr external_filehdr
 #define scnhdr external_scnhdr
 #define syment external_syment
@@ -195,16 +183,13 @@ struct aouthdr
   unsigned long                text_start;/* base of text used for this file */
   unsigned long                data_start;/* base of data used for this file */
 };
-
-
-#else /* not MSDOS */
-#include <a.out.h>
 #endif /* not MSDOS */
-#endif
+#else  /* not COFF */
+#include <a.out.h>
+#endif /* not COFF */
 
-/* Define getpagesize () if the system does not.
-   Note that this may depend on symbols defined in a.out.h
- */
+/* Define getpagesize if the system does not.
+   Note that this may depend on symbols defined in a.out.h.  */
 #include "getpagesize.h"
 
 #ifndef makedev                        /* Try to detect types.h already loaded */
@@ -242,6 +227,8 @@ long lnnoptr;                       /* Pointer to line-number info within file */
 static long text_scnptr;
 static long data_scnptr;
 
+static long coff_offset;
+
 #else /* not COFF */
 
 #ifdef HPUX
@@ -263,11 +250,6 @@ extern char *sbrk ();
 
 #define SYMS_START ((long) N_SYMOFF (ohdr))
 
-/* Some machines override the structure name for an a.out header.  */
-#ifndef EXEC_HDR_TYPE
-#define EXEC_HDR_TYPE struct exec
-#endif
-
 #ifdef HPUX
 #ifdef HP9000S200_ID
 #define MY_ID HP9000S200_ID
@@ -279,11 +261,11 @@ static MAGIC OLDMAGIC = {MY_ID, SHARE_MAGIC};
 static MAGIC NEWMAGIC = {MY_ID, DEMAND_MAGIC};
 #define N_TXTOFF(x) TEXT_OFFSET(x)
 #define N_SYMOFF(x) LESYM_OFFSET(x)
-static EXEC_HDR_TYPE hdr, ohdr;
+static struct exec hdr, ohdr;
 
 #else /* not HPUX */
 
-#if defined (USG) && !defined (IBMAIX) && !defined (IRIS) && !defined (COFF_ENCAPSULATE) && !defined (LINUX)
+#if defined (USG) && !defined (IRIS) && !defined (GNU_LINUX)
 static struct bhdr hdr, ohdr;
 #define a_magic fmagic
 #define a_text tsize
@@ -297,20 +279,15 @@ static struct bhdr hdr, ohdr;
     (((x).fmagic)!=OMAGIC && ((x).fmagic)!=NMAGIC &&\
      ((x).fmagic)!=FMAGIC && ((x).fmagic)!=IMAGIC)
 #define NEWMAGIC FMAGIC
-#else /* IRIS or IBMAIX or not USG */
-static EXEC_HDR_TYPE hdr, ohdr;
+#else /* IRIS or not USG */
+static struct exec hdr, ohdr;
 #define NEWMAGIC ZMAGIC
-#endif /* IRIS or IBMAIX not USG */
+#endif /* IRIS or not USG */
 #endif /* not HPUX */
 
 static int unexec_text_start;
 static int unexec_data_start;
 
-#ifdef COFF_ENCAPSULATE
-/* coffheader is defined in the GNU a.out.encap.h file.  */
-struct coffheader coffheader;
-#endif
-
 #endif /* not COFF */
 
 static int pagemask;
@@ -362,48 +339,6 @@ static int copy_text_and_data ();
 static int copy_sym ();
 static void mark_x ();
 
-/* ****************************************************************
- * unexec
- *
- * driving logic.
- */
-unexec (new_name, a_name, data_start, bss_start, entry_address)
-     char *new_name, *a_name;
-     unsigned data_start, bss_start, entry_address;
-{
-  int new, a_out = -1;
-
-  if (a_name && (a_out = open (a_name, O_RDONLY)) < 0)
-    {
-      PERROR (a_name);
-    }
-  if ((new = creat (new_name, 0666)) < 0)
-    {
-      PERROR (new_name);
-    }
-
-  if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
-      || copy_text_and_data (new, a_out) < 0
-      || copy_sym (new, a_out, a_name, new_name) < 0
-#ifdef COFF
-#ifndef COFF_BSD_SYMBOLS
-      || adjust_lnnoptrs (new, a_out, new_name) < 0
-#endif
-#endif
-      )
-    {
-      close (new);
-      /* unlink (new_name);            /* Failed, unlink new a.out */
-      return -1;       
-    }
-
-  close (new);
-  if (a_out >= 0)
-    close (a_out);
-  mark_x (new_name);
-  return 0;
-}
-
 /* ****************************************************************
  * make_hdr
  *
@@ -473,9 +408,32 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
     }
 
 #ifdef COFF
+  coff_offset = 0L;            /* stays zero, except in DJGPP */
+
   /* Salvage as much info from the existing file as possible */
   if (a_out >= 0)
     {
+#ifdef MSDOS
+#if __DJGPP__ > 1
+      /* Support the coff-go32-exe format with a prepended stub, since
+        this is what GCC 2.8.0 and later generates by default in DJGPP.  */
+      unsigned short mz_header[3];
+
+      if (read (a_out, &mz_header, sizeof (mz_header)) != sizeof (mz_header))
+       {
+         PERROR (a_name);
+       }
+      if (mz_header[0] == 0x5a4d || mz_header[0] == 0x4d5a) /* "MZ" or "ZM" */
+       {
+         coff_offset = (long)mz_header[2] * 512L;
+         if (mz_header[1])
+           coff_offset += (long)mz_header[1] - 512L;
+         lseek (a_out, coff_offset, 0);
+       }
+      else
+       lseek (a_out, 0L, 0);
+#endif /* __DJGPP__ > 1 */
+#endif /* MSDOS */
       if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
        {
          PERROR (a_name);
@@ -490,6 +448,7 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
          block_copy_start += sizeof (f_ohdr);
        }
       /* Loop through section headers, copying them in */
+      lseek (a_out, coff_offset + sizeof (f_hdr) + f_hdr.f_opthdr, 0);
       for (scns = f_hdr.f_nscns; scns > 0; scns--) {
        if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
          {
@@ -534,12 +493,6 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
 #endif
 
   f_hdr.f_flags |= (F_RELFLG | F_EXEC);
-#ifdef TPIX
-  f_hdr.f_nscns = 3;
-#endif
-#ifdef EXEC_MAGIC
-  f_ohdr.magic = EXEC_MAGIC;
-#endif
 #ifndef NO_REMAP
   f_ohdr.text_start = (long) start_of_text ();
   f_ohdr.tsize = data_start - f_ohdr.text_start;
@@ -547,13 +500,11 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
 #endif /* NO_REMAP */
   f_ohdr.dsize = bss_start - f_ohdr.data_start;
   f_ohdr.bsize = bss_end - bss_start;
-#ifndef KEEP_OLD_TEXT_SCNPTR
   /* On some machines, the old values are right.
      ??? Maybe on all machines with NO_REMAP.  */
   f_thdr.s_size = f_ohdr.tsize;
   f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr);
   f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr));
-#endif /* KEEP_OLD_TEXT_SCNPTR */
 #ifdef ADJUST_TEXT_SCNHDR_SIZE
   /* On some machines, `text size' includes all headers.  */
   f_thdr.s_size -= f_thdr.s_scnptr;
@@ -565,16 +516,8 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
   f_thdr.s_scnptr
     = (f_thdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
 #endif /* SECTION_ALIGNMENT */
-#ifdef TPIX
-  f_thdr.s_scnptr = 0xd0;
-#endif
   text_scnptr = f_thdr.s_scnptr;
-#ifdef ADJUST_TEXTBASE
-  text_scnptr = sizeof (f_hdr) + sizeof (f_ohdr) + (f_hdr.f_nscns) * (sizeof (f_thdr));
-#endif
-#ifndef KEEP_OLD_PADDR
   f_dhdr.s_paddr = f_ohdr.data_start;
-#endif /* KEEP_OLD_PADDR */
   f_dhdr.s_vaddr = f_ohdr.data_start;
   f_dhdr.s_size = f_ohdr.dsize;
   f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size;
@@ -591,9 +534,7 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
     = (f_dhdr.s_scnptr + DATA_SECTION_ALIGNMENT) & ~DATA_SECTION_ALIGNMENT;
 #endif /* DATA_SECTION_ALIGNMENT */
   data_scnptr = f_dhdr.s_scnptr;
-#ifndef KEEP_OLD_PADDR
   f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize;
-#endif /* KEEP_OLD_PADDR */
   f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
   f_bhdr.s_size = f_ohdr.bsize;
   f_bhdr.s_scnptr = 0L;
@@ -657,7 +598,9 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
    * will not adjust the file pointer for that section correctly.
    */
 
-  lseek (a_out, sizeof (f_hdr) + sizeof (f_ohdr), 0);
+  /* This used to use sizeof (f_ohdr) instead of .f_opthdr.
+     .f_opthdr is said to be right when there is no optional header.  */
+  lseek (a_out, sizeof (f_hdr) + f_hdr.f_opthdr, 0);
 
   for (scns = f_hdr.f_nscns; scns > 0; scns--)
     {
@@ -696,16 +639,6 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
   /* Get symbol table info from header of a.out file if given one. */
   if (a_out >= 0)
     {
-#ifdef COFF_ENCAPSULATE
-      if (read (a_out, &coffheader, sizeof coffheader) != sizeof coffheader)
-       {
-         PERROR(a_name);
-       }
-      if (coffheader.f_magic != COFF_MAGIC)
-       {
-         ERROR1("%s doesn't have legal coff magic number\n", a_name);
-       }
-#endif
       if (read (a_out, &ohdr, sizeof hdr) != sizeof hdr)
        {
          PERROR (a_name);
@@ -719,17 +652,10 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
     }
   else
     {
-#ifdef COFF_ENCAPSULATE
-      /* We probably could without too much trouble. The code is in gld
-       * but I don't have that much time or incentive.
-       */
-      ERROR0 ("can't build a COFF file from scratch yet");
-#else
 #ifdef MSDOS   /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
       bzero ((void *)&hdr, sizeof hdr);
 #else
       bzero (&hdr, sizeof hdr);
-#endif
 #endif
     }
 
@@ -759,43 +685,18 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
 
 #endif /* not NO_REMAP */
 
-#ifdef COFF_ENCAPSULATE
-  /* We are encapsulating BSD format within COFF format.  */
-  {
-    struct coffscn *tp, *dp, *bp;
-    tp = &coffheader.scns[0];
-    dp = &coffheader.scns[1];
-    bp = &coffheader.scns[2];
-    tp->s_size = hdr.a_text + sizeof(struct exec);
-    dp->s_paddr = data_start;
-    dp->s_vaddr = data_start;
-    dp->s_size = hdr.a_data;
-    bp->s_paddr = dp->s_vaddr + dp->s_size;
-    bp->s_vaddr = bp->s_paddr;
-    bp->s_size = hdr.a_bss;
-    coffheader.tsize = tp->s_size;
-    coffheader.dsize = dp->s_size;
-    coffheader.bsize = bp->s_size;
-    coffheader.text_start = tp->s_vaddr;
-    coffheader.data_start = dp->s_vaddr;
-  }
-  if (write (new, &coffheader, sizeof coffheader) != sizeof coffheader)
-    {
-      PERROR(new_name);
-    }
-#endif /* COFF_ENCAPSULATE */
-
   if (write (new, &hdr, sizeof hdr) != sizeof hdr)
     {
       PERROR (new_name);
     }
 
+#if 0 /* This #ifndef caused a bug on GNU/Linux when using QMAGIC.  */
   /* This adjustment was done above only #ifndef NO_REMAP,
      so only undo it now #ifndef NO_REMAP.  */
-#ifndef NO_REMAP
+  /* #ifndef NO_REMAP  */
+#endif
 #ifdef A_TEXT_OFFSET
   hdr.a_text -= A_TEXT_OFFSET (ohdr);
-#endif
 #endif
 
   return 0;
@@ -803,6 +704,61 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
 #endif /* not COFF */
 }
 \f
+write_segment (new, ptr, end)
+     int new;
+     register char *ptr, *end;
+{
+  register int i, nwrite, ret;
+  char buf[80];
+#ifndef USE_CRT_DLL
+  extern int errno;
+#endif
+  /* This is the normal amount to write at once.
+     It is the size of block that NFS uses.  */
+  int writesize = 1 << 13;
+  int pagesize = getpagesize ();
+  char zeros[1 << 13];
+
+  bzero (zeros, sizeof (zeros));
+
+  for (i = 0; ptr < end;)
+    {
+      /* Distance to next multiple of writesize.  */
+      nwrite = (((int) ptr + writesize) & -writesize) - (int) ptr;
+      /* But not beyond specified end.  */
+      if (nwrite > end - ptr) nwrite = end - ptr;
+      ret = write (new, ptr, nwrite);
+      /* If write gets a page fault, it means we reached
+        a gap between the old text segment and the old data segment.
+        This gap has probably been remapped into part of the text segment.
+        So write zeros for it.  */
+      if (ret == -1
+#ifdef EFAULT
+         && errno == EFAULT
+#endif
+         )
+       {
+         /* Write only a page of zeros at once,
+            so that we we don't overshoot the start
+            of the valid memory in the old data segment.  */
+         if (nwrite > pagesize)
+           nwrite = pagesize;
+         write (new, zeros, nwrite);
+       }
+#if 0 /* Now that we have can ask `write' to write more than a page,
+        it is legit for write do less than the whole amount specified.  */
+      else if (nwrite != ret)
+       {
+         sprintf (buf,
+                  "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
+                  ptr, new, nwrite, ret, errno);
+         PERROR (buf);
+       }
+#endif
+      i += nwrite;
+      ptr += nwrite;
+    }
+}
 /* ****************************************************************
  * copy_text_and_data
  *
@@ -874,12 +830,21 @@ copy_text_and_data (new, a_out)
 
 #else /* COFF, but not USG_SHARED_LIBRARIES */
 
+#ifdef MSDOS
+#if __DJGPP__ >= 2
+  /* Dump the original table of exception handlers, not the one
+     where our exception hooks are registered.  */
+  __djgpp_exception_toggle ();
+
+  /* Switch off startup flags that might have been set at runtime
+     and which might change the way that dumped Emacs works.  */
+  save_djgpp_startup_flags = _crt0_startup_flags;
+  _crt0_startup_flags &= ~(_CRT0_FLAG_NO_LFN | _CRT0_FLAG_NEARPTR);
+#endif
+#endif
+
   lseek (new, (long) text_scnptr, 0);
   ptr = (char *) f_ohdr.text_start;
-#ifdef HEADER_INCL_IN_TEXT
-  /* For Gould UTX/32, text starts after headers */
-  ptr = (char *) (ptr + text_scnptr);
-#endif /* HEADER_INCL_IN_TEXT */
   end = ptr + f_ohdr.tsize;
   write_segment (new, ptr, end);
 
@@ -888,13 +853,23 @@ copy_text_and_data (new, a_out)
   end = ptr + f_ohdr.dsize;
   write_segment (new, ptr, end);
 
+#ifdef MSDOS
+#if __DJGPP__ >= 2
+  /* Restore our exception hooks.  */
+  __djgpp_exception_toggle ();
+
+  /* Restore the startup flags.  */
+  _crt0_startup_flags = save_djgpp_startup_flags;
+#endif
+#endif
+
 #endif /* USG_SHARED_LIBRARIES */
 
 #else /* if not COFF */
 
 /* Some machines count the header as part of the text segment.
    That is to say, the header appears in core
-   just before the address that start_of_text () returns.
+   just before the address that start_of_text returns.
    For them, N_TXTOFF is the place where the header goes.
    We must adjust the seek to the place after the header.
    Note that at this point hdr.a_text does *not* count
@@ -922,46 +897,6 @@ copy_text_and_data (new, a_out)
 
   return 0;
 }
-
-write_segment (new, ptr, end)
-     int new;
-     register char *ptr, *end;
-{
-  register int i, nwrite, ret;
-  char buf[80];
-  extern int errno;
-  char zeros[128];
-
-  bzero (zeros, sizeof zeros);
-
-  for (i = 0; ptr < end;)
-    {
-      /* distance to next multiple of 128.  */
-      nwrite = (((int) ptr + 128) & -128) - (int) ptr;
-      /* But not beyond specified end.  */
-      if (nwrite > end - ptr) nwrite = end - ptr;
-      ret = write (new, ptr, nwrite);
-      /* If write gets a page fault, it means we reached
-        a gap between the old text segment and the old data segment.
-        This gap has probably been remapped into part of the text segment.
-        So write zeros for it.  */
-      if (ret == -1
-#ifdef EFAULT
-         && errno == EFAULT
-#endif
-         )
-       write (new, zeros, nwrite);
-      else if (nwrite != ret)
-       {
-         sprintf (buf,
-                  "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
-                  ptr, new, nwrite, ret, errno);
-         PERROR (buf);
-       }
-      i += nwrite;
-      ptr += nwrite;
-    }
-}
 \f
 /* ****************************************************************
  * copy_sym
@@ -986,10 +921,12 @@ copy_sym (new, a_out, a_name, new_name)
 
 #ifdef COFF
   if (lnnoptr)                 /* if there is line number info */
-    lseek (a_out, lnnoptr, 0); /* start copying from there */
+    lseek (a_out, coff_offset + lnnoptr, 0);   /* start copying from there */
   else
-#endif /* COFF */
-    lseek (a_out, SYMS_START, 0);      /* Position a.out to symtab. */
+    lseek (a_out, coff_offset + SYMS_START, 0);        /* Position a.out to symtab. */
+#else  /* not COFF */
+  lseek (a_out, SYMS_START, 0);        /* Position a.out to symtab. */
+#endif /* not COFF */
 
   while ((n = read (a_out, page, sizeof page)) > 0)
     {
@@ -1061,13 +998,8 @@ adjust_lnnoptrs (writedesc, readdesc, new_name)
 {
   register int nsyms;
   register int new;
-#if defined (amdahl_uts) || defined (pfa)
-  SYMENT symentry;
-  AUXENT auxentry;
-#else
   struct syment symentry;
   union auxent auxentry;
-#endif
 
   if (!lnnoptr || !f_hdr.f_symptr)
     return 0;
@@ -1108,6 +1040,49 @@ adjust_lnnoptrs (writedesc, readdesc, new_name)
 
 #endif /* COFF */
 
-#endif /* not CANNOT_UNEXEC */
+/* ****************************************************************
+ * unexec
+ *
+ * driving logic.
+ */
+unexec (new_name, a_name, data_start, bss_start, entry_address)
+     char *new_name, *a_name;
+     unsigned data_start, bss_start, entry_address;
+{
+  int new, a_out = -1;
+
+  if (a_name && (a_out = open (a_name, O_RDONLY)) < 0)
+    {
+      PERROR (a_name);
+    }
+  if ((new = creat (new_name, 0666)) < 0)
+    {
+      PERROR (new_name);
+    }
+
+  if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
+      || copy_text_and_data (new, a_out) < 0
+      || copy_sym (new, a_out, a_name, new_name) < 0
+#ifdef COFF
+#ifndef COFF_BSD_SYMBOLS
+      || adjust_lnnoptrs (new, a_out, new_name) < 0
+#endif
+#endif
+      )
+    {
+      close (new);
+      /* unlink (new_name);            /* Failed, unlink new a.out */
+      return -1;
+    }
+
+  close (new);
+  if (a_out >= 0)
+    close (a_out);
+  mark_x (new_name);
+  return 0;
+}
 
 #endif /* not CANNOT_DUMP */
+
+/* arch-tag: 62409b69-e27a-4a7c-9413-0210d6b54e7f
+   (do not change this comment) */