Example #1
0
// Print a classic memory dump with configurable base and grouping.
void memdump(const char* data, size_t length, u_int8_t base, u_int8_t gsize, u_int8_t gcount)
{
    int group_size = gsize;
    int group_count = gcount;
    
    int line_width = group_size * group_count;
    unsigned int offset = 0;
    while (length > offset) {
        const char* line = &data[offset];
        size_t lineMax = MIN((length - offset), line_width);
        printf("  %p %06u |", &line[0], offset);
        for (int c = 0; c < lineMax; c++) {
            if ( (c % group_size) == 0 ) printf(" ");
            char* str = memstr(&line[c], 1, base);
            printf("%s ", str); FREE_BUFFER(str);
        }
        printf("|");
        for (int c = 0; c < lineMax; c++) {
            if ( (c % group_size) == 0 ) printf(" ");
            char chr = line[c] & 0xFF;
            if (chr < 32) // ASCII unprintable
                chr = '.';
            printf("%c", chr);
        }
        printf(" |\n");
        offset += line_width;
    }
}
Example #2
0
/* validate a path as OK */
void validatePath(char **path)
{
    struct Buffer_char pathok;
    struct stat sbuf;
    char *rpath;

    if (!*path) return;

    /* first make sure it's absolute */
    if (**path != '/') {
        *path = NULL;
        return;
    }

    /* then get its real path (don't worry about deallocation, there aren't
     * many of these) */
    *path = realpath(*path, NULL);
    if (*path == NULL) return;

    /* then check the ok file */
    INIT_BUFFER(pathok);
    WRITE_BUFFER(pathok, *path, strlen(*path));
    WRITE_STR_BUFFER(pathok, OKFILE);
    WRITE_STR_BUFFER(pathok, "\0");
    if (stat(pathok.buf, &sbuf) < 0) {
        /* file not found or otherwise very bad, kill it */
        *path = NULL;
        FREE_BUFFER(pathok);
        return;
    }
    FREE_BUFFER(pathok);
    if (sbuf.st_uid != geteuid()) {
        /* wrong owner */
        *path = NULL;
        return;
    }

    /* it's valid */
}
Example #3
0
void VbufReqd(                  // ENSURE BUFFER IS OF SUFFICIENT SIZE
    VBUF *vbuf,                 // - VBUF structure
    size_t reqd )               // - required size
{
    char    *new_buffer;        // - old buffer

    if( reqd >= vbuf->len ) {
        reqd = BUFFER_SIZE( reqd );
        new_buffer = _MemoryAllocate( reqd );
        stxvcpy( new_buffer, vbuf->buf, vbuf->used );
        FREE_BUFFER( vbuf );
        vbuf->buf = new_buffer;
        vbuf->len = reqd;
    }
}
Example #4
0
ssize_t hfs_read_range(void* buffer, const HFSVolume *hfs, size_t size, size_t offset)
{
    debug("Reading from volume at (%d, %d)", offset, size);
    
    // Range check.
    if (hfs->length && offset > hfs->length) {
        error("Request for logical offset larger than the size of the volume (%d, %d)", offset, hfs->length);
        errno = ESPIPE; // Illegal seek
        return -1;
    }
    
    if ( hfs->length && (offset + size) > hfs->length ) {
        size = hfs->length - offset;
        debug("Adjusted read to (%d, %d)", offset, size);
    }
    
    if (size < 1) {
        error("Zero-size request.");
        errno = EINVAL;
        return -1;
    }
    
    // The range starts somewhere in this block.
    size_t start_block = (size_t)(offset / hfs->block_size);
    
    // Offset of the request within the start block.
    size_t byte_offset = (offset % hfs->block_size);
    
    // Add a block to the read if the offset is not block-aligned.
    size_t block_count = (size / hfs->block_size) + ( ((offset + size) % hfs->block_size) ? 1 : 0);
    
    // Use the calculated size instead of the passed size to account for block alignment.
    char* read_buffer; INIT_BUFFER(read_buffer, block_count * hfs->block_size);
    
    // Fetch the data into a read buffer (it may fail).
    ssize_t read_blocks = hfs_read_blocks(read_buffer, hfs, block_count, start_block);
    
    // On success, copy the output.
    if (read_blocks) memcpy(buffer, read_buffer + byte_offset, size);
    
    // Clean up.
    FREE_BUFFER(read_buffer);
    
    // The amount we added to the buffer.
    return size;
}
Example #5
0
int main(int argc, char **argv)
{
    struct Buffer_charp rpaths;
    struct Buffer_char options;
    char *wpath = NULL, *arg;
    char *envpaths;
    int i, j, argi, tmpi;
    unsigned long mountflags = 0;
    int allowclear = 0, clear = 0, userwpath = 1;

    INIT_BUFFER(rpaths);
    WRITE_ONE_BUFFER(rpaths, NULL); /* filled in by forced dir later */

    /* get all the paths out of the environment */
    envpaths = getenv(PATHENV);
    if (envpaths && envpaths[0]) {
        char *saveptr;
        arg = strtok_r(envpaths, ":", &saveptr);
        while (arg) {
            WRITE_ONE_BUFFER(rpaths, arg);
            arg = strtok_r(NULL, ":", &saveptr);
        }
    }

    /* get all the paths out of the args */
    for (argi = 1; argi < argc; argi++) {
        arg = argv[argi];
        if (arg[0] == '-') {
            if (!strcmp(arg, "-w") && argi < argc - 1) {
                argi++;
                wpath = argv[argi];

            } else if (!strcmp(arg, "-r")) {
                /* reset current paths (ignore environment) */
                rpaths.bufused = 1;
                allowclear = 1;

            } else if (!strcmp(arg, "--") && argi < argc - 1) {
                argi++;
                break;

            } else {
                fprintf(stderr, "Unrecognized option %s\n", arg);
            }

        } else {
            WRITE_ONE_BUFFER(rpaths, arg);

        }
    }
    if (argi >= argc) {
        if (getuid() != geteuid()) {
            fprintf(stderr, "Only root may remount an existing view\n");
            return 1;
        }
        mountflags |= MS_REMOUNT;
    }

    /* validate all our paths */
    for (i = 1; i < rpaths.bufused; i++) {
        validatePath(&rpaths.buf[i]);
    }
    validatePath(&wpath);
    rpaths.buf[0] = FORCEDIR;
    if (!wpath) {
        wpath = DEFAULTWRITEDIR;
        userwpath = 0;
    }

    /* make sure there are no duplicates */
    for (i = 1; i < rpaths.bufused; i++) {
        if (!rpaths.buf[i]) continue;
        if (!strcmp(rpaths.buf[i], wpath)) {
            rpaths.buf[i] = NULL;
            continue;
        }
        for (j = 0; j < i; j++) {
            if (rpaths.buf[j] &&
                !strcmp(rpaths.buf[i], rpaths.buf[j])) {
                rpaths.buf[i] = NULL;
                break;
            }
        }
    }

    /* are we trying to clear /usr? */
    if (rpaths.bufused == 1) {
        /* no options = unmount all */
        if (!allowclear) {
            fprintf(stderr, "To explicitly clear all /usr mounts, -r must be specified\n");
            return 1;
        }
        clear = 1;
    }

    /* perform the mount */
    if (!(mountflags & MS_REMOUNT))
        SF(tmpi, unshare, -1, (CLONE_NEWNS));
    if (clear) {
        do {
            tmpi = umount("/usr");
        } while (tmpi == 0);
        if (errno != EINVAL)
            perror("/usr");
    } else {
        /* first mount */
        INIT_BUFFER(options);
        WRITE_STR_BUFFER(options, "br:");
        WRITE_BUFFER(options, wpath, strlen(wpath) + 1);
        tmpi = mount("none", BASE, "aufs", mountflags, options.buf);
        if (tmpi == -1 && (mountflags & MS_REMOUNT)) {
            /* OK, we tried to remount, maybe it just wasn't mounted though */
            mountflags &= ~(MS_REMOUNT);
            tmpi = mount("none", BASE, "aufs", mountflags, options.buf);
        }

        /* remaining mounts */
        for (i = 0; tmpi != -1 && i < rpaths.bufused; i++) {
            if (!rpaths.buf[i]) continue;
            options.bufused = 0;
            WRITE_STR_BUFFER(options, "append:");
            WRITE_BUFFER(options, rpaths.buf[i], strlen(rpaths.buf[i]));
            if (!userwpath)
                WRITE_STR_BUFFER(options, "=rw");
            WRITE_STR_BUFFER(options, "\0");
            tmpi = mount("none", BASE, "aufs", mountflags|MS_REMOUNT, options.buf);
        }

        if (tmpi == -1) {
            perror("mount");
            return 1;
        }
    }

    /* drop privs */
    SF(tmpi, setuid, -1, (getuid()));
    SF(tmpi, setgid, -1, (getgid()));

    /* free our mount options */
    FREE_BUFFER(options);

    /* add it to the environment */
    INIT_BUFFER(options);
    for (i = 0; i < rpaths.bufused; i++) {
        arg = rpaths.buf[i];
        if (arg) {
            if (options.bufused) WRITE_STR_BUFFER(options, ":");
            WRITE_BUFFER(options, arg, strlen(arg));
        }
    }
    WRITE_STR_BUFFER(options, "\0");
    SF(tmpi, setenv, -1, (PATHENV, options.buf, 1));
    FREE_BUFFER(options);

    if (userwpath) {
        SF(tmpi, setenv, -1, (WRITEENV, wpath, 1));
    } else {
        SF(tmpi, unsetenv, -1, (WRITEENV));
    }

    /* then run it */
    if (argi < argc) {
        execvp(argv[argi], argv + argi);
        fprintf(stderr, "[usrview] ");
        perror(argv[argi]);

        return 1;

    } else {
        return 0;

    }
}
Example #6
0
void VbufFree(                  // FREE BUFFER
    VBUF *vbuf )                // - VBUF structure
{
    FREE_BUFFER( vbuf );
    VbufInit( vbuf );
}
Example #7
0
static void
check_init (tree exp, words before)
{
  tree tmp;
 again:
  switch (TREE_CODE (exp))
    {
    case VAR_DECL:
    case PARM_DECL:
      if (! FIELD_STATIC (exp) && DECL_NAME (exp) != NULL_TREE
	  && DECL_NAME (exp) != this_identifier_node)
	{
	  int index = DECL_BIT_INDEX (exp);
	  /* We don't want to report and mark as non-initialized class
	     initialization flags. */
	  if (! LOCAL_CLASS_INITIALIZATION_FLAG_P (exp)
	      && index >= 0 && ! ASSIGNED_P (before, index))
	    {
	      parse_error_context 
		(wfl, "Variable %qs may not have been initialized",
		 IDENTIFIER_POINTER (DECL_NAME (exp)));
	      /* Suppress further errors. */
	      DECL_BIT_INDEX (exp) = -2;
	    }
	}
      break;

    case COMPONENT_REF:
      check_init (TREE_OPERAND (exp, 0), before);
      if ((tmp = get_variable_decl (exp)) != NULL_TREE)
	{
	  int index = DECL_BIT_INDEX (tmp);
	  if (index >= 0 && ! ASSIGNED_P (before, index))
	    {
	      parse_error_context 
		(wfl, "variable %qs may not have been initialized",
		 IDENTIFIER_POINTER (DECL_NAME (tmp)));
	      /* Suppress further errors. */
	      DECL_BIT_INDEX (tmp) = -2;
	    }
	}
      break;
      
    case MODIFY_EXPR:
      tmp = TREE_OPERAND (exp, 0);
      /* We're interested in variable declaration and parameter
         declaration when they're declared with the `final' modifier. */
      if ((tmp = get_variable_decl (tmp)) != NULL_TREE)
	{
	  int index;
	  check_init (TREE_OPERAND (exp, 1), before);
	  check_final_reassigned (tmp, before);
	  index = DECL_BIT_INDEX (tmp);
	  if (index >= 0)
	    {
	      SET_ASSIGNED (before, index);
	      CLEAR_UNASSIGNED (before, index);
	    }
	  /* Minor optimization.  See comment for start_current_locals.
	     If we're optimizing for class initialization, we keep
	     this information to check whether the variable is
	     definitely assigned when once we checked the whole
	     function. */
	  if (! STATIC_CLASS_INIT_OPT_P () /* FIXME */
	      && ! DECL_FINAL (tmp)
	      && index >= start_current_locals
	      && index == num_current_locals - 1)
	    {
	      num_current_locals--;
	      DECL_BIT_INDEX (tmp) = -1;
	    }
	 break;
       }
      else if (TREE_CODE (tmp = TREE_OPERAND (exp, 0)) == COMPONENT_REF)
	{
	  tree decl;
	  check_init (tmp, before);
	  check_init (TREE_OPERAND (exp, 1), before);
	  decl = TREE_OPERAND (tmp, 1);
	  if (DECL_FINAL (decl))
	    final_assign_error (DECL_NAME (decl));
	  break;
	}
      else if (TREE_CODE (tmp) == COMPONENT_REF && IS_ARRAY_LENGTH_ACCESS (tmp))
	{
	  /* We can't emit a more specific message here, because when
	     compiling to bytecodes we don't get here. */
	  final_assign_error (length_identifier_node);
	}
     else
       goto binop;
    case BLOCK:
      if (BLOCK_EXPR_BODY (exp))
	{
	  tree decl = BLOCK_EXPR_DECLS (exp);
	  int words_needed;
	  word* tmp;
	  int i;
	  int save_start_current_locals = start_current_locals;
	  int save_num_current_words = num_current_words;
	  start_current_locals = num_current_locals;
	  for (;  decl != NULL_TREE;  decl = TREE_CHAIN (decl))
	    {
	      DECL_BIT_INDEX (decl) = num_current_locals++;
	    }
	  words_needed = WORDS_NEEDED (2 * num_current_locals);
	  if (words_needed > num_current_words)
	    {
	      tmp = ALLOC_WORDS (words_needed);
	      COPY (tmp, before);
	      num_current_words = words_needed;
	    }
	  else
	    tmp = before;
	  for (i = start_current_locals;  i < num_current_locals;  i++)
	    {
	      CLEAR_ASSIGNED (tmp, i);
	      SET_UNASSIGNED (tmp, i);
	    }
	  check_init (BLOCK_EXPR_BODY (exp), tmp);

	  /* Re-set DECL_BIT_INDEX since it is also DECL_POINTER_ALIAS_SET. */
	  for (decl = BLOCK_EXPR_DECLS (exp);
	       decl != NULL_TREE;  decl = TREE_CHAIN (decl))
	    {
	      if (LOCAL_CLASS_INITIALIZATION_FLAG_P (decl))
		{
		  int index = DECL_BIT_INDEX (decl);
		  tree fndecl = DECL_CONTEXT (decl);
		  if (fndecl && METHOD_STATIC (fndecl)
		      && (DECL_INITIAL (decl) == boolean_true_node
			  || (index >= 0 && ASSIGNED_P (tmp, index))))
		    *(htab_find_slot 
		      (DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl),
		       DECL_FUNCTION_INIT_TEST_CLASS (decl), INSERT)) =
		      DECL_FUNCTION_INIT_TEST_CLASS (decl);
		}
	      DECL_BIT_INDEX (decl) = -1;
	    }

	  num_current_locals = start_current_locals;
	  start_current_locals = save_start_current_locals;
	  if (tmp != before)
	    {
	      num_current_words = save_num_current_words;
	      COPY (before, tmp);
	      FREE_WORDS (tmp);
	    }
	}
      break;
    case LOOP_EXPR:
      {
	/* The JLS 2nd edition discusses a complication determining
	   definite unassignment of loop statements.  They define a
	   "hypothetical" analysis model.  We do something much
	   simpler: We just disallow assignments inside loops to final
	   variables declared outside the loop.  This means we may
	   disallow some contrived assignments that the JLS allows, but I
	   can't see how anything except a very contrived testcase (a
	   do-while whose condition is false?) would care. */

	struct alternatives alt;
	int save_loop_current_locals = loop_current_locals;
	int save_start_current_locals = start_current_locals;
	loop_current_locals = num_current_locals;
	start_current_locals = num_current_locals;
	BEGIN_ALTERNATIVES (before, alt);
	alt.block = exp;
	check_init (TREE_OPERAND (exp, 0), before);
	END_ALTERNATIVES (before, alt);
	loop_current_locals = save_loop_current_locals;
	start_current_locals = save_start_current_locals;
	return;
      }
    case EXIT_EXPR:
      {
	struct alternatives *alt = alternatives;
	DECLARE_BUFFERS(when_true, 2);
	words when_false = when_true + num_current_words;
#ifdef ENABLE_JC1_CHECKING
	if (TREE_CODE (alt->block) != LOOP_EXPR)
	  abort ();
#endif
	check_bool_init (TREE_OPERAND (exp, 0), before, when_false, when_true);
	done_alternative (when_true, alt);
	COPY (before, when_false);
	RELEASE_BUFFERS(when_true);
	return;
      }
    case LABELED_BLOCK_EXPR:
      {
	struct alternatives alt;
	BEGIN_ALTERNATIVES (before, alt);
	alt.block = exp;
	if (LABELED_BLOCK_BODY (exp))
	  check_init (LABELED_BLOCK_BODY (exp), before);
	done_alternative (before, &alt);
	END_ALTERNATIVES (before, alt);
	return;
      }
    case EXIT_BLOCK_EXPR:
      {
	tree block = TREE_OPERAND (exp, 0);
	struct alternatives *alt = alternatives;
	while (alt->block != block)
	  alt = alt->outer;
	done_alternative (before, alt);
	SET_ALL (before);
	return;
      }
    case SWITCH_EXPR:
      {
	struct alternatives alt;
	word buf[2];
	check_init (TREE_OPERAND (exp, 0), before);
	BEGIN_ALTERNATIVES (before, alt);
	alt.saved = ALLOC_BUFFER(buf, num_current_words);
	COPY (alt.saved, before);
	alt.block = exp;
	check_init (TREE_OPERAND (exp, 1), before);
	done_alternative (before, &alt);
	if (! SWITCH_HAS_DEFAULT (exp))
	  done_alternative (alt.saved, &alt);
	FREE_BUFFER(alt.saved, buf);
	END_ALTERNATIVES (before, alt);
	return;
      }
    case CASE_EXPR:
    case DEFAULT_EXPR:
      {
	int i;
	struct alternatives *alt = alternatives;
	while (TREE_CODE (alt->block) != SWITCH_EXPR)
	  alt = alt->outer;
	COPYN (before, alt->saved, WORDS_NEEDED (2 * alt->num_locals));
	for (i = alt->num_locals;  i < num_current_locals;  i++)
	  CLEAR_ASSIGNED (before, i);
	break;
      }

    case TRY_EXPR:
      {
	tree try_clause = TREE_OPERAND (exp, 0);
	tree clause = TREE_OPERAND (exp, 1);
	word buf[2*2];
	words tmp = (num_current_words <= 2 ? buf
		    : ALLOC_WORDS (2 * num_current_words));
	words save = tmp + num_current_words;
	struct alternatives alt;
	BEGIN_ALTERNATIVES (before, alt);
	COPY (save, before);
	COPY (tmp, save);
	check_init (try_clause, tmp);
	done_alternative (tmp, &alt);
	for ( ; clause != NULL_TREE;  clause = TREE_CHAIN (clause))
	  {
	    tree catch_clause = TREE_OPERAND (clause, 0);
	    COPY (tmp, save);
	    check_init (catch_clause, tmp);
	    done_alternative (tmp, &alt);
	  }
	if (tmp != buf)
	  {
	    FREE_WORDS (tmp);
	  }
	END_ALTERNATIVES (before, alt);
      }
    return;

    case TRY_FINALLY_EXPR:
      {
	DECLARE_BUFFERS(tmp, 1);
	COPY (tmp, before);
	check_init (TREE_OPERAND (exp, 0), before);
	check_init (TREE_OPERAND (exp, 1), tmp);
	UNION (before, before, tmp);
	RELEASE_BUFFERS(tmp);
      }
      return;

    case RETURN_EXPR:
    case THROW_EXPR:
      if (TREE_OPERAND (exp, 0))
	check_init (TREE_OPERAND (exp, 0), before);
      goto never_continues;

    case ERROR_MARK:
    never_continues:
      SET_ALL (before);
      return;
      
    case COND_EXPR:
    case TRUTH_ANDIF_EXPR:
    case TRUTH_ORIF_EXPR:
      {
	DECLARE_BUFFERS(when_true, 2);
	words when_false = when_true + num_current_words;
	check_bool_init (exp, before, when_false, when_true);
	INTERSECT (before, when_false, when_true);
	RELEASE_BUFFERS(when_true);
      }
      break;

    case NOP_EXPR:
      if (IS_EMPTY_STMT (exp))
	break;
      /* ... else fall through ... */
    case UNARY_PLUS_EXPR:
    case NEGATE_EXPR:
    case TRUTH_AND_EXPR:
    case TRUTH_OR_EXPR:
    case TRUTH_XOR_EXPR:
    case TRUTH_NOT_EXPR:
    case BIT_NOT_EXPR:
    case CONVERT_EXPR:
    case BIT_FIELD_REF:
    case FLOAT_EXPR:
    case FIX_TRUNC_EXPR:
    case INDIRECT_REF:
    case ADDR_EXPR:
    case NON_LVALUE_EXPR:
    case INSTANCEOF_EXPR:
    case FIX_CEIL_EXPR:
    case FIX_FLOOR_EXPR:
    case FIX_ROUND_EXPR:
    case ABS_EXPR:
      /* Avoid needless recursion. */
      exp = TREE_OPERAND (exp, 0);
      goto again;

    case PREDECREMENT_EXPR:
    case PREINCREMENT_EXPR:
    case POSTDECREMENT_EXPR:
    case POSTINCREMENT_EXPR:
      tmp = get_variable_decl (TREE_OPERAND (exp, 0));
      if (tmp != NULL_TREE && DECL_FINAL (tmp))
	final_assign_error (DECL_NAME (tmp));      

      /* Avoid needless recursion.  */
      exp = TREE_OPERAND (exp, 0);
      goto again;

    case SAVE_EXPR:
      if (IS_INIT_CHECKED (exp))
	return;
      IS_INIT_CHECKED (exp) = 1;
      exp = TREE_OPERAND (exp, 0);
      goto again;

    case COMPOUND_EXPR:
    case PLUS_EXPR:
    case MINUS_EXPR:
    case MULT_EXPR:
    case TRUNC_DIV_EXPR:
    case TRUNC_MOD_EXPR:
    case RDIV_EXPR:
    case LSHIFT_EXPR:
    case RSHIFT_EXPR:
    case URSHIFT_EXPR:
    case BIT_AND_EXPR:
    case BIT_XOR_EXPR:
    case BIT_IOR_EXPR:
    case EQ_EXPR: 
    case NE_EXPR:
    case GT_EXPR:
    case GE_EXPR:
    case LT_EXPR:
    case LE_EXPR:
    case MAX_EXPR:
    case MIN_EXPR:
    case ARRAY_REF:
    case LROTATE_EXPR:
    case RROTATE_EXPR:
    case CEIL_DIV_EXPR:
    case FLOOR_DIV_EXPR:
    case ROUND_DIV_EXPR:
    case CEIL_MOD_EXPR:
    case FLOOR_MOD_EXPR:
    case ROUND_MOD_EXPR:
    case EXACT_DIV_EXPR:
    case UNLT_EXPR:
    case UNLE_EXPR:
    case UNGT_EXPR:
    case UNGE_EXPR:
    case UNEQ_EXPR:
    case LTGT_EXPR:
    binop:
      check_init (TREE_OPERAND (exp, 0), before);
      /* Avoid needless recursion, especially for COMPOUND_EXPR. */
      exp = TREE_OPERAND (exp, 1);
      goto again;

    case RESULT_DECL:
    case FUNCTION_DECL:
    case INTEGER_CST:
    case REAL_CST:
    case STRING_CST:
    case JAVA_EXC_OBJ_EXPR:
      break;

    case NEW_CLASS_EXPR:
    case CALL_EXPR:
      {
	tree func = TREE_OPERAND (exp, 0);
	tree x = TREE_OPERAND (exp, 1);
	if (TREE_CODE (func) == ADDR_EXPR)
	  func = TREE_OPERAND (func, 0);
	check_init (func, before);

	for ( ;  x != NULL_TREE;  x = TREE_CHAIN (x))
	  check_init (TREE_VALUE (x), before);
	if (func == throw_node)
	  goto never_continues;
      }
      break;

    case NEW_ARRAY_INIT:
      {
	tree x = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0));
	for ( ;  x != NULL_TREE;  x = TREE_CHAIN (x))
	  check_init (TREE_VALUE (x), before);
      }
      break;

    case EXPR_WITH_FILE_LOCATION:
      {
	location_t saved_location = input_location;
	tree saved_wfl = wfl;
	tree body = EXPR_WFL_NODE (exp);
	if (IS_EMPTY_STMT (body))
	  break;
	wfl = exp;
#ifdef USE_MAPPED_LOCATION
	input_location = EXPR_LOCATION (exp);
#else
	input_filename = EXPR_WFL_FILENAME (exp);
	input_line = EXPR_WFL_LINENO (exp);
#endif
	check_init (body, before);
	input_location = saved_location;
	wfl = saved_wfl;
      }
      break;
      
    default:
      internal_error
	("internal error in check-init: tree code not implemented: %s",
	 tree_code_name [(int) TREE_CODE (exp)]);
    }
}
int client_main(void)
{
    int fd, r, n, m, wait = 0, retries,pid;
    void *binder, *cookie;
    bcmd_txn_t *txn;
    bwr_t bwr;
    inst_buf_t *inst, *inst_reply;
    inst_entry_t *entry, copy;
    unsigned char rbuf[RBUF_SIZE], *ibuf, *p;
    struct timeval ref, delta;
    char labels[INST_MAX_ENTRIES][8];
    unsigned long long total_usecs[INST_MAX_ENTRIES];
    unsigned long long min[INST_MAX_ENTRIES],max[INST_MAX_ENTRIES],record[INST_MAX_ENTRIES];
    FILE *fp;

    if (!share_cpus) {
        cpu_set_t cpuset;

        CPU_ZERO(&cpuset);
        CPU_SET(id + 1, &cpuset);
        r = sched_setaffinity(0, sizeof(cpuset), &cpuset);
        if (!r)
            printf("client %d is bound to CPU %d\n", id, id + 1);
        else
            fprintf(stderr, "client %d failed to be bound to CPU %d\n", id, id + 1);
    }

    fd = open("/dev/binder", O_RDWR);
    if (fd < 0) {
        fprintf(stderr, "client %d failed to open binder device\n", id);
        return -1;
    }

#if (!defined(INLINE_TRANSACTION_DATA))
    if (mmap(NULL, 128 * 1024, PROT_READ, MAP_PRIVATE, fd, 0) == MAP_FAILED) {
        fprintf(stderr, "server failed to mmap shared buffer\n");
        return -1;
    }
#endif

    while (1) {
        r = lookup_service(fd, service, sizeof(service) / 2, &binder, &cookie);
        if (r < 0) {
            fprintf(stderr, "client %d failed to find the instrumentation service\n", id);
            return -1;
        } else if (r > 0)
            break;

        if (wait++ > 1)
            fprintf(stderr, "client %d still waiting on instrumentation service to be ready\n", id);
        sleep(1);
    }
    printf("client %d found instrumentation service\n", id);

    txn = create_transaction(0, binder, cookie, 0, NULL, sizeof(inst_buf_t) + data_SZ, NULL, 0);
    if (!txn) {
        fprintf(stderr, "client %d failed to prepare transaction buffer\n", id);
        return -1;
    }

    bwr.write_buffer = (unsigned long)txn;
    bwr.read_buffer = (unsigned long)rbuf;

    inst = (inst_buf_t *)txn->tdata.data.ptr.buffer;
    INST_INIT(inst);

    ibuf = malloc((iterations + 1) * sizeof(inst_entry_t) * INST_MAX_ENTRIES);
    if (!ibuf)
        fprintf(stderr, "client %d failed to allocate instrumentation buffer\n", id);

    p = ibuf;
    n = iterations + 1;
    while (n-- > 0) {
        INST_BEGIN(inst);

        retries = 2;

        bwr.write_size = sizeof(*txn);
        bwr.write_consumed = 0;
        bwr.read_size = sizeof(rbuf);
        bwr.read_consumed = 0;

        INST_ENTRY(inst, "C_SEND");

        ioctl_write++;
wait_reply:
        ioctl_read++;
        r = ioctl(fd, BINDER_WRITE_READ, &bwr);
        if (r < 0) {
            fprintf(stderr, "client %d failed ioctl\n", id);
            return r;
        }
        INST_RECORD(&copy);

        r = client_parse_command(id, rbuf, bwr.read_consumed, &inst_reply);
        if (r < 0)
            return r;

        if (!inst_reply) {
            //hexdump(rbuf, bwr.read_consumed);
            if (retries-- > 0) {
                bwr.write_size = 0;
                bwr.read_consumed = 0;
                goto wait_reply;
            } else {
                fprintf(stderr, "client %d failed to receive reply\n", id);
                return -1;
            }
        }

        memcpy(inst, inst_reply, sizeof(*inst)+data_SZ);
        //acsiidump(inst_reply,sizeof(*inst)+data_SZ);
        INST_ENTRY_COPY(inst, "C_RECV", &copy);
        INST_END(inst, &p);

#if (defined(SIMULATE_FREE_BUFFER) || !defined(INLINE_TRANSACTION_DATA))
        if (FREE_BUFFER(fd, inst_reply) < 0) {
            fprintf(stderr, "client %d: failed to free shared buffer\n", id);
            return -1;
        }
#endif
    }

    if (output_file) {
        if (clients > 1) {
            char *p = malloc(strlen(output_file) + 16);

            if (!p) {
                fprintf(stderr, "client %d failed to alloc memory for filename\n", id);
                return -1;
            }
            sprintf(p, "%s-%d", output_file, id);
            output_file = p;
        }

        fp = fopen(output_file, "w");
        if (!fp) {
            fprintf(stderr, "client %d failed to open dump file\n", id);
            return -1;
        }
    } else
        fp = stdout;

    memset(total_usecs, 0, sizeof(total_usecs));
    memset(max,0,sizeof(max));
    memset(min,255,sizeof(min));
    entry = (inst_entry_t *)ibuf;

    int i;
    //acsiidump(ibuf,80);
    for (n = 0; n < inst->seq; n++) {
        for (m = 0; m < inst->next_entry; m++) {
            if (n > 0) {
                if (m == 0) {
                    if (time_ref == 0)	// absolute time
                        ref.tv_sec = ref.tv_usec = 0;
                    else
                        ref = entry->tv;
                }

                delta.tv_sec = entry->tv.tv_sec - ref.tv_sec;
                delta.tv_usec = entry->tv.tv_usec - ref.tv_usec;
                if (delta.tv_usec < 0) {
                    delta.tv_sec--;
                    delta.tv_usec += 1000000;
                }
                record[m] = delta.tv_sec * 1000000 + delta.tv_usec;

                //fprintf(fp, "%ld.%06ld\t", delta.tv_sec, delta.tv_usec);

                if (time_ref > 0) {
                    total_usecs[m] += delta.tv_sec * 1000000 + delta.tv_usec;
                    if( m == inst->next_entry -1) {
                        if (min[m] > record[m] ) {
                            for( i = 0; i < inst->next_entry; i++ ) {
                                min[i] = record[i];
                            }
                        }
                        if (max[m] < record[m] ) {
                            for( i = 0; i < inst->next_entry; i++ ) {
                                max[i] = record[i];
                            }
                        }
                    }
                }
                if (time_ref > 1)	// relative to the previous entry
                    ref = entry->tv;
            } else {
                //fprintf(fp, "%8s\t", entry->label);
                if (time_ref > 0)
                    strcpy(labels[m], entry->label);
            }

            entry++;
        }
        //fprintf(fp, "\n");
    }

    if (fp != stdout)
        fclose(fp);
    free(txn);

    pid =getpid();
    printf("client(%d) %d: ioctl read: %u\n",pid,id, ioctl_read);
    printf("client(%d) %d: ioctl write: %u\n",pid,id, ioctl_write);
    printf("client(%d) %d: ioctl buffer: %u\n",pid,id, ioctl_buffer);

    if (time_ref > 0 && iterations > 0) {
        int pos = 0,minpos=0,maxpos=0;
        char *buf = malloc(64 * m);
        char *minbuf = malloc(64 * m);
        char *maxbuf = malloc(64 * m);

        if (!buf||!minbuf||!maxbuf)
            return 1;
        for (n = 0; n < m; n++) {
            pos += sprintf(buf + pos, "\t%s: %lld.%02lldus\n", labels[n],
                           (total_usecs[n] / iterations),
                           (total_usecs[n] % iterations) * 100 / iterations);

            minpos += sprintf(minbuf + minpos, "\t%s: %lldus\n", labels[n],
                              min[n]);
            maxpos += sprintf(maxbuf + maxpos, "\t%s: %lldus\n", labels[n],
                              max[n]);
        }
        printf("client %d: average results:\n%s\n", id, buf);
        printf("client %d: min results:\n%s\n", id, minbuf);
        printf("client %d: max results:\n%s\n", id, maxbuf);
        free(buf);
        free(minbuf);
        free(maxbuf);
    }
    return 0;
}
int server_main(void)
{
    int fd, r, len;
    void *binder, *cookie;
    bwr_t bwr;
    unsigned char rbuf[RBUF_SIZE], *p;
    bcmd_txn_t *reply;
    tdata_t *tdata = NULL;
    inst_buf_t *inst;
    inst_entry_t copy;

    if (!share_cpus) {
        cpu_set_t cpuset;

        CPU_ZERO(&cpuset);
        CPU_SET(0, &cpuset);
        r = sched_setaffinity(0, sizeof(cpuset), &cpuset);
        if (!r)
            printf("server is bound to CPU 0\n");
        else
            fprintf(stderr, "server failed to be bound to CPU 0\n");
    }

    fd = open("/dev/binder", O_RDWR);
    if (fd < 0) {
        fprintf(stderr, "failed to open binder device\n");
        return -1;
    }

#if (!defined(INLINE_TRANSACTION_DATA))
    if (mmap(NULL, 128 * 1024, PROT_READ, MAP_PRIVATE, fd, 0) == MAP_FAILED) {
        fprintf(stderr, "server failed to mmap shared buffer\n");
        return -1;
    }
#endif

    binder = SVC_BINDER;
    cookie = SVC_COOKIE;

    r = add_service(fd, binder, cookie, service, sizeof(service) / 2);
    if (r < 0) {
        printf("server failed to add instrumentation service\n");
        return -1;
    }
    printf("server added instrumentation service\n");

    r = start_looper(fd);
    if (r < 0) {
        printf("server failed to start looper\n");
        return -1;
    }

    bwr.read_buffer = (unsigned long)rbuf;
    while (1) {
        bwr.read_size = sizeof(rbuf);
        bwr.read_consumed = 0;
        bwr.write_size = 0;

        ioctl_read++;
        r = ioctl(fd, BINDER_WRITE_READ, &bwr);
        if (r < 0) {
            fprintf(stderr, "server failed ioctl\n");
            return r;
        }
        INST_RECORD(&copy);

        p = rbuf;
        len = bwr.read_consumed;
        while (len > 0) {
            r = server_parse_command(p, len, &tdata, &reply);
            //hexdump(tdata, bwr.read_consumed);
            if (r < 0)
                return r;

            p += r;
            len -= r;

#if (defined(SIMULATE_FREE_BUFFER) || !defined(INLINE_TRANSACTION_DATA))
            if (tdata)
                FREE_BUFFER(fd, (void *)tdata->data.ptr.buffer);
#endif
            if (!reply) {
                //hexdump(rbuf, bwr.read_consumed);
                continue;
            }

            inst = (inst_buf_t *)reply->tdata.data.ptr.buffer;
            INST_ENTRY_COPY(inst, "S_RECV", &copy);
            //acsiidump(inst,sizeof(*inst)+data_SZ);
            bwr.write_buffer = (unsigned long)reply;
            bwr.write_size = sizeof(*reply);
            bwr.write_consumed = 0;
            bwr.read_size = 0;

            INST_ENTRY(inst, "S_REPLY");

            ioctl_write++;
            r = ioctl(fd, BINDER_WRITE_READ, &bwr);
            if (r < 0) {
                fprintf(stderr, "server failed reply ioctl\n");
                return r;
            }

#if (!defined(INLINE_TRANSACTION_DATA))
            free(reply);
#endif
        }
    }

    free(reply);
    return 0;
}
int add_service(int fd, void *binder, void *cookie, uint16_t *name, int len)
{
    unsigned char buf[1024], *p;
    obj_t *obj;
    size_t *offsets;
    bcmd_txn_t *txn;
    tdata_t *tdata;
    int r;

    p = buf;

    // strict_policy
    *(uint32_t *)p = 0;
    p += 4;

    // svcmgr_id
    *(uint32_t *)p = sizeof(svcmgr_id) / 2;
    p += 4;
    memcpy(p, svcmgr_id, sizeof(svcmgr_id));
    p += sizeof(svcmgr_id);
    *(uint16_t *)p = 0;
    p += 2;
    p = (unsigned char *)ALIGN((unsigned long)p);

    // name
    *(uint32_t *)p = len;
    p += 4;
    memcpy(p, name, len * 2);
    p += len * 2;
    *(uint16_t *)p = 0;
    p += 2;
    p = (unsigned char *)ALIGN((unsigned long)p);

    // flat_binder_obj
    obj = (obj_t *)p;
    obj->type = BINDER_TYPE_BINDER;
    obj->flags = 0;
    obj->binder = binder;
    obj->cookie = cookie;
    p = (unsigned char *)(obj + 1);

    // offsets
    offsets = (size_t *)p;
    *offsets = (unsigned char *)obj - buf;

    txn = create_transaction(0, NULL, NULL, 3, buf, p - buf, (unsigned char *)offsets, 4);
    if (!txn)
        return -1;

    r = simple_transact(fd, txn, &tdata, buf, sizeof(buf));
    if (r < 0)
        return r;

    if (tdata->data_size != 4 || *(unsigned int *)tdata->data.ptr.buffer) {
        fprintf(stderr, "server invalid reply data received\n");
        return -1;
    }

#if (defined(SIMULATE_FREE_BUFFER) || !defined(INLINE_TRANSACTION_DATA))
    if (FREE_BUFFER(fd, (void *)tdata->data.ptr.buffer) < 0) {
        fprintf(stderr, "failed to free shared buffer\n");
        return -1;
    }
#endif
    free(txn);
    return 0;
}