root/mtcp/mtcp_util.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mtcp_strtol
  2. mtcp_strlen
  3. mtcp_strncpy
  4. mtcp_strcpy
  5. mtcp_strncat
  6. mtcp_strncmp
  7. mtcp_strcmp
  8. mtcp_strstr
  9. mtcp_strchr
  10. mtcp_strstartswith
  11. mtcp_strendswith
  12. mtcp_memset
  13. mtcp_memcpy
  14. mtcp_read_all
  15. mtcp_mkdir
  16. mtcp_readfile
  17. mtcp_skipfile
  18. mtcp_write_all
  19. mtcp_readchar
  20. mtcp_readdec
  21. mtcp_readhex
  22. mtcp_readmapsline
  23. mtcp_get_memory_region_of_this_library
  24. rwrite
  25. mtcp_printf

   1 /*****************************************************************************
   2  * Copyright (C) 2006-2009 Michael Rieker <mrieker@nii.net>                  *
   3  * Copyright (C) 2010-2014 Kapil Arya <kapil@ccs.neu.edu>                    *
   4  * Copyright (C) 2010-2014 Gene Cooperman <gene@ccs.neu.edu>                 *
   5  *                                                                           *
   6  * DMTCP is free software: you can redistribute it and/or                    *
   7  * modify it under the terms of the GNU Lesser General Public License as     *
   8  * published by the Free Software Foundation, either version 3 of the        *
   9  * License, or (at your option) any later version.                           *
  10  *                                                                           *
  11  * DMTCP 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 Lesser General Public License for more details.                       *
  15  *                                                                           *
  16  * You should have received a copy of the GNU Lesser General Public          *
  17  * License along with DMTCP.  If not, see <http://www.gnu.org/licenses/>.    *
  18  *****************************************************************************/
  19 
  20 /*****************************************************************************
  21  *
  22  *  Read from file without using any external memory routines (like malloc,
  23  *  fget, etc)
  24  *
  25  *
  26  *****************************************************************************/
  27 
  28 #include <unistd.h>
  29 #include <string.h>
  30 #include <errno.h>
  31 #include <sys/sysmacros.h>
  32 #include <limits.h>
  33 
  34 #include "mtcp_util.h"
  35 #include "../membarrier.h"
  36 
  37 unsigned long mtcp_strtol (char *str)
  38 {
  39   int mtcp_sys_errno=0;
  40   unsigned long int v = 0;
  41   int base = 10;
  42   if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
  43     str += 2;
  44     base = 16;
  45   } else if (str[0] == '0') {
  46     str += 1;
  47     base = 8;
  48   } else {
  49     base = 10;
  50   }
  51 
  52   while (*str != '\0') {
  53     int c;
  54     if ((*str >= '0') && (*str <= '9')) c = *str - '0';
  55     else if ((*str >= 'a') && (*str <= 'f')) c = *str + 10 - 'a';
  56     else if ((*str >= 'A') && (*str <= 'F')) c = *str + 10 - 'A';
  57     else {
  58       MTCP_PRINTF("Error converting str to int\n");
  59       mtcp_abort();
  60     }
  61     MTCP_ASSERT(c < base);
  62     v = v * base + c;
  63     str++;
  64   }
  65   return v;
  66 }
  67 
  68 size_t mtcp_strlen(const char *s)
  69 {
  70   size_t len = 0;
  71   while (*s++ != '\0') {
  72     len++;
  73   }
  74   return len;
  75 }
  76 
  77 void mtcp_strncpy(char *dest, const char *src, size_t n)
  78 {
  79   size_t i;
  80 
  81   for (i = 0; i < n && src[i] != '\0'; i++)
  82     dest[i] = src[i];
  83   if (i < n) {
  84     dest[i] = '\0';
  85   }
  86 
  87   //return dest;
  88 }
  89 
  90 void mtcp_strcpy(char *dest, const char *src)
  91 {
  92   while (*src != '\0') {
  93     *dest++ = *src++;
  94   }
  95 }
  96 
  97 void mtcp_strncat(char *dest, const char *src, size_t n)
  98 {
  99   mtcp_strncpy(dest + mtcp_strlen(dest), src, n);
 100   //return dest;
 101 }
 102 
 103 int mtcp_strncmp (const char *s1, const char *s2, size_t n)
 104 {
 105   unsigned char c1 = '\0';
 106   unsigned char c2 = '\0';
 107 
 108   while (n > 0) {
 109     c1 = (unsigned char) *s1++;
 110     c2 = (unsigned char) *s2++;
 111     if (c1 == '\0' || c1 != c2)
 112       return c1 - c2;
 113     n--;
 114   }
 115   return c1 - c2;
 116 }
 117 
 118 int mtcp_strcmp (const char *s1, const char *s2)
 119 {
 120   size_t n = mtcp_strlen(s2);
 121   unsigned char c1 = '\0';
 122   unsigned char c2 = '\0';
 123 
 124   while (n > 0) {
 125     c1 = (unsigned char) *s1++;
 126     c2 = (unsigned char) *s2++;
 127     if (c1 == '\0' || c1 != c2)
 128       return c1 - c2;
 129     n--;
 130   }
 131   return c1 - c2;
 132 }
 133 
 134 const void *mtcp_strstr(const char *string, const char *substring)
 135 {
 136   for ( ; *string != '\0' ; string++) {
 137     const char *ptr1, *ptr2;
 138     for (ptr1 = string, ptr2 = substring;
 139          *ptr1 == *ptr2 && *ptr2 != '\0';
 140          ptr1++, ptr2++) ;
 141     if (*ptr2 == '\0')
 142       return string;
 143   }
 144   return NULL;
 145 }
 146 
 147 //   The  strchr() function from earlier C library returns a ptr to the first
 148 //   occurrence  of  c  (converted  to a  char) in string s, or a
 149 //   null pointer  if  c  does  not  occur  in  the  string.
 150 char *mtcp_strchr(const char *s, int c) {
 151   for (; *s != (char)'\0'; s++)
 152     if (*s == (char)c)
 153       return (char *)s;
 154   return NULL;
 155 }
 156 
 157 int mtcp_strstartswith (const char *s1, const char *s2)
 158 {
 159   if (mtcp_strlen(s1) >= mtcp_strlen(s2)) {
 160     return mtcp_strncmp(s1, s2, mtcp_strlen(s2)) == 0;
 161   }
 162   return 0;
 163 }
 164 
 165 int mtcp_strendswith (const char *s1, const char *s2)
 166 {
 167   size_t len1 = mtcp_strlen(s1);
 168   size_t len2 = mtcp_strlen(s2);
 169 
 170   if (len1 < len2)
 171     return 0;
 172 
 173   s1 += (len1 - len2);
 174 
 175   return mtcp_strncmp(s1, s2, len2) == 0;
 176 }
 177 
 178 void *mtcp_memset(void *s, int c, size_t n)
 179 {
 180   char *p = s;
 181   while (n-- > 0) {
 182     *p++ = (char)c;
 183   }
 184   return s;
 185 }
 186 
 187 void *mtcp_memcpy(void *dstpp, const void *srcpp, size_t len)
 188 {
 189   char *dst = (char*) dstpp;
 190   const char *src = (const char*) srcpp;
 191   while (len > 0) {
 192     *dst++ = *src++;
 193     len--;
 194   }
 195   return dstpp;
 196 }
 197 
 198 ssize_t mtcp_read_all(int fd, void *buf, size_t count)
 199 {
 200   int mtcp_sys_errno;
 201   int rc;
 202   char *ptr = (char *) buf;
 203   size_t num_read = 0;
 204   for (num_read = 0; num_read < count;) {
 205     rc = mtcp_sys_read (fd, ptr + num_read, count - num_read);
 206     if (rc == -1) {
 207       if (mtcp_sys_errno == EINTR || mtcp_sys_errno == EAGAIN)
 208         continue;
 209       else
 210         return -1;
 211     }
 212     else if (rc == 0)
 213       break;
 214     else // else rc > 0
 215       num_read += rc;
 216   }
 217   return num_read;
 218 }
 219 
 220 void mtcp_mkdir(const char *dir)
 221 {
 222   int mtcp_sys_errno;
 223   char tmp[PATH_MAX];
 224   size_t i;
 225   size_t len = mtcp_strlen(dir);
 226   MTCP_ASSERT(len < PATH_MAX);
 227 
 228   mtcp_memset(tmp, 0, sizeof(tmp));
 229   mtcp_strcpy(tmp, dir);
 230 
 231   while (tmp[len - 1] == '/') {
 232     tmp[len - 1] = 0;
 233     len--;
 234   }
 235 
 236   for(i = 1; i < len; i++) {
 237     if(tmp[i] == '/') {
 238       tmp[i] = '\0';
 239       mtcp_sys_mkdir(tmp, S_IRWXU);
 240       tmp[i] = '/';
 241     }
 242   }
 243   mtcp_sys_mkdir(tmp, S_IRWXU);
 244 }
 245 
 246 int mtcp_readfile(int fd, void *buf, size_t size)
 247 {
 248   int mtcp_sys_errno;
 249   ssize_t rc;
 250   size_t ar = 0;
 251   int tries = 0;
 252 
 253 #if __arm__ || __aarch64__
 254   /* ARM requires DMB instruction to ensure that any store to memory
 255    * by a prior kernel mmap call has completed.
 256    * SEE ARM Information Center article:
 257    *   "In what siutations might I need to insert memory barrier instructions?"
 258    *   (and especially section on "Memory Remapping"
 259    */
 260   WMB;
 261 #endif
 262 
 263   while(ar != size) {
 264     rc = mtcp_sys_read(fd, buf + ar, size - ar);
 265     if (rc < 0 && rc > -4096) { /* kernel could return large unsigned int */
 266       if (rc == -1 && (mtcp_sys_errno == EAGAIN || mtcp_sys_errno == EINTR)) {
 267         tries++;
 268         if (tries++ >= 10) {
 269           MTCP_PRINTF(" failed to read after 10 tries in a row.\n");
 270           mtcp_abort();
 271         }
 272         continue;
 273       } else {  /* else error:  rc < 0 and not EAGAIN and not EINTR */
 274         MTCP_PRINTF("error %d reading checkpoint\n", mtcp_sys_errno);
 275         MTCP_PRINTF("only read %u bytes instead of %u from checkpoint file\n",
 276                     (unsigned)ar, (unsigned)size);
 277         mtcp_abort();
 278       }
 279     }
 280     else if (rc == 0) {  /* if end of file */
 281       return 0;  /* success:  end of file */
 282     }
 283     ar += rc;
 284   }
 285 #if __arm__ || __aarch64__
 286   /* ARM requires DSB and ISB instructions to ensure that prior read
 287    * instructions complete, and prevent instructions being fetched prior to this.
 288    * SEE ARM Information Center article:
 289    *   "In what siutations might I need to insert memory barrier instructions?"
 290    *   (and especially section on "Memory Remapping"
 291    */
 292   WMB;
 293   IMB;
 294 #endif
 295   return ar;  /* read ar characters */
 296 }
 297 
 298 // FIXME:  Equiv. to mtcp_sys_lseek(fd, size, SEEK_CUR), but doesn't work
 299 //         on sockets.  Why not just call mtcp_readfile(fd, tmp_addr, size)?
 300 void mtcp_skipfile(int fd, size_t size)
 301 {
 302   int mtcp_sys_errno;
 303   VA tmp_addr = mtcp_sys_mmap(0, size, PROT_WRITE | PROT_READ,
 304                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 305   if (tmp_addr == MAP_FAILED) {
 306     MTCP_PRINTF("mtcp_sys_mmap() failed with error: %d", mtcp_sys_errno);
 307     mtcp_abort();
 308   }
 309   mtcp_readfile(fd, tmp_addr, size);
 310   if (mtcp_sys_munmap(tmp_addr, size) == -1) {
 311     MTCP_PRINTF("mtcp_sys_munmap() failed with error: %d", mtcp_sys_errno);
 312     mtcp_abort();
 313   }
 314 }
 315 
 316 // NOTE: This functions is called by mtcp_printf() so do not invoke
 317 // mtcp_printf() from within this function.
 318 ssize_t mtcp_write_all(int fd, const void *buf, size_t count)
 319 {
 320   int mtcp_sys_errno;
 321   const char *ptr = (const char *) buf;
 322   size_t num_written = 0;
 323 
 324   do {
 325     ssize_t rc = mtcp_sys_write (fd, ptr + num_written, count - num_written);
 326     if (rc == -1) {
 327       if (mtcp_sys_errno == EINTR || mtcp_sys_errno == EAGAIN)
 328         continue;
 329       else
 330         return rc;
 331     }
 332     else if (rc == 0)
 333       break;
 334     else // else rc > 0
 335       num_written += rc;
 336   } while (num_written < count);
 337   return num_written;
 338 }
 339 
 340 /* Read non-null character, return null if EOF */
 341 char mtcp_readchar (int fd)
 342 {
 343   int mtcp_sys_errno;
 344   char c;
 345   int rc;
 346 
 347   do {
 348     rc = mtcp_sys_read (fd, &c, 1);
 349   } while ( rc == -1 && mtcp_sys_errno == EINTR );
 350   if (rc <= 0) return (0);
 351   return (c);
 352 }
 353 
 354 /* Read decimal number, return value and terminating character */
 355 char mtcp_readdec (int fd, VA *value)
 356 {
 357   char c;
 358   unsigned long int v;
 359 
 360   v = 0;
 361   while (1) {
 362     c = mtcp_readchar (fd);
 363     if ((c >= '0') && (c <= '9')) c -= '0';
 364     else break;
 365     v = v * 10 + c;
 366   }
 367   *value = (VA)v;
 368   return (c);
 369 }
 370 
 371 /* Read decimal number, return value and terminating character */
 372 char mtcp_readhex (int fd, VA *value)
 373 {
 374   char c;
 375   unsigned long int v;
 376 
 377   v = 0;
 378   while (1) {
 379     c = mtcp_readchar (fd);
 380       if ((c >= '0') && (c <= '9')) c -= '0';
 381     else if ((c >= 'a') && (c <= 'f')) c -= 'a' - 10;
 382     else if ((c >= 'A') && (c <= 'F')) c -= 'A' - 10;
 383     else break;
 384     v = v * 16 + c;
 385   }
 386   *value = (VA)v;
 387   return (c);
 388 }
 389 
 390 /*****************************************************************************
 391  *
 392  *  Read /proc/self/maps line, converting it to an Area descriptor struct
 393  *    Input:
 394  *      mapsfd = /proc/self/maps file, positioned to beginning of a line
 395  *    Output:
 396  *      mtcp_readmapsline = 0 : was at end-of-file, nothing read
 397  *      *area = filled in
 398  *    Note:
 399  *      Line from /procs/self/maps is in form:
 400  *      <startaddr>-<endaddrexclusive> rwxs <fileoffset> <devmaj>:<devmin>
 401  *          <inode>    <filename>\n
 402  *      all numbers in hexadecimal except inode is in decimal
 403  *      anonymous will be shown with offset=devmaj=devmin=inode=0 and
 404  *          no '     filename'
 405  *
 406  *****************************************************************************/
 407 
 408 int mtcp_readmapsline (int mapsfd, Area *area)
 409 {
 410   int mtcp_sys_errno __attribute__((unused));
 411   char c, rflag, sflag, wflag, xflag;
 412   int i;
 413   off_t offset;
 414   unsigned int long devmajor, devminor, inodenum;
 415   VA startaddr, endaddr;
 416 
 417   c = mtcp_readhex (mapsfd, &startaddr);
 418   if (c != '-') {
 419     if ((c == 0) && (startaddr == 0)) return (0);
 420     goto skipeol;
 421   }
 422   c = mtcp_readhex (mapsfd, &endaddr);
 423   if (c != ' ') goto skipeol;
 424   if (endaddr < startaddr) goto skipeol;
 425 
 426   rflag = c = mtcp_readchar (mapsfd);
 427   if ((c != 'r') && (c != '-')) goto skipeol;
 428   wflag = c = mtcp_readchar (mapsfd);
 429   if ((c != 'w') && (c != '-')) goto skipeol;
 430   xflag = c = mtcp_readchar (mapsfd);
 431   if ((c != 'x') && (c != '-')) goto skipeol;
 432   sflag = c = mtcp_readchar (mapsfd);
 433   if ((c != 's') && (c != 'p')) goto skipeol;
 434 
 435   c = mtcp_readchar (mapsfd);
 436   if (c != ' ') goto skipeol;
 437 
 438   c = mtcp_readhex (mapsfd, (VA *)&offset);
 439   if (c != ' ') goto skipeol;
 440   area -> offset = offset;
 441 
 442   c = mtcp_readhex (mapsfd, (VA *)&devmajor);
 443   if (c != ':') goto skipeol;
 444   c = mtcp_readhex (mapsfd, (VA *)&devminor);
 445   if (c != ' ') goto skipeol;
 446   c = mtcp_readdec (mapsfd, (VA *)&inodenum);
 447   area -> name[0] = '\0';
 448   while (c == ' ') c = mtcp_readchar (mapsfd);
 449   if (c == '/' || c == '[') { /* absolute pathname, or [stack], [vdso], etc. */
 450     i = 0;
 451     do {
 452       area -> name[i++] = c;
 453       if (i == sizeof area -> name) goto skipeol;
 454       c = mtcp_readchar (mapsfd);
 455     } while (c != '\n');
 456     area -> name[i] = '\0';
 457   }
 458 
 459   if (c != '\n') goto skipeol;
 460 
 461   area -> addr = startaddr;
 462   area -> endAddr = endaddr;
 463   area -> size = endaddr - startaddr;
 464   area -> prot = 0;
 465   if (rflag == 'r') area -> prot |= PROT_READ;
 466   if (wflag == 'w') area -> prot |= PROT_WRITE;
 467   if (xflag == 'x') area -> prot |= PROT_EXEC;
 468   area -> flags = MAP_FIXED;
 469   if (sflag == 's') area -> flags |= MAP_SHARED;
 470   if (sflag == 'p') area -> flags |= MAP_PRIVATE;
 471   if (area -> name[0] == '\0') area -> flags |= MAP_ANONYMOUS;
 472 
 473   area->devmajor = devmajor;
 474   area->devminor = devminor;
 475   area->inodenum = inodenum;
 476   return (1);
 477 
 478 skipeol:
 479   DPRINTF("ERROR:  mtcp readmapsline*: bad maps line <%c", c);
 480   while ((c != '\n') && (c != '\0')) {
 481     c = mtcp_readchar (mapsfd);
 482     mtcp_printf ("%c", c);
 483   }
 484   mtcp_printf (">\n");
 485   mtcp_abort ();
 486   return (0);  /* NOTREACHED : stop compiler warning */
 487 }
 488 
 489 /*****************************************************************************
 490  *  Discover the memory occupied by this library (libmtcp.so)
 491  *
 492  * This is used to find:  mtcp_shareable_begin mtcp_shareable_end
 493  * The standard way is to modifiy the linker script (mtcp.t in Makefile).
 494  * The method here works by looking at /proc/PID/maps
 495  * However, this is error-prone.  It assumes that the kernel labels
 496  *   all memory regions of this library with the library filename,
 497  *   except for a single memory region for static vars in lib.  The
 498  *   latter case is handled by assuming a single region adjacent to
 499  *   to the labelled regions, and occuring after the labelled regions.
 500  *   This assumes that all of these memory regions form a contiguous region.
 501  * We optionally call this only because Fedora uses eu-strip in rpmlint,
 502  *   and eu-strip modifies libmtcp.so in a way that libmtcp.so no longer works.
 503  * This is arguably a bug in eu-strip.
 504  *****************************************************************************/
 505 // static int dummy_uninitialized_static_var;
 506 void mtcp_get_memory_region_of_this_library(VA *startaddr, VA *endaddr)
 507 {
 508   int mtcp_sys_errno;
 509   ino_t lib_inode;
 510   struct {
 511     VA start_addr;
 512     VA end_addr;
 513   } text, guard, rodata, rwdata, bssdata;
 514 
 515   Area area;
 516   VA thislib_fnc = (void*) &mtcp_get_memory_region_of_this_library;
 517   // VA thislib_static_var = (VA) &dummy_uninitialized_static_var;
 518   char filename[PATH_MAX] = {0};
 519   text.start_addr = guard.start_addr = rodata.start_addr = NULL;
 520   rwdata.start_addr = bssdata.start_addr = bssdata.end_addr = NULL;
 521   int mapsfd = mtcp_sys_open("/proc/self/maps", O_RDONLY, 0);
 522   MTCP_ASSERT(mapsfd != -1);
 523 
 524   while (mtcp_readmapsline (mapsfd, &area)) {
 525     VA start_addr = area.addr;
 526     VA end_addr = area.addr + area.size;
 527 
 528     if (thislib_fnc >= start_addr && thislib_fnc < end_addr) {
 529       MTCP_ASSERT(text.start_addr == NULL);
 530       text.start_addr = start_addr; text.end_addr = end_addr;
 531       mtcp_strcpy(filename, area.name);
 532       lib_inode = area.inodenum;
 533       continue;
 534     }
 535 
 536     if (text.start_addr != NULL && guard.start_addr == NULL &&
 537         area.inodenum == lib_inode) {
 538       MTCP_ASSERT(mtcp_strcmp(filename, area.name) == 0);
 539       MTCP_ASSERT(area.addr == text.end_addr);
 540       if (area.prot == 0) {
 541         /* The guard pages are unreadable due to the "---p" protection. Even if
 542          * the protection is changed to "r--p", a read will result in a SIGSEGV
 543          * as the pages are not backed by the kernel. A better way to handle
 544          * this is to remap these pages with anonymous memory.
 545          */
 546         MTCP_ASSERT(mtcp_sys_mmap(start_addr, area.size, PROT_READ,
 547                                   MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED,
 548                                   -1, 0) == start_addr);
 549         guard.start_addr = start_addr; guard.end_addr = end_addr;
 550         continue;
 551       } else {
 552         // No guard pages found. This is probably the ROData section.
 553         guard.start_addr = start_addr; guard.end_addr = start_addr;
 554       }
 555     }
 556 
 557     if (guard.start_addr != NULL && rodata.start_addr == NULL &&
 558         area.inodenum == lib_inode) {
 559       MTCP_ASSERT(mtcp_strcmp(filename, area.name) == 0);
 560       MTCP_ASSERT(area.addr == guard.end_addr);
 561       if (area.prot == PROT_READ ||
 562           // On some systems, all sections of the library have exec
 563           // permissions.
 564           area.prot == (PROT_READ|PROT_EXEC)) {
 565         rodata.start_addr = start_addr; rodata.end_addr = end_addr;
 566         continue;
 567       } else {
 568         // No ROData section. This is probably the RWData section.
 569         rodata.start_addr = start_addr; rodata.end_addr = start_addr;
 570       }
 571     }
 572 
 573     if (rodata.start_addr != NULL && rwdata.start_addr == NULL &&
 574         area.inodenum == lib_inode) {
 575       MTCP_ASSERT(mtcp_strcmp(filename, area.name) == 0);
 576       MTCP_ASSERT(area.addr == rodata.end_addr);
 577       MTCP_ASSERT(area.prot == (PROT_READ|PROT_WRITE) ||
 578                   // On some systems, all sections of the library have exec
 579                   // permissions.
 580                   area.prot == (PROT_READ|PROT_WRITE|PROT_EXEC));
 581       rwdata.start_addr = start_addr; rwdata.end_addr = end_addr;
 582       continue;
 583     }
 584 
 585     if (rwdata.start_addr != NULL && bssdata.start_addr == NULL &&
 586         area.name[0] == '\0') {
 587       /* /proc/PID/maps does not label the filename for memory region holding
 588        * static variables in a library.  But that is also part of this
 589        * library (libmtcp.so).
 590        * So, find the meory region for static memory variables and add it.
 591        */
 592       MTCP_ASSERT(area.addr == rwdata.end_addr);
 593       MTCP_ASSERT(area.prot == (PROT_READ|PROT_WRITE) ||
 594                   // On some systems, all sections of the library have exec
 595                   // permissions.
 596                   area.prot == (PROT_READ|PROT_WRITE|PROT_EXEC));
 597       //MTCP_ASSERT(thislib_static_var >= start_addr &&
 598                   //thislib_static_var < end_addr);
 599       bssdata.start_addr = start_addr; bssdata.end_addr = end_addr;
 600       break;
 601     }
 602   }
 603   mtcp_sys_close(mapsfd);
 604 
 605   MTCP_ASSERT(text.start_addr != NULL);
 606   *startaddr = text.start_addr;
 607 
 608   if (bssdata.end_addr != NULL) {
 609     *endaddr = bssdata.end_addr;
 610   } else if (rwdata.end_addr != NULL) {
 611     *endaddr = rwdata.end_addr;
 612   } else if (rodata.end_addr != NULL) {
 613     *endaddr = rodata.end_addr;
 614   } else {
 615     MTCP_PRINTF("Not implemented.\n");
 616     mtcp_abort();
 617   }
 618 }
 619 
 620 /*****************************************************************************
 621  *  Print on stderr without using any malloc stuff
 622  *
 623  *  We can't use vsnprintf or anything like that as it calls malloc.
 624  *  This routine supports only simple %c, %d, %o, %p, %s, %u, %x (or %X)
 625  *****************************************************************************/
 626 
 627 static void rwrite (char const *buff, int size) {
 628   mtcp_write_all(2, buff, size);
 629 }
 630 
 631 void mtcp_printf (char const *format, ...)
 632 {
 633   char hexdigits[] = "0123456789abcdef";
 634   char const *p, *q;
 635   va_list ap;
 636 
 637   va_start (ap, format);
 638 
 639   /* Scan along until we find a % */
 640 
 641   for (p = format; (q = mtcp_strchr (p, '%')) != NULL; p = ++ q) {
 642 
 643     /* Print all before the % as is */
 644 
 645     if (q > p) rwrite (p, q - p);
 646 
 647     /* Process based on character following the % */
 648 
 649 gofish:
 650     switch (*(++ q)) {
 651 
 652       /* Ignore digits (field width) */
 653 
 654       case '0' ... '9': {
 655         goto gofish;
 656       }
 657 
 658       /* Single character */
 659 
 660       case 'c': {
 661         char buff[4];
 662 
 663         buff[0] = va_arg (ap, int); // va_arg (ap, char);
 664         rwrite (buff, 1);
 665         break;
 666       }
 667 
 668       /* Signed decimal integer */
 669 
 670       case 'd': {
 671         // On 64-bit machines the largest unsigned is 20 digits.
 672         char buff[20];
 673         int i, n, neg;
 674 
 675         i = sizeof buff;
 676         n = va_arg (ap, int);
 677         neg = (n < 0);
 678         if (neg) n = - n;
 679         do {
 680           buff[--i] = (n % 10) + '0';
 681           n /= 10;
 682         } while (n > 0);
 683         if (neg) buff[--i] = '-';
 684         rwrite (buff + i, sizeof buff - i);
 685         break;
 686       }
 687 
 688       /* Unsigned octal number */
 689 
 690       case 'o': {
 691         // On 64-bit machines the largest unsigned is 22 digits.
 692         char buff[24];
 693         int i;
 694         unsigned int n;
 695 
 696         i = sizeof buff;
 697         n = va_arg (ap, unsigned int);
 698         do {
 699           buff[--i] = (n & 7) + '0';
 700           n /= 8;
 701         } while (n > 0);
 702         rwrite (buff + i, sizeof buff - i);
 703         break;
 704       }
 705 
 706       /* Address in hexadecimal */
 707 
 708       case 'p': {
 709         // On 64-bit machines the largest unsigned is 16 digits.
 710         char buff[18];
 711         int i;
 712         unsigned long int n;
 713 
 714         i = sizeof buff;
 715         n = (unsigned long int) va_arg (ap, void *);
 716         do {
 717           buff[--i] = hexdigits[n%16];
 718           n /= 16;
 719         } while (n > 0);
 720         buff[--i] = 'x';
 721         buff[--i] = '0';
 722         rwrite (buff + i, sizeof buff - i);
 723         break;
 724       }
 725 
 726       /* Null terminated string */
 727 
 728       case 's': {
 729         p = va_arg (ap, char *);
 730         rwrite (p, mtcp_strlen (p));
 731         break;
 732       }
 733 
 734       /* Unsigned decimal integer */
 735 
 736       case 'u': {
 737         // On 64-bit machines the largest unsigned is 20 digits.
 738         char buff[18];
 739         int i;
 740         unsigned int n;
 741 
 742         i = sizeof buff;
 743         n = va_arg (ap, unsigned int);
 744         do {
 745           buff[--i] = (n % 10) + '0';
 746           n /= 10;
 747         } while (n > 0);
 748         rwrite (buff + i, sizeof buff - i);
 749         break;
 750       }
 751 
 752       /* Unsigned hexadecimal number */
 753 
 754       case 'X':
 755       case 'x': {
 756         // On 64-bit machines the largest unsigned is 16 digits.
 757         char buff[18];
 758         int i;
 759         unsigned int n;
 760 
 761         i = sizeof buff;
 762         n = va_arg (ap, unsigned int);
 763         do {
 764           buff[--i] = hexdigits[n%16];
 765           n /= 16;
 766         } while (n > 0);
 767         rwrite (buff + i, sizeof buff - i);
 768         break;
 769       }
 770 
 771       /* Anything else, print the character as is */
 772 
 773       default: {
 774         rwrite (q, 1);
 775         break;
 776       }
 777     }
 778   }
 779 
 780   va_end (ap);
 781 
 782   /* Print whatever comes after the last format spec */
 783 
 784   rwrite (p, mtcp_strlen (p));
 785 }

/* [<][>][^][v][top][bottom][index][help] */