aboutsummaryrefslogtreecommitdiffstats
path: root/toolchain/glibc
Commit message (Expand)AuthorAgeFilesLines
* toolchain: Rework external toolchain libc selectionFlorian Fainelli2016-09-281-1/+1
* glibc: re-enable parallel buildsFelix Fietkau2016-08-301-2/+2
* glibc: switch to 2.24 by default and remove old versions, fixes security issuesFelix Fietkau2016-08-305-85/+2
* glibc: add 2.24Dirk Neukirchen2016-08-305-2/+84
* toolchain: skip gcc/minimal for muslFelix Fietkau2016-07-071-0/+1
* toolchain/glibc: remove obsolete versionsFelix Fietkau2016-02-2516-1393/+1
* toolchain: use latest glibc 2.21 and 2.22 revisionsJo-Philipp Wich2016-02-174-22/+22
* toolchain: mark eglibc 2.19 brokenJo-Philipp Wich2016-02-171-0/+1
* glibc: switch to downloading version 2.22 via tarball instead of git to impro...Felix Fietkau2016-01-292-7/+13
* glibc: switch to version 2.22 by defaultFelix Fietkau2016-01-292-2/+2
* toolchain: Reverse glibc/eglibc conditionals to check for eglibcFelix Fietkau2016-01-201-4/+4
* toolchain: Add glibc 2.22Felix Fietkau2016-01-195-1/+76
* toolchain: fix eglibc build when TOOLCHAINOPTS is not setJohn Crispin2015-03-261-1/+5
* toolchain/glibc: remove broken eglibc 2.15 supportFelix Fietkau2015-03-253-20/+1
* toolchain: The glorious return of glibc, ver 2.21John Crispin2015-03-1219-0/+1586
* purge support for glibc - use eglibc instead!Mirko Vogt2012-04-285-224/+0
* glibc: remove all previous (ancient) versions, add 2.14 (partially based on a...Felix Fietkau2012-02-1215-266/+43
* fix glibc to work with all versions of binutils, fixes #7133 - thanks to mare...Mirko Vogt2011-06-172-0/+35
* fix a compile error when compiling with glibc (#7816)Felix Fietkau2010-09-011-1/+1
* toolchain: fix the sysroot mess by getting rid of $(TOOLCHAIN_DIR)/usr and mo...Felix Fietkau2010-08-191-6/+6
* add support for glibc-2.4 (#5213)Florian Fainelli2009-05-263-0/+8
* define libc_cv_slibdir, fixes mips64 compilation (#5011)Florian Fainelli2009-04-301-0/+1
* uClibc cleanup: - use full version string (0.9.30.1), instead of base (0.9.30...Nicolas Thill2009-04-241-1/+1
* add a modified version of the mips64 patch from #4603Felix Fietkau2009-04-182-3/+4
* fix stampfile variables for the toolchain build (fixes gcc compile error)Felix Fietkau2009-03-131-2/+2
* move common variables to a dedicated include fileNicolas Thill2009-02-231-6/+1
* build system refactoring in preparation for allowing packages to do host-buil...Felix Fietkau2009-02-221-25/+25
* cosmetic & coherency fixesNicolas Thill2009-02-031-7/+6
* add support for gcc v4.3.1 & v4.3.2 (closes: #3479), thanks to Luigi Mantellini!Nicolas Thill2009-01-214-0/+100
* add support for alternative C libraries (currently only glibc/eglibc) other (...Nicolas Thill2009-01-087-0/+308
='#n381'>381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
/******************************************************************************
 * tools/xentrace/xentrace.c
 *
 * Tool for collecting trace buffer data from Xen.
 *
 * Copyright (C) 2004 by Intel Research Cambridge
 *
 * Author: Mark Williamson, mark.a.williamson@intel.com
 * Date:   February 2004
 */

#include <time.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <argp.h>
#include <signal.h>

#include "../xc/lib/xc_private.h"

#include <xeno/trace.h>

extern FILE *stdout;


/***** Compile time configuration of defaults ********************************/

/* when we've got more records than this waiting, we log it to the output */
#define NEW_DATA_THRESH 1

/* sleep for this long (milliseconds) between checking the trace buffers */
#define POLL_SLEEP_MILLIS 100


/***** The code **************************************************************/

typedef struct settings_st {
    char *outfile;
    struct timespec poll_sleep;
    unsigned long new_data_thresh;
} settings_t;

settings_t opts;

int interrupted = 0; /* gets set if we get a SIGHUP */

void close_handler(int signal)
{
    interrupted = 1;
    fprintf(stderr,"Received signal %d, now exiting\n", signal);
}

/**
 * millis_to_timespec - convert a time in milliseconds to a struct timespec
 * @millis:             time interval in milliseconds
 */
struct timespec millis_to_timespec(unsigned long millis)
{
    struct timespec spec;
    
    spec.tv_sec = millis / 1000;
    spec.tv_nsec = (millis % 1000) * 1000;

    return spec;
}


/**
 * print_rec - plain print an event given a pointer to its start
 * @cpu:       CPU the data came from
 * @data:      pointer to the start of the event data
 * @out:       file stream to print out to
 *
 * Takes a pointer to a record and prints out the data.
 */
void print_rec(unsigned int cpu, struct t_rec *rec, FILE *out)
{    
    fprintf(out, "%u %llu %lu %lu %lu %lu %lu %lu\n",
	    cpu, rec->cycles, rec->event, rec->d1, rec->d2,
	    rec->d3, rec->d4, rec->d5);
}


/**
 * get_tbufs - get pointer to and size of the trace buffers
 * @phys_addr: location to store physical address if the trace buffers to
 * @size:      location to store the size of a trace buffer to
 *
 * Gets the physical address of the trace pointer area and the size of the
 * per CPU buffers.
 */
void get_tbufs(unsigned long *phys_addr, unsigned long *size)
{
    int ret;
    dom0_op_t op;                        /* dom0 op we'll build             */
    int xc_handle = xc_interface_open(); /* for accessing control interface */

    op.cmd = DOM0_GETTBUFS;
    op.interface_version = DOM0_INTERFACE_VERSION;

    ret = do_dom0_op(xc_handle, &op);

    xc_interface_close(xc_handle);

    if ( ret != 0 )
    {
        PERROR("Failure to get trace buffer pointer from Xen");
        exit(EXIT_FAILURE);
    }

    *phys_addr = op.u.gettbufs.phys_addr;
    *size      = op.u.gettbufs.size;
}

/**
 * map_tbufs - memory map Xen trace buffers into user space
 * @tbufs:     physical address of the trace buffers
 * @num:       number of trace buffers to map
 * @size:      size of each trace buffer
 *
 * Maps the Xen trace buffers them into process address space by memory mapping
 * /dev/mem.  Returns the location the buffers have been mapped to.
 */
struct t_buf *map_tbufs(unsigned long tbufs_phys, unsigned int num,
                        unsigned long size)
{
    int dm_fd;                               /* file descriptor for /dev/mem */
    struct t_buf *tbufs_mapped;

    dm_fd = open("/dev/mem", O_RDONLY);

    if ( dm_fd < 0 ) 
    {
        PERROR("Open /dev/mem when mapping trace buffers\n");
        exit(EXIT_FAILURE);
    }

    tbufs_mapped = (struct t_buf *)mmap(NULL, size * num,
                                        PROT_READ, MAP_SHARED,
                                        dm_fd, (off_t)tbufs_phys);

    close(dm_fd);

    if ( tbufs_mapped == MAP_FAILED ) 
    {
        PERROR("Failed to mmap trace buffers");
        exit(EXIT_FAILURE);
    }

    return (struct t_buf *)tbufs_mapped;
}


/**
 * init_bufs_ptrs - initialises an array of pointers to the trace buffers
 * @bufs_mapped:    the userspace address where the trace buffers are mapped
 * @num:            number of trace buffers
 * @size:           trace buffer size
 *
 * Initialises an array of pointers to individual trace buffers within the
 * mapped region containing all trace buffers.
 */
struct t_buf **init_bufs_ptrs(void *bufs_mapped, unsigned int num,
                              unsigned long size)
{
    int i;
    struct t_buf **user_ptrs;

    user_ptrs = (struct t_buf **)calloc(num, sizeof(struct t_buf *));
    if ( user_ptrs == NULL )
    {
        PERROR( "Failed to allocate memory for buffer pointers\n");
        exit(EXIT_FAILURE);
    }
    
    /* initialise pointers to the trace buffers - given the size of a trace
     * buffer and the value of bufs_maped, we can easily calculate these */
    for ( i = 0; i<num; i++ )
        user_ptrs[i] = (struct t_buf *)(
            (unsigned long)bufs_mapped + size * i);

    return user_ptrs;
}


/**
 * init_rec_ptrs - initialises data area pointers to locations in user space
 * @tbufs_phys:    physical base address of the trace buffer area
 * @tbufs_mapped:  user virtual address of base of trace buffer area
 * @meta:          array of user-space pointers to struct t_buf's of metadata
 * @num:           number of trace buffers
 *
 * Initialises data area pointers to the locations that data areas have been
 * mapped in user space.  Note that the trace buffer metadata contains physical
 * pointers - the array returned allows more convenient access to them.
 */
struct t_rec **init_rec_ptrs(unsigned long tbufs_phys,
                             struct t_buf *tbufs_mapped,
                             struct t_buf **meta,
                             unsigned int num)
{
    int i;
    struct t_rec **data;
    
    data = calloc(num, sizeof(struct t_rec *));
    if ( data == NULL )
    {
        PERROR("Failed to allocate memory for data pointers\n");
        exit(EXIT_FAILURE);
    }

    for ( i = 0; i<num; i++ )
        data[i] = (struct t_rec *)((unsigned long)meta[i]->data -
                                   tbufs_phys + (unsigned long)tbufs_mapped);

    return data;
}

/**
 * init_tail_idxs - initialise an array of tail indexes
 * @bufs:           array of pointers to trace buffer metadata
 * @num:            number of trace buffers
 *
 * The tail indexes indicate where we're read to so far in the data array of a
 * trace buffer.  Each entry in this table corresponds to the tail index for a
 * particular trace buffer.
 */
int *init_tail_idxs(struct t_buf **bufs, unsigned int num)
{
    int i;
    int *tails = calloc(num, sizeof(unsigned int));
 
    if ( tails == NULL )
    {
        PERROR("Failed to allocate memory for tail pointers\n");
        exit(EXIT_FAILURE);
    }
    
    for ( i = 0; i<num; i++ )
        tails[i] = bufs[i]->head;

    return tails;
}

/**
 * get_num_cpus - get the number of logical CPUs
 */
unsigned int get_num_cpus()
{
    dom0_op_t op;
    int xc_handle = xc_interface_open();
    int ret;
    
    op.cmd = DOM0_PHYSINFO;
    op.interface_version = DOM0_INTERFACE_VERSION;

    ret = do_dom0_op(xc_handle, &op);
    
    if ( ret != 0 )
    {
        PERROR("Failure to get logical CPU count from Xen");
        exit(EXIT_FAILURE);
    }

    xc_interface_close(xc_handle);

    return op.u.physinfo.ht_per_core * op.u.physinfo.cores;
}


/**
 * monitor_tbufs - monitor the contents of tbufs and output to a file
 * @logfile:       the FILE * representing the file to log to
 */
int monitor_tbufs(FILE *logfile)
{
    int i, j;
    void *tbufs_mapped;          /* pointer to where the tbufs are mapped    */
    struct t_buf **meta;         /* pointers to the trace buffer metadata    */
    struct t_rec **data;         /* pointers to the trace buffer data areas
                                  * where they are mapped into user space.   */
    int *tails;                  /* store tail indexes for the trace buffers */
    unsigned long tbufs_phys;    /* physical address of the tbufs            */
    unsigned int  num;           /* number of trace buffers / logical CPUS   */
    unsigned long size;          /* size of a single trace buffer            */

    /* get number of logical CPUs (and therefore number of trace buffers) */
    num = get_num_cpus();

    /* setup access to trace buffers */
    get_tbufs(&tbufs_phys, &size);
    tbufs_mapped = map_tbufs(tbufs_phys, num, size);

    /* build arrays of convenience ptrs */
    meta  = init_bufs_ptrs (tbufs_mapped, num, size);
    data  = init_rec_ptrs  (tbufs_phys, tbufs_mapped, meta, num);
    tails = init_tail_idxs (meta, num);

    /* now, scan buffers for events */
    while ( !interrupted )
    {
        for ( i = 0; ( i < num ) && !interrupted; i++ )
        {
            signed long newdata = meta[i]->head - tails[i];
            signed long prewrap = newdata;

	    /* correct newdata and prewrap in case of a pointer wrap */
            if ( newdata < 0 )
            {
                newdata += meta[i]->size;
                prewrap  = meta[i]->size - tails[i];
            }

            if ( newdata >= opts.new_data_thresh )
            {
                /* output pre-wrap data */
                for(j = 0; j < prewrap; j++)
                    print_rec(i, data[i] + tails[i] + j, logfile);
                
                /* output post-wrap data, if any */                    
                for(j = 0; j < (newdata - prewrap); j++)
                    print_rec(i, data[i] + j, logfile);  
                
                tails[i] += newdata;
                if(tails[i] >= meta[i]->size) tails[i] = 0;
            }
        }
        nanosleep(&opts.poll_sleep, NULL);
    }

    /* cleanup */
    free(meta);
    free(data);
    free(tails);
    /* don't need to munmap - cleanup is automatic */
    fclose(logfile);

    return 0;
}


/******************************************************************************
 * Various declarations / definitions GNU argp needs to do its work
 *****************************************************************************/


/* command parser for GNU argp - see GNU docs for more info */
error_t cmd_parser(int key, char *arg, struct argp_state *state)
{
    settings_t *setup = (settings_t *)state->input;

    switch ( key )
    {
    case 't': /* set new records threshold for logging */
    {
        char *inval;
        setup->new_data_thresh = strtol(arg, &inval, 0);
        if ( inval == arg )
            argp_usage(state);
    }
    break;

    case 's': /* set sleep time (given in milliseconds) */
    {
        char *inval;
        setup->poll_sleep = millis_to_timespec(strtol(arg, &inval, 0));
        if ( inval == arg )
            argp_usage(state);
    }
    break;
    
    case ARGP_KEY_ARG:
    {
        if ( state->arg_num == 0 )
            setup->outfile = arg;
        else
            argp_usage(state);
    }
    break;
        
    default:
        return ARGP_ERR_UNKNOWN;
    }

    return 0;
}

#define xstr(x) str(x)
#define str(x) #x

const struct argp_option cmd_opts[] =
{
    { .name = "log-thresh", .key='t', .arg="l",
      .doc =
      "Set number, l, of new records required to trigger a write to output "
      "(default " xstr(NEW_DATA_THRESH) ")." },

    { .name = "poll-sleep", .key='s', .arg="p",
      .doc = 
      "Set sleep time, p, in milliseconds between polling the trace buffer "
      "for new data (default " xstr(POLL_SLEEP_MILLIS) ")." },

    {0}
};

const struct argp parser_def =
{
    .options = cmd_opts,
    .parser = cmd_parser,
    .args_doc = "[output file]",
    .doc =
    "Tool to capure Xen trace buffer data"
    "\v"
    "This tool is used to capture trace buffer data from Xen.  The data is "
    "output as space-separated decimal numbers, represented in ASCII, in "
    "the following order:\n\n"
    "  CPU TSC EVENT DATA1 DATA2 DATA3 DATA4 DATA5\n"
};


const char *argp_program_version     = "xentrace v1.1";
const char *argp_program_bug_address = "<mark.a.williamson@intel.com>";
        
    
int main(int argc, char **argv)
{
    int ret;
    FILE *logfile = stdout;
    struct sigaction act;

    opts.outfile = 0;
    opts.poll_sleep = millis_to_timespec(POLL_SLEEP_MILLIS);
    opts.new_data_thresh = NEW_DATA_THRESH;

    argp_parse(&parser_def, argc, argv, 0, 0, &opts);

    if ( opts.outfile )
        logfile = fopen(opts.outfile, "w");
    
    /* ensure that if we get a signal, we'll do cleanup, then exit */
    act.sa_handler = close_handler;
    sigaction(SIGHUP,  &act, 0);
    sigaction(SIGTERM, &act, 0);
    sigaction(SIGINT,  &act, 0);

    ret = monitor_tbufs(logfile);

    return ret;
}