struct file_struct *make_file(const char *fname, struct file_list *flist,
			      STRUCT_STAT *stp, int flags, int filter_level)
{
	static char *lastdir;
	static int lastdir_len = -1;
	struct file_struct *file;
	char thisname[MAXPATHLEN];
	char linkname[MAXPATHLEN];
	int alloc_len, basename_len, linkname_len;
	int extra_len = file_extra_cnt * EXTRA_LEN;
	const char *basename;
	alloc_pool_t *pool;
	STRUCT_STAT st;
	char *bp;

	if (strlcpy(thisname, fname, sizeof thisname) >= sizeof thisname) {
		io_error |= IOERR_GENERAL;
		rprintf(FERROR_XFER, "skipping overly long name: %s\n", fname);
		return NULL;
	}
	clean_fname(thisname, 0);
	if (sanitize_paths)
		sanitize_path(thisname, thisname, "", 0, SP_DEFAULT);

	if (stp && (S_ISDIR(stp->st_mode) || IS_MISSING_FILE(*stp))) {
		/* This is needed to handle a "symlink/." with a --relative
		 * dir, or a request to delete a specific file. */
		st = *stp;
		*linkname = '\0'; /* make IBM code checker happy */
	} else if (readlink_stat(thisname, &st, linkname) != 0) {
		int save_errno = errno;
		/* See if file is excluded before reporting an error. */
		if (filter_level != NO_FILTERS
		 && (is_excluded(thisname, 0, filter_level)
		  || is_excluded(thisname, 1, filter_level))) {
			if (ignore_perishable && save_errno != ENOENT)
				non_perishable_cnt++;
			return NULL;
		}
		if (save_errno == ENOENT) {
#ifdef SUPPORT_LINKS
			/* When our options tell us to follow a symlink that
			 * points nowhere, tell the user about the symlink
			 * instead of giving a "vanished" message.  We only
			 * dereference a symlink if one of the --copy*links
			 * options was specified, so there's no need for the
			 * extra lstat() if one of these options isn't on. */
			if ((copy_links || copy_unsafe_links || copy_dirlinks)
			 && x_lstat(thisname, &st, NULL) == 0
			 && S_ISLNK(st.st_mode)) {
				io_error |= IOERR_GENERAL;
				rprintf(FERROR_XFER, "symlink has no referent: %s\n",
					full_fname(thisname));
			} else
#endif
			{
				enum logcode c = am_daemon && protocol_version < 28
					       ? FERROR : FWARNING;
				io_error |= IOERR_VANISHED;
				rprintf(c, "file has vanished: %s\n",
					full_fname(thisname));
			}
		} else {
			io_error |= IOERR_GENERAL;
			rsyserr(FERROR_XFER, save_errno, "readlink_stat(%s) failed",
				full_fname(thisname));
		}
		return NULL;
	} else if (IS_MISSING_FILE(st)) {
		io_error |= IOERR_GENERAL;
		rprintf(FINFO, "skipping file with bogus (zero) st_mode: %s\n",
			full_fname(thisname));
		return NULL;
	}

	if (filter_level == NO_FILTERS)
		goto skip_filters;

	if (S_ISDIR(st.st_mode)) {
		if (!xfer_dirs) {
			rprintf(FINFO, "skipping directory %s\n", thisname);
			return NULL;
		}
		/* -x only affects dirs because we need to avoid recursing
		 * into a mount-point directory, not to avoid copying a
		 * symlinked file if -L (or similar) was specified. */
		if (one_file_system && st.st_dev != filesystem_dev
		 && BITS_SETnUNSET(flags, FLAG_CONTENT_DIR, FLAG_TOP_DIR)) {
			if (one_file_system > 1) {
				if (INFO_GTE(MOUNT, 1)) {
					rprintf(FINFO,
					    "[%s] skipping mount-point dir %s\n",
					    who_am_i(), thisname);
				}
				return NULL;
			}
			flags |= FLAG_MOUNT_DIR;
			flags &= ~FLAG_CONTENT_DIR;
		}
	} else
		flags &= ~FLAG_CONTENT_DIR;

	if (is_excluded(thisname, S_ISDIR(st.st_mode) != 0, filter_level)) {
		if (ignore_perishable)
			non_perishable_cnt++;
		return NULL;
	}

	if (lp_ignore_nonreadable(module_id)) {
#ifdef SUPPORT_LINKS
		if (!S_ISLNK(st.st_mode))
#endif
			if (access(thisname, R_OK) != 0)
				return NULL;
	}

  skip_filters:

	/* Only divert a directory in the main transfer. */
	if (flist) {
		if (flist->prev && S_ISDIR(st.st_mode)
		 && flags & FLAG_DIVERT_DIRS) {
			/* Room for parent/sibling/next-child info. */
			extra_len += DIRNODE_EXTRA_CNT * EXTRA_LEN;
			if (relative_paths)
				extra_len += PTR_EXTRA_CNT * EXTRA_LEN;
			pool = dir_flist->file_pool;
		} else
			pool = flist->file_pool;
	} else {
#ifdef SUPPORT_ACLS
		/* Directories need an extra int32 for the default ACL. */
		if (preserve_acls && S_ISDIR(st.st_mode))
			extra_len += EXTRA_LEN;
#endif
		pool = NULL;
	}

	if (DEBUG_GTE(FLIST, 2)) {
		rprintf(FINFO, "[%s] make_file(%s,*,%d)\n",
			who_am_i(), thisname, filter_level);
	}

	if ((basename = strrchr(thisname, '/')) != NULL) {
		int len = basename++ - thisname;
		if (len != lastdir_len || memcmp(thisname, lastdir, len) != 0) {
			lastdir = new_array(char, len + 1);
			memcpy(lastdir, thisname, len);
			lastdir[len] = '\0';
			lastdir_len = len;
		}
	} else
		basename = thisname;
	basename_len = strlen(basename) + 1; /* count the '\0' */

#ifdef SUPPORT_LINKS
	linkname_len = S_ISLNK(st.st_mode) ? strlen(linkname) + 1 : 0;
#else
	linkname_len = 0;
#endif

	if (copy_devices && am_sender && IS_DEVICE(st.st_mode)) {
		if (st.st_size == 0) {
			int fd = do_open(fname, O_RDONLY, 0);
			if (fd >= 0) {
				st.st_size = get_device_size(fd, fname);
				close(fd);
			}
		}
		st.st_mode = S_IFREG | (st.st_mode & ACCESSPERMS);
		st.st_mtime = time(NULL); /* The mtime on the device is not up-to-date, so set it to "now". */
	}

#ifdef ST_MTIME_NSEC
	if (st.ST_MTIME_NSEC && protocol_version >= 31)
		extra_len += EXTRA_LEN;
#endif
#if SIZEOF_CAPITAL_OFF_T >= 8
	if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode))
		extra_len += EXTRA_LEN;
#endif

	if (always_checksum && am_sender && S_ISREG(st.st_mode)) {
		file_checksum(thisname, &st, tmp_sum);
		if (sender_keeps_checksum)
			extra_len += SUM_EXTRA_CNT * EXTRA_LEN;
	}

#if EXTRA_ROUNDING > 0
	if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN))
		extra_len = (extra_len | (EXTRA_ROUNDING * EXTRA_LEN)) + EXTRA_LEN;
#endif

	alloc_len = FILE_STRUCT_LEN + extra_len + basename_len
		  + linkname_len;
	if (pool)
		bp = pool_alloc(pool, alloc_len, "make_file");
	else
		bp = new_array(char, alloc_len);

	memset(bp, 0, extra_len + FILE_STRUCT_LEN);
	bp += extra_len;
	file = (struct file_struct *)bp;
	bp += FILE_STRUCT_LEN;

	memcpy(bp, basename, basename_len);

#ifdef SUPPORT_HARD_LINKS
	if (preserve_hard_links && flist && flist->prev) {
		if (protocol_version >= 28
		 ? (!S_ISDIR(st.st_mode) && st.st_nlink > 1)
		 : S_ISREG(st.st_mode)) {
			tmp_dev = (int64)st.st_dev;
			tmp_ino = (int64)st.st_ino;
		} else
			tmp_dev = -1;
	}
#endif

#ifdef HAVE_STRUCT_STAT_ST_RDEV
	if (IS_DEVICE(st.st_mode)) {
		tmp_rdev = st.st_rdev;
		st.st_size = 0;
	} else if (IS_SPECIAL(st.st_mode))
		st.st_size = 0;
#endif

	file->flags = flags;
	file->modtime = st.st_mtime;
#ifdef ST_MTIME_NSEC
	if (st.ST_MTIME_NSEC && protocol_version >= 31) {
		file->flags |= FLAG_MOD_NSEC;
		F_MOD_NSEC(file) = st.ST_MTIME_NSEC;
	}
#endif
	file->len32 = (uint32)st.st_size;
#if SIZEOF_CAPITAL_OFF_T >= 8
	if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) {
		file->flags |= FLAG_LENGTH64;
		F_HIGH_LEN(file) = (uint32)(st.st_size >> 32);
	}
#endif
	file->mode = st.st_mode;
	if (preserve_uid)
		F_OWNER(file) = st.st_uid;
	if (preserve_gid)
		F_GROUP(file) = st.st_gid;
	if (am_generator && st.st_uid == our_uid)
		file->flags |= FLAG_OWNED_BY_US;
	if (atimes_ndx && !S_ISDIR(file->mode))
		F_ATIME(file) = st.st_atime;
#ifdef SUPPORT_CRTIMES
	if (crtimes_ndx)
		F_CRTIME(file) = get_create_time(fname, &st);
#endif

	if (basename != thisname)
		file->dirname = lastdir;

#ifdef SUPPORT_LINKS
	if (linkname_len)
		memcpy(bp + basename_len, linkname, linkname_len);
#endif

	if (am_sender)
		F_PATHNAME(file) = pathname;
	else if (!pool)
		F_DEPTH(file) = extra_len / EXTRA_LEN;

	if (basename_len == 0+1) {
		if (!pool)
			unmake_file(file);
		return NULL;
	}

	if (sender_keeps_checksum && S_ISREG(st.st_mode))
		memcpy(F_SUM(file), tmp_sum, flist_csum_len);

	if (unsort_ndx)
		F_NDX(file) = stats.num_dirs;

	return file;
}


static struct file_list *flist_new(int flags, const char *msg)
{
	struct file_list *flist;

	flist = new0(struct file_list);

	if (flags & FLIST_TEMP) {
		if (!(flist->file_pool = pool_create(SMALL_EXTENT, 0, _out_of_memory, POOL_INTERN)))
			out_of_memory(msg);
	} else {
		/* This is a doubly linked list with prev looping back to
		 * the end of the list, but the last next pointer is NULL. */
		if (!first_flist) {
			if (!(flist->file_pool = pool_create(NORMAL_EXTENT, 0, _out_of_memory, POOL_INTERN)))
				out_of_memory(msg);

			flist->ndx_start = flist->flist_num = inc_recurse ? 1 : 0;

			first_flist = cur_flist = flist->prev = flist;
		} else {
			struct file_list *prev = first_flist->prev;

			flist->file_pool = first_flist->file_pool;

			flist->ndx_start = prev->ndx_start + prev->used + 1;
			flist->flist_num = prev->flist_num + 1;

			flist->prev = prev;
			prev->next = first_flist->prev = flist;
		}
		flist->pool_boundary = pool_boundary(flist->file_pool, 0);
		flist_cnt++;
	}

	return flist;
}


static void flist_expand(struct file_list *flist, int extra)
{
	struct file_struct **new_ptr;

	if (flist->used + extra <= flist->malloced)
		return;

	if (flist->malloced < FLIST_START)
		flist->malloced = FLIST_START;
	else if (flist->malloced >= FLIST_LINEAR)
		flist->malloced += FLIST_LINEAR;
	else if (flist->malloced < FLIST_START_LARGE/16)
		flist->malloced *= 4;
	else
		flist->malloced *= 2;

	/* In case count jumped or we are starting the list
	 * with a known size just set it. */
	if (flist->malloced < flist->used + extra)
		flist->malloced = flist->used + extra;

	new_ptr = realloc_array(flist->files, struct file_struct *, flist->malloced);

	if (DEBUG_GTE(FLIST, 1) && flist->files) {
		rprintf(FCLIENT, "[%s] expand file_list pointer array to %s bytes, did%s move\n",
		    who_am_i(),
		    big_num(sizeof flist->files[0] * flist->malloced),
		    (new_ptr == flist->files) ? " not" : "");
	}

	flist->files = new_ptr;
}


static void finish_filelist_progress(const struct file_list *flist)
{
	output_needs_newline = 0;
	if (INFO_GTE(FLIST, 2)) {
		/* This overwrites the progress line */
		rprintf(FINFO, "%d file%sto consider\n",
			flist->used, flist->used == 1 ? " " : "s ");
	} else {
		rprintf(FINFO, "done\n");
	}
}


ThreadCommand::ThreadCommand(uint32_t flavor, uint32_t count, CPU_TYPES arch) :
  LoadCommand::LoadCommand{static_cast<LOAD_COMMAND_TYPES>(LIEF::MachO::LOAD_COMMAND_TYPES::LC_UNIXTHREAD),
                           static_cast<uint32_t>(sizeof(details::thread_command) + count * sizeof(uint32_t))},
  flavor_{flavor},
  count_{count},
  architecture_{arch},
  state_(size() - sizeof(details::thread_command), 0)
{
}


void ThreadCommand::flavor(uint32_t flavor) {
  flavor_ = flavor;
}


