qemu/etrace.c
<<
>>
Prefs
   1/*
   2 * Execution trace packager for QEMU.
   3 * Copyright (c) 2013 Xilinx Inc.
   4 * Written by Edgar E. Iglesias
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21
  22#include <unistd.h>
  23#ifndef _WIN32
  24#include <sys/socket.h>
  25#include <qemu/sockets.h>
  26#include <sys/un.h>
  27#endif
  28
  29#include "qemu-common.h"
  30#include "qemu/etrace.h"
  31#include "qemu/timer.h"
  32#include "exec/memory.h"
  33#include "exec/address-spaces.h"
  34#include "cpu.h"
  35#include "exec/exec-all.h"
  36
  37/* Still under development.  */
  38#define ETRACE_VERSION_MAJOR 0
  39#define ETRACE_VERSION_MINOR 0
  40
  41enum {
  42    TYPE_EXEC = 1,
  43    TYPE_TB = 2,
  44    TYPE_NOTE = 3,
  45    TYPE_MEM = 4,
  46    TYPE_ARCH = 5,
  47    TYPE_BARRIER = 6,
  48    TYPE_OLD_EVENT_U64 = 7,
  49    TYPE_EVENT_U64 = 8,
  50    TYPE_INFO = 0x4554,
  51};
  52
  53struct etrace_hdr {
  54    uint16_t type;
  55    uint16_t unit_id;
  56    uint32_t len;
  57} QEMU_PACKED;
  58
  59enum etrace_info_flags {
  60    ETRACE_INFO_F_TB_CHAINING   = (1 << 0),
  61};
  62
  63struct etrace_info_data {
  64    uint64_t attr;
  65    struct {
  66        uint16_t major;
  67        uint16_t minor;
  68    } version;
  69} QEMU_PACKED;
  70
  71struct etrace_arch {
  72    struct {
  73        uint32_t arch_id;
  74        uint8_t arch_bits;
  75        uint8_t big_endian;
  76    } guest, host;
  77} QEMU_PACKED;
  78
  79struct etrace_exec {
  80    uint64_t start_time;
  81} QEMU_PACKED;
  82
  83struct etrace_note {
  84    uint64_t time;
  85} QEMU_PACKED;
  86
  87struct etrace_mem {
  88    uint64_t time;
  89    uint64_t vaddr;
  90    uint64_t paddr;
  91    uint64_t value;
  92    uint32_t attr;
  93    uint8_t size;
  94    uint8_t padd[3];
  95} QEMU_PACKED;
  96
  97struct etrace_tb {
  98    uint64_t vaddr;
  99    uint64_t paddr;
 100    uint64_t host_addr;
 101    uint32_t guest_code_len;
 102    uint32_t host_code_len;
 103} QEMU_PACKED;
 104
 105struct etrace_event_u64 {
 106    uint32_t flags;
 107    uint16_t unit_id;
 108    uint16_t __reserved;
 109    uint64_t time;
 110    uint64_t val;
 111    uint64_t prev_val;
 112    uint16_t dev_name_len;
 113    uint16_t event_name_len;
 114} QEMU_PACKED;
 115
 116const char *qemu_arg_etrace;
 117const char *qemu_arg_etrace_flags;
 118struct etracer qemu_etracer = {0};
 119bool qemu_etrace_enabled;
 120
 121void qemu_etrace_cleanup(void)
 122{
 123    etrace_close(&qemu_etracer);
 124}
 125
 126struct {
 127    const char *name;
 128    enum qemu_etrace_flag flags;
 129} qemu_etrace_flagmap[] = {
 130    { "none", ETRACE_F_NONE },
 131    { "exec", ETRACE_F_EXEC },
 132    { "disas", ETRACE_F_TRANSLATION },
 133    { "mem", ETRACE_F_MEM },
 134    { "cpu", ETRACE_F_CPU },
 135    { "gpio", ETRACE_F_GPIO },
 136    { "all", ~0 },
 137    { NULL, 0 },
 138};
 139
 140static uint64_t qemu_etrace_str2flags(const char *str, size_t len)
 141{
 142    uint64_t flags = 0;
 143    unsigned int pos = 0;
 144
 145    while (qemu_etrace_flagmap[pos].name) {
 146        if (len != strlen(qemu_etrace_flagmap[pos].name)) {
 147            pos++;
 148            continue;
 149        }
 150
 151        if (!memcmp(qemu_etrace_flagmap[pos].name, str, len)) {
 152            flags |= qemu_etrace_flagmap[pos].flags;
 153            break;
 154        }
 155        pos++;
 156    }
 157    if (!flags) {
 158        fprintf(stderr, "Invalid etrace flag %s\n", str);
 159        exit(EXIT_FAILURE);
 160    }
 161    return flags;
 162}
 163
 164static uint64_t qemu_etrace_opts2flags(const char *opts)
 165{
 166    uint64_t flags = 0;
 167    const char *prev = opts, *end = opts;
 168
 169    while (prev && *prev) {
 170        while (*end != ',' && *end != 0) {
 171            end++;
 172        }
 173        flags |= qemu_etrace_str2flags(prev, end - prev);
 174        while (*end == ',') {
 175            end++;
 176        }
 177        prev = end;
 178    }
 179    return flags;
 180}
 181
 182static void etrace_write(struct etracer *t, const void *buf, size_t len)
 183{
 184    size_t r;
 185
 186    r = fwrite(buf, 1, len, t->fp);
 187    if (feof(t->fp) || ferror(t->fp)) {
 188        fprintf(stderr, "Etrace peer EOF/disconnected!\n");
 189        /* FIXME: Allow qemu to continue?  */
 190        fclose(t->fp);
 191        t->fp = NULL;
 192        exit(1);
 193    }
 194    /* FIXME: Make this more robust.  */
 195    assert(r == len);
 196}
 197
 198static void etrace_write_header(struct etracer *t, uint16_t type,
 199                                uint16_t unit_id, uint32_t len)
 200{
 201    struct etrace_hdr hdr = {
 202        .type = type,
 203        .unit_id = unit_id,
 204        .len = len
 205    };
 206    etrace_write(t, &hdr, sizeof hdr);
 207}
 208
 209#define UNIX_PREFIX "unix:"
 210
 211static int sk_unix_client(const char *descr)
 212{
 213#ifndef _WIN32
 214    struct sockaddr_un addr;
 215    int fd, nfd;
 216
 217    fd = socket(AF_UNIX, SOCK_STREAM, 0);
 218    printf("connect to %s\n", descr + strlen(UNIX_PREFIX));
 219
 220    memset(&addr, 0, sizeof addr);
 221    addr.sun_family = AF_UNIX;
 222    strncpy(addr.sun_path, descr + strlen(UNIX_PREFIX),
 223            sizeof addr.sun_path);
 224    if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) >= 0) {
 225        return fd;
 226    }
 227
 228    printf("Failed to connect to %s, attempt to listen\n", addr.sun_path);
 229    unlink(addr.sun_path);
 230    /* Failed to connect. Bind, listen and accept.  */
 231    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
 232        goto fail;
 233    }
 234
 235    listen(fd, 5);
 236    nfd = accept(fd, NULL, NULL);
 237    close(fd);
 238    return nfd;
 239fail:
 240    close(fd);
 241#endif
 242    return -1;
 243}
 244
 245static FILE *etrace_open(const char *descr)
 246{
 247    FILE *fp = NULL;
 248    int fd = -1;
 249
 250    if (descr == NULL) {
 251        return NULL;
 252    }
 253
 254    if (memcmp(UNIX_PREFIX, descr, strlen(UNIX_PREFIX)) == 0) {
 255        /* UNIX.  */
 256        fd = sk_unix_client(descr);
 257        fp = fdopen(fd, "w");
 258    } else {
 259        fp = fopen(descr, "w");
 260    }
 261    return fp;
 262}
 263
 264/*
 265 * Initialize a tracing context.
 266 *
 267 * arch_id should identify the architecture. Maybe the ELF machine code?
 268 */
 269bool etrace_init(struct etracer *t, const char *filename,
 270                 const char *opts,
 271                 unsigned int arch_id, unsigned int arch_bits)
 272{
 273    struct etrace_info_data id;
 274    struct etrace_arch arch;
 275
 276    memset(t, 0, sizeof *t);
 277    t->fp = etrace_open(filename);
 278    if (!t->fp) {
 279        return false;
 280    }
 281
 282    memset(&id, 0, sizeof id);
 283    id.version.major = ETRACE_VERSION_MAJOR;
 284    id.version.minor = ETRACE_VERSION_MINOR;
 285    id.attr = 0;
 286    if (tcg_tb_chain) {
 287        id.attr |= ETRACE_INFO_F_TB_CHAINING;
 288    }
 289    etrace_write_header(t, TYPE_INFO, 0, sizeof id);
 290    etrace_write(t, &id, sizeof id);
 291
 292
 293    /* FIXME: Pass info about host.  */
 294    arch.guest.arch_id = arch_id;
 295    t->arch_bits = arch.guest.arch_bits = arch_bits;
 296#ifdef TARGET_WORDS_BIGENDIAN
 297    arch.guest.big_endian = 1;
 298#endif
 299    etrace_write_header(t, TYPE_ARCH, 0, sizeof arch);
 300    etrace_write(t, &arch, sizeof arch);
 301
 302    t->flags = qemu_etrace_opts2flags(opts);
 303    return true;
 304}
 305
 306static void etrace_flush_exec_cache(struct etracer *t)
 307{
 308    size_t size64 = t->exec_cache.pos * sizeof t->exec_cache.t64[0];
 309    size_t size32 = t->exec_cache.pos * sizeof t->exec_cache.t32[0];
 310    size_t size = t->arch_bits == 32 ? size32 : size64;
 311    struct etrace_exec ex;
 312
 313    if (!size) {
 314        return;
 315    }
 316
 317    ex.start_time = t->exec_cache.start_time;
 318
 319    etrace_write_header(t, TYPE_EXEC, t->exec_cache.unit_id, size + sizeof ex);
 320    etrace_write(t, &ex, sizeof ex);
 321    etrace_write(t, &t->exec_cache.t64[0], size);
 322    t->exec_cache.pos = 0;
 323    memset(&t->exec_cache.t64[0], 0, sizeof t->exec_cache.t64);
 324
 325    /* A barrier indicates that the other side can assume order across the
 326       the barrier.  */
 327    etrace_write_header(t, TYPE_BARRIER, t->exec_cache.unit_id, 0);
 328}
 329
 330#define PROXIMITY_MASK (~0xfff)
 331
 332/* Check that the addresses are reasonably near. I.e we didnt change
 333   address space or similar.  */
 334static bool address_near(uint64_t a, uint64_t b)
 335{
 336    a &= PROXIMITY_MASK;
 337    b &= PROXIMITY_MASK;
 338    return a == b;
 339}
 340
 341static bool qualify_merge(uint64_t start, uint64_t end,
 342                          uint64_t new_start, uint64_t new_end)
 343{
 344    if (end != new_start) {
 345        return false;
 346    }
 347
 348    if (start == end || new_start == new_end) {
 349        return false;
 350    }
 351
 352    if (!address_near(start, end)) {
 353        return false;
 354    }
 355    if (!address_near(new_start, new_end)) {
 356        return false;
 357    }
 358
 359    return true;
 360}
 361
 362/* Exec cache accessors. To avoid duplicating src code we use the cpp.  */
 363#define XC_ACCESSOR(field)                                                \
 364static inline void execache_set_ ## field(struct etracer *t,              \
 365                                          unsigned int pos, uint64_t v)   \
 366{                                                                         \
 367    if (t->arch_bits == 32) {                                             \
 368        t->exec_cache.t32[pos].field = v;                                 \
 369    } else {                                                              \
 370        t->exec_cache.t64[pos].field = v;                                 \
 371    }                                                                     \
 372}                                                                         \
 373static inline uint64_t execache_get_ ## field(struct etracer *t,          \
 374                                              unsigned int pos)           \
 375{                                                                         \
 376    if (t->arch_bits == 32) {                                             \
 377        return t->exec_cache.t32[pos].field;                              \
 378    } else {                                                              \
 379        return t->exec_cache.t64[pos].field;                              \
 380    }                                                                     \
 381}
 382
 383XC_ACCESSOR(start)
 384XC_ACCESSOR(end)
 385XC_ACCESSOR(duration)
 386
 387/*
 388 * dump an execution record.
 389 *
 390 * unit_id idenfies the master, e.g CPU #0 or #1 etc.
 391 *
 392 */
 393void etrace_dump_exec(struct etracer *t, unsigned int unit_id,
 394                      uint64_t start, uint64_t end,
 395                      uint64_t start_time, uint32_t duration)
 396{
 397    unsigned int pos;
 398
 399    if (unit_id != t->exec_cache.unit_id) {
 400        etrace_flush_exec_cache(t);
 401        t->exec_cache.unit_id = unit_id;
 402    }
 403
 404    pos = t->exec_cache.pos;
 405    if (pos == 0) {
 406        t->exec_cache.start_time = start_time;
 407    }
 408
 409    assert(t->arch_bits == 32 || t->arch_bits == 64);
 410    if (pos &&
 411        qualify_merge(execache_get_start(t, pos), execache_get_end(t, pos),
 412                      start, end)) {
 413        /* Reuse the old entry.  */
 414        pos -= 1;
 415        execache_set_duration(t, pos, execache_get_duration(t, pos) + duration);
 416    } else {
 417        /* Advance.  */
 418        t->exec_cache.pos += 1;
 419        execache_set_start(t, pos, start);
 420        execache_set_duration(t, pos, duration);
 421    }
 422
 423    execache_set_end(t, pos, end);
 424    if (!tcg_tb_chain) {
 425        assert(execache_get_start(t, pos) <= execache_get_end(t, pos));
 426    }
 427
 428    if (t->exec_cache.pos == EXEC_CACHE_SIZE) {
 429        etrace_flush_exec_cache(t);
 430    }
 431}
 432
 433static void etrace_dump_guestmem(struct etracer *t, AddressSpace *as,
 434                                 uint64_t guest_vaddr, uint64_t guest_paddr,
 435                                 size_t guest_len)
 436{
 437#if defined(CONFIG_USER_ONLY)
 438    /* Currently, user mode address are directly addressable.  */
 439    etrace_write(t, (void *) (uintptr_t) guest_vaddr, guest_len);
 440#else
 441    unsigned char buf[8 * 1024];
 442
 443    /* Once we have per-master address-space support, we can assert()
 444       as not beeing NULL. But for now, provide this fallback.  */
 445    if (as == NULL) {
 446        as = &address_space_memory;
 447    }
 448
 449    /* TODO: We know that tb guest mem is mapped in at this time, so we could
 450       dig out the host ram pointer and directly write from it.  */
 451    while (guest_len) {
 452        unsigned int copylen = guest_len > sizeof buf ? sizeof buf : guest_len;
 453
 454        address_space_rw(as, guest_paddr, MEMTXATTRS_UNSPECIFIED, buf, copylen, 0);
 455        etrace_write(t, buf, copylen);
 456        guest_len -= copylen;
 457    }
 458#endif
 459}
 460
 461/*
 462 * Dump a pkg of TB info.
 463 *
 464 * unit_id idenfies the master
 465 * guest vaddr and paddr are the virtual and physical addresses
 466 * containing guest code.
 467 *
 468 * host_buf points the translated host machine code.
 469 */
 470void etrace_dump_tb(struct etracer *t, AddressSpace *as, uint16_t unit_id,
 471                    uint64_t guest_vaddr, uint64_t guest_paddr,
 472                    size_t guest_len,
 473                    void *host_buf, size_t host_len)
 474{
 475    struct etrace_tb tb;
 476    size_t size;
 477
 478    tb.vaddr = guest_vaddr;
 479    tb.paddr = guest_paddr;
 480    tb.host_addr = (intptr_t) host_buf;
 481    tb.guest_code_len = guest_len;
 482    tb.host_code_len = host_len;
 483
 484    size = sizeof tb + guest_len + host_len;
 485    /* Write headers.  */
 486    etrace_write_header(t, TYPE_TB, unit_id, size);
 487    etrace_write(t, &tb, sizeof tb);
 488    /* Guest code.  */
 489    etrace_dump_guestmem(t, as, guest_vaddr, guest_paddr, guest_len);
 490    /* Host/native code.  */
 491    etrace_write(t, host_buf, host_len);
 492}
 493
 494static uint64_t etrace_time(void)
 495{
 496#if defined(CONFIG_USER_ONLY)
 497    return 0;
 498#else
 499    uint64_t t;
 500    CPUState *cpu = current_cpu;
 501
 502    if (cpu) {
 503        void *tb = cpu->current_tb;
 504
 505       /* FIXME: We are not executing any tb at this stage.
 506           set current_tb to NULL to allow icount reads.  */
 507        cpu->current_tb = NULL;
 508        t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 509        cpu->current_tb = tb;
 510    } else {
 511        t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 512    }
 513    return t;
 514#endif
 515}
 516
 517void etrace_mem_access(struct etracer *t, uint16_t unit_id,
 518                       uint64_t guest_vaddr, uint64_t guest_paddr,
 519                       size_t size, uint64_t attr, uint64_t val)
 520{
 521    struct etrace_mem mem;
 522
 523    etrace_flush_exec_cache(t);
 524    mem.time = etrace_time();
 525    mem.vaddr = guest_vaddr;
 526    mem.paddr = guest_paddr;
 527    mem.attr = attr;
 528    mem.size = size;
 529    mem.value = val;
 530
 531    /* Write headers.  */
 532    etrace_write_header(t, TYPE_MEM, unit_id, sizeof mem);
 533    etrace_write(t, &mem, sizeof mem);
 534}
 535
 536void etrace_dump_exec_start(struct etracer *t,
 537                            unsigned int unit_id,
 538                            uint64_t start)
 539{
 540    assert(!t->exec_start_valid);
 541    t->exec_start = start;
 542    t->exec_start_time = etrace_time();
 543    t->exec_start_valid = true;
 544}
 545
 546void etrace_dump_exec_end(struct etracer *t,
 547                          unsigned int unit_id,
 548                          uint64_t end)
 549{
 550    int64_t tdiff;
 551    if (!t->exec_start_valid) {
 552        printf("exec_start not valid! %" PRIx64 " %" PRIx64 "\n", t->exec_start, end);
 553    }
 554    tdiff = etrace_time() - t->exec_start_time;
 555    if (tdiff < 0) {
 556        printf("tdiff=%" PRId64 "\n", tdiff);
 557        fflush(NULL);
 558    }
 559    assert(tdiff >= 0);
 560    assert(t->exec_start_valid);
 561    t->exec_start_valid = false;
 562    etrace_dump_exec(t, unit_id, t->exec_start, end, t->exec_start_time, tdiff);
 563}
 564
 565void etrace_note_write(struct etracer *t, unsigned int unit_id,
 566                       void *buf, size_t len)
 567{
 568    struct etrace_note nt;
 569
 570    etrace_flush_exec_cache(t);
 571
 572    nt.time = etrace_time();
 573    etrace_write_header(t, TYPE_NOTE, unit_id, sizeof nt + len);
 574    etrace_write(t, &nt, sizeof nt);
 575    etrace_write(t, buf, len);
 576}
 577
 578int etrace_note_fprintf(FILE *fp,
 579                        const char *fmt, ...)
 580{
 581    struct etracer *t = (void *) fp;
 582    va_list ap;
 583    char *s;
 584    int r;
 585
 586    va_start(ap, fmt);
 587    r = vasprintf(&s, fmt, ap);
 588    if (r > 0) {
 589        etrace_note_write(t, t->current_unit_id, s, r);
 590    }
 591    va_end(ap);
 592    return r;
 593}
 594
 595void etrace_event_u64(struct etracer *t, uint16_t unit_id,
 596                      uint32_t flags,
 597                      const char *dev_name,
 598                      const char *event_name,
 599                      uint64_t val, uint64_t prev_val)
 600{
 601    struct etrace_event_u64 event;
 602    size_t dev_len, event_len;
 603
 604    etrace_flush_exec_cache(t);
 605
 606    dev_len = strlen(dev_name) + 1;
 607    event_len = strlen(event_name) + 1;
 608
 609    event.time = etrace_time();
 610    event.flags = flags;
 611    event.unit_id = unit_id;
 612    event.dev_name_len = dev_len;
 613    event.event_name_len = event_len;
 614    event.val = val;
 615    event.prev_val = prev_val;
 616    etrace_write_header(t, TYPE_EVENT_U64, unit_id,
 617                        sizeof event + dev_len + event_len);
 618    etrace_write(t, &event, sizeof event);
 619    etrace_write(t, dev_name, dev_len);
 620    etrace_write(t, event_name, event_len);
 621}
 622
 623void etrace_close(struct etracer *t)
 624{
 625    if (t->fp) {
 626        etrace_flush_exec_cache(t);
 627        fclose(t->fp);
 628    }
 629}
 630