Example #1
0
  XDEBUG_NOTIMPLEMENTED

static Variant HHVM_FUNCTION(xdebug_start_trace,
                             const Variant& traceFileVar,
                             int64_t options /* = 0 */) {
  // Allowed to pass null.
  folly::StringPiece trace_file;
  if (traceFileVar.isString()) {
    // We're not constructing a new String, we're just using the one in
    // traceFileVar, so this is safe.
    trace_file = traceFileVar.toString().slice();
  }

  // Initialize the profiler if it isn't already.
  if (!XDEBUG_GLOBAL(ProfilerAttached)) {
    attach_xdebug_profiler();
  }

  // php5 xdebug returns false when tracing already started.
  auto profiler = xdebug_profiler();
  if (profiler->isTracing()) {
    return false;
  }

  // Start tracing, then grab the current begin frame
  start_tracing(profiler, trace_file, options);
  profiler->beginFrame(nullptr);
  return HHVM_FN(xdebug_get_tracefile_name)();
}
Example #2
0
int main(int argc, char *argv[]) 
{
    errval_t err;

    coreid_t mycore = disp_get_core_id();

    debug_printf("This is mem_bench\n");

    if (argc >= 2) {
        assert(mycore == 0);

        int num_cores = strtol(argv[1], NULL, 10);

        debug_printf("spawning on %d cores\n", num_cores);

        err = init_tracing();
        if (err_is_fail(err)) {
            DEBUG_ERR(err, "initialising tracing");
            return EXIT_FAILURE;
        }
        prepare_dump();

        start_tracing();

        char *path = argv[0];
        argv[1] = NULL;

        for (int i = 1; i <= num_cores; i++) {
            err = spawn_program(i, path, argv, NULL, 0, NULL);
            if (err_is_fail(err)) {
                DEBUG_ERR(err, "failed spawn %d", i);
                return EXIT_FAILURE;
            } 
            debug_printf("spawned on core %d\n", i);
        }

        //start_tracing();

        run_benchmark_0(mycore);

        ns_barrier_master(1, num_cores, "mem_bench");

        debug_printf("all benchmarks completed\n");

        stop_tracing();
        // dump_trace();
    } else {
        run_benchmark(mycore);
    }

    return EXIT_SUCCESS;
}
Example #3
0
// Attempts to attach the xdebug profiler to the current thread. Assumes it
// is not already attached. Raises an error on failure.
static void attach_xdebug_profiler() {
  assert(!XDEBUG_GLOBAL(ProfilerAttached));
  if (s_profiler_factory->start(ProfilerKind::XDebug, 0, false)) {
    XDEBUG_GLOBAL(ProfilerAttached) = true;
    // Enable profiling and tracing if we need to
    auto profiler = xdebug_profiler();
    if (XDebugProfiler::isProfilingNeeded()) {
      start_profiling(profiler);
    }
    if (XDebugProfiler::isTracingNeeded()) {
      start_tracing(profiler);
    }
    profiler->setCollectMemory(XDEBUG_GLOBAL(CollectMemory));
    profiler->setCollectTime(XDEBUG_GLOBAL(CollectTime));
    profiler->setMaxNestingLevel(XDEBUG_GLOBAL(MaxNestingLevel));
  } else {
    raise_error("Could not start xdebug profiler. Another profiler is "
                "likely already attached to this thread.");
  }
}
/* I/O write */
static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value)
{
    trace_dev_state *s = (trace_dev_state *)opaque;

    switch (offset >> 2) {
    case TRACE_DEV_REG_SWITCH:  // context switch, switch to pid
        if (trace_filename != NULL) {
            trace_switch(value);
#ifdef DEBUG
            printf("QEMU.trace: kernel, context switch %u\n", value);
#endif
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_switch(value);
        }
#endif  // CONFIG_MEMCHECK
        break;
    case TRACE_DEV_REG_TGID:    // save the tgid for the following fork/clone
        tgid = value;
#ifdef DEBUG
        if (trace_filename != NULL) {
            printf("QEMU.trace: kernel, tgid %u\n", value);
        }
#endif
        break;
    case TRACE_DEV_REG_FORK:    // fork, fork new pid
        if (trace_filename != NULL) {
            trace_fork(tgid, value);
#ifdef DEBUG
            printf("QEMU.trace: kernel, fork %u\n", value);
#endif
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_fork(tgid, value);
        }
#endif  // CONFIG_MEMCHECK
        break;
    case TRACE_DEV_REG_CLONE:    // fork, clone new pid (i.e. thread)
        if (trace_filename != NULL) {
            trace_clone(tgid, value);
#ifdef DEBUG
            printf("QEMU.trace: kernel, clone %u\n", value);
#endif
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_clone(tgid, value);
        }
#endif  // CONFIG_MEMCHECK
        break;
    case TRACE_DEV_REG_EXECVE_VMSTART:  // execve, vstart
        vstart = value;
        break;
    case TRACE_DEV_REG_EXECVE_VMEND:    // execve, vend
        vend = value;
        break;
    case TRACE_DEV_REG_EXECVE_OFFSET:   // execve, offset in EXE
        eoff = value;
        break;
    case TRACE_DEV_REG_EXECVE_EXEPATH:  // init exec, path of EXE
        vstrcpy(value, path, CLIENT_PAGE_SIZE);
        if (trace_filename != NULL) {
            trace_init_exec(vstart, vend, eoff, path);
#ifdef DEBUG
            printf("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n",
                   vstart, vend, eoff, path);
#endif
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            if (path[0] == '\0') {
                // vstrcpy may fail to copy path. In this case lets do it
                // differently.
                memcheck_get_guest_kernel_string(path, value, CLIENT_PAGE_SIZE);
            }
            memcheck_mmap_exepath(vstart, vend, eoff, path);
        }
#endif  // CONFIG_MEMCHECK
        path[0] = 0;
        break;
    case TRACE_DEV_REG_CMDLINE_LEN:     // execve, process cmdline length
        cmdlen = value;
        break;
    case TRACE_DEV_REG_CMDLINE:         // execve, process cmdline
        cpu_memory_rw_debug(cpu_single_env, value, arg, cmdlen, 0);
        if (trace_filename != NULL) {
            trace_execve(arg, cmdlen);
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_set_cmd_line(arg, cmdlen);
        }
#endif  // CONFIG_MEMCHECK
#ifdef DEBUG
        if (trace_filename != NULL) {
            int i;
            for (i = 0; i < cmdlen; i ++)
                if (i != cmdlen - 1 && arg[i] == 0)
                    arg[i] = ' ';
            printf("QEMU.trace: kernel, execve %s[%d]\n", arg, cmdlen);
            arg[0] = 0;
        }
#endif
        break;
    case TRACE_DEV_REG_EXIT:            // exit, exit current process with exit code
        if (trace_filename != NULL) {
            trace_exit(value);
#ifdef DEBUG
            printf("QEMU.trace: kernel, exit %x\n", value);
#endif
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_exit(value);
        }
#endif  // CONFIG_MEMCHECK
        break;
    case TRACE_DEV_REG_NAME:            // record thread name
        vstrcpy(value, path, CLIENT_PAGE_SIZE);

        // Remove the trailing newline if it exists
        int len = strlen(path);
        if (path[len - 1] == '\n') {
            path[len - 1] = 0;
        }
        if (trace_filename != NULL) {
            trace_name(path);
#ifdef DEBUG
            printf("QEMU.trace: kernel, name %s\n", path);
#endif
        }
        break;
    case TRACE_DEV_REG_MMAP_EXEPATH:    // mmap, path of EXE, the others are same as execve
        vstrcpy(value, path, CLIENT_PAGE_SIZE);
        if (trace_filename != NULL) {
            trace_mmap(vstart, vend, eoff, path);
#ifdef DEBUG
            printf("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
#endif
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            if (path[0] == '\0') {
                // vstrcpy may fail to copy path. In this case lets do it
                // differently.
                memcheck_get_guest_kernel_string(path, value, CLIENT_PAGE_SIZE);
            }
            memcheck_mmap_exepath(vstart, vend, eoff, path);
        }
#endif  // CONFIG_MEMCHECK
        path[0] = 0;
        break;
    case TRACE_DEV_REG_INIT_PID:        // init, name the pid that starts before device registered
        pid = value;
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_init_pid(value);
        }
#endif  // CONFIG_MEMCHECK
        break;
    case TRACE_DEV_REG_INIT_NAME:       // init, the comm of the init pid
        vstrcpy(value, path, CLIENT_PAGE_SIZE);
        if (trace_filename != NULL) {
            trace_init_name(tgid, pid, path);
#ifdef DEBUG
            printf("QEMU.trace: kernel, init name %u [%s]\n", pid, path);
#endif
        }
        path[0] = 0;
        break;

    case TRACE_DEV_REG_DYN_SYM_ADDR:    // dynamic symbol address
        dsaddr = value;
        break;
    case TRACE_DEV_REG_DYN_SYM:         // add dynamic symbol
        vstrcpy(value, arg, CLIENT_PAGE_SIZE);
        if (trace_filename != NULL) {
            trace_dynamic_symbol_add(dsaddr, arg);
#ifdef DEBUG
            printf("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, arg);
#endif
        }
        arg[0] = 0;
        break;
    case TRACE_DEV_REG_REMOVE_ADDR:         // remove dynamic symbol addr
        if (trace_filename != NULL) {
            trace_dynamic_symbol_remove(value);
#ifdef DEBUG
            printf("QEMU.trace: dynamic symbol remove %lx\n", dsaddr);
#endif
        }
        break;

    case TRACE_DEV_REG_PRINT_STR:       // print string
        vstrcpy(value, arg, CLIENT_PAGE_SIZE);
        printf("%s", arg);
        arg[0] = 0;
        break;
    case TRACE_DEV_REG_PRINT_NUM_DEC:   // print number in decimal
        printf("%d", value);
        break;
    case TRACE_DEV_REG_PRINT_NUM_HEX:   // print number in hexical
        printf("%x", value);
        break;

    case TRACE_DEV_REG_STOP_EMU:        // stop the VM execution
        if (trace_filename != NULL) {
            // To ensure that the number of instructions executed in this
            // block is correct, we pretend that there was an exception.
            trace_exception(0);
        }
        cpu_single_env->exception_index = EXCP_HLT;
        cpu_single_env->halted = 1;
        qemu_system_shutdown_request();
        cpu_loop_exit();
        break;

    case TRACE_DEV_REG_ENABLE:          // tracing enable: 0 = stop, 1 = start
        if (value == 1) {
            if (trace_filename != NULL) {
                start_tracing();
            }
        }
        else if (value == 0) {
            if (trace_filename != NULL) {
                stop_tracing();

                // To ensure that the number of instructions executed in this
                // block is correct, we pretend that there was an exception.
                trace_exception(0);
            }
        }
        break;

    case TRACE_DEV_REG_UNMAP_START:
        unmap_start = value;
        break;
    case TRACE_DEV_REG_UNMAP_END:
        if (trace_filename != NULL) {
            trace_munmap(unmap_start, value);
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_unmap(unmap_start, value);
        }
#endif  // CONFIG_MEMCHECK
        break;

    case TRACE_DEV_REG_METHOD_ENTRY:
    case TRACE_DEV_REG_METHOD_EXIT:
    case TRACE_DEV_REG_METHOD_EXCEPTION:
    case TRACE_DEV_REG_NATIVE_ENTRY:
    case TRACE_DEV_REG_NATIVE_EXIT:
    case TRACE_DEV_REG_NATIVE_EXCEPTION:
        if (trace_filename != NULL) {
            if (tracing) {
                int call_type = (offset - 4096) >> 2;
                trace_interpreted_method(value, call_type);
            }
        }
        break;

#ifdef CONFIG_MEMCHECK
    case TRACE_DEV_REG_MALLOC:
        if (memcheck_enabled) {
            memcheck_guest_alloc(value);
        }
        break;

    case TRACE_DEV_REG_FREE_PTR:
        if (memcheck_enabled) {
            memcheck_guest_free(value);
        }
        break;

    case TRACE_DEV_REG_QUERY_MALLOC:
        if (memcheck_enabled) {
            memcheck_guest_query_malloc(value);
        }
        break;

    case TRACE_DEV_REG_LIBC_INIT:
        if (memcheck_enabled) {
            memcheck_guest_libc_initialized(value);
        }
        break;

    case TRACE_DEV_REG_PRINT_USER_STR:
        if (memcheck_enabled) {
            memcheck_guest_print_str(value);
        }
        break;
#endif // CONFIG_MEMCHECK

    default:
        if (offset < 4096) {
            cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset);
        }
        break;
    }
}
Example #5
0
int
main(int ac, char **av)
{
	struct sigaction sa;
	struct trussinfo *trussinfo;
	char *fname;
	char **command;
	pid_t pid;
	int c;

	fname = NULL;

	/* Initialize the trussinfo struct */
	trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo));
	if (trussinfo == NULL)
		errx(1, "calloc() failed");

	pid = 0;
	trussinfo->outfile = stderr;
	trussinfo->strsize = 32;
	trussinfo->curthread = NULL;
	LIST_INIT(&trussinfo->proclist);
	init_syscalls();
	while ((c = getopt(ac, av, "p:o:facedDs:SH")) != -1) {
		switch (c) {
		case 'p':	/* specified pid */
			pid = atoi(optarg);
			/* make sure i don't trace me */
			if (pid == getpid()) {
				errx(2, "attempt to grab self.");
			}
			break;
		case 'f': /* Follow fork()'s */
			trussinfo->flags |= FOLLOWFORKS;
			break;
		case 'a': /* Print execve() argument strings. */
			trussinfo->flags |= EXECVEARGS;
			break;
		case 'c': /* Count number of system calls and time. */
			trussinfo->flags |= (COUNTONLY | NOSIGS);
			break;
		case 'e': /* Print execve() environment strings. */
			trussinfo->flags |= EXECVEENVS;
			break;
		case 'd': /* Absolute timestamps */
			trussinfo->flags |= ABSOLUTETIMESTAMPS;
			break;
		case 'D': /* Relative timestamps */
			trussinfo->flags |= RELATIVETIMESTAMPS;
			break;
		case 'o':	/* Specified output file */
			fname = optarg;
			break;
		case 's':	/* Specified string size */
			trussinfo->strsize = atoi(optarg);
			break;
		case 'S':	/* Don't trace signals */
			trussinfo->flags |= NOSIGS;
			break;
		case 'H':
			trussinfo->flags |= DISPLAYTIDS;
			break;
		default:
			usage();
		}
	}

	ac -= optind; av += optind;
	if ((pid == 0 && ac == 0) ||
	    (pid != 0 && ac != 0))
		usage();

	if (fname != NULL) { /* Use output file */
		/*
		 * Set close-on-exec ('e'), so that the output file is not
		 * shared with the traced process.
		 */
		if ((trussinfo->outfile = fopen(fname, "we")) == NULL)
			err(1, "cannot open %s", fname);
	}

	/*
	 * If truss starts the process itself, it will ignore some signals --
	 * they should be passed off to the process, which may or may not
	 * exit.  If, however, we are examining an already-running process,
	 * then we restore the event mask on these same signals.
	 */
	if (pid == 0) {
		/* Start a command ourselves */
		command = av;
		setup_and_wait(trussinfo, command);
		signal(SIGINT, SIG_IGN);
		signal(SIGTERM, SIG_IGN);
		signal(SIGQUIT, SIG_IGN);
	} else {
		sa.sa_handler = restore_proc;
		sa.sa_flags = 0;
		sigemptyset(&sa.sa_mask);
		sigaction(SIGINT, &sa, NULL);
		sigaction(SIGQUIT, &sa, NULL);
		sigaction(SIGTERM, &sa, NULL);
		start_tracing(trussinfo, pid);
	}

	/*
	 * At this point, if we started the process, it is stopped waiting to
	 * be woken up, either in exit() or in execve().
	 */
	if (LIST_FIRST(&trussinfo->proclist)->abi == NULL) {
		/*
		 * If we are not able to handle this ABI, detach from the
		 * process and exit.  If we just created a new process to
		 * run a command, kill the new process rather than letting
		 * it run untraced.
		 */
		if (pid == 0)
			kill(LIST_FIRST(&trussinfo->proclist)->pid, SIGKILL);
		ptrace(PT_DETACH, LIST_FIRST(&trussinfo->proclist)->pid, NULL,
		    0);
		return (1);
	}
	ptrace(PT_SYSCALL, LIST_FIRST(&trussinfo->proclist)->pid, (caddr_t)1,
	    0);

	/*
	 * At this point, it's a simple loop, waiting for the process to
	 * stop, finding out why, printing out why, and then continuing it.
	 * All of the grunt work is done in the support routines.
	 */
	clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);

	eventloop(trussinfo);

	if (trussinfo->flags & COUNTONLY)
		print_summary(trussinfo);

	fflush(trussinfo->outfile);

	return (0);
}
Example #6
0
int
main(int ac, char **av) {
  int c, i, mntsize;
  char **command;
  struct procfs_status pfs;
  struct ex_types *funcs;
  struct statfs *mntbuf;
  int in_exec = 0;
  char *fname = NULL;
  int sigexit = 0;
  struct trussinfo *trussinfo;

  /* Initialize the trussinfo struct */
  trussinfo = (struct trussinfo *)malloc(sizeof(struct trussinfo));
  if (trussinfo == NULL)
	  errx(1, "malloc() failed");
  bzero(trussinfo, sizeof(struct trussinfo));
  trussinfo->outfile = stderr;

  /* Check where procfs is mounted if it is mounted */
  if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
	  err(1, "getmntinfo");
  for (i = 0; i < mntsize; i++) {
	  if (strcasecmp(mntbuf[i].f_mntfromname, "procfs") == 0) {
		  strlcpy(procfs_path, mntbuf[i].f_mntonname, sizeof(procfs_path));
		  have_procfs = 1;
		  break;
	  }
  }
  if (!have_procfs) {
	  errno = 2;
	  err(1, "You must have a mounted procfs to use truss");
  }

  while ((c = getopt(ac, av, "p:o:S")) != -1) {
    switch (c) {
    case 'p':	/* specified pid */
      trussinfo->pid = atoi(optarg);
      if (trussinfo->pid == getpid()) {
	      /* make sure truss doesn't trace itself */
	      fprintf(stderr, "truss: attempt to self trace: %d\n", trussinfo->pid);
	      exit(2);
      }
      break;
    case 'o':	/* Specified output file */
      fname = optarg;
      break;
    case 'S':	/* Don't trace signals */ 
      trussinfo->flags |= NOSIGS;
      break;
    default:
      usage();
    }
  }

  ac -= optind; av += optind;
  if ((trussinfo->pid == 0 && ac == 0) || (trussinfo->pid != 0 && ac != 0))
    usage();

  if (fname != NULL) { /* Use output file */
    if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
      errx(1, "cannot open %s", fname);
  }

  /*
   * If truss starts the process itself, it will ignore some signals --
   * they should be passed off to the process, which may or may not
   * exit.  If, however, we are examining an already-running process,
   * then we restore the event mask on these same signals.
   */

  if (trussinfo->pid == 0) {	/* Start a command ourselves */
    command = av;
    trussinfo->pid = setup_and_wait(command);
    signal(SIGINT, SIG_IGN);
    signal(SIGTERM, SIG_IGN);
    signal(SIGQUIT, SIG_IGN);
  } else {
    signal(SIGINT, restore_proc);
    signal(SIGTERM, restore_proc);
    signal(SIGQUIT, restore_proc);
  }


  /*
   * At this point, if we started the process, it is stopped waiting to
   * be woken up, either in exit() or in execve().
   */

  Procfd = start_tracing(
      trussinfo->pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT |
		     ((trussinfo->flags & NOSIGS) ? 0 : S_SIG));
  if (Procfd == -1)
    return 0;

  pfs.why = 0;

  funcs = set_etype(trussinfo);
  /*
   * At this point, it's a simple loop, waiting for the process to
   * stop, finding out why, printing out why, and then continuing it.
   * All of the grunt work is done in the support routines.
   */

  do {
    int val = 0;

    if (ioctl(Procfd, PIOCWAIT, &pfs) == -1)
      warn("PIOCWAIT top of loop");
    else {
      switch(i = pfs.why) {
      case S_SCE:
	funcs->enter_syscall(trussinfo, pfs.val);
	break;
      case S_SCX:
	/*
	 * This is so we don't get two messages for an exec -- one
	 * for the S_EXEC, and one for the syscall exit.  It also,
	 * conveniently, ensures that the first message printed out
	 * isn't the return-from-syscall used to create the process.
	 */

	if (in_exec) {
	  in_exec = 0;
	  break;
	}
	funcs->exit_syscall(trussinfo, pfs.val);
	break;
      case S_SIG:
	fprintf(trussinfo->outfile, "SIGNAL %lu\n", pfs.val);
	sigexit = pfs.val;
	break;
      case S_EXIT:
	fprintf (trussinfo->outfile, "process exit, rval = %lu\n", pfs.val);
	break;
      case S_EXEC:
	funcs = set_etype(trussinfo);
	in_exec = 1;
	break;
      default:
	fprintf (trussinfo->outfile, "Process stopped because of:  %d\n", i);
	break;
      }
    }
    if (ioctl(Procfd, PIOCCONT, val) == -1) {
      if (kill(trussinfo->pid, 0) == -1 && errno == ESRCH)
	break;
      else
	warn("PIOCCONT");
    }
  } while (pfs.why != S_EXIT);
  fflush(trussinfo->outfile);
  if (sigexit) {
    if (sigexit == SIGQUIT)
      exit(sigexit);
    (void) signal(sigexit, SIG_DFL);
    (void) kill(getpid(), sigexit);
  }
  return 0;
}
/* Handles UI control command received from the UI.
 * Param:
 *  corecmd - CoreCmdImpl instance that received the command.
 *  cmd_header - Command header.
 *  cmd_param - Command data.
 */