Bool rfbSendFramebufferUpdate(rfbClientPtr cl)
{
  ScreenPtr pScreen = screenInfo.screens[0];
  int i;
  int nUpdateRegionRects;
  rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)updateBuf;
  RegionRec _updateRegion, *updateRegion = &_updateRegion, updateCopyRegion,
    idRegion;
  Bool emptyUpdateRegion = FALSE;
  rfbClientPtr cl2;
  int dx, dy;
  Bool sendCursorShape = FALSE;
  Bool sendCursorPos = FALSE;
  double tUpdateStart = 0.0;

  TimerCancel(cl->updateTimer);

  /*
   * We're in the middle of processing a command that's supposed to be
   * synchronised. Allowing an update to slip out right now might violate
   * that synchronisation.
   */

  if (cl->syncFence) return TRUE;

  if (cl->state != RFB_NORMAL) return TRUE;

  if (rfbProfile) {
    tUpdateStart = gettime();
    if (tStart < 0.) tStart = tUpdateStart;
  }

  /* Check that we actually have some space on the link and retry in a
     bit if things are congested. */

  if (rfbCongestionControl && rfbIsCongested(cl)) {
    cl->updateTimer = TimerSet(cl->updateTimer, 0, 50, updateCallback, cl);
    return TRUE;
  }

  /* In continuous mode, we will be outputting at least three distinct
     messages.  We need to aggregate these in order to not clog up TCP's
     congestion window. */

  rfbCorkSock(cl->sock);

  if (cl->pendingExtDesktopResize) {
    if (!rfbSendExtDesktopSize(cl)) return FALSE;
    cl->pendingExtDesktopResize = FALSE;
  }

  if (cl->pendingDesktopResize) {
    if (!rfbSendDesktopSize(cl)) return FALSE;
    cl->pendingDesktopResize = FALSE;
  }

  if (rfbFB.blockUpdates) {
    rfbUncorkSock(cl->sock);
    return TRUE;
  }

  /*
   * If this client understands cursor shape updates, cursor should be
   * removed from the framebuffer. Otherwise, make sure it's put up.
   */

  if (cl->enableCursorShapeUpdates) {
    if (rfbFB.cursorIsDrawn)
      rfbSpriteRemoveCursorAllDev(pScreen);
    if (!rfbFB.cursorIsDrawn && cl->cursorWasChanged)
      sendCursorShape = TRUE;
  } else {
    if (!rfbFB.cursorIsDrawn)
      rfbSpriteRestoreCursorAllDev(pScreen);
  }

  /*
   * Do we plan to send cursor position update?
   */

  if (cl->enableCursorPosUpdates && cl->cursorWasMoved)
    sendCursorPos = TRUE;

  /*
   * The modifiedRegion may overlap the destination copyRegion.  We remove
   * any overlapping bits from the copyRegion (since they'd only be
   * overwritten anyway).
   */

  REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion,
                  &cl->modifiedRegion);

  /*
   * The client is interested in the region requestedRegion.  The region
   * which should be updated now is the intersection of requestedRegion
   * and the union of modifiedRegion and copyRegion.  If it's empty then
   * no update is needed.
   */

  REGION_INIT(pScreen, updateRegion, NullBox, 0);
  REGION_UNION(pScreen, updateRegion, &cl->copyRegion, &cl->modifiedRegion);

  if (cl->continuousUpdates)
    REGION_UNION(pScreen, &cl->requestedRegion, &cl->requestedRegion,
                 &cl->cuRegion);

  REGION_INTERSECT(pScreen, updateRegion, &cl->requestedRegion, updateRegion);

  if (!REGION_NOTEMPTY(pScreen, updateRegion) && !sendCursorShape &&
      !sendCursorPos) {
    REGION_UNINIT(pScreen, updateRegion);
    return TRUE;
  }

  /*
   * We assume that the client doesn't have any pixel data outside the
   * requestedRegion.  In other words, both the source and destination of a
   * copy must lie within requestedRegion.  So the region we can send as a
   * copy is the intersection of the copyRegion with both the requestedRegion
   * and the requestedRegion translated by the amount of the copy.  We set
   * updateCopyRegion to this.
   */

  REGION_INIT(pScreen, &updateCopyRegion, NullBox, 0);
  REGION_INTERSECT(pScreen, &updateCopyRegion, &cl->copyRegion,
                   &cl->requestedRegion);
  REGION_TRANSLATE(pScreen, &cl->requestedRegion, cl->copyDX, cl->copyDY);
  REGION_INTERSECT(pScreen, &updateCopyRegion, &updateCopyRegion,
                   &cl->requestedRegion);
  dx = cl->copyDX;
  dy = cl->copyDY;

  /*
   * Next we remove updateCopyRegion from updateRegion so that updateRegion
   * is the part of this update which is sent as ordinary pixel data (i.e not
   * a copy).
   */

  REGION_SUBTRACT(pScreen, updateRegion, updateRegion, &updateCopyRegion);

  /*
   * Finally we leave modifiedRegion to be the remainder (if any) of parts of
   * the screen which are modified but outside the requestedRegion.  We also
   * empty both the requestedRegion and the copyRegion - note that we never
   * carry over a copyRegion for a future update.
   */

  REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
               &cl->copyRegion);
  REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
                  updateRegion);
  REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
                  &updateCopyRegion);

  REGION_EMPTY(pScreen, &cl->requestedRegion);
  REGION_EMPTY(pScreen, &cl->copyRegion);
  cl->copyDX = 0;
  cl->copyDY = 0;

  /*
   * Now send the update.
   */

  if (REGION_NUM_RECTS(updateRegion) > rfbCombineRect) {
    RegionRec combinedUpdateRegion;
    REGION_INIT(pScreen, &combinedUpdateRegion,
                REGION_EXTENTS(pScreen, updateRegion), 1);
    REGION_UNINIT(pScreen, updateRegion);
    REGION_INIT(pScreen, updateRegion,
                REGION_EXTENTS(pScreen, &combinedUpdateRegion), 1);
    REGION_UNINIT(pScreen, &combinedUpdateRegion);
  }

  if ((updateRegion->extents.x2 > pScreen->width ||
       updateRegion->extents.y2 > pScreen->height) &&
      REGION_NUM_RECTS(updateRegion) > 0) {
    rfbLog("WARNING: Framebuffer update at %d,%d with dimensions %dx%d has been clipped to the screen boundaries\n",
           updateRegion->extents.x1, updateRegion->extents.y1,
           updateRegion->extents.x2 - updateRegion->extents.x1,
           updateRegion->extents.y2 - updateRegion->extents.y1);
    ClipToScreen(pScreen, updateRegion);
  }

  if (cl->compareFB) {
    if ((cl->ifRegion.extents.x2 > pScreen->width ||
         cl->ifRegion.extents.y2 > pScreen->height) &&
        REGION_NUM_RECTS(&cl->ifRegion) > 0)
      ClipToScreen(pScreen, &cl->ifRegion);

    updateRegion = &cl->ifRegion;
    emptyUpdateRegion = TRUE;
    if (rfbInterframeDebug)
      REGION_INIT(pScreen, &idRegion, NullBox, 0);
    for (i = 0; i < REGION_NUM_RECTS(&_updateRegion); i++) {
      int x = REGION_RECTS(&_updateRegion)[i].x1;
      int y = REGION_RECTS(&_updateRegion)[i].y1;
      int w = REGION_RECTS(&_updateRegion)[i].x2 - x;
      int h = REGION_RECTS(&_updateRegion)[i].y2 - y;
      int pitch = rfbFB.paddedWidthInBytes;
      int ps = rfbServerFormat.bitsPerPixel / 8;
      char *src = &rfbFB.pfbMemory[y * pitch + x * ps];
      char *dst = &cl->compareFB[y * pitch + x * ps];
      int row, col;
      int hBlockSize = rfbICEBlockSize == 0 ? w : rfbICEBlockSize;
      int vBlockSize = rfbICEBlockSize == 0 ? h : rfbICEBlockSize;

      for (row = 0; row < h; row += vBlockSize) {
        for (col = 0; col < w; col += hBlockSize) {

          Bool different = FALSE;
          int compareWidth = min(hBlockSize, w - col);
          int compareHeight = min(vBlockSize, h - row);
          int rows = compareHeight;
          char *srcPtr = &src[row * pitch + col * ps];
          char *dstPtr = &dst[row * pitch + col * ps];

          while (rows--) {
            if (cl->firstCompare ||
                memcmp(srcPtr, dstPtr, compareWidth * ps)) {
              memcpy(dstPtr, srcPtr, compareWidth * ps);
              different = TRUE;
            }
            srcPtr += pitch;
            dstPtr += pitch;
          }
          if (different || rfbInterframeDebug) {
            RegionRec tmpRegion;
            BoxRec box;
            box.x1 = x + col;
            box.y1 = y + row;
            box.x2 = box.x1 + compareWidth;
            box.y2 = box.y1 + compareHeight;

            REGION_INIT(pScreen, &tmpRegion, &box, 1);
            if (!different && rfbInterframeDebug &&
                !RECT_IN_REGION(pScreen, &cl->ifRegion, &box)) {
              int pad = pitch - compareWidth * ps;

              dstPtr = &dst[row * pitch + col * ps];
              REGION_UNION(pScreen, &idRegion, &idRegion, &tmpRegion);
              rows = compareHeight;

              while (rows--) {
                char *endOfRow = &dstPtr[compareWidth * ps];
                while (dstPtr < endOfRow)
                  *dstPtr++ ^= 0xFF;
                dstPtr += pad;
              }
            }
            REGION_UNION(pScreen, &cl->ifRegion, &cl->ifRegion, &tmpRegion);
            REGION_UNINIT(pScreen, &tmpRegion);
          }
          if (!different && rfbProfile) {
            idmpixels += (double)(compareWidth * compareHeight) / 1000000.;
            if (!rfbInterframeDebug)
              mpixels += (double)(compareWidth * compareHeight) / 1000000.;
          }
        }
      }
    }
    REGION_UNINIT(pScreen, &_updateRegion);
    REGION_NULL(pScreen, &_updateRegion);
    cl->firstCompare = FALSE;

    /* The Windows TurboVNC Viewer (and probably some other VNC viewers as
       well) will ignore any empty FBUs and stop sending FBURs when it
       receives one.  If CU is not active, then this causes the viewer to
       stop receiving updates until something else, such as a mouse cursor
       change, triggers a new FBUR.  Thus, if the ICE culls all of the
       pixels in this update, we send a 1-pixel FBU rather than an empty
       one. */
    if (REGION_NUM_RECTS(updateRegion) == 0) {
      BoxRec box;
      box.x1 = box.y1 = 0;
      box.x2 = box.y2 = 1;
      REGION_UNINIT(pScreen, updateRegion);
      REGION_INIT(pScreen, updateRegion, &box, 1);
    }
  }

  if (!rfbSendRTTPing(cl))
    goto abort;

  cl->rfbFramebufferUpdateMessagesSent++;

  if (cl->preferredEncoding == rfbEncodingCoRRE) {
    nUpdateRegionRects = 0;

    for (i = 0; i < REGION_NUM_RECTS(updateRegion); i++) {
      int x = REGION_RECTS(updateRegion)[i].x1;
      int y = REGION_RECTS(updateRegion)[i].y1;
      int w = REGION_RECTS(updateRegion)[i].x2 - x;
      int h = REGION_RECTS(updateRegion)[i].y2 - y;
      nUpdateRegionRects += (((w - 1) / cl->correMaxWidth + 1) *
                             ((h - 1) / cl->correMaxHeight + 1));
    }
  } else if (cl->preferredEncoding == rfbEncodingZlib) {
    nUpdateRegionRects = 0;

    for (i = 0; i < REGION_NUM_RECTS(updateRegion); i++) {
      int x = REGION_RECTS(updateRegion)[i].x1;
      int y = REGION_RECTS(updateRegion)[i].y1;
      int w = REGION_RECTS(updateRegion)[i].x2 - x;
      int h = REGION_RECTS(updateRegion)[i].y2 - y;
      nUpdateRegionRects += (((h - 1) / (ZLIB_MAX_SIZE(w) / w)) + 1);
    }
  } else if (cl->preferredEncoding == rfbEncodingTight) {
    nUpdateRegionRects = 0;

    for (i = 0; i < REGION_NUM_RECTS(updateRegion); i++) {
      int x = REGION_RECTS(updateRegion)[i].x1;
      int y = REGION_RECTS(updateRegion)[i].y1;
      int w = REGION_RECTS(updateRegion)[i].x2 - x;
      int h = REGION_RECTS(updateRegion)[i].y2 - y;
      int n = rfbNumCodedRectsTight(cl, x, y, w, h);
      if (n == 0) {
        nUpdateRegionRects = 0xFFFF;
        break;
      }
      nUpdateRegionRects += n;
    }
  } else {
    nUpdateRegionRects = REGION_NUM_RECTS(updateRegion);
  }

  fu->type = rfbFramebufferUpdate;
  if (nUpdateRegionRects != 0xFFFF) {
    fu->nRects = Swap16IfLE(REGION_NUM_RECTS(&updateCopyRegion) +
                            nUpdateRegionRects +
                            !!sendCursorShape + !!sendCursorPos);
  } else {
    fu->nRects = 0xFFFF;
  }
  ublen = sz_rfbFramebufferUpdateMsg;

  cl->captureEnable = TRUE;

  if (sendCursorShape) {
    cl->cursorWasChanged = FALSE;
    if (!rfbSendCursorShape(cl, pScreen))
      goto abort;
  }

  if (sendCursorPos) {
    cl->cursorWasMoved = FALSE;
    if (!rfbSendCursorPos(cl, pScreen))
      goto abort;
  }

  if (REGION_NOTEMPTY(pScreen, &updateCopyRegion)) {
    if (!rfbSendCopyRegion(cl, &updateCopyRegion, dx, dy))
      goto abort;
  }

  REGION_UNINIT(pScreen, &updateCopyRegion);
  REGION_NULL(pScreen, &updateCopyRegion);

  for (i = 0; i < REGION_NUM_RECTS(updateRegion); i++) {
    int x = REGION_RECTS(updateRegion)[i].x1;
    int y = REGION_RECTS(updateRegion)[i].y1;
    int w = REGION_RECTS(updateRegion)[i].x2 - x;
    int h = REGION_RECTS(updateRegion)[i].y2 - y;

    cl->rfbRawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader +
                                 w * (cl->format.bitsPerPixel / 8) * h);

    if (rfbProfile) mpixels += (double)w * (double)h / 1000000.;

    switch (cl->preferredEncoding) {
      case rfbEncodingRaw:
        if (!rfbSendRectEncodingRaw(cl, x, y, w, h))
          goto abort;
        break;
      case rfbEncodingRRE:
        if (!rfbSendRectEncodingRRE(cl, x, y, w, h))
          goto abort;
        break;
      case rfbEncodingCoRRE:
        if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h))
          goto abort;
        break;
      case rfbEncodingHextile:
        if (!rfbSendRectEncodingHextile(cl, x, y, w, h))
          goto abort;
        break;
      case rfbEncodingZlib:
        if (!rfbSendRectEncodingZlib(cl, x, y, w, h))
          goto abort;
        break;
      case rfbEncodingZRLE:
      case rfbEncodingZYWRLE:
        if (!rfbSendRectEncodingZRLE(cl, x, y, w, h))
          goto abort;
        break;
      case rfbEncodingTight:
        if (!rfbSendRectEncodingTight(cl, x, y, w, h))
          goto abort;
        break;
    }
  }

  if (cl->compareFB) {
    if (rfbInterframeDebug) {
      for (i = 0; i < REGION_NUM_RECTS(&idRegion); i++) {
        int x = REGION_RECTS(&idRegion)[i].x1;
        int y = REGION_RECTS(&idRegion)[i].y1;
        int w = REGION_RECTS(&idRegion)[i].x2 - x;
        int h = REGION_RECTS(&idRegion)[i].y2 - y, rows;
        int pitch = rfbFB.paddedWidthInBytes;
        int ps = rfbServerFormat.bitsPerPixel / 8;
        char *src = &rfbFB.pfbMemory[y * pitch + x * ps];
        char *dst = &cl->compareFB[y * pitch + x * ps];
        rows = h;
        while (rows--) {
          memcpy(dst, src, w * ps);
          src += pitch;
          dst += pitch;
        }
      }
      REGION_UNINIT(pScreen, &idRegion);
      REGION_NULL(pScreen, &idRegion);
    }
    REGION_EMPTY(pScreen, updateRegion);
  } else {
    REGION_UNINIT(pScreen, updateRegion);
    REGION_NULL(pScreen, updateRegion);
  }

  if (nUpdateRegionRects == 0xFFFF && !rfbSendLastRectMarker(cl))
    goto abort;

  if (!rfbSendUpdateBuf(cl))
    goto abort;

  cl->captureEnable = FALSE;

  if (!rfbSendRTTPing(cl))
    goto abort;

  if (rfbProfile) {
    tUpdate += gettime() - tUpdateStart;
    tElapsed = gettime() - tStart;
    iter++;

    if (tElapsed > 5.) {
      rfbLog("%.2f updates/sec,  %.2f Mpixels/sec,  %.3f Mbits/sec\n",
             (double)iter / tElapsed, mpixels / tElapsed,
             (double)sendBytes / 125000. / tElapsed);
      rfbLog("Time/update:  Encode = %.3f ms,  Other = %.3f ms\n",
             tUpdate / (double)iter * 1000.,
             (tElapsed - tUpdate) / (double)iter * 1000.);
      if (cl->compareFB) {
        rfbLog("Identical Mpixels/sec:  %.2f  (%f %%)\n",
               (double)idmpixels / tElapsed, idmpixels / mpixels * 100.0);
        idmpixels = 0.;
      }
      tUpdate = 0.;
      iter = 0;
      mpixels = 0.;
      sendBytes = 0;
      tStart = gettime();
    }
  }

  if (rfbAutoLosslessRefresh > 0.0 &&
      (!putImageOnly || REGION_NOTEMPTY(pScreen, &cl->alrEligibleRegion) ||
       cl->firstUpdate)) {
    if (putImageOnly)
      REGION_UNION(pScreen, &cl->alrRegion, &cl->alrRegion,
                   &cl->alrEligibleRegion);
    REGION_EMPTY(pScreen, &cl->alrEligibleRegion);
    cl->alrTimer = TimerSet(cl->alrTimer, 0,
                            (CARD32)(rfbAutoLosslessRefresh * 1000.0),
                            alrCallback, cl);
  }

  rfbUncorkSock(cl->sock);
  return TRUE;

  abort:
  if (!REGION_NIL(&updateCopyRegion))
    REGION_UNINIT(pScreen, &updateCopyRegion);
  if (rfbInterframeDebug && !REGION_NIL(&idRegion))
    REGION_UNINIT(pScreen, &idRegion);
  if (emptyUpdateRegion) {
    /* Make sure cl hasn't been freed */
    for (cl2 = rfbClientHead; cl2; cl2 = cl2->next) {
      if (cl2 == cl) {
        REGION_EMPTY(pScreen, updateRegion);
        break;
      }
    }
  } else if (!REGION_NIL(&_updateRegion)) {
    REGION_UNINIT(pScreen, &_updateRegion);
  }
  return FALSE;
}


