diff options
Diffstat (limited to 'trace-input.c')
-rw-r--r-- | trace-input.c | 133 |
1 files changed, 120 insertions, 13 deletions
diff --git a/trace-input.c b/trace-input.c index a8fa871..f3dff08 100644 --- a/trace-input.c +++ b/trace-input.c | |||
@@ -740,6 +740,28 @@ static void free_next(struct tracecmd_input *handle, int cpu) | |||
740 | free_record(record); | 740 | free_record(record); |
741 | } | 741 | } |
742 | 742 | ||
743 | static int read_page_flags(struct pevent *pevent, void **ptr) | ||
744 | { | ||
745 | unsigned int flags; | ||
746 | |||
747 | *ptr += 8; | ||
748 | switch (pevent->header_page_size_size) { | ||
749 | case 4: | ||
750 | flags = data2host4(pevent, *ptr); | ||
751 | *ptr += 4; | ||
752 | break; | ||
753 | case 8: | ||
754 | flags = (unsigned int)data2host8(pevent, *ptr); | ||
755 | *ptr += 8; | ||
756 | break; | ||
757 | default: | ||
758 | warning("bad long size"); | ||
759 | return -1; | ||
760 | } | ||
761 | |||
762 | return flags; | ||
763 | } | ||
764 | |||
743 | /* | 765 | /* |
744 | * Page is mapped, now read in the page header info. | 766 | * Page is mapped, now read in the page header info. |
745 | */ | 767 | */ |
@@ -756,20 +778,9 @@ static int update_page_info(struct tracecmd_input *handle, int cpu) | |||
756 | } | 778 | } |
757 | 779 | ||
758 | handle->cpu_data[cpu].timestamp = data2host8(pevent, ptr); | 780 | handle->cpu_data[cpu].timestamp = data2host8(pevent, ptr); |
759 | ptr += 8; | 781 | flags = read_page_flags(pevent, &ptr); |
760 | switch (pevent->header_page_size_size) { | 782 | if (flags == -1U) |
761 | case 4: | ||
762 | flags = data2host4(pevent, ptr); | ||
763 | ptr += 4; | ||
764 | break; | ||
765 | case 8: | ||
766 | flags = (unsigned int)data2host8(pevent, ptr); | ||
767 | ptr += 8; | ||
768 | break; | ||
769 | default: | ||
770 | warning("bad long size"); | ||
771 | return -1; | 783 | return -1; |
772 | } | ||
773 | 784 | ||
774 | handle->cpu_data[cpu].page_size = flags & COMMIT_MASK; | 785 | handle->cpu_data[cpu].page_size = flags & COMMIT_MASK; |
775 | 786 | ||
@@ -1506,6 +1517,102 @@ tracecmd_translate_data(struct tracecmd_input *handle, | |||
1506 | } | 1517 | } |
1507 | 1518 | ||
1508 | /** | 1519 | /** |
1520 | * tracecmd_read_page_record - read a record off of a page | ||
1521 | * @pevent: pevent used to parse the page | ||
1522 | * @page: the page to read | ||
1523 | * @size: the size of the page | ||
1524 | * @last_record: last record read from this page. | ||
1525 | * | ||
1526 | * If a ring buffer page is available, and the need to parse it | ||
1527 | * without having a handle, then this function can be used. | ||
1528 | * | ||
1529 | * The @pevent needs to be initialized to have the page header information | ||
1530 | * already available. | ||
1531 | * | ||
1532 | * The @last_record is used to know where to read the next record from. | ||
1533 | * If @last_record is NULL, the first record on the page will be read. | ||
1534 | * | ||
1535 | * Returns: | ||
1536 | * A newly allocated record that must be freed with free_record() if | ||
1537 | * a record is found. Otherwise NULL is returned if the record is bad | ||
1538 | * or no more records exist. | ||
1539 | */ | ||
1540 | struct record * | ||
1541 | tracecmd_read_page_record(struct pevent *pevent, void *page, int size, | ||
1542 | struct record *last_record) | ||
1543 | { | ||
1544 | unsigned long long extend; | ||
1545 | unsigned long long ts; | ||
1546 | unsigned int type_len; | ||
1547 | unsigned int flags; | ||
1548 | struct record *record; | ||
1549 | int page_size; | ||
1550 | int length; | ||
1551 | void *ptr; | ||
1552 | |||
1553 | if (!last_record) { | ||
1554 | ptr = page; | ||
1555 | flags = read_page_flags(pevent, &ptr); | ||
1556 | if (flags == -1U) | ||
1557 | return NULL; | ||
1558 | page_size = flags & COMMIT_MASK; | ||
1559 | if (page_size > size) { | ||
1560 | warning("tracecmd_read_page_record: page_size > size"); | ||
1561 | return NULL; | ||
1562 | } | ||
1563 | ptr = page + pevent->header_page_data_offset; | ||
1564 | ts = data2host8(pevent, page); | ||
1565 | } else { | ||
1566 | if (last_record->data < page || last_record->data >= (page + size)) { | ||
1567 | warning("tracecmd_read_page_record: bad last record (size=%u)", | ||
1568 | last_record->size); | ||
1569 | return NULL; | ||
1570 | } | ||
1571 | ptr = last_record->data + last_record->size; | ||
1572 | ts = last_record->ts; | ||
1573 | } | ||
1574 | |||
1575 | if (ptr >= page + size) | ||
1576 | return NULL; | ||
1577 | |||
1578 | read_again: | ||
1579 | type_len = translate_data(pevent, &ptr, &extend, &length); | ||
1580 | |||
1581 | switch (type_len) { | ||
1582 | case RINGBUF_TYPE_PADDING: | ||
1583 | return NULL; | ||
1584 | case RINGBUF_TYPE_TIME_EXTEND: | ||
1585 | ts += extend; | ||
1586 | /* fall through */ | ||
1587 | case RINGBUF_TYPE_TIME_STAMP: | ||
1588 | goto read_again; | ||
1589 | default: | ||
1590 | break; | ||
1591 | } | ||
1592 | |||
1593 | if (length < 0 || ptr + length > page + size) { | ||
1594 | warning("tracecmd_read_page_record: bad record (size=%u)", | ||
1595 | length); | ||
1596 | return NULL; | ||
1597 | } | ||
1598 | |||
1599 | ts += extend; | ||
1600 | |||
1601 | record = malloc(sizeof(*record)); | ||
1602 | if (!record) | ||
1603 | return NULL; | ||
1604 | memset(record, 0, sizeof(*record)); | ||
1605 | |||
1606 | record->ts = ts; | ||
1607 | record->size = length; | ||
1608 | record->cpu = 0; | ||
1609 | record->data = ptr; | ||
1610 | record->ref_count = 1; | ||
1611 | |||
1612 | return record; | ||
1613 | } | ||
1614 | |||
1615 | /** | ||
1509 | * tracecmd_peek_data - return the record at the current location. | 1616 | * tracecmd_peek_data - return the record at the current location. |
1510 | * @handle: input handle for the trace.dat file | 1617 | * @handle: input handle for the trace.dat file |
1511 | * @cpu: the CPU to pull from | 1618 | * @cpu: the CPU to pull from |