static void
_coreCmdImpl_handle_command(CoreCmdImpl* corecmd,
                            const UICmdHeader* cmd_header,
                            const uint8_t* cmd_param)
{
    switch (cmd_header->cmd_type) {
        case AUICMD_SET_COARSE_ORIENTATION:
        {
            UICmdSetCoarseOrientation* cmd =
                (UICmdSetCoarseOrientation*)cmd_param;
            android_sensors_set_coarse_orientation(cmd->orient);
            break;
        }

        case AUICMD_TOGGLE_NETWORK:
            qemu_net_disable = !qemu_net_disable;
            if (android_modem) {
                amodem_set_data_registration(
                        android_modem,
                qemu_net_disable ? A_REGISTRATION_UNREGISTERED
                    : A_REGISTRATION_HOME);
            }
            break;

        case AUICMD_TRACE_CONTROL:
        {
            UICmdTraceControl* cmd = (UICmdTraceControl*)cmd_param;
            if (cmd->start) {
                start_tracing();
            } else {
                stop_tracing();
            }
            break;
        }

        case AUICMD_CHK_NETWORK_DISABLED:
        {
            UICmdRespHeader resp;
            resp.resp_data_size = 0;
            resp.result = qemu_net_disable;
            _coreCmdImpl_respond(corecmd, &resp, NULL);
            break;
        }

        case AUICMD_GET_NETSPEED:
        {
            UICmdRespHeader resp;
            UICmdGetNetSpeedResp* resp_data = NULL;
            UICmdGetNetSpeed* cmd = (UICmdGetNetSpeed*)cmd_param;

            resp.resp_data_size = 0;
            resp.result = 0;

            if (cmd->index >= android_netspeeds_count ||
                android_netspeeds[cmd->index].name == NULL) {
                resp.result = -1;
            } else {
                const NetworkSpeed* netspeed = &android_netspeeds[cmd->index];
                // Calculate size of the response data:
                // fixed header + zero-terminated netspeed name.
                resp.resp_data_size = sizeof(UICmdGetNetSpeedResp) +
                                      strlen(netspeed->name) + 1;
                // Count in zero-terminated netspeed display.
                if (netspeed->display != NULL) {
                    resp.resp_data_size += strlen(netspeed->display) + 1;
                } else {
                    resp.resp_data_size++;
                }
                // Allocate and initialize response data buffer.
                resp_data =
                    (UICmdGetNetSpeedResp*)qemu_malloc(resp.resp_data_size);
                resp_data->upload = netspeed->upload;
                resp_data->download = netspeed->download;
                strcpy(resp_data->name, netspeed->name);
                if (netspeed->display != NULL) {
                    strcpy(resp_data->name + strlen(resp_data->name) + 1,
                           netspeed->display);
                } else {
                    strcpy(resp_data->name + strlen(resp_data->name) + 1, "");
                }
            }
            _coreCmdImpl_respond(corecmd, &resp, resp_data);
            if (resp_data != NULL) {
                qemu_free(resp_data);
            }
            break;
        }

        case AUICMD_GET_NETDELAY:
        {
            UICmdRespHeader resp;
            UICmdGetNetDelayResp* resp_data = NULL;
            UICmdGetNetDelay* cmd = (UICmdGetNetDelay*)cmd_param;

            resp.resp_data_size = 0;
            resp.result = 0;

            if (cmd->index >= android_netdelays_count ||
                android_netdelays[cmd->index].name == NULL) {
                resp.result = -1;
            } else {
                const NetworkLatency* netdelay = &android_netdelays[cmd->index];
                // Calculate size of the response data:
                // fixed header + zero-terminated netdelay name.
                resp.resp_data_size = sizeof(UICmdGetNetDelayResp) +
                                      strlen(netdelay->name) + 1;
                // Count in zero-terminated netdelay display.
                if (netdelay->display != NULL) {
                    resp.resp_data_size += strlen(netdelay->display) + 1;
                } else {
                    resp.resp_data_size++;
                }
                // Allocate and initialize response data buffer.
                resp_data =
                    (UICmdGetNetDelayResp*)qemu_malloc(resp.resp_data_size);
                resp_data->min_ms = netdelay->min_ms;
                resp_data->max_ms = netdelay->max_ms;
                strcpy(resp_data->name, netdelay->name);
                if (netdelay->display != NULL) {
                    strcpy(resp_data->name + strlen(resp_data->name) + 1,
                           netdelay->display);
                } else {
                    strcpy(resp_data->name + strlen(resp_data->name) + 1, "");
                }
            }
            _coreCmdImpl_respond(corecmd, &resp, resp_data);
            if (resp_data != NULL) {
                qemu_free(resp_data);
            }
            break;
        }

        case AUICMD_GET_QEMU_PATH:
        {
            UICmdRespHeader resp;
            UICmdGetQemuPath* cmd = (UICmdGetQemuPath*)cmd_param;
            char* filepath = NULL;

            resp.resp_data_size = 0;
            resp.result = -1;
            filepath = qemu_find_file(cmd->type, cmd->filename);
            if (filepath != NULL) {
                resp.resp_data_size = strlen(filepath) + 1;
            }
            _coreCmdImpl_respond(corecmd, &resp, filepath);
            if (filepath != NULL) {
                qemu_free(filepath);
            }
            break;
        }

        case AUICMD_GET_LCD_DENSITY:
        {
            UICmdRespHeader resp;
            resp.resp_data_size = 0;
            resp.result = android_hw->hw_lcd_density;
            _coreCmdImpl_respond(corecmd, &resp, NULL);
            break;
        }

        default:
            derror("Unknown UI control command %d is received by the Core.\n",
                   cmd_header->cmd_type);
            break;
    }
}
/* I/O write */
static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value)
{
    trace_dev_state *s = (trace_dev_state *)opaque;

    offset -= s->base;
    switch (offset >> 2) {
    case TRACE_DEV_REG_SWITCH:  // context switch, switch to pid
        trace_switch(value);
#ifdef DEBUG
        printf("QEMU.trace: kernel, context switch %u\n", value);
#endif
        break;
    case TRACE_DEV_REG_TGID:    // save the tgid for the following fork/clone
        tgid = value;
#ifdef DEBUG
        printf("QEMU.trace: kernel, tgid %u\n", value);
#endif
        break;
    case TRACE_DEV_REG_FORK:    // fork, fork new pid
        trace_fork(tgid, value);
#ifdef DEBUG
        printf("QEMU.trace: kernel, fork %u\n", value);
#endif
        break;
    case TRACE_DEV_REG_CLONE:    // fork, clone new pid (i.e. thread)
        trace_clone(tgid, value);
#ifdef DEBUG
        printf("QEMU.trace: kernel, clone %u\n", value);
#endif
        break;
    case TRACE_DEV_REG_EXECVE_VMSTART:  // execve, vstart
        vstart = value;
        break;
    case TRACE_DEV_REG_EXECVE_VMEND:    // execve, vend
        vend = value;
        break;
    case TRACE_DEV_REG_EXECVE_OFFSET:   // execve, offset in EXE
        eoff = value;
        break;
    case TRACE_DEV_REG_EXECVE_EXEPATH:  // init exec, path of EXE
        vstrcpy(value, path, CLIENT_PAGE_SIZE);
        trace_init_exec(vstart, vend, eoff, path);
#ifdef DEBUG
        printf("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
#endif
        path[0] = 0;
        break;
    case TRACE_DEV_REG_CMDLINE_LEN:     // execve, process cmdline length
        cmdlen = value;
        break;
    case TRACE_DEV_REG_CMDLINE:         // execve, process cmdline
        vmemcpy(value, arg, cmdlen);
        trace_execve(arg, cmdlen);
#ifdef DEBUG
        {
            int i;
            for (i = 0; i < cmdlen; i ++)
                if (i != cmdlen - 1 && arg[i] == 0)
                    arg[i] = ' ';
            printf("QEMU.trace: kernel, execve %s[%d]\n", arg, cmdlen);
        }
#endif
        arg[0] = 0;
        break;
    case TRACE_DEV_REG_EXIT:            // exit, exit current process with exit code
        trace_exit(value);
#ifdef DEBUG
        printf("QEMU.trace: kernel, exit %x\n", value);
#endif
        break;
    case TRACE_DEV_REG_NAME:            // record thread name
        vstrcpy(value, path, CLIENT_PAGE_SIZE);

        // Remove the trailing newline if it exists
        int len = strlen(path);
        if (path[len - 1] == '\n') {
            path[len - 1] = 0;
        }
        trace_name(path);
#ifdef DEBUG
        printf("QEMU.trace: kernel, name %s\n", path);
#endif
        break;
    case TRACE_DEV_REG_MMAP_EXEPATH:    // mmap, path of EXE, the others are same as execve
        vstrcpy(value, path, CLIENT_PAGE_SIZE);
        trace_mmap(vstart, vend, eoff, path);
#ifdef DEBUG
        printf("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
#endif
        path[0] = 0;
        break;
    case TRACE_DEV_REG_INIT_PID:        // init, name the pid that starts before device registered
        pid = value;
        break;
    case TRACE_DEV_REG_INIT_NAME:       // init, the comm of the init pid
        vstrcpy(value, path, CLIENT_PAGE_SIZE);
        trace_init_name(tgid, pid, path);
#ifdef DEBUG
        printf("QEMU.trace: kernel, init name %u [%s]\n", pid, path);
#endif
        path[0] = 0;
        break;

    case TRACE_DEV_REG_DYN_SYM_ADDR:    // dynamic symbol address
        dsaddr = value;
        break;
    case TRACE_DEV_REG_DYN_SYM:         // add dynamic symbol
        vstrcpy(value, arg, CLIENT_PAGE_SIZE);
        trace_dynamic_symbol_add(dsaddr, arg);
#ifdef DEBUG
        printf("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, arg);
#endif
        arg[0] = 0;
        break;
    case TRACE_DEV_REG_REMOVE_ADDR:         // remove dynamic symbol addr
        trace_dynamic_symbol_remove(value);
#ifdef DEBUG
        printf("QEMU.trace: dynamic symbol remove %lx\n", dsaddr);
#endif
        arg[0] = 0;
        break;

    case TRACE_DEV_REG_PRINT_STR:       // print string
        vstrcpy(value, arg, CLIENT_PAGE_SIZE);
        printf("%s", arg);
        arg[0] = 0;
        break;
    case TRACE_DEV_REG_PRINT_NUM_DEC:   // print number in decimal
        printf("%d", value);
        break;
    case TRACE_DEV_REG_PRINT_NUM_HEX:   // print number in hexical
        printf("%x", value);
        break;

    case TRACE_DEV_REG_STOP_EMU:        // stop the VM execution
        // To ensure that the number of instructions executed in this
        // block is correct, we pretend that there was an exception.
        trace_exception(0);

        cpu_single_env->exception_index = EXCP_HLT;
        cpu_single_env->halted = 1;
        qemu_system_shutdown_request();
        cpu_loop_exit();
        break;

    case TRACE_DEV_REG_ENABLE:          // tracing enable: 0 = stop, 1 = start
        if (value == 1)
            start_tracing();
        else if (value == 0) {
            stop_tracing();

            // To ensure that the number of instructions executed in this
            // block is correct, we pretend that there was an exception.
            trace_exception(0);
        }
        break;

    case TRACE_DEV_REG_UNMAP_START:
        unmap_start = value;
        break;
    case TRACE_DEV_REG_UNMAP_END:
        trace_munmap(unmap_start, value);
        break;

    default:
        cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset);
        break;
    }
}
Example #9
0
int
main(int ac, char **av)
{
	struct timespec timediff;
	struct sigaction sa;
	struct ex_types *funcs;
	struct trussinfo *trussinfo;
	char *fname;
	char *signame;
	char **command;
	pid_t childpid;
	int c, initial_open, status;

	fname = NULL;
	initial_open = 1;

	/* Initialize the trussinfo struct */
	trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo));
	if (trussinfo == NULL)
		errx(1, "calloc() failed");

	trussinfo->outfile = stderr;
	trussinfo->strsize = 32;
	trussinfo->pr_why = S_NONE;
	trussinfo->curthread = NULL;
	SLIST_INIT(&trussinfo->threadlist);
	while ((c = getopt(ac, av, "p:o:facedDs:S")) != -1) {
		switch (c) {
		case 'p':	/* specified pid */
			trussinfo->pid = atoi(optarg);
			/* make sure i don't trace me */
			if (trussinfo->pid == getpid()) {
				fprintf(stderr, "attempt to grab self.\n");
				exit(2);
			}
			break;
		case 'f': /* Follow fork()'s */
			trussinfo->flags |= FOLLOWFORKS;
			break;
		case 'a': /* Print execve() argument strings. */
			trussinfo->flags |= EXECVEARGS;
			break;
		case 'c': /* Count number of system calls and time. */
			trussinfo->flags |= COUNTONLY;
			break;
		case 'e': /* Print execve() environment strings. */
			trussinfo->flags |= EXECVEENVS;
			break;
		case 'd': /* Absolute timestamps */
			trussinfo->flags |= ABSOLUTETIMESTAMPS;
			break;
		case 'D': /* Relative timestamps */
			trussinfo->flags |= RELATIVETIMESTAMPS;
			break;
		case 'o':	/* Specified output file */
			fname = optarg;
			break;
		case 's':	/* Specified string size */
			trussinfo->strsize = atoi(optarg);
			break;
		case 'S':	/* Don't trace signals */
			trussinfo->flags |= NOSIGS;
			break;
		default:
			usage();
		}
	}

	ac -= optind; av += optind;
	if ((trussinfo->pid == 0 && ac == 0) ||
	    (trussinfo->pid != 0 && ac != 0))
		usage();

	if (fname != NULL) { /* Use output file */
		/*
		 * Set close-on-exec ('e'), so that the output file is not
		 * shared with the traced process.
		 */
		if ((trussinfo->outfile = fopen(fname, "we")) == NULL)
			err(1, "cannot open %s", fname);
	}

	/*
	 * If truss starts the process itself, it will ignore some signals --
	 * they should be passed off to the process, which may or may not
	 * exit.  If, however, we are examining an already-running process,
	 * then we restore the event mask on these same signals.
	 */

	if (trussinfo->pid == 0) {	/* Start a command ourselves */
		command = av;
		trussinfo->pid = setup_and_wait(command);
		signal(SIGINT, SIG_IGN);
		signal(SIGTERM, SIG_IGN);
		signal(SIGQUIT, SIG_IGN);
	} else {
		sa.sa_handler = restore_proc;
		sa.sa_flags = 0;
		sigemptyset(&sa.sa_mask);
		sigaction(SIGINT, &sa, NULL);
		sigaction(SIGQUIT, &sa, NULL);
		sigaction(SIGTERM, &sa, NULL);
		start_tracing(trussinfo->pid);
	}


	/*
	 * At this point, if we started the process, it is stopped waiting to
	 * be woken up, either in exit() or in execve().
	 */

START_TRACE:
	funcs = set_etype(trussinfo);

	initial_open = 0;
	/*
	 * At this point, it's a simple loop, waiting for the process to
	 * stop, finding out why, printing out why, and then continuing it.
	 * All of the grunt work is done in the support routines.
	 */

	clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);

	do {
		waitevent(trussinfo);

		switch (trussinfo->pr_why) {
		case S_SCE:
			funcs->enter_syscall(trussinfo, MAXARGS);
			clock_gettime(CLOCK_REALTIME,
			    &trussinfo->curthread->before);
			break;
		case S_SCX:
			clock_gettime(CLOCK_REALTIME,
			    &trussinfo->curthread->after);

			if (trussinfo->curthread->in_fork &&
			    (trussinfo->flags & FOLLOWFORKS)) {
				trussinfo->curthread->in_fork = 0;
				childpid = funcs->exit_syscall(trussinfo,
				    trussinfo->pr_data);

				/*
				 * Fork a new copy of ourself to trace
				 * the child of the original traced
				 * process.
				 */
				if (fork() == 0) {
					trussinfo->pid = childpid;
					start_tracing(trussinfo->pid);
					goto START_TRACE;
				}
				break;
			}
			funcs->exit_syscall(trussinfo, MAXARGS);
			break;
		case S_SIG:
			if (trussinfo->flags & NOSIGS)
				break;
			if (trussinfo->flags & FOLLOWFORKS)
				fprintf(trussinfo->outfile, "%5d: ",
				    trussinfo->pid);
			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
				timespecsubt(&trussinfo->curthread->after,
				    &trussinfo->start_time, &timediff);
				fprintf(trussinfo->outfile, "%jd.%09ld ",
				    (intmax_t)timediff.tv_sec,
				    timediff.tv_nsec);
			}
			if (trussinfo->flags & RELATIVETIMESTAMPS) {
				timespecsubt(&trussinfo->curthread->after,
				    &trussinfo->curthread->before, &timediff);
				fprintf(trussinfo->outfile, "%jd.%09ld ",
				    (intmax_t)timediff.tv_sec,
				    timediff.tv_nsec);
			}
			signame = strsig(trussinfo->pr_data);
			fprintf(trussinfo->outfile,
			    "SIGNAL %u (%s)\n", trussinfo->pr_data,
			    signame == NULL ? "?" : signame);
			break;
		case S_EXIT:
			if (trussinfo->flags & COUNTONLY)
				break;
			if (trussinfo->flags & FOLLOWFORKS)
				fprintf(trussinfo->outfile, "%5d: ",
				    trussinfo->pid);
			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
				timespecsubt(&trussinfo->curthread->after,
				    &trussinfo->start_time, &timediff);
				fprintf(trussinfo->outfile, "%jd.%09ld ",
				    (intmax_t)timediff.tv_sec,
				    timediff.tv_nsec);
			}
			if (trussinfo->flags & RELATIVETIMESTAMPS) {
				timespecsubt(&trussinfo->curthread->after,
				    &trussinfo->curthread->before, &timediff);
				fprintf(trussinfo->outfile, "%jd.%09ld ",
				    (intmax_t)timediff.tv_sec,
				    timediff.tv_nsec);
			}
			fprintf(trussinfo->outfile,
			    "process exit, rval = %u\n", trussinfo->pr_data);
			break;
		default:
			break;
		}
	} while (trussinfo->pr_why != S_EXIT &&
	    trussinfo->pr_why != S_DETACHED);

	if (trussinfo->flags & FOLLOWFORKS) {
		do {
			childpid = wait(&status);
		} while (childpid != -1);
	}

	if (trussinfo->flags & COUNTONLY)
		print_summary(trussinfo);

	fflush(trussinfo->outfile);

	return (0);
}
Example #10
0
static int run_master(coreid_t mycore, int argc, char *argv[])
{
    errval_t err;
    int num_spawn = strtol(argv[1], NULL, 10);
    int first_core = mycore + 1;

    debug_printf("spawning on %d cores\n", num_spawn);

#ifdef TRACING
    err = init_tracing();
    if (err_is_fail(err)) {
        DEBUG_ERR(err, "initialising tracing");
        return EXIT_FAILURE;
    }
    // start_tracing();

    prepare_dump();
#endif 

    trace_event(TRACE_SUBSYS_MEMTEST, TRACE_EVENT_MEMTEST_STARTED, 0);

    // spawn some dispatchers

    char *path = argv[0];      // reuse argv and path
    argv[1] = NULL;

    for (int i = first_core; i <= num_spawn; i++) {
        err = spawn_program(i, path, argv, NULL, 0, NULL);
        if (err_is_fail(err)) {
            DEBUG_ERR(err, "spawning on core %d", i);
        } else {
            //debug_printf("dispatcher %d on core %d spawned\n", i, i);
        }

    }

    trace_event(TRACE_SUBSYS_MEMTEST, TRACE_EVENT_MEMTEST_WAIT, 0);

    //    debug_printf("waiting for all spawns to start\n");
    err = ns_barrier_master(first_core, num_spawn, "mem_bench_ready");
    if (err_is_fail(err)) {
        DEBUG_ERR(err, "failed barrier_master");
        return EXIT_FAILURE;
    }

    start_tracing();

    trace_event(TRACE_SUBSYS_MEMTEST, TRACE_EVENT_MEMTEST_RUN, 0);

    //    run_benchmark(mycore, MAX_REQUESTS_0);

    trace_event(TRACE_SUBSYS_MEMTEST, TRACE_EVENT_MEMTEST_WAIT, 0);

    //    debug_printf("waiting for all spawns to complete\n");
    err = ns_barrier_master(first_core, num_spawn, "mem_bench_finished");
    if (err_is_fail(err)) {
        DEBUG_ERR(err, "failed barrier_master");
        return EXIT_FAILURE;
    }

    trace_event(TRACE_SUBSYS_MEMTEST, TRACE_EVENT_MEMTEST_DONE, 0);

    debug_printf("all benchmarks completed\n");

#ifdef TRACING
    stop_tracing();
    // dump_trace();
#endif 

    return EXIT_SUCCESS;
}
static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value)
{
    trace_dev_state *s = (trace_dev_state *)opaque;

    (void)s;

    switch (offset >> 2) {
    case TRACE_DEV_REG_SWITCH:  
        DPID("QEMU.trace: context switch tid=%u\n", value);
        if (trace_filename != NULL) {
            trace_switch(value);
            D("QEMU.trace: kernel, context switch %u\n", value);
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_switch(value);
        }
#endif  
        tid = (unsigned) value;
        break;
    case TRACE_DEV_REG_TGID:    
        DPID("QEMU.trace: tgid=%u\n", value);
        tgid = value;
        if (trace_filename != NULL) {
            D("QEMU.trace: kernel, tgid %u\n", value);
        }
        break;
    case TRACE_DEV_REG_FORK:    
        DPID("QEMU.trace: fork (pid=%d tgid=%d value=%d)\n", pid, tgid, value);
        if (trace_filename != NULL) {
            trace_fork(tgid, value);
            D("QEMU.trace: kernel, fork %u\n", value);
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_fork(tgid, value);
        }
#endif  
        break;
    case TRACE_DEV_REG_CLONE:    
        DPID("QEMU.trace: clone (pid=%d tgid=%d value=%d)\n", pid, tgid, value);
        if (trace_filename != NULL) {
            trace_clone(tgid, value);
            D("QEMU.trace: kernel, clone %u\n", value);
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_clone(tgid, value);
        }
#endif  
        break;
    case TRACE_DEV_REG_EXECVE_VMSTART:  
        vstart = value;
        break;
    case TRACE_DEV_REG_EXECVE_VMEND:    
        vend = value;
        break;
    case TRACE_DEV_REG_EXECVE_OFFSET:   
        eoff = value;
        break;
    case TRACE_DEV_REG_EXECVE_EXEPATH:  
        vstrcpy(value, exec_path, CLIENT_PAGE_SIZE);
        if (trace_filename != NULL) {
            trace_init_exec(vstart, vend, eoff, exec_path);
            D("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n",
              vstart, vend, eoff, exec_path);
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            if (exec_path[0] == '\0') {
                
                
                memcheck_get_guest_kernel_string(exec_path, value, CLIENT_PAGE_SIZE);
            }
            memcheck_mmap_exepath(vstart, vend, eoff, exec_path);
        }
#endif  
        exec_path[0] = 0;
        break;
    case TRACE_DEV_REG_CMDLINE_LEN:     
        cmdlen = value;
        break;
    case TRACE_DEV_REG_CMDLINE:         
        safe_memory_rw_debug(cpu_single_env, value, (uint8_t*)exec_arg, cmdlen, 0);
        if (trace_filename != NULL) {
            trace_execve(exec_arg, cmdlen);
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_set_cmd_line(exec_arg, cmdlen);
        }
#endif  
#if DEBUG || DEBUG_PID
        if (trace_filename != NULL) {
            int i;
            for (i = 0; i < cmdlen; i ++)
                if (i != cmdlen - 1 && exec_arg[i] == 0)
                    exec_arg[i] = ' ';
            printf("QEMU.trace: kernel, execve %s[%d]\n", exec_arg, cmdlen);
            exec_arg[0] = 0;
        }
#endif
        break;
    case TRACE_DEV_REG_EXIT:            
        DPID("QEMU.trace: exit tid=%u\n", value);
        if (trace_filename != NULL) {
            trace_exit(value);
            D("QEMU.trace: kernel, exit %x\n", value);
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_exit(value);
        }
#endif  
        break;
    case TRACE_DEV_REG_NAME:            
        vstrcpy(value, exec_path, CLIENT_PAGE_SIZE);
        DPID("QEMU.trace: thread name=%s\n", exec_path);

        
        int len = strlen(exec_path);
        if (exec_path[len - 1] == '\n') {
            exec_path[len - 1] = 0;
        }
        if (trace_filename != NULL) {
            trace_name(exec_path);
            D("QEMU.trace: kernel, name %s\n", exec_path);
        }
        break;
    case TRACE_DEV_REG_MMAP_EXEPATH:    
        vstrcpy(value, exec_path, CLIENT_PAGE_SIZE);
        DPID("QEMU.trace: mmap exe=%s\n", exec_path);
        if (trace_filename != NULL) {
            trace_mmap(vstart, vend, eoff, exec_path);
            D("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, exec_path);
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            if (exec_path[0] == '\0') {
                
                
                memcheck_get_guest_kernel_string(exec_path, value, CLIENT_PAGE_SIZE);
            }
            memcheck_mmap_exepath(vstart, vend, eoff, exec_path);
        }
#endif  
        exec_path[0] = 0;
        break;
    case TRACE_DEV_REG_INIT_PID:        
        pid = value;
        DPID("QEMU.trace: pid=%d\n", value);
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_init_pid(value);
        }
#endif  
        break;
    case TRACE_DEV_REG_INIT_NAME:       
        vstrcpy(value, exec_path, CLIENT_PAGE_SIZE);
        DPID("QEMU.trace: tgid=%d pid=%d name=%s\n", tgid, pid, exec_path);
        if (trace_filename != NULL) {
            trace_init_name(tgid, pid, exec_path);
            D("QEMU.trace: kernel, init name %u [%s]\n", pid, exec_path);
        }
        exec_path[0] = 0;
        break;

    case TRACE_DEV_REG_DYN_SYM_ADDR:    
        dsaddr = value;
        break;
    case TRACE_DEV_REG_DYN_SYM:         
        vstrcpy(value, exec_arg, CLIENT_PAGE_SIZE);
        if (trace_filename != NULL) {
            trace_dynamic_symbol_add(dsaddr, exec_arg);
            D("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, exec_arg);
        }
        exec_arg[0] = 0;
        break;
    case TRACE_DEV_REG_REMOVE_ADDR:         
        if (trace_filename != NULL) {
            trace_dynamic_symbol_remove(value);
            D("QEMU.trace: dynamic symbol remove %lx\n", dsaddr);
        }
        break;

    case TRACE_DEV_REG_PRINT_STR:       
        vstrcpy(value, exec_arg, CLIENT_PAGE_SIZE);
        printf("%s", exec_arg);
        exec_arg[0] = 0;
        break;
    case TRACE_DEV_REG_PRINT_NUM_DEC:   
        printf("%d", value);
        break;
    case TRACE_DEV_REG_PRINT_NUM_HEX:   
        printf("%x", value);
        break;

    case TRACE_DEV_REG_STOP_EMU:        
        if (trace_filename != NULL) {
            
            
            trace_exception(0);
        }
        cpu_single_env->exception_index = EXCP_HLT;
        cpu_single_env->halted = 1;
        qemu_system_shutdown_request();
        cpu_loop_exit();
        break;

    case TRACE_DEV_REG_ENABLE:          
        if (value == 1) {
            if (trace_filename != NULL) {
                start_tracing();
            }
        }
        else if (value == 0) {
            if (trace_filename != NULL) {
                stop_tracing();

                
                
                trace_exception(0);
            }
        }
        break;

    case TRACE_DEV_REG_UNMAP_START:
        unmap_start = value;
        break;
    case TRACE_DEV_REG_UNMAP_END:
        if (trace_filename != NULL) {
            trace_munmap(unmap_start, value);
        }
#ifdef CONFIG_MEMCHECK
        if (memcheck_enabled) {
            memcheck_unmap(unmap_start, value);
        }
#endif  
        break;

    case TRACE_DEV_REG_METHOD_ENTRY:
    case TRACE_DEV_REG_METHOD_EXIT:
    case TRACE_DEV_REG_METHOD_EXCEPTION:
    case TRACE_DEV_REG_NATIVE_ENTRY:
    case TRACE_DEV_REG_NATIVE_EXIT:
    case TRACE_DEV_REG_NATIVE_EXCEPTION:
        if (trace_filename != NULL) {
            if (tracing) {
                int call_type = (offset - 4096) >> 2;
                trace_interpreted_method(value, call_type);
            }
        }
        break;

#ifdef CONFIG_MEMCHECK
    case TRACE_DEV_REG_MALLOC:
        if (memcheck_enabled) {
            memcheck_guest_alloc(value);
        }
        break;

    case TRACE_DEV_REG_FREE_PTR:
        if (memcheck_enabled) {
            memcheck_guest_free(value);
        }
        break;

    case TRACE_DEV_REG_QUERY_MALLOC:
        if (memcheck_enabled) {
            memcheck_guest_query_malloc(value);
        }
        break;

    case TRACE_DEV_REG_LIBC_INIT:
        if (memcheck_enabled) {
            memcheck_guest_libc_initialized(value);
        }
        break;

    case TRACE_DEV_REG_PRINT_USER_STR:
        if (memcheck_enabled) {
            memcheck_guest_print_str(value);
        }
        break;
#endif 

    default:
        if (offset < 4096) {
            cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset);
        } else {
            D("%s: offset=%d (0x%x) value=%d (0x%x)\n", __FUNCTION__, offset,
              offset, value, value);
        }
        break;
    }
}