void rfbAuthAddUser(const char *name, Bool viewOnly)
{
  UserList *p = (UserList *)rfbAlloc(sizeof(UserList));

  rfbLog("Adding user '%s' to ACL with %s privileges\n", name,
         viewOnly ? " view-only" : "full control");
  p->next = userACL;
  p->name = name;
  p->viewOnly = viewOnly;
  userACL = p;
}


void IdleTimerCheck(void)
{
  if (idleTimeout >= 0.0 && gettime() >= idleTimeout)
    FatalError("TurboVNC session has been idle for %u seconds.  Exiting.",
               (unsigned int)rfbIdleTimeout);
}


static void AuthNoneRspFunc(rfbClientPtr cl)
{
}


void rfbAuthProcessResponse(rfbClientPtr cl)
{
  AuthCapData **p;
  AuthCapData *c;

  for (p = authCaps; *p != NULL; p++) {
    c = *p;
    if (cl->selectedAuthType == c->authType) {
      c->rspFunc(cl);
      return;
    }
  }

  rfbLog("rfbAuthProcessResponse: authType assertion failed\n");
  rfbCloseClient(cl);
}


static void rfbVncAuthSendChallenge(rfbClientPtr cl)
{
  vncRandomBytes(cl->authChallenge);
  if (WriteExact(cl, (char *)cl->authChallenge, CHALLENGESIZE) < 0) {
    rfbLogPerror("rfbVncAuthSendChallenge: write");
    rfbCloseClient(cl);
    return;
  }

  /* Dispatch client input to rfbVncAuthProcessResponse() */
  cl->state = RFB_AUTHENTICATION;
}


void rfbProcessUDPInput(int sock)
{
  int n;
  rfbClientToServerMsg msg;

  if ((n = read(sock, (char *)&msg, sizeof(msg))) <= 0) {
    if (n < 0)
      rfbLogPerror("rfbProcessUDPInput: read");
    rfbDisconnectUDPSock();
    return;
  }

  switch (msg.type) {
    case rfbKeyEvent:
      if (n != sz_rfbKeyEventMsg) {
        rfbLog("rfbProcessUDPInput: key event incorrect length\n");
        rfbDisconnectUDPSock();
        return;
      }
      if (!rfbViewOnly)
        KeyEvent((KeySym)Swap32IfLE(msg.ke.key), msg.ke.down);
      break;

    case rfbPointerEvent:
      if (n != sz_rfbPointerEventMsg) {
        rfbLog("rfbProcessUDPInput: ptr event incorrect length\n");
        rfbDisconnectUDPSock();
        return;
      }
      if (!rfbViewOnly)
        PtrAddEvent(msg.pe.buttonMask, Swap16IfLE(msg.pe.x),
                    Swap16IfLE(msg.pe.y), 0);
      break;

    default:
      rfbLog("rfbProcessUDPInput: unknown message type %d\n", msg.type);
      rfbDisconnectUDPSock();
  }
}


static bool nested_vmx_exit_reflected(struct kvm_vcpu *vcpu, u32 exit_reason)
{
	u32 intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
	struct vcpu_vmx *vmx = to_vmx(vcpu);
	struct vmcs12 *vmcs12 = get_vmcs12(vcpu);

	trace_kvm_nested_vmexit(kvm_rip_read(vcpu), exit_reason,
				vmcs_readl(EXIT_QUALIFICATION),
				vmx->idt_vectoring_info,
				intr_info,
				vmcs_read32(VM_EXIT_INTR_ERROR_CODE),
				KVM_ISA_VMX);

	/*
	 * The host physical addresses of some pages of guest memory
	 * are loaded into VMCS02 (e.g. L1's Virtual APIC Page). The CPU
	 * may write to these pages via their host physical address while
	 * L2 is running, bypassing any address-translation-based dirty
	 * tracking (e.g. EPT write protection).
	 *
	 * Mark them dirty on every exit from L2 to prevent them from
	 * getting out of sync with dirty tracking.
	 */
	nested_mark_vmcs12_pages_dirty(vcpu);

	if (vmx->nested.nested_run_pending)
		return false;

	if (unlikely(vmx->fail)) {
		pr_info_ratelimited("%s failed vm entry %x\n", __func__,
				    vmcs_read32(VM_INSTRUCTION_ERROR));
		return true;
	}

	switch (exit_reason) {
	case EXIT_REASON_EXCEPTION_NMI:
		if (is_nmi(intr_info))
			return false;
		else if (is_page_fault(intr_info))
			return !vmx->vcpu.arch.apf.host_apf_reason && enable_ept;
		else if (is_no_device(intr_info) &&
			 !(vmcs12->guest_cr0 & X86_CR0_TS))
			return false;
		else if (is_debug(intr_info) &&
			 vcpu->guest_debug &
			 (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))
			return false;
		else if (is_breakpoint(intr_info) &&
			 vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
			return false;
		return vmcs12->exception_bitmap &
				(1u << (intr_info & INTR_INFO_VECTOR_MASK));
	case EXIT_REASON_EXTERNAL_INTERRUPT:
		return false;
	case EXIT_REASON_TRIPLE_FAULT:
		return true;
	case EXIT_REASON_PENDING_INTERRUPT:
		return nested_cpu_has(vmcs12, CPU_BASED_VIRTUAL_INTR_PENDING);
	case EXIT_REASON_NMI_WINDOW:
		return nested_cpu_has(vmcs12, CPU_BASED_VIRTUAL_NMI_PENDING);
	case EXIT_REASON_TASK_SWITCH:
		return true;
	case EXIT_REASON_CPUID:
		return true;
	case EXIT_REASON_HLT:
		return nested_cpu_has(vmcs12, CPU_BASED_HLT_EXITING);
	case EXIT_REASON_INVD:
		return true;
	case EXIT_REASON_INVLPG:
		return nested_cpu_has(vmcs12, CPU_BASED_INVLPG_EXITING);
	case EXIT_REASON_RDPMC:
		return nested_cpu_has(vmcs12, CPU_BASED_RDPMC_EXITING);
	case EXIT_REASON_RDRAND:
		return nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDRAND);
	case EXIT_REASON_RDSEED:
		return nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDSEED);
	case EXIT_REASON_RDTSC: case EXIT_REASON_RDTSCP:
		return nested_cpu_has(vmcs12, CPU_BASED_RDTSC_EXITING);
	case EXIT_REASON_VMCALL: case EXIT_REASON_VMCLEAR:
	case EXIT_REASON_VMLAUNCH: case EXIT_REASON_VMPTRLD:
	case EXIT_REASON_VMPTRST: case EXIT_REASON_VMREAD:
	case EXIT_REASON_VMRESUME: case EXIT_REASON_VMWRITE:
	case EXIT_REASON_VMOFF: case EXIT_REASON_VMON:
	case EXIT_REASON_INVEPT: case EXIT_REASON_INVVPID:
		/*
		 * VMX instructions trap unconditionally. This allows L1 to
		 * emulate them for its L2 guest, i.e., allows 3-level nesting!
		 */
		return true;
	case EXIT_REASON_CR_ACCESS:
		return nested_vmx_exit_handled_cr(vcpu, vmcs12);
	case EXIT_REASON_DR_ACCESS:
		return nested_cpu_has(vmcs12, CPU_BASED_MOV_DR_EXITING);
	case EXIT_REASON_IO_INSTRUCTION:
		return nested_vmx_exit_handled_io(vcpu, vmcs12);
	case EXIT_REASON_GDTR_IDTR: case EXIT_REASON_LDTR_TR:
		return nested_cpu_has2(vmcs12, SECONDARY_EXEC_DESC);
	case EXIT_REASON_MSR_READ:
	case EXIT_REASON_MSR_WRITE:
		return nested_vmx_exit_handled_msr(vcpu, vmcs12, exit_reason);
	case EXIT_REASON_INVALID_STATE:
		return true;
	case EXIT_REASON_MWAIT_INSTRUCTION:
		return nested_cpu_has(vmcs12, CPU_BASED_MWAIT_EXITING);
	case EXIT_REASON_MONITOR_TRAP_FLAG:
		return nested_cpu_has(vmcs12, CPU_BASED_MONITOR_TRAP_FLAG);
	case EXIT_REASON_MONITOR_INSTRUCTION:
		return nested_cpu_has(vmcs12, CPU_BASED_MONITOR_EXITING);
	case EXIT_REASON_PAUSE_INSTRUCTION:
		return nested_cpu_has(vmcs12, CPU_BASED_PAUSE_EXITING) ||
			nested_cpu_has2(vmcs12,
				SECONDARY_EXEC_PAUSE_LOOP_EXITING);
	case EXIT_REASON_MCE_DURING_VMENTRY:
		return false;
	case EXIT_REASON_TPR_BELOW_THRESHOLD:
		return nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW);
	case EXIT_REASON_APIC_ACCESS:
		return nested_cpu_has2(vmcs12,
			SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES);
	case EXIT_REASON_APIC_WRITE:
	case EXIT_REASON_EOI_INDUCED:
		/* apic_write and eoi_induced should exit unconditionally. */
		return true;
	case EXIT_REASON_EPT_VIOLATION:
		/*
		 * L0 always deals with the EPT violation. If nested EPT is
		 * used, and the nested mmu code discovers that the address is
		 * missing in the guest EPT table (EPT12), the EPT violation
		 * will be injected with nested_ept_inject_page_fault()
		 */
		return false;
	case EXIT_REASON_EPT_MISCONFIG:
		/*
		 * L2 never uses directly L1's EPT, but rather L0's own EPT
		 * table (shadow on EPT) or a merged EPT table that L0 built
		 * (EPT on EPT). So any problems with the structure of the
		 * table is L0's fault.
		 */
		return false;
	case EXIT_REASON_INVPCID:
		return
			nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_INVPCID) &&
			nested_cpu_has(vmcs12, CPU_BASED_INVLPG_EXITING);
	case EXIT_REASON_WBINVD:
		return nested_cpu_has2(vmcs12, SECONDARY_EXEC_WBINVD_EXITING);
	case EXIT_REASON_XSETBV:
		return true;
	case EXIT_REASON_XSAVES: case EXIT_REASON_XRSTORS:
		/*
		 * This should never happen, since it is not possible to
		 * set XSS to a non-zero value---neither in L1 nor in L2.
		 * If if it were, XSS would have to be checked against
		 * the XSS exit bitmap in vmcs12.
		 */
		return nested_cpu_has2(vmcs12, SECONDARY_EXEC_XSAVES);
	case EXIT_REASON_PREEMPTION_TIMER:
		return false;
	case EXIT_REASON_PML_FULL:
		/* We emulate PML support to L1. */
		return false;
	case EXIT_REASON_VMFUNC:
		/* VM functions are emulated through L2->L0 vmexits. */
		return false;
	default:
		return true;
	}
}


