Exemplo n.º 1
0
/* Add an activity to the global list. */
struct activity *
add_activity (const char *name, int flags)
{
  struct activity *ret;
  size_t i;

  /* You shouldn't have two activities with the same name. */
  assert (!activity_exists (name));

  nr_activities++;
  activities = realloc (activities, sizeof (struct activity) * nr_activities);
  if (activities == NULL)
    error (EXIT_FAILURE, errno, "realloc");
  ret = &activities[nr_activities-1];
  ret->name = strdup (name);
  if (ret->name == NULL)
    error (EXIT_FAILURE, errno, "strdup");
  ret->flags = flags;

  for (i = 0; i < NR_TEST_PASSES; ++i)
    ret->start_event[i] = ret->end_event[i] = 0;

  return ret;
}
/* Handling of initcall is so peculiar that we hide it in a separate
 * function from the rest.
 */
static void
construct_initcall_timeline (void)
{
  size_t i, j, k;
  struct pass_data *data;
  struct activity *activity;

  for (i = 0; i < NR_TEST_PASSES; ++i) {
    data = &pass_data[i];

    /* Each kernel initcall is bracketed by:
     *
     * calling  ehci_hcd_init+0x0/0xc1 @ 1"
     * initcall ehci_hcd_init+0x0/0xc1 returned 0 after 420 usecs"
     *
     * For initcall functions in modules:
     *
     * calling  virtio_mmio_init+0x0/0x1000 [virtio_mmio] @ 1"
     * initcall virtio_mmio_init+0x0/0x1000 [virtio_mmio] returned 0 after 14 usecs"
     *
     * Initcall functions can be nested, and do not have unique names.
     */
    for (j = 0; j < data->nr_events; ++j) {
      int vec[30], r;
      const char *message = data->events[j].message;

      if (data->events[j].source == GUESTFS_EVENT_APPLIANCE &&
          ((r = pcre_exec (re_initcall_calling_module, NULL,
                           message, strlen (message),
                           0, 0, vec, sizeof vec / sizeof vec[0])) >= 1 ||
           (r = pcre_exec (re_initcall_calling, NULL,
                           message, strlen (message),
                           0, 0, vec, sizeof vec / sizeof vec[0])) >= 1)) {

        CLEANUP_FREE char *fn_name = NULL, *module_name = NULL;
        if (r >= 2) /* because pcre_exec returns 1 + number of captures */
          fn_name = strndup (message + vec[2], vec[3]-vec[2]);
        if (r >= 3)
          module_name = strndup (message + vec[4], vec[5]-vec[4]);

        CLEANUP_FREE char *fullname;
        if (asprintf (&fullname, "%s.%s",
                      module_name ? module_name : "kernel", fn_name) == -1)
          error (EXIT_FAILURE, errno, "asprintf");

        CLEANUP_FREE char *initcall_match;
        if (asprintf (&initcall_match, "initcall %s", fn_name) == -1)
          error (EXIT_FAILURE, errno, "asprintf");

        /* Get a unique name for this activity.  Unfortunately
         * kernel initcall function names are not unique!
         */
        CLEANUP_FREE char *activity_name;
        if (asprintf (&activity_name, "initcall %s", fullname) == -1)
          error (EXIT_FAILURE, errno, "asprintf");

        if (i == 0) {
          int n = 1;
          while (activity_exists (activity_name)) {
            free (activity_name);
            if (asprintf (&activity_name, "initcall %s:%d", fullname, n) == -1)
              error (EXIT_FAILURE, errno, "asprintf");
            n++;
          }
        }
        else {
          int n = 1;
          while (!activity_exists_with_no_data (activity_name, i)) {
            free (activity_name);
            if (asprintf (&activity_name, "initcall %s:%d", fullname, n) == -1)
              error (EXIT_FAILURE, errno, "asprintf");
            n++;
          }
        }

        /* Find the matching end event.  It might be some time later,
         * since it appears initcalls can be nested.
         */
        for (k = j+1; k < data->nr_events; ++k) {
          if (data->events[k].source == GUESTFS_EVENT_APPLIANCE &&
              strstr (data->events[k].message, initcall_match)) {
            if (i == 0)
              activity = add_activity (activity_name, 0);
            else
              activity = find_activity (activity_name);
            activity->start_event[i] = j;
            activity->end_event[i] = k;
            break;
          }
        }
      }
    }
  }
}