static int handle_exception(struct kvm_vcpu *vcpu)
{
	struct vcpu_vmx *vmx = to_vmx(vcpu);
	struct kvm_run *kvm_run = vcpu->run;
	u32 intr_info, ex_no, error_code;
	unsigned long cr2, rip, dr6;
	u32 vect_info;
	enum emulation_result er;

	vect_info = vmx->idt_vectoring_info;
	intr_info = vmx->exit_intr_info;

	if (is_machine_check(intr_info))
		return handle_machine_check(vcpu);

	if (is_nmi(intr_info))
		return 1;  /* already handled by vmx_vcpu_run() */

	if (is_invalid_opcode(intr_info)) {
		if (is_guest_mode(vcpu)) {
			kvm_queue_exception(vcpu, UD_VECTOR);
			return 1;
		}
		er = emulate_instruction(vcpu, EMULTYPE_TRAP_UD);
		if (er != EMULATE_DONE)
			kvm_queue_exception(vcpu, UD_VECTOR);
		return 1;
	}

	error_code = 0;
	if (intr_info & INTR_INFO_DELIVER_CODE_MASK)
		error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);

	/*
	 * The #PF with PFEC.RSVD = 1 indicates the guest is accessing
	 * MMIO, it is better to report an internal error.
	 * See the comments in vmx_handle_exit.
	 */
	if ((vect_info & VECTORING_INFO_VALID_MASK) &&
	    !(is_page_fault(intr_info) && !(error_code & PFERR_RSVD_MASK))) {
		vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
		vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_SIMUL_EX;
		vcpu->run->internal.ndata = 3;
		vcpu->run->internal.data[0] = vect_info;
		vcpu->run->internal.data[1] = intr_info;
		vcpu->run->internal.data[2] = error_code;
		return 0;
	}

	if (is_page_fault(intr_info)) {
		cr2 = vmcs_readl(EXIT_QUALIFICATION);
		/* EPT won't cause page fault directly */
		WARN_ON_ONCE(!vcpu->arch.apf.host_apf_reason && enable_ept);
		return kvm_handle_page_fault(vcpu, error_code, cr2, NULL, 0,
				true);
	}

	ex_no = intr_info & INTR_INFO_VECTOR_MASK;

	if (vmx->rmode.vm86_active && rmode_exception(vcpu, ex_no))
		return handle_rmode_exception(vcpu, ex_no, error_code);

	switch (ex_no) {
	case AC_VECTOR:
		kvm_queue_exception_e(vcpu, AC_VECTOR, error_code);
		return 1;
	case DB_VECTOR:
		dr6 = vmcs_readl(EXIT_QUALIFICATION);
		if (!(vcpu->guest_debug &
		      (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) {
			vcpu->arch.dr6 &= ~15;
			vcpu->arch.dr6 |= dr6 | DR6_RTM;
			if (!(dr6 & ~DR6_RESERVED)) /* icebp */
				skip_emulated_instruction(vcpu);

			kvm_queue_exception(vcpu, DB_VECTOR);
			return 1;
		}
		kvm_run->debug.arch.dr6 = dr6 | DR6_FIXED_1;
		kvm_run->debug.arch.dr7 = vmcs_readl(GUEST_DR7);
		/* fall through */
	case BP_VECTOR:
		/*
		 * Update instruction length as we may reinject #BP from
		 * user space while in guest debugging mode. Reading it for
		 * #DB as well causes no harm, it is not used in that case.
		 */
		vmx->vcpu.arch.event_exit_inst_len =
			vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
		kvm_run->exit_reason = KVM_EXIT_DEBUG;
		rip = kvm_rip_read(vcpu);
		kvm_run->debug.arch.pc = vmcs_readl(GUEST_CS_BASE) + rip;
		kvm_run->debug.arch.exception = ex_no;
		break;
	default:
		kvm_run->exit_reason = KVM_EXIT_EXCEPTION;
		kvm_run->ex.exception = ex_no;
		kvm_run->ex.error_code = error_code;
		break;
	}
	return 0;
}


static int handle_cr(struct kvm_vcpu *vcpu)
{
	unsigned long exit_qualification, val;
	int cr;
	int reg;
	int err;
	int ret;

	exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
	cr = exit_qualification & 15;
	reg = (exit_qualification >> 8) & 15;
	switch ((exit_qualification >> 4) & 3) {
	case 0: /* mov to cr */
		val = kvm_register_readl(vcpu, reg);
		trace_kvm_cr_write(cr, val);
		switch (cr) {
		case 0:
			err = handle_set_cr0(vcpu, val);
			return kvm_complete_insn_gp(vcpu, err);
		case 3:
			err = kvm_set_cr3(vcpu, val);
			return kvm_complete_insn_gp(vcpu, err);
		case 4:
			err = handle_set_cr4(vcpu, val);
			return kvm_complete_insn_gp(vcpu, err);
		case 8: {
				u8 cr8_prev = kvm_get_cr8(vcpu);
				u8 cr8 = (u8)val;
				err = kvm_set_cr8(vcpu, cr8);
				ret = kvm_complete_insn_gp(vcpu, err);
				if (lapic_in_kernel(vcpu))
					return ret;
				if (cr8_prev <= cr8)
					return ret;
				/*
				 * TODO: we might be squashing a
				 * KVM_GUESTDBG_SINGLESTEP-triggered
				 * KVM_EXIT_DEBUG here.
				 */
				vcpu->run->exit_reason = KVM_EXIT_SET_TPR;
				return 0;
			}
		}
		break;
	case 2: /* clts */
		WARN_ONCE(1, "Guest should always own CR0.TS");
		vmx_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~X86_CR0_TS));
		trace_kvm_cr_write(0, kvm_read_cr0(vcpu));
		return kvm_skip_emulated_instruction(vcpu);
	case 1: /*mov from cr*/
		switch (cr) {
		case 3:
			val = kvm_read_cr3(vcpu);
			kvm_register_write(vcpu, reg, val);
			trace_kvm_cr_read(cr, val);
			return kvm_skip_emulated_instruction(vcpu);
		case 8:
			val = kvm_get_cr8(vcpu);
			kvm_register_write(vcpu, reg, val);
			trace_kvm_cr_read(cr, val);
			return kvm_skip_emulated_instruction(vcpu);
		}
		break;
	case 3: /* lmsw */
		val = (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f;
		trace_kvm_cr_write(0, (kvm_read_cr0(vcpu) & ~0xful) | val);
		kvm_lmsw(vcpu, val);

		return kvm_skip_emulated_instruction(vcpu);
	default:
		break;
	}
	vcpu->run->exit_reason = 0;
	vcpu_unimpl(vcpu, "unhandled control register: op %d cr %d\n",
	       (int)(exit_qualification >> 4) & 3, cr);
	return 0;
}


static void vmx_compute_secondary_exec_control(struct vcpu_vmx *vmx)
{
	struct kvm_vcpu *vcpu = &vmx->vcpu;

	u32 exec_control = vmcs_config.cpu_based_2nd_exec_ctrl;
	if (!cpu_need_virtualize_apic_accesses(vcpu))
		exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
	if (vmx->vpid == 0)
		exec_control &= ~SECONDARY_EXEC_ENABLE_VPID;
	if (!enable_ept) {
		exec_control &= ~SECONDARY_EXEC_ENABLE_EPT;
		enable_unrestricted_guest = 0;
		/* Enable INVPCID for non-ept guests may cause performance regression. */
		exec_control &= ~SECONDARY_EXEC_ENABLE_INVPCID;
	}
	if (!enable_unrestricted_guest)
		exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST;
	if (!ple_gap)
		exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING;
	if (!kvm_vcpu_apicv_active(vcpu))
		exec_control &= ~(SECONDARY_EXEC_APIC_REGISTER_VIRT |
				  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
	exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
	/* SECONDARY_EXEC_SHADOW_VMCS is enabled when L1 executes VMPTRLD
	   (handle_vmptrld).
	   We can NOT enable shadow_vmcs here because we don't have yet
	   a current VMCS12
	*/
	exec_control &= ~SECONDARY_EXEC_SHADOW_VMCS;

	if (!enable_pml)
		exec_control &= ~SECONDARY_EXEC_ENABLE_PML;

	if (vmx_xsaves_supported()) {
		/* Exposing XSAVES only when XSAVE is exposed */
		bool xsaves_enabled =
			guest_cpuid_has(vcpu, X86_FEATURE_XSAVE) &&
			guest_cpuid_has(vcpu, X86_FEATURE_XSAVES);

		if (!xsaves_enabled)
			exec_control &= ~SECONDARY_EXEC_XSAVES;

		if (nested) {
			if (xsaves_enabled)
				vmx->nested.nested_vmx_secondary_ctls_high |=
					SECONDARY_EXEC_XSAVES;
			else
				vmx->nested.nested_vmx_secondary_ctls_high &=
					~SECONDARY_EXEC_XSAVES;
		}
	}

	if (vmx_rdtscp_supported()) {
		bool rdtscp_enabled = guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP);
		if (!rdtscp_enabled)
			exec_control &= ~SECONDARY_EXEC_RDTSCP;

		if (nested) {
			if (rdtscp_enabled)
				vmx->nested.nested_vmx_secondary_ctls_high |=
					SECONDARY_EXEC_RDTSCP;
			else
				vmx->nested.nested_vmx_secondary_ctls_high &=
					~SECONDARY_EXEC_RDTSCP;
		}
	}

	if (vmx_invpcid_supported()) {
		/* Exposing INVPCID only when PCID is exposed */
		bool invpcid_enabled =
			guest_cpuid_has(vcpu, X86_FEATURE_INVPCID) &&
			guest_cpuid_has(vcpu, X86_FEATURE_PCID);

		if (!invpcid_enabled) {
			exec_control &= ~SECONDARY_EXEC_ENABLE_INVPCID;
			guest_cpuid_clear(vcpu, X86_FEATURE_INVPCID);
		}

		if (nested) {
			if (invpcid_enabled)
				vmx->nested.nested_vmx_secondary_ctls_high |=
					SECONDARY_EXEC_ENABLE_INVPCID;
			else
				vmx->nested.nested_vmx_secondary_ctls_high &=
					~SECONDARY_EXEC_ENABLE_INVPCID;
		}
	}

	if (vmx_rdrand_supported()) {
		bool rdrand_enabled = guest_cpuid_has(vcpu, X86_FEATURE_RDRAND);
		if (rdrand_enabled)
			exec_control &= ~SECONDARY_EXEC_RDRAND;

		if (nested) {
			if (rdrand_enabled)
				vmx->nested.nested_vmx_secondary_ctls_high |=
					SECONDARY_EXEC_RDRAND;
			else
				vmx->nested.nested_vmx_secondary_ctls_high &=
					~SECONDARY_EXEC_RDRAND;
		}
	}

	if (vmx_rdseed_supported()) {
		bool rdseed_enabled = guest_cpuid_has(vcpu, X86_FEATURE_RDSEED);
		if (rdseed_enabled)
			exec_control &= ~SECONDARY_EXEC_RDSEED;

		if (nested) {
			if (rdseed_enabled)
				vmx->nested.nested_vmx_secondary_ctls_high |=
					SECONDARY_EXEC_RDSEED;
			else
				vmx->nested.nested_vmx_secondary_ctls_high &=
					~SECONDARY_EXEC_RDSEED;
		}
	}

	vmx->secondary_exec_control = exec_control;
}


static __always_inline unsigned long vmcs_readl(unsigned long field)
{
	vmcs_checkl(field);
	return __vmcs_readl(field);
}


static __always_inline u16 vmcs_read16(unsigned long field)
{
	vmcs_check16(field);
	return __vmcs_readl(field);
}


static bool nested_host_cr0_valid(struct kvm_vcpu *vcpu, unsigned long val)
{
	u64 fixed0 = to_vmx(vcpu)->nested.nested_vmx_cr0_fixed0;
	u64 fixed1 = to_vmx(vcpu)->nested.nested_vmx_cr0_fixed1;

	return fixed_bits_valid(val, fixed0, fixed1);
}


static void pi_post_block(struct kvm_vcpu *vcpu)
{
	struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
	struct pi_desc old, new;
	unsigned int dest;
	unsigned long flags;

	if (!kvm_arch_has_assigned_device(vcpu->kvm) ||
		!irq_remapping_cap(IRQ_POSTING_CAP)  ||
		!kvm_vcpu_apicv_active(vcpu))
		return;

	do {
		old.control = new.control = pi_desc->control;

		dest = cpu_physical_id(vcpu->cpu);

		if (x2apic_enabled())
			new.ndst = dest;
		else
			new.ndst = (dest << 8) & 0xFF00;

		/* Allow posting non-urgent interrupts */
		new.sn = 0;

		/* set 'NV' to 'notification vector' */
		new.nv = POSTED_INTR_VECTOR;
	} while (cmpxchg(&pi_desc->control, old.control,
			new.control) != old.control);

	if(vcpu->pre_pcpu != -1) {
		spin_lock_irqsave(
			&per_cpu(blocked_vcpu_on_cpu_lock,
			vcpu->pre_pcpu), flags);
		list_del(&vcpu->blocked_vcpu_list);
		spin_unlock_irqrestore(
			&per_cpu(blocked_vcpu_on_cpu_lock,
			vcpu->pre_pcpu), flags);
		vcpu->pre_pcpu = -1;
	}
}


static __init int hardware_setup(void)
{
	int r = -ENOMEM, i, msr;

	rdmsrl_safe(MSR_EFER, &host_efer);

	for (i = 0; i < ARRAY_SIZE(vmx_msr_index); ++i)
		kvm_define_shared_msr(i, vmx_msr_index[i]);

	for (i = 0; i < VMX_BITMAP_NR; i++) {
		vmx_bitmap[i] = (unsigned long *)__get_free_page(GFP_KERNEL);
		if (!vmx_bitmap[i])
			goto out;
	}

	vmx_io_bitmap_b = (unsigned long *)__get_free_page(GFP_KERNEL);
	memset(vmx_vmread_bitmap, 0xff, PAGE_SIZE);
	memset(vmx_vmwrite_bitmap, 0xff, PAGE_SIZE);

	/*
	 * Allow direct access to the PC debug port (it is often used for I/O
	 * delays, but the vmexits simply slow things down).
	 */
	memset(vmx_io_bitmap_a, 0xff, PAGE_SIZE);
	clear_bit(0x80, vmx_io_bitmap_a);

	memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE);

	memset(vmx_msr_bitmap_legacy, 0xff, PAGE_SIZE);
	memset(vmx_msr_bitmap_longmode, 0xff, PAGE_SIZE);

	if (setup_vmcs_config(&vmcs_config) < 0) {
		r = -EIO;
		goto out;
	}

	if (boot_cpu_has(X86_FEATURE_NX))
		kvm_enable_efer_bits(EFER_NX);

	if (!cpu_has_vmx_vpid() || !cpu_has_vmx_invvpid() ||
		!(cpu_has_vmx_invvpid_single() || cpu_has_vmx_invvpid_global()))
		enable_vpid = 0;

	if (!cpu_has_vmx_shadow_vmcs())
		enable_shadow_vmcs = 0;
	if (enable_shadow_vmcs)
		init_vmcs_shadow_fields();

	if (!cpu_has_vmx_ept() ||
	    !cpu_has_vmx_ept_4levels() ||
	    !cpu_has_vmx_ept_mt_wb()) {
		enable_ept = 0;
		enable_unrestricted_guest = 0;
		enable_ept_ad_bits = 0;
	}

	if (!cpu_has_vmx_ept_ad_bits() || !enable_ept)
		enable_ept_ad_bits = 0;

	if (!cpu_has_vmx_unrestricted_guest())
		enable_unrestricted_guest = 0;

	if (!cpu_has_vmx_flexpriority())
		flexpriority_enabled = 0;

	/*
	 * set_apic_access_page_addr() is used to reload apic access
	 * page upon invalidation.  No need to do anything if not
	 * using the APIC_ACCESS_ADDR VMCS field.
	 */
	if (!flexpriority_enabled)
		kvm_x86_ops->set_apic_access_page_addr = NULL;

	if (!cpu_has_vmx_tpr_shadow())
		kvm_x86_ops->update_cr8_intercept = NULL;

	if (enable_ept && !cpu_has_vmx_ept_2m_page())
		kvm_disable_largepages();

	if (!cpu_has_vmx_ple())
		ple_gap = 0;

	if (!cpu_has_vmx_apicv()) {
		enable_apicv = 0;
		kvm_x86_ops->sync_pir_to_irr = NULL;
	}

	if (cpu_has_vmx_tsc_scaling()) {
		kvm_has_tsc_control = true;
		kvm_max_tsc_scaling_ratio = KVM_VMX_TSC_MULTIPLIER_MAX;
		kvm_tsc_scaling_ratio_frac_bits = 48;
	}

	vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
	vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
	vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
	vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
	vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
	vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);

	memcpy(vmx_msr_bitmap_legacy_x2apic_apicv,
			vmx_msr_bitmap_legacy, PAGE_SIZE);
	memcpy(vmx_msr_bitmap_longmode_x2apic_apicv,
			vmx_msr_bitmap_longmode, PAGE_SIZE);
	memcpy(vmx_msr_bitmap_legacy_x2apic,
			vmx_msr_bitmap_legacy, PAGE_SIZE);
	memcpy(vmx_msr_bitmap_longmode_x2apic,
			vmx_msr_bitmap_longmode, PAGE_SIZE);

	set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */

	for (msr = 0x800; msr <= 0x8ff; msr++) {
		if (msr == 0x839 /* TMCCT */)
			continue;
		vmx_disable_intercept_msr_x2apic(msr, MSR_TYPE_R, true);
	}

	/*
	 * TPR reads and writes can be virtualized even if virtual interrupt
	 * delivery is not in use.
	 */
	vmx_disable_intercept_msr_x2apic(0x808, MSR_TYPE_W, true);
	vmx_disable_intercept_msr_x2apic(0x808, MSR_TYPE_R | MSR_TYPE_W, false);

	/* EOI */
	vmx_disable_intercept_msr_x2apic(0x80b, MSR_TYPE_W, true);
	/* SELF-IPI */
	vmx_disable_intercept_msr_x2apic(0x83f, MSR_TYPE_W, true);

	if (enable_ept)
		vmx_enable_tdp();
	else
		kvm_disable_tdp();

	update_ple_window_actual_max();

	/*
	 * Only enable PML when hardware supports PML feature, and both EPT
	 * and EPT A/D bit features are enabled -- PML depends on them to work.
	 */
	if (!enable_ept || !enable_ept_ad_bits || !cpu_has_vmx_pml())
		enable_pml = 0;

	if (!enable_pml) {
		kvm_x86_ops->slot_enable_log_dirty = NULL;
		kvm_x86_ops->slot_disable_log_dirty = NULL;
		kvm_x86_ops->flush_log_dirty = NULL;
		kvm_x86_ops->enable_log_dirty_pt_masked = NULL;
	}

	if (cpu_has_vmx_preemption_timer() && enable_preemption_timer) {
		u64 vmx_msr;

		rdmsrl(MSR_IA32_VMX_MISC, vmx_msr);
		cpu_preemption_timer_multi =
			 vmx_msr & VMX_MISC_PREEMPTION_TIMER_RATE_MASK;
	} else {
		kvm_x86_ops->set_hv_timer = NULL;
		kvm_x86_ops->cancel_hv_timer = NULL;
	}

	kvm_set_posted_intr_wakeup_handler(wakeup_handler);

	kvm_mce_cap_supported |= MCG_LMCE_P;

	return alloc_kvm_area();

out:
	for (i = 0; i < VMX_BITMAP_NR; i++)
		free_page((unsigned long)vmx_bitmap[i]);

    return r;
}


static bool vmx_rdrand_supported(void)
{
	return vmcs_config.cpu_based_2nd_exec_ctrl &
		SECONDARY_EXEC_RDRAND;
}


static int hardware_enable(void)
{
	int cpu = raw_smp_processor_id();
	u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
	u64 old, test_bits;

	if (cr4_read_shadow() & X86_CR4_VMXE)
		return -EBUSY;

	INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu));
	INIT_LIST_HEAD(&per_cpu(blocked_vcpu_on_cpu, cpu));
	spin_lock_init(&per_cpu(blocked_vcpu_on_cpu_lock, cpu));

	/*
	 * Now we can enable the vmclear operation in kdump
	 * since the loaded_vmcss_on_cpu list on this cpu
	 * has been initialized.
	 *
	 * Though the cpu is not in VMX operation now, there
	 * is no problem to enable the vmclear operation
	 * for the loaded_vmcss_on_cpu list is empty!
	 */
	crash_enable_local_vmclear(cpu);

	rdmsrl(MSR_IA32_FEATURE_CONTROL, old);

	test_bits = FEATURE_CONTROL_LOCKED;
	test_bits |= FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX;
	if (tboot_enabled())
		test_bits |= FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX;

	if ((old & test_bits) != test_bits) {
		/* enable and lock */
		wrmsrl(MSR_IA32_FEATURE_CONTROL, old | test_bits);
	}
	kvm_cpu_vmxon(phys_addr);
	ept_sync_global();

	return 0;
}


static __always_inline void vmcs_write32(unsigned long field, u32 value)
{
	vmcs_check32(field);
	__vmcs_writel(field, value);
}


static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
						int vector)
{
	struct vcpu_vmx *vmx = to_vmx(vcpu);

	if (is_guest_mode(vcpu) &&
	    vector == vmx->nested.posted_intr_nv) {
		/* the PIR and ON have been set by L1. */
		kvm_vcpu_trigger_posted_interrupt(vcpu, true);
		/*
		 * If a posted intr is not recognized by hardware,
		 * we will accomplish it in the next vmentry.
		 */
		vmx->nested.pi_pending = true;
		kvm_make_request(KVM_REQ_EVENT, vcpu);
		return 0;
	}
	return -1;
}


static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
{
	/*
	 * Pass through host's Machine Check Enable value to hw_cr4, which
	 * is in force while we are in guest mode.  Do not let guests control
	 * this bit, even if host CR4.MCE == 0.
	 */
	unsigned long hw_cr4 =
		(cr4_read_shadow() & X86_CR4_MCE) |
		(cr4 & ~X86_CR4_MCE) |
		(to_vmx(vcpu)->rmode.vm86_active ?
		 KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON);

	if (cr4 & X86_CR4_VMXE) {
		/*
		 * To use VMXON (and later other VMX instructions), a guest
		 * must first be able to turn on cr4.VMXE (see handle_vmon()).
		 * So basically the check on whether to allow nested VMX
		 * is here.
		 */
		if (!nested_vmx_allowed(vcpu))
			return 1;
	}

	if (to_vmx(vcpu)->nested.vmxon && !nested_cr4_valid(vcpu, cr4))
		return 1;

	vcpu->arch.cr4 = cr4;
	if (enable_ept) {
		if (!is_paging(vcpu)) {
			hw_cr4 &= ~X86_CR4_PAE;
			hw_cr4 |= X86_CR4_PSE;
		} else if (!(cr4 & X86_CR4_PAE)) {
			hw_cr4 &= ~X86_CR4_PAE;
		}
	}

	if (!enable_unrestricted_guest && !is_paging(vcpu))
		/*
		 * SMEP/SMAP/PKU is disabled if CPU is in non-paging mode in
		 * hardware.  To emulate this behavior, SMEP/SMAP/PKU needs
		 * to be manually disabled when guest switches to non-paging
		 * mode.
		 *
		 * If !enable_unrestricted_guest, the CPU is always running
		 * with CR0.PG=1 and CR4 needs to be modified.
		 * If enable_unrestricted_guest, the CPU automatically
		 * disables SMEP/SMAP/PKU when the guest sets CR0.PG=0.
		 */
		hw_cr4 &= ~(X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE);

	vmcs_writel(CR4_READ_SHADOW, cr4);
	vmcs_writel(GUEST_CR4, hw_cr4);
	return 0;
}


static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu,
						     bool nested)
{
#ifdef CONFIG_SMP
	int pi_vec = nested ? POSTED_INTR_NESTED_VECTOR : POSTED_INTR_VECTOR;

	if (vcpu->mode == IN_GUEST_MODE) {
		struct vcpu_vmx *vmx = to_vmx(vcpu);

		/*
		 * Currently, we don't support urgent interrupt,
		 * all interrupts are recognized as non-urgent
		 * interrupt, so we cannot post interrupts when
		 * 'SN' is set.
		 *
		 * If the vcpu is in guest mode, it means it is
		 * running instead of being scheduled out and
		 * waiting in the run queue, and that's the only
		 * case when 'SN' is set currently, warning if
		 * 'SN' is set.
		 */
		WARN_ON_ONCE(pi_test_sn(&vmx->pi_desc));

		apic->send_IPI_mask(get_cpu_mask(vcpu->cpu), pi_vec);
		return true;
	}
#endif
	return false;
}


static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
	struct vcpu_vmx *vmx = to_vmx(vcpu);
	bool already_loaded = vmx->loaded_vmcs->cpu == cpu;

	if (!already_loaded) {
		loaded_vmcs_clear(vmx->loaded_vmcs);
		local_irq_disable();
		crash_disable_local_vmclear(cpu);

		/*
		 * Read loaded_vmcs->cpu should be before fetching
		 * loaded_vmcs->loaded_vmcss_on_cpu_link.
		 * See the comments in __loaded_vmcs_clear().
		 */
		smp_rmb();

		list_add(&vmx->loaded_vmcs->loaded_vmcss_on_cpu_link,
			 &per_cpu(loaded_vmcss_on_cpu, cpu));
		crash_enable_local_vmclear(cpu);
		local_irq_enable();
	}

	if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) {
		per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs;
		vmcs_load(vmx->loaded_vmcs->vmcs);
	}

	if (!already_loaded) {
		void *gdt = get_current_gdt_ro();
		unsigned long sysenter_esp;

		kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);

		/*
		 * Linux uses per-cpu TSS and GDT, so set these when switching
		 * processors.  See 22.2.4.
		 */
		vmcs_writel(HOST_TR_BASE,
			    (unsigned long)this_cpu_ptr(&cpu_tss));
		vmcs_writel(HOST_GDTR_BASE, (unsigned long)gdt);   /* 22.2.4 */

		/*
		 * VM exits change the host TR limit to 0x67 after a VM
		 * exit.  This is okay, since 0x67 covers everything except
		 * the IO bitmap and have have code to handle the IO bitmap
		 * being lost after a VM exit.
		 */
		BUILD_BUG_ON(IO_BITMAP_OFFSET - 1 != 0x67);

		rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
		vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */

		vmx->loaded_vmcs->cpu = cpu;
	}

	/* Setup TSC multiplier */
	if (kvm_has_tsc_control &&
	    vmx->current_tsc_ratio != vcpu->arch.tsc_scaling_ratio)
		decache_tsc_multiplier(vmx);

	vmx_vcpu_pi_load(vcpu, cpu);
	vmx->host_pkru = read_pkru();
}


static void vmx_queue_exception(struct kvm_vcpu *vcpu)
{
	struct vcpu_vmx *vmx = to_vmx(vcpu);
	unsigned nr = vcpu->arch.exception.nr;
	bool has_error_code = vcpu->arch.exception.has_error_code;
	u32 error_code = vcpu->arch.exception.error_code;
	u32 intr_info = nr | INTR_INFO_VALID_MASK;

	if (has_error_code) {
		vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
		intr_info |= INTR_INFO_DELIVER_CODE_MASK;
	}

	if (vmx->rmode.vm86_active) {
		int inc_eip = 0;
		if (kvm_exception_is_soft(nr))
			inc_eip = vcpu->arch.event_exit_inst_len;
		if (kvm_inject_realmode_interrupt(vcpu, nr, inc_eip) != EMULATE_DONE)
			kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
		return;
	}

	if (kvm_exception_is_soft(nr)) {
		vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
			     vmx->vcpu.arch.event_exit_inst_len);
		intr_info |= INTR_TYPE_SOFT_EXCEPTION;
	} else
		intr_info |= INTR_TYPE_HARD_EXCEPTION;

	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info);
}


static int vsock_stream_connect(struct socket *sock, struct sockaddr *addr,
				int addr_len, int flags)
{
	int err;
	struct sock *sk;
	struct vsock_sock *vsk;
	struct sockaddr_vm *remote_addr;
	long timeout;
	DEFINE_WAIT(wait);

	err = 0;
	sk = sock->sk;
	vsk = vsock_sk(sk);

	lock_sock(sk);

	/* XXX AF_UNSPEC should make us disconnect like AF_INET. */
	switch (sock->state) {
	case SS_CONNECTED:
		err = -EISCONN;
		goto out;
	case SS_DISCONNECTING:
		err = -EINVAL;
		goto out;
	case SS_CONNECTING:
		/* This continues on so we can move sock into the SS_CONNECTED
		 * state once the connection has completed (at which point err
		 * will be set to zero also).  Otherwise, we will either wait
		 * for the connection or return -EALREADY should this be a
		 * non-blocking call.
		 */
		err = -EALREADY;
		break;
	default:
		if ((sk->sk_state == SS_LISTEN) ||
		    vsock_addr_cast(addr, addr_len, &remote_addr) != 0) {
			err = -EINVAL;
			goto out;
		}

		/* The hypervisor and well-known contexts do not have socket
		 * endpoints.
		 */
		if (!transport->stream_allow(remote_addr->svm_cid,
					     remote_addr->svm_port)) {
			err = -ENETUNREACH;
			goto out;
		}

		/* Set the remote address that we are connecting to. */
		memcpy(&vsk->remote_addr, remote_addr,
		       sizeof(vsk->remote_addr));

		/* Autobind this socket to the local address if necessary. */
		if (!vsock_addr_bound(&vsk->local_addr)) {
			struct sockaddr_vm local_addr;

			vsock_addr_init(&local_addr, VMADDR_CID_ANY,
					VMADDR_PORT_ANY);
			err = __vsock_bind(sk, &local_addr);
			if (err != 0)
				goto out;

		}

		sk->sk_state = SS_CONNECTING;

		err = transport->connect(vsk);
		if (err < 0)
			goto out;

		/* Mark sock as connecting and set the error code to in
		 * progress in case this is a non-blocking connect.
		 */
		sock->state = SS_CONNECTING;
		err = -EINPROGRESS;
	}

	/* The receive path will handle all communication until we are able to
	 * enter the connected state.  Here we wait for the connection to be
	 * completed or a notification of an error.
	 */
	timeout = vsk->connect_timeout;
	prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);

	while (sk->sk_state != SS_CONNECTED && sk->sk_err == 0) {
		if (flags & O_NONBLOCK) {
			/* If we're not going to block, we schedule a timeout
			 * function to generate a timeout on the connection
			 * attempt, in case the peer doesn't respond in a
			 * timely manner. We hold on to the socket until the
			 * timeout fires.
			 */
			sock_hold(sk);
			INIT_DELAYED_WORK(&vsk->dwork,
					  vsock_connect_timeout);
			schedule_delayed_work(&vsk->dwork, timeout);

			/* Skip ahead to preserve error code set above. */
			goto out_wait;
		}

		release_sock(sk);
		timeout = schedule_timeout(timeout);
		lock_sock(sk);

		if (signal_pending(current)) {
			err = sock_intr_errno(timeout);
			goto out_wait_error;
		} else if (timeout == 0) {
			err = -ETIMEDOUT;
			goto out_wait_error;
		}

		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
	}

	if (sk->sk_err) {
		err = -sk->sk_err;
		goto out_wait_error;
	} else
		err = 0;

out_wait:
	finish_wait(sk_sleep(sk), &wait);
out:
	release_sock(sk);
	return err;

out_wait_error:
	sk->sk_state = SS_UNCONNECTED;
	sock->state = SS_UNCONNECTED;
	goto out_wait;
}


static void free_export_entry(RBinWasmExportEntry *entry) {
	if (entry) {
		free (entry->field_str);
		free (entry);
	}
}


RPVector *r_bin_wasm_get_exports(RBinWasmObj *bin) {
	r_return_val_if_fail (bin && bin->g_sections, NULL);
	return bin->g_exports? bin->g_exports: parse_unique_subsec_vec_by_id (bin, R_BIN_WASM_SECTION_EXPORT);
}


static RBinWasmGlobalEntry *parse_global_entry(RBinWasmObj *bin, ut64 bound, ut32 index) {
	RBuffer *b = bin->buf;
	RBinWasmGlobalEntry *ptr = R_NEW0 (RBinWasmGlobalEntry);
	if (ptr) {
		ptr->sec_i = index;
		ptr->file_offset = r_buf_tell (b);
		if (!consume_u7_r (b, bound, (ut8 *)&ptr->content_type)) {
			goto beach;
		}
		if (!consume_u1_r (b, bound, &ptr->mutability)) {
			goto beach;
		}
		if (!consume_init_expr_r (b, bound, R_BIN_WASM_END_OF_CODE, NULL)) {
			goto beach;
		}
	}
	return ptr;

beach:
	free (ptr);
	return NULL;
}


static inline void wasm_custom_local_names_free(RBinWasmCustomNameLocalNames *local) {
	if (local) {
		r_list_free (local->locals);
		R_FREE (local);
	}
}


static size_t consume_locals_r(RBuffer *b, ut64 bound, RBinWasmCodeEntry *out) {
	r_return_val_if_fail (out, 0);
	ut32 count = out->local_count;
	if (count <= 0) {
		return 0;
	}
	out->locals = R_NEWS0 (struct r_bin_wasm_local_entry_t, count);
	if (!out->locals) {
		return 0;
	}

	ut32 i = 0;
	for (i = 0; i < count; i++) {
		struct r_bin_wasm_local_entry_t *local = &out->locals[i];
		if (!consume_u32_r (b, bound, &local->count)) {
			return 0;
		}
		if (!consume_s7_r (b, bound, &local->type)) {
			return 0;
		}
	}
	return i;
}


static RBinWasmMemoryEntry *parse_memory_entry(RBinWasmObj *bin, ut64 bound, ut32 index) {
	RBuffer *b = bin->buf;
	RBinWasmMemoryEntry *ptr = R_NEW0 (RBinWasmMemoryEntry);
	if (ptr) {
		ptr->sec_i = index;
		ptr->file_offset = r_buf_tell (b);
		if (!consume_limits_r (b, bound, &ptr->limits)) {
			free (ptr);
			return NULL;
		}
	}
	return ptr;
}


static RList *r_bin_wasm_get_sections_by_id(RList *sections, ut8 id) {
	RList *ret = r_list_newf (NULL);
	if (ret) {
		RBinWasmSection *sec;
		RListIter *iter;
		r_list_foreach (sections, iter, sec) {
			if (sec->id == id) {
				r_list_append (ret, sec);
			}
		}
	}
	return ret;
}


RPVector *r_bin_wasm_get_datas(RBinWasmObj *bin) {
	r_return_val_if_fail (bin && bin->g_sections, NULL);
	return bin->g_datas? bin->g_datas: parse_unique_subsec_vec_by_id (bin, R_BIN_WASM_SECTION_DATA);
}


static inline RPVector *parse_vec(RBinWasmObj *bin, ut64 bound, ParseEntryFcn parse_entry, RPVectorFree free_entry) {
	RBuffer *buf = bin->buf;

	ut32 count;
	if (!consume_u32_r (buf, bound, &count)) {
		return NULL;
	}

	RPVector *vec = r_pvector_new (free_entry);
	if (vec) {
		r_pvector_reserve (vec, count);
		ut32 i;
		for (i = 0; i < count; i++) {
			ut64 start = r_buf_tell (buf);
			void *e = parse_entry (bin, bound, i);
			if (!e || !r_pvector_push (vec, e)) {
				eprintf ("[wasm] Failed to parse entry %u/%u of vec at 0x%" PFMT64x "\n", i, count, start);
				free_entry (e);
				break;
			}
		}
	}
	return vec;
}


CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize)
{
	STPFileHeader fileHeader;
	if(!file.ReadStruct(fileHeader))
	{
		return ProbeWantMoreData;
	}
	if(!ValidateHeader(fileHeader))
	{
		return ProbeFailure;
	}
	MPT_UNREFERENCED_PARAMETER(pfilesize);
	return ProbeSuccess;
}


int __export rad_packet_add_octets(struct rad_packet_t *pack, const char *vendor_name, const char *name, const uint8_t *val, int len)
{
	struct rad_attr_t *ra;
	struct rad_dict_attr_t *attr;
	struct rad_dict_vendor_t *vendor;

	if (pack->len + (vendor_name ? 8 : 2) + len >= REQ_LENGTH_MAX)
		return -1;

	if (vendor_name) {
		vendor = rad_dict_find_vendor_name(vendor_name);
		if (!vendor)
			return -1;
		attr = rad_dict_find_vendor_attr(vendor, name);
	} else {
		vendor = NULL;
		attr = rad_dict_find_attr(name);
	}

	if (!attr)
		return -1;

	ra = mempool_alloc(attr_pool);
	if (!ra) {
		log_emerg("radius: out of memory\n");
		return -1;
	}

	memset(ra, 0, sizeof(*ra));
	ra->vendor = vendor;
	ra->attr = attr;
	ra->len = len;

	if (len) {
		ra->alloc = 1;
		ra->val.octets = _malloc(len);
		if (!ra->val.octets) {
			log_emerg("radius: out of memory\n");
			_free(ra);
			return -1;
		}
		memcpy(ra->val.octets, val, len);
	}

	ra->raw = ra->val.octets;

	list_add_tail(&ra->entry, &pack->attrs);
	pack->len += (vendor_name ? 8 : 2) + len;

	return 0;
}


void enc_untrusted_thread_wait(int32_t *const queue,
                               uint64_t timeout_microsec) {
  enc_untrusted_thread_wait_value(queue, kWaitQueueEnabled, timeout_microsec);
}


int enc_untrusted_setitimer(int which, const struct itimerval *new_value,
                            struct itimerval *old_value) {
  struct klinux_itimerval klinux_new_value {};
  struct klinux_itimerval klinux_old_value {};
  if (!TokLinuxItimerval(new_value, &klinux_new_value)) {
    errno = EFAULT;
    return -1;
  }

  int result = EnsureInitializedAndDispatchSyscall(
      asylo::system_call::kSYS_setitimer, TokLinuxItimerType(which),
      &klinux_new_value, &klinux_old_value);

  if (old_value != nullptr &&
      !FromkLinuxItimerval(&klinux_old_value, old_value)) {
    errno = EFAULT;
    return -1;
  }
  return result;
}


int enc_untrusted_getrusage(int who, struct rusage *usage) {
  struct klinux_rusage klinux_usage {};
  int result = EnsureInitializedAndDispatchSyscall(
      asylo::system_call::kSYS_getrusage, TokLinuxRusageTarget(who),
      &klinux_usage);

  if (result != -1) {
    if (!FromkLinuxRusage(&klinux_usage, usage)) {
      errno = EINVAL;
      return -1;
    }
  }
  return result;
}


void CheckStatusAndParamCount(const asylo::primitives::PrimitiveStatus &status,
                              const MessageReader &output, const char *name,
                              int expected_params, bool match_exact_params) {
  if (!status.ok()) {
    std::string message = absl::StrCat("Host call '", name, "' failed.");
    TrustedPrimitives::BestEffortAbort(message.c_str());
  }

  if (!match_exact_params) {
    if (output.size() < expected_params) {
      std::string message = absl::StrCat(
          "Host call '", name, "': Expected at least ", expected_params,
          " parameters on the MessageReader, found ", output.size());
      TrustedPrimitives::BestEffortAbort(message.c_str());
    }
  } else {
    if (output.size() != expected_params) {
      std::string message = absl::StrCat(
          "Host call '", name, "': Expected ", expected_params,
          " parameters on the MessageReader, found ", output.size());
      TrustedPrimitives::BestEffortAbort(message.c_str());
    }
  }
}


int enc_untrusted_nanosleep(const struct timespec *req, struct timespec *rem) {
  struct kLinux_timespec klinux_req;
  if (!TokLinuxtimespec(req, &klinux_req)) {
    errno = EINVAL;
    return -1;
  }
  struct kLinux_timespec klinux_rem;

  int result = EnsureInitializedAndDispatchSyscall(
      asylo::system_call::kSYS_nanosleep, &klinux_req, &klinux_rem);
  FromkLinuxtimespec(&klinux_rem, rem);
  return result;
}


int enc_untrusted_utime(const char *filename, const struct utimbuf *times) {
  struct kLinux_utimbuf klinux_times {};

  // We do not check the return value of the conversion function since utimbuf
  // is allowed to be null.
  TokLinuxutimbuf(times, &klinux_times);
  return EnsureInitializedAndDispatchSyscall(asylo::system_call::kSYS_utime,
                                             filename, &klinux_times);
}


gid_t enc_untrusted_getgid() {
  return EnsureInitializedAndDispatchSyscall(asylo::system_call::kSYS_getgid);
}


ssize_t enc_untrusted_fgetxattr(int fd, const char *name, void *value,
                                size_t size) {
  return EnsureInitializedAndDispatchSyscall(asylo::system_call::kSYS_fgetxattr,
                                             fd, name, value, size);
}


int enc_untrusted_getpeername(int sockfd, struct sockaddr *addr,
                              socklen_t *addrlen) {
  if (!addr || !addrlen) {
    errno = EFAULT;
    return -1;
  }
  // Guard against -1 being passed as addrlen even though it's unsigned.
  if (*addrlen == 0 || *addrlen > INT32_MAX) {
    errno = EINVAL;
    return -1;
  }
  MessageWriter input;
  input.Push<int>(sockfd);
  MessageReader output;
  const auto status = NonSystemCallDispatcher(
      ::asylo::host_call::kGetPeernameHandler, &input, &output);
  CheckStatusAndParamCount(status, output, "enc_untrusted_getpeername", 3);

  int result = output.next<int>();
  int klinux_errno = output.next<int>();

  // getpeername() returns -1 on failure, with errno set to indicate the cause
  // of the error.
  if (result == -1) {
    errno = FromkLinuxErrorNumber(klinux_errno);
    return result;
  }

  auto klinux_sockaddr_buf = output.next();
  const struct klinux_sockaddr *klinux_addr =
      klinux_sockaddr_buf.As<struct klinux_sockaddr>();
  FromkLinuxSockAddr(klinux_addr, klinux_sockaddr_buf.size(), addr, addrlen,
                     TrustedPrimitives::BestEffortAbort);
  return result;
}


int enc_untrusted_rename(const char *oldpath, const char *newpath) {
  return EnsureInitializedAndDispatchSyscall(asylo::system_call::kSYS_rename,
                                             oldpath, newpath);
}


pid_t enc_untrusted_getppid() {
  return EnsureInitializedAndDispatchSyscall(asylo::system_call::kSYS_getppid);
}


void enc_freeaddrinfo(struct addrinfo *res) {
  struct addrinfo *prev_info = nullptr;
  for (struct addrinfo *info = res; info != nullptr; info = info->ai_next) {
    if (prev_info) free(prev_info);
    if (info->ai_addr) free(info->ai_addr);
    if (info->ai_canonname) free(info->ai_canonname);
    prev_info = info;
  }
  if (prev_info) free(prev_info);
}


int enc_untrusted_ioctl1(int fd, uint64_t request) {
  return EnsureInitializedAndDispatchSyscall(asylo::system_call::kSYS_ioctl, fd,
                                             request);
}


  void Compute(OpKernelContext* context) override {
    const Tensor& input = context->input(0);
    const TensorShape& input_shape = input.shape();
    const int32 input_dims = input_shape.dims();

    const Tensor& segment_id = context->input(1);
    const TensorShape& segment_id_shape = segment_id.shape();
    const int32 segment_dims = segment_id_shape.dims();

    const Tensor& num_segments_tensor = context->input(2);
    OP_REQUIRES(context, num_segments_tensor.NumElements() != 0,
                errors::InvalidArgument("Number of segments cannot be empty."));
    auto num_segments = num_segments_tensor.scalar<NUM_SEGMENTS_TYPE>()();

    OP_REQUIRES(context, segment_dims != 0,
                errors::InvalidArgument("Segment_id cannot have rank 0"));

    OP_REQUIRES(
        context, segment_dims <= input_dims,
        errors::OutOfRange("Invalid segment_id rank ", segment_dims,
                           " for input with ", input_dims, " dimension(s)"));
    for (auto i = 0; i < segment_dims; i++) {
      OP_REQUIRES(
          context, segment_id_shape.dim_size(i) == input_shape.dim_size(i),
          errors::InvalidArgument(
              "Segment dimension is ", segment_id_shape.dim_size(i),
              " while input dimension is ", input_dims, " in rank ", i));
    }

    // Making output tensor.
    Tensor* output_tensor = nullptr;
    TensorShape output_shape =
        GetOutputShape(input_shape, segment_id_shape, num_segments);
    OP_REQUIRES_OK(context, context->allocate_output("output", output_shape,
                                                     &output_tensor));

    // Preparating flat tensors.
    auto output_flat = output_tensor->flat<tstring>();
    auto flat_segment_id = segment_id.flat<INDICES_TYPE>();
    auto flat_input = input.flat<tstring>();

    for (int i = 0; i < flat_segment_id.size(); i++) {
      OP_REQUIRES(
          context,
          ((flat_segment_id(i) < num_segments) && (flat_segment_id(i) >= 0)),
          errors::InvalidArgument(
              "segment_ids are not allowed to exceed num_segments or"
              " to have negative values."));
    }

    int64 big_stride;
    int64 small_stride;
    std::tie(big_stride, small_stride) =
        GetStrides<INDICES_TYPE>(input_shape, segment_id_shape);
    auto relative_offset_set =
        GetFlattenedRelativeOffsets<INDICES_TYPE>(small_stride, big_stride);
    for (auto start_offset = 0; start_offset < big_stride; start_offset++) {
      for (auto i = 0; i < relative_offset_set.size(); i++) {
        auto output_index = start_offset + flat_segment_id(i) * big_stride;
        auto offset = start_offset + relative_offset_set[i];
        if (output_flat(output_index).length() != 0)
          output_flat(output_index).append(separator_.c_str());
        output_flat(output_index).append(flat_input(offset));
      }
    }
  }


static int sctp_getsockopt(struct sock *sk, int level, int optname,
			   char __user *optval, int __user *optlen)
{
	int retval = 0;
	int len;

	pr_debug("%s: sk:%p, optname:%d\n", __func__, sk, optname);

	/* I can hardly begin to describe how wrong this is.  This is
	 * so broken as to be worse than useless.  The API draft
	 * REALLY is NOT helpful here...  I am not convinced that the
	 * semantics of getsockopt() with a level OTHER THAN SOL_SCTP
	 * are at all well-founded.
	 */
	if (level != SOL_SCTP) {
		struct sctp_af *af = sctp_sk(sk)->pf->af;

		retval = af->getsockopt(sk, level, optname, optval, optlen);
		return retval;
	}

	if (get_user(len, optlen))
		return -EFAULT;

	lock_sock(sk);

	switch (optname) {
	case SCTP_STATUS:
		retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen);
		break;
	case SCTP_DISABLE_FRAGMENTS:
		retval = sctp_getsockopt_disable_fragments(sk, len, optval,
							   optlen);
		break;
	case SCTP_EVENTS:
		retval = sctp_getsockopt_events(sk, len, optval, optlen);
		break;
	case SCTP_AUTOCLOSE:
		retval = sctp_getsockopt_autoclose(sk, len, optval, optlen);
		break;
	case SCTP_SOCKOPT_PEELOFF:
		retval = sctp_getsockopt_peeloff(sk, len, optval, optlen);
		break;
	case SCTP_PEER_ADDR_PARAMS:
		retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
							  optlen);
		break;
	case SCTP_DELAYED_SACK:
		retval = sctp_getsockopt_delayed_ack(sk, len, optval,
							  optlen);
		break;
	case SCTP_INITMSG:
		retval = sctp_getsockopt_initmsg(sk, len, optval, optlen);
		break;
	case SCTP_GET_PEER_ADDRS:
		retval = sctp_getsockopt_peer_addrs(sk, len, optval,
						    optlen);
		break;
	case SCTP_GET_LOCAL_ADDRS:
		retval = sctp_getsockopt_local_addrs(sk, len, optval,
						     optlen);
		break;
	case SCTP_SOCKOPT_CONNECTX3:
		retval = sctp_getsockopt_connectx3(sk, len, optval, optlen);
		break;
	case SCTP_DEFAULT_SEND_PARAM:
		retval = sctp_getsockopt_default_send_param(sk, len,
							    optval, optlen);
		break;
	case SCTP_DEFAULT_SNDINFO:
		retval = sctp_getsockopt_default_sndinfo(sk, len,
							 optval, optlen);
		break;
	case SCTP_PRIMARY_ADDR:
		retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen);
		break;
	case SCTP_NODELAY:
		retval = sctp_getsockopt_nodelay(sk, len, optval, optlen);
		break;
	case SCTP_RTOINFO:
		retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen);
		break;
	case SCTP_ASSOCINFO:
		retval = sctp_getsockopt_associnfo(sk, len, optval, optlen);
		break;
	case SCTP_I_WANT_MAPPED_V4_ADDR:
		retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen);
		break;
	case SCTP_MAXSEG:
		retval = sctp_getsockopt_maxseg(sk, len, optval, optlen);
		break;
	case SCTP_GET_PEER_ADDR_INFO:
		retval = sctp_getsockopt_peer_addr_info(sk, len, optval,
							optlen);
		break;
	case SCTP_ADAPTATION_LAYER:
		retval = sctp_getsockopt_adaptation_layer(sk, len, optval,
							optlen);
		break;
	case SCTP_CONTEXT:
		retval = sctp_getsockopt_context(sk, len, optval, optlen);
		break;
	case SCTP_FRAGMENT_INTERLEAVE:
		retval = sctp_getsockopt_fragment_interleave(sk, len, optval,
							     optlen);
		break;
	case SCTP_PARTIAL_DELIVERY_POINT:
		retval = sctp_getsockopt_partial_delivery_point(sk, len, optval,
								optlen);
		break;
	case SCTP_MAX_BURST:
		retval = sctp_getsockopt_maxburst(sk, len, optval, optlen);
		break;
	case SCTP_AUTH_KEY:
	case SCTP_AUTH_CHUNK:
	case SCTP_AUTH_DELETE_KEY:
		retval = -EOPNOTSUPP;
		break;
	case SCTP_HMAC_IDENT:
		retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen);
		break;
	case SCTP_AUTH_ACTIVE_KEY:
		retval = sctp_getsockopt_active_key(sk, len, optval, optlen);
		break;
	case SCTP_PEER_AUTH_CHUNKS:
		retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval,
							optlen);
		break;
	case SCTP_LOCAL_AUTH_CHUNKS:
		retval = sctp_getsockopt_local_auth_chunks(sk, len, optval,
							optlen);
		break;
	case SCTP_GET_ASSOC_NUMBER:
		retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen);
		break;
	case SCTP_GET_ASSOC_ID_LIST:
		retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen);
		break;
	case SCTP_AUTO_ASCONF:
		retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen);
		break;
	case SCTP_PEER_ADDR_THLDS:
		retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen);
		break;
	case SCTP_GET_ASSOC_STATS:
		retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen);
		break;
	case SCTP_RECVRCVINFO:
		retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen);
		break;
	case SCTP_RECVNXTINFO:
		retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen);
		break;
	default:
		retval = -ENOPROTOOPT;
		break;
	}

	release_sock(sk);
	return retval;
}


static void sctp_close(struct sock *sk, long timeout)
{
	struct net *net = sock_net(sk);
	struct sctp_endpoint *ep;
	struct sctp_association *asoc;
	struct list_head *pos, *temp;
	unsigned int data_was_unread;

	pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout);

	lock_sock(sk);
	sk->sk_shutdown = SHUTDOWN_MASK;
	sk->sk_state = SCTP_SS_CLOSING;

	ep = sctp_sk(sk)->ep;

	/* Clean up any skbs sitting on the receive queue.  */
	data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue);
	data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby);

	/* Walk all associations on an endpoint.  */
	list_for_each_safe(pos, temp, &ep->asocs) {
		asoc = list_entry(pos, struct sctp_association, asocs);

		if (sctp_style(sk, TCP)) {
			/* A closed association can still be in the list if
			 * it belongs to a TCP-style listening socket that is
			 * not yet accepted. If so, free it. If not, send an
			 * ABORT or SHUTDOWN based on the linger options.
			 */
			if (sctp_state(asoc, CLOSED)) {
				sctp_unhash_established(asoc);
				sctp_association_free(asoc);
				continue;
			}
		}

		if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) ||
		    !skb_queue_empty(&asoc->ulpq.reasm) ||
		    (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) {
			struct sctp_chunk *chunk;

			chunk = sctp_make_abort_user(asoc, NULL, 0);
			if (chunk)
				sctp_primitive_ABORT(net, asoc, chunk);
		} else
			sctp_primitive_SHUTDOWN(net, asoc, NULL);
	}

	/* On a TCP-style socket, block for at most linger_time if set. */
	if (sctp_style(sk, TCP) && timeout)
		sctp_wait_for_close(sk, timeout);

	/* This will run the backlog queue.  */
	release_sock(sk);

	/* Supposedly, no process has access to the socket, but
	 * the net layers still may.
	 * Also, sctp_destroy_sock() needs to be called with addr_wq_lock
	 * held and that should be grabbed before socket lock.
	 */
	spin_lock_bh(&net->sctp.addr_wq_lock);
	bh_lock_sock(sk);

	/* Hold the sock, since sk_common_release() will put sock_put()
	 * and we have just a little more cleanup.
	 */
	sock_hold(sk);
	sk_common_release(sk);

	bh_unlock_sock(sk);
	spin_unlock_bh(&net->sctp.addr_wq_lock);

	sock_put(sk);

	SCTP_DBG_OBJCNT_DEC(sock);
}


    KillRing() : size(0), index(0), lastAction(actionOther) {
        theRing.reserve(capacity);
    }


static void setDisplayAttribute(bool enhancedDisplay) {
#ifdef _WIN32
    if (enhancedDisplay) {
        CONSOLE_SCREEN_BUFFER_INFO inf;
        GetConsoleScreenBufferInfo(console_out, &inf);
        oldDisplayAttribute = inf.wAttributes;
        BYTE oldLowByte = oldDisplayAttribute & 0xFF;
        BYTE newLowByte;
        switch (oldLowByte) {
            case 0x07:
                // newLowByte = FOREGROUND_BLUE | FOREGROUND_INTENSITY;  // too dim
                // newLowByte = FOREGROUND_BLUE;                         // even dimmer
                newLowByte =
                    FOREGROUND_BLUE | FOREGROUND_GREEN;  // most similar to xterm appearance
                break;
            case 0x70:
                newLowByte = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
                break;
            default:
                newLowByte = oldLowByte ^ 0xFF;  // default to inverse video
                break;
        }
        inf.wAttributes = (inf.wAttributes & 0xFF00) | newLowByte;
        SetConsoleTextAttribute(console_out, inf.wAttributes);
    } else {
        SetConsoleTextAttribute(console_out, oldDisplayAttribute);
    }
#else
    if (enhancedDisplay) {
        if (write(1, "\x1b[1;34m", 7) == -1)
            return; /* bright blue (visible with both B&W bg) */
    } else {
        if (write(1, "\x1b[0m", 4) == -1)
            return; /* reset */
    }
#endif
}


static UChar32 escRoutine(UChar32 c) {
    c = readUnicodeCharacter();
    if (c == 0)
        return 0;
    return doDispatch(c, escDispatch);
}


void linenoiseAddCompletion(linenoiseCompletions* lc, const char* str) {
    lc->completionStrings.push_back(Utf32String(reinterpret_cast<const UChar8*>(str)));
}


PromptBase() : promptPreviousInputLen(0) {}


static UChar32 setMetaRoutine(UChar32 c) {
    thisKeyMetaCtrl = META;
    if (c == 0x1B) {  // another ESC, stay in ESC processing mode
        c = readUnicodeCharacter();
        if (c == 0)
            return 0;
        return doDispatch(c, escDispatch);
    }
    return doDispatch(c, initialDispatch);
}


static void recomputeCharacterWidths(const UChar32* text, char* widths, int charCount) {
    for (int i = 0; i < charCount; ++i) {
        widths[i] = mk_wcwidth(text[i]);
    }
}


static char *build_hash_string(int mode, const char *chksum, ut8 *data, ut32 datalen) {
	char *chkstr = NULL, *aux, *ret = NULL;
	const char *ptr = chksum;
	char tmp[128];
	int i;
	do {
		for (i = 0; *ptr && *ptr != ',' && i < sizeof (tmp) -1; i++) {
			tmp[i] = *ptr++;
		}
		tmp[i] = '\0';
		r_str_trim_head_tail (tmp);
		chkstr = r_hash_to_string (NULL, tmp, data, datalen);
		if (!chkstr) {
			if (*ptr && *ptr == ',') {
				ptr++;
			}
			continue;
		}
		if (IS_MODE_SIMPLE (mode)) {
			aux = r_str_newf ("%s ", chkstr);
		} else if (IS_MODE_JSON (mode)) {
			aux = r_str_newf ("\"%s\":\"%s\",", tmp, chkstr);
		} else {
			aux = r_str_newf ("%s=%s ", tmp, chkstr);
		}
		ret = r_str_append (ret, aux);
		free (chkstr);
		free (aux);
		if (*ptr && *ptr == ',') ptr++;
	} while (*ptr);

	return ret;
}


static bool has_canary(RBinFile *bf) {
	bool ret = false;
	RList* imports_list = imports (bf);
	RListIter *iter;
	RBinImport *import;
	if (imports_list) {
		r_list_foreach (imports_list, iter, import) {
			if (!strcmp (import->name, "__stack_chk_fail") || !strcmp (import->name, "__stack_smash_handler")) {
				ret = true;
				break;
			}
		}
		imports_list->free = r_bin_import_free;
		r_list_free (imports_list);
	}
	return ret;
}


R_API int r_core_bin_raise(RCore *core, ut32 binfile_idx, ut32 binobj_idx) {
	RBin *bin = core->bin;
	RBinFile *binfile = NULL;

	if (binfile_idx == UT32_MAX && binobj_idx == UT32_MAX) {
		return false;
	}
	if (!r_bin_select_by_ids (bin, binfile_idx, binobj_idx)) {
		return false;
	}
	binfile = r_core_bin_cur (core);
	if (binfile) {
		r_io_use_fd (core->io, binfile->fd);
	}
	// it should be 0 to use r_io_use_fd in r_core_block_read
	core->switch_file_view = 0;
	return binfile && r_core_bin_set_env (core, binfile) && r_core_block_read (core);
}


static int bin_fields(RCore *r, int mode, int va) {
	RList *fields;
	RListIter *iter;
	RBinField *field;
	int i = 0;
	RBin *bin = r->bin;
	RBinFile *binfile = r_core_bin_cur (r);
	ut64 size = binfile ? binfile->size : UT64_MAX;
	ut64 baddr = r_bin_get_baddr (r->bin);

	if (!(fields = r_bin_get_fields (bin))) {
		return false;
	}
	if (IS_MODE_JSON (mode)) {
		r_cons_print ("[");
	} else if (IS_MODE_RAD (mode)) {
		r_cons_println ("fs header");
	} else if (IS_MODE_NORMAL (mode)) {
		r_cons_println ("[Header fields]");
	}
//why this? there is an overlap in bin_sections with ehdr
//because there can't be two sections with the same name
#if 0
	else if (IS_MODE_SET (mode)) {
		// XXX: Need more flags??
		// this will be set even if the binary does not have an ehdr
		int fd = r_core_file_cur_fd(r);
		r_io_section_add (r->io, 0, baddr, size, size, 7, "ehdr", 0, fd);
	}
#endif
	r_list_foreach (fields, iter, field) {
		ut64 addr = rva (bin, field->paddr, field->vaddr, va);

		if (IS_MODE_RAD (mode)) {
			r_name_filter (field->name, -1);
			r_cons_printf ("f header.%s @ 0x%08"PFMT64x"\n", field->name, addr);
			if (field->comment && *field->comment) {
				r_cons_printf ("CC %s @ 0x%"PFMT64x"\n", field->comment, addr);
			}
			if (field->format && *field->format) {
				r_cons_printf ("pf.%s %s\n", field->name, field->format);
			}
		} else if (IS_MODE_JSON (mode)) {
			r_cons_printf ("%s{\"name\":\"%s\","
				"\"vaddr\":%"PFMT64d","
				"\"paddr\":%"PFMT64d,
				iter->p? ",": "",
				field->name,
				field->vaddr,
				field->paddr
				);
			if (field->comment && *field->comment) {
				// TODO: filter comment before json
				r_cons_printf (",\"comment\":\"%s\"", field->comment);
			}
			if (field->format && *field->format) {
				// TODO: filter comment before json
				r_cons_printf (",\"format\":\"%s\"", field->format);
			}
			r_cons_printf ("}");
		} else if (IS_MODE_NORMAL (mode)) {
			const bool haveComment = (field->comment && *field->comment);
			r_cons_printf ("0x%08"PFMT64x" 0x%08"PFMT64x" %s%s%s\n",
				field->vaddr, field->paddr, field->name,
				haveComment? "; ": "",
				haveComment? field->comment: "");
		}
		i++;
	}
	if (IS_MODE_JSON (mode)) {
		r_cons_printf ("]");
	} else if (IS_MODE_RAD (mode)) {
		/* add program header section */
		r_cons_printf ("S 0 0x%"PFMT64x" 0x%"PFMT64x" 0x%"PFMT64x" ehdr rwx\n",
			baddr, size, size);
	} else if (IS_MODE_NORMAL (mode)) {
		r_cons_printf ("\n%i fields\n", i);
	}

	return true;
}


R_API int r_core_bin_update_arch_bits(RCore *r) {
	RBinFile *binfile = NULL;
	const char *name = NULL, *arch = NULL;
	ut16 bits = 0;
	if (!r) {
		return 0;
	}
	if (r->assembler) {
		bits = r->assembler->bits;
	   	if (r->assembler->cur) {
			arch = r->assembler->cur->arch;
		}
	}
	binfile = r_core_bin_cur (r);
	name = binfile ? binfile->file : NULL;
	if (binfile && binfile->curxtr) {
		r_anal_hint_clear (r->anal);
	}
	return r_core_bin_set_arch_bits (r, name, arch, bits);
}


static bool ht_insert_intu64(SdbHash* ht, int key, ut64 value) {
	ut64 *mvalue = malloc (sizeof (ut64));
	if (!mvalue) {
		return false;
	}
	*mvalue = value;
	return ht_insert (ht, sdb_fmt ("%d", key), (void *)mvalue);
}


R_API int r_core_bin_refresh_strings(RCore *r) {
	return r_bin_reset_strings (r->bin) ? true: false;
}


static RList* fields(RBinFile *bf) {
	RList *ret = NULL;
	RBinField *ptr = NULL;
	struct r_bin_elf_field_t *field = NULL;
	int i;

	if (!(ret = r_list_new ())) {
		return NULL;
	}
	ret->free = free;
	if (!(field = Elf_(r_bin_elf_get_fields) (bf->o->bin_obj))) {
		return ret;
	}
	for (i = 0; !field[i].last; i++) {
		if (!(ptr = R_NEW0 (RBinField))) {
			break;
		}
		ptr->name = strdup (field[i].name);
		ptr->comment = NULL;
		ptr->vaddr = field[i].offset;
		ptr->paddr = field[i].offset;
		r_list_append (ret, ptr);
	}
	free (field);
	return ret;
}


static int bin_sections(RCore *r, int mode, ut64 laddr, int va, ut64 at, const char *name, const char *chksum) {
	char *str = NULL;
	RBinSection *section;
	RBinInfo *info = NULL;
	RList *sections;
	RListIter *iter;
	int i = 0;
	int fd = -1;
	bool printHere = false;
	sections = r_bin_get_sections (r->bin);
	bool inDebugger = r_config_get_i (r->config, "cfg.debug");
	SdbHash *dup_chk_ht = ht_new (NULL, NULL, NULL);
	bool ret = false;

	if (!dup_chk_ht) {
		return false;
	}

	if (chksum && *chksum == '.') {
		printHere = true;
	}
	if (IS_MODE_JSON (mode) && !printHere) r_cons_printf ("[");
	else if (IS_MODE_RAD (mode) && !at) r_cons_printf ("fs sections\n");
	else if (IS_MODE_NORMAL (mode) && !at && !printHere) r_cons_printf ("[Sections]\n");
	else if (IS_MODE_NORMAL (mode) && printHere) r_cons_printf("Current section\n");
	else if (IS_MODE_SET (mode)) {
		fd = r_core_file_cur_fd (r);
		r_flag_space_set (r->flags, "sections");
	}
	r_list_foreach (sections, iter, section) {
		char perms[] = "----";
		int va_sect = va;
		ut64 addr;

		if (va && !(section->srwx & R_BIN_SCN_READABLE)) {
			va_sect = VA_NOREBASE;
		}
		addr = rva (r->bin, section->paddr, section->vaddr, va_sect);

		if (name && strcmp (section->name, name)) {
			continue;
		}

		if ((printHere && !(section->paddr <= r->offset && r->offset < (section->paddr + section->size)))
				&& (printHere && !(addr <= r->offset && r->offset < (addr + section->size)))) {
			continue;
		}

		r_name_filter (section->name, sizeof (section->name));
		if (at && (!section->size || !is_in_range (at, addr, section->size))) {
			continue;
		}

		if (section->srwx & R_BIN_SCN_SHAREABLE) perms[0] = 's';
		if (section->srwx & R_BIN_SCN_READABLE) perms[1] = 'r';
		if (section->srwx & R_BIN_SCN_WRITABLE) perms[2] = 'w';
		if (section->srwx & R_BIN_SCN_EXECUTABLE) perms[3] = 'x';

		if (IS_MODE_SET (mode)) {
#if LOAD_BSS_MALLOC
			if (!strcmp (section->name, ".bss")) {
				// check if there's already a file opened there
				int loaded = 0;
				RListIter *iter;
				RIOMap *m;
				r_list_foreach (r->io->maps, iter, m) {
					if (m->from == addr) {
						loaded = 1;
					}
				}
				if (!loaded && !inDebugger) {
					r_core_cmdf (r, "on malloc://%d 0x%"PFMT64x" # bss\n",
						section->vsize, addr);
				}
			}
#endif
			r_name_filter (section->name, 128);
			if (section->format) {
				// This is damn slow if section vsize is HUGE
				if (section->vsize < 1024 * 1024 * 2) {
					r_core_cmdf (r, "%s @ 0x%"PFMT64x, section->format, section->vaddr);
				}
			}
			if (r->bin->prefix) {
				str = r_str_newf ("%s.section.%s", r->bin->prefix, section->name);
			} else {
				str = r_str_newf ("section.%s", section->name);

			}
			r_flag_set (r->flags, str, addr, section->size);
			R_FREE (str);

			if (r->bin->prefix) {
				str = r_str_newf ("%s.section_end.%s", r->bin->prefix, section->name);
			} else {
				str = r_str_newf ("section_end.%s", section->name);
			}
			r_flag_set (r->flags, str, addr + section->vsize, 0);
			R_FREE (str);

			if (section->arch || section->bits) {
				const char *arch = section->arch;
				int bits = section->bits;
				if (info) {
					if (!arch) {
						arch = info->arch;
					}
					if (!bits) {
						bits = info->bits;
					}
				}
				//r_io_section_set_archbits (r->io, addr, arch, bits);
			}
			char *pfx = r->bin->prefix;
			str = r_str_newf ("[%02d] %s section size %" PFMT64d" named %s%s%s",
				i, perms, section->size,
				pfx? pfx: "", pfx? ".": "", section->name);
			r_meta_add (r->anal, R_META_TYPE_COMMENT, addr, addr, str);
			R_FREE (str);
			if (section->add) {
				str = r_str_newf ("%"PFMT64x".%"PFMT64x".%"PFMT64x".%"PFMT64x".%"PFMT32u".%s.%"PFMT32u".%d",
					section->paddr, addr, section->size, section->vsize, section->srwx, section->name, r->bin->cur->id, fd);
				if (!ht_find (dup_chk_ht, str, NULL) && r_io_section_add (r->io, section->paddr, addr,
						section->size, section->vsize,
						section->srwx, section->name,
						r->bin->cur->id, fd)) {
					ht_insert (dup_chk_ht, str, NULL);
				}
				R_FREE (str);
			}
		} else if (IS_MODE_SIMPLE (mode)) {
			char *hashstr = NULL;
			if (chksum) {
				ut8 *data = malloc (section->size);
				if (!data) {
					goto out;
				}
				ut32 datalen = section->size;
				r_io_pread_at (r->io, section->paddr, data, datalen);
				hashstr = build_hash_string (mode, chksum,
							data, datalen);
				free (data);
			}
			r_cons_printf ("0x%"PFMT64x" 0x%"PFMT64x" %s %s%s%s\n",
				addr, addr + section->size,
				perms,
				hashstr ? hashstr : "", hashstr ? " " : "",
				section->name
			);
			free (hashstr);
		} else if (IS_MODE_JSON (mode)) {
			char *hashstr = NULL;
			if (chksum) {
				ut8 *data = malloc (section->size);
				if (!data) {
					goto out;
				}
				ut32 datalen = section->size;
				r_io_pread_at (r->io, section->paddr, data, datalen);
				hashstr = build_hash_string (mode, chksum,
							data, datalen);
				free (data);

			}
			r_cons_printf ("%s{\"name\":\"%s\","
				"\"size\":%"PFMT64d","
				"\"vsize\":%"PFMT64d","
				"\"flags\":\"%s\","
				"%s"
				"\"paddr\":%"PFMT64d","
				"\"vaddr\":%"PFMT64d"}",
				(iter->p && !printHere)?",":"",
				section->name,
				section->size,
				section->vsize,
				perms,
				hashstr ? hashstr : "",
				section->paddr,
				addr);
			free (hashstr);
		} else if (IS_MODE_RAD (mode)) {
			if (!strcmp (section->name, ".bss") && !inDebugger) {
#if LOAD_BSS_MALLOC
				r_cons_printf ("on malloc://%d 0x%"PFMT64x" # bss\n",
						section->vsize, addr);
#endif
			}
			if (r->bin->prefix) {
				r_cons_printf ("S 0x%08"PFMT64x" 0x%08"PFMT64x" 0x%08"PFMT64x" 0x%08"PFMT64x" %s.%s %d\n",
					section->paddr, addr, section->size, section->vsize,
					r->bin->prefix, section->name, (int)section->srwx);
			} else {
				r_cons_printf ("S 0x%08"PFMT64x" 0x%08"PFMT64x" 0x%08"PFMT64x" 0x%08"PFMT64x" %s %d\n",
					section->paddr, addr, section->size, section->vsize,
					section->name, (int)section->srwx);

			}
			if (section->arch || section->bits) {
				const char *arch = section->arch;
				int bits = section->bits;
				if (info) {
					if (!arch) arch = info->arch;
					if (!bits) bits = info->bits;
				}
				if (!arch) {
					arch = r_config_get (r->config, "asm.arch");
				}
				r_cons_printf ("Sa %s %d @ 0x%08"
					PFMT64x"\n", arch, bits, addr);
			}
			if (r->bin->prefix) {
				r_cons_printf ("f %s.section.%s %"PFMT64d" 0x%08"PFMT64x"\n",
						r->bin->prefix, section->name, section->size, addr);
				r_cons_printf ("f %s.section_end.%s 1 0x%08"PFMT64x"\n",
						r->bin->prefix, section->name, addr + section->vsize);
				r_cons_printf ("CC section %i va=0x%08"PFMT64x" pa=0x%08"PFMT64x" sz=%"PFMT64d" vsz=%"PFMT64d" "
						"rwx=%s %s.%s @ 0x%08"PFMT64x"\n",
						i, addr, section->paddr, section->size, section->vsize,
						perms, r->bin->prefix, section->name, addr);

			} else {
				r_cons_printf ("f section.%s %"PFMT64d" 0x%08"PFMT64x"\n",
						section->name, section->size, addr);
				r_cons_printf ("f section_end.%s 1 0x%08"PFMT64x"\n",
						section->name, addr + section->vsize);
				r_cons_printf ("CC section %i va=0x%08"PFMT64x" pa=0x%08"PFMT64x" sz=%"PFMT64d" vsz=%"PFMT64d" "
						"rwx=%s %s @ 0x%08"PFMT64x"\n",
						i, addr, section->paddr, section->size, section->vsize,
						perms, section->name, addr);
			}
		} else {
			char *hashstr = NULL, str[128];
			if (chksum) {
				ut8 *data = malloc (section->size);
				if (!data) {
					goto out;
				}
				ut32 datalen = section->size;
				// VA READ IS BROKEN?
				r_io_pread_at (r->io, section->paddr, data, datalen);
				hashstr = build_hash_string (mode, chksum,
							data, datalen);
				free (data);
			}
			if (section->arch || section->bits) {
				const char *arch = section->arch;
				int bits = section->bits;
				if (!arch && info) {
					arch = info->arch;
					if (!arch) {
						arch = r_config_get (r->config, "asm.arch");
					}
				}
				if (!bits) {
					bits = info? info->bits: R_SYS_BITS;
				}
				snprintf (str, sizeof (str), "arch=%s bits=%d ",
					r_str_get2 (arch), bits);
			} else {
				str[0] = 0;
			}
			if (r->bin->prefix) {
#if 0
				r_cons_printf ("idx=%02i vaddr=0x%08"PFMT64x" paddr=0x%08"PFMT64x" sz=%"PFMT64d" vsz=%"PFMT64d" "
					"perm=%s %s%sname=%s.%s\n",
					i, addr, section->paddr, section->size, section->vsize,
					perms, str, hashstr ?hashstr : "", r->bin->prefix, section->name);
#endif
				// r_cons_printf ("%02i 0x%08"PFMT64x" %10"PFMT64d" 0x%08"PFMT64x" %10"PFMT64d" "
				r_cons_printf ("%02i 0x%08"PFMT64x" %5"PFMT64d" 0x%08"PFMT64x" %5"PFMT64d" "
					"%s %s% %s.%s\n",
					i, section->paddr, section->size, addr, section->vsize,
					perms, str, hashstr ?hashstr : "", r->bin->prefix, section->name);
			} else {
#if 0
				r_cons_printf ("idx=%02i vaddr=0x%08"PFMT64x" paddr=0x%08"PFMT64x" sz=%"PFMT64d" vsz=%"PFMT64d" "
					"perm=%s %s%sname=%s\n",
					i, addr, section->paddr, section->size, section->vsize,
					perms, str, hashstr ?hashstr : "", section->name);
#endif
				// r_cons_printf ("%02i 0x%08"PFMT64x" %10"PFMT64d" 0x%08"PFMT64x" %10"PFMT64d" "
				r_cons_printf ("%02i 0x%08"PFMT64x" %5"PFMT64d" 0x%08"PFMT64x" %5"PFMT64d" "
					"%s %s%s%s\n",
					i, section->paddr, (ut64)section->size, addr, (ut64)section->vsize,
					perms, str, hashstr ?hashstr : "", section->name);
			}
			free (hashstr);
		}
		i++;
		if (printHere) {
			break;
		}
	}
	if (r->bin && r->bin->cur && r->io && !r_io_desc_is_dbg (r->io->desc)) {
		r_io_section_apply_bin (r->io, r->bin->cur->id, R_IO_SECTION_APPLY_FOR_ANALYSIS);
	}
	if (IS_MODE_JSON (mode) && !printHere) {
		r_cons_println ("]");
	} else if (IS_MODE_NORMAL (mode) && !at && !printHere) {
		// r_cons_printf ("\n%i sections\n", i);
	}

	ret = true;
out:
	ht_free (dup_chk_ht);
	return ret;
}


static const char *getPrefixFor(const char *s) {
	if (s) {
		if (!strcmp (s, "NOTYPE")) {
			return "loc";
		}
		if (!strcmp (s, "OBJECT")) {
			return "obj";
		}
	}
	return "sym";
}


static void pair_ut64(const char *a, ut64 n, int mode, bool last) {
	pair (a, sdb_fmt ("%"PFMT64d, n), mode, last);
}


static int bin_mem(RCore *r, int mode) {
	RList *mem = NULL;
	if (!r)	return false;
	if (!IS_MODE_JSON(mode)) {
		if (!(IS_MODE_RAD (mode) || IS_MODE_SET (mode))) {
			r_cons_println ("[Memory]\n");
		}
	}
	if (!(mem = r_bin_get_mem (r->bin))) {
		if (IS_MODE_JSON (mode)) {
			r_cons_print("[]");
		}
		return false;
	}
	if (IS_MODE_JSON (mode)) {
		r_cons_print ("[");
		bin_mem_print (mem, 7, 0, R_CORE_BIN_JSON);
		r_cons_println ("]");
		return true;
	} else if (!(IS_MODE_RAD (mode) || IS_MODE_SET (mode))) {
		bin_mem_print (mem, 7, 0, mode);
	}
	return true;
}


static inline __m128i SSE2_mm_abs_epi16(__m128i a) {
	__m128i t = _mm_srai_epi16(a, 15);
	return _mm_xor_si128(_mm_add_epi16(a, t), t);
}


static struct inotify_inode_mark *inotify_idr_find_locked(struct fsnotify_group *group,
								int wd)
{
	struct idr *idr = &group->inotify_data.idr;
	spinlock_t *idr_lock = &group->inotify_data.idr_lock;
	struct inotify_inode_mark *i_mark;

	assert_spin_locked(idr_lock);

	i_mark = idr_find(idr, wd);
	if (i_mark) {
		struct fsnotify_mark *fsn_mark = &i_mark->fsn_mark;

		fsnotify_get_mark(fsn_mark);
		/* One ref for being in the idr, one ref we just took */
		BUG_ON(atomic_read(&fsn_mark->refcnt) < 2);
	}

	return i_mark;
}