kbuffer-parse.c (18654B)
1// SPDX-License-Identifier: LGPL-2.1 2/* 3 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 4 * 5 */ 6#include <stdio.h> 7#include <stdlib.h> 8#include <string.h> 9 10#include "kbuffer.h" 11 12#define MISSING_EVENTS (1UL << 31) 13#define MISSING_STORED (1UL << 30) 14 15#define COMMIT_MASK ((1 << 27) - 1) 16 17enum { 18 KBUFFER_FL_HOST_BIG_ENDIAN = (1<<0), 19 KBUFFER_FL_BIG_ENDIAN = (1<<1), 20 KBUFFER_FL_LONG_8 = (1<<2), 21 KBUFFER_FL_OLD_FORMAT = (1<<3), 22}; 23 24#define ENDIAN_MASK (KBUFFER_FL_HOST_BIG_ENDIAN | KBUFFER_FL_BIG_ENDIAN) 25 26/** kbuffer 27 * @timestamp - timestamp of current event 28 * @lost_events - # of lost events between this subbuffer and previous 29 * @flags - special flags of the kbuffer 30 * @subbuffer - pointer to the sub-buffer page 31 * @data - pointer to the start of data on the sub-buffer page 32 * @index - index from @data to the @curr event data 33 * @curr - offset from @data to the start of current event 34 * (includes metadata) 35 * @next - offset from @data to the start of next event 36 * @size - The size of data on @data 37 * @start - The offset from @subbuffer where @data lives 38 * 39 * @read_4 - Function to read 4 raw bytes (may swap) 40 * @read_8 - Function to read 8 raw bytes (may swap) 41 * @read_long - Function to read a long word (4 or 8 bytes with needed swap) 42 */ 43struct kbuffer { 44 unsigned long long timestamp; 45 long long lost_events; 46 unsigned long flags; 47 void *subbuffer; 48 void *data; 49 unsigned int index; 50 unsigned int curr; 51 unsigned int next; 52 unsigned int size; 53 unsigned int start; 54 55 unsigned int (*read_4)(void *ptr); 56 unsigned long long (*read_8)(void *ptr); 57 unsigned long long (*read_long)(struct kbuffer *kbuf, void *ptr); 58 int (*next_event)(struct kbuffer *kbuf); 59}; 60 61static void *zmalloc(size_t size) 62{ 63 return calloc(1, size); 64} 65 66static int host_is_bigendian(void) 67{ 68 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; 69 unsigned int *ptr; 70 71 ptr = (unsigned int *)str; 72 return *ptr == 0x01020304; 73} 74 75static int do_swap(struct kbuffer *kbuf) 76{ 77 return ((kbuf->flags & KBUFFER_FL_HOST_BIG_ENDIAN) + kbuf->flags) & 78 ENDIAN_MASK; 79} 80 81static unsigned long long __read_8(void *ptr) 82{ 83 unsigned long long data = *(unsigned long long *)ptr; 84 85 return data; 86} 87 88static unsigned long long __read_8_sw(void *ptr) 89{ 90 unsigned long long data = *(unsigned long long *)ptr; 91 unsigned long long swap; 92 93 swap = ((data & 0xffULL) << 56) | 94 ((data & (0xffULL << 8)) << 40) | 95 ((data & (0xffULL << 16)) << 24) | 96 ((data & (0xffULL << 24)) << 8) | 97 ((data & (0xffULL << 32)) >> 8) | 98 ((data & (0xffULL << 40)) >> 24) | 99 ((data & (0xffULL << 48)) >> 40) | 100 ((data & (0xffULL << 56)) >> 56); 101 102 return swap; 103} 104 105static unsigned int __read_4(void *ptr) 106{ 107 unsigned int data = *(unsigned int *)ptr; 108 109 return data; 110} 111 112static unsigned int __read_4_sw(void *ptr) 113{ 114 unsigned int data = *(unsigned int *)ptr; 115 unsigned int swap; 116 117 swap = ((data & 0xffULL) << 24) | 118 ((data & (0xffULL << 8)) << 8) | 119 ((data & (0xffULL << 16)) >> 8) | 120 ((data & (0xffULL << 24)) >> 24); 121 122 return swap; 123} 124 125static unsigned long long read_8(struct kbuffer *kbuf, void *ptr) 126{ 127 return kbuf->read_8(ptr); 128} 129 130static unsigned int read_4(struct kbuffer *kbuf, void *ptr) 131{ 132 return kbuf->read_4(ptr); 133} 134 135static unsigned long long __read_long_8(struct kbuffer *kbuf, void *ptr) 136{ 137 return kbuf->read_8(ptr); 138} 139 140static unsigned long long __read_long_4(struct kbuffer *kbuf, void *ptr) 141{ 142 return kbuf->read_4(ptr); 143} 144 145static unsigned long long read_long(struct kbuffer *kbuf, void *ptr) 146{ 147 return kbuf->read_long(kbuf, ptr); 148} 149 150static int calc_index(struct kbuffer *kbuf, void *ptr) 151{ 152 return (unsigned long)ptr - (unsigned long)kbuf->data; 153} 154 155static int __next_event(struct kbuffer *kbuf); 156 157/** 158 * kbuffer_alloc - allocat a new kbuffer 159 * @size; enum to denote size of word 160 * @endian: enum to denote endianness 161 * 162 * Allocates and returns a new kbuffer. 163 */ 164struct kbuffer * 165kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian) 166{ 167 struct kbuffer *kbuf; 168 int flags = 0; 169 170 switch (size) { 171 case KBUFFER_LSIZE_4: 172 break; 173 case KBUFFER_LSIZE_8: 174 flags |= KBUFFER_FL_LONG_8; 175 break; 176 default: 177 return NULL; 178 } 179 180 switch (endian) { 181 case KBUFFER_ENDIAN_LITTLE: 182 break; 183 case KBUFFER_ENDIAN_BIG: 184 flags |= KBUFFER_FL_BIG_ENDIAN; 185 break; 186 default: 187 return NULL; 188 } 189 190 kbuf = zmalloc(sizeof(*kbuf)); 191 if (!kbuf) 192 return NULL; 193 194 kbuf->flags = flags; 195 196 if (host_is_bigendian()) 197 kbuf->flags |= KBUFFER_FL_HOST_BIG_ENDIAN; 198 199 if (do_swap(kbuf)) { 200 kbuf->read_8 = __read_8_sw; 201 kbuf->read_4 = __read_4_sw; 202 } else { 203 kbuf->read_8 = __read_8; 204 kbuf->read_4 = __read_4; 205 } 206 207 if (kbuf->flags & KBUFFER_FL_LONG_8) 208 kbuf->read_long = __read_long_8; 209 else 210 kbuf->read_long = __read_long_4; 211 212 /* May be changed by kbuffer_set_old_format() */ 213 kbuf->next_event = __next_event; 214 215 return kbuf; 216} 217 218/** kbuffer_free - free an allocated kbuffer 219 * @kbuf: The kbuffer to free 220 * 221 * Can take NULL as a parameter. 222 */ 223void kbuffer_free(struct kbuffer *kbuf) 224{ 225 free(kbuf); 226} 227 228static unsigned int type4host(struct kbuffer *kbuf, 229 unsigned int type_len_ts) 230{ 231 if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) 232 return (type_len_ts >> 29) & 3; 233 else 234 return type_len_ts & 3; 235} 236 237static unsigned int len4host(struct kbuffer *kbuf, 238 unsigned int type_len_ts) 239{ 240 if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) 241 return (type_len_ts >> 27) & 7; 242 else 243 return (type_len_ts >> 2) & 7; 244} 245 246static unsigned int type_len4host(struct kbuffer *kbuf, 247 unsigned int type_len_ts) 248{ 249 if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) 250 return (type_len_ts >> 27) & ((1 << 5) - 1); 251 else 252 return type_len_ts & ((1 << 5) - 1); 253} 254 255static unsigned int ts4host(struct kbuffer *kbuf, 256 unsigned int type_len_ts) 257{ 258 if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) 259 return type_len_ts & ((1 << 27) - 1); 260 else 261 return type_len_ts >> 5; 262} 263 264/* 265 * Linux 2.6.30 and earlier (not much ealier) had a different 266 * ring buffer format. It should be obsolete, but we handle it anyway. 267 */ 268enum old_ring_buffer_type { 269 OLD_RINGBUF_TYPE_PADDING, 270 OLD_RINGBUF_TYPE_TIME_EXTEND, 271 OLD_RINGBUF_TYPE_TIME_STAMP, 272 OLD_RINGBUF_TYPE_DATA, 273}; 274 275static unsigned int old_update_pointers(struct kbuffer *kbuf) 276{ 277 unsigned long long extend; 278 unsigned int type_len_ts; 279 unsigned int type; 280 unsigned int len; 281 unsigned int delta; 282 unsigned int length; 283 void *ptr = kbuf->data + kbuf->curr; 284 285 type_len_ts = read_4(kbuf, ptr); 286 ptr += 4; 287 288 type = type4host(kbuf, type_len_ts); 289 len = len4host(kbuf, type_len_ts); 290 delta = ts4host(kbuf, type_len_ts); 291 292 switch (type) { 293 case OLD_RINGBUF_TYPE_PADDING: 294 kbuf->next = kbuf->size; 295 return 0; 296 297 case OLD_RINGBUF_TYPE_TIME_EXTEND: 298 extend = read_4(kbuf, ptr); 299 extend <<= TS_SHIFT; 300 extend += delta; 301 delta = extend; 302 ptr += 4; 303 length = 0; 304 break; 305 306 case OLD_RINGBUF_TYPE_TIME_STAMP: 307 /* should never happen! */ 308 kbuf->curr = kbuf->size; 309 kbuf->next = kbuf->size; 310 kbuf->index = kbuf->size; 311 return -1; 312 default: 313 if (len) 314 length = len * 4; 315 else { 316 length = read_4(kbuf, ptr); 317 length -= 4; 318 ptr += 4; 319 } 320 break; 321 } 322 323 kbuf->timestamp += delta; 324 kbuf->index = calc_index(kbuf, ptr); 325 kbuf->next = kbuf->index + length; 326 327 return type; 328} 329 330static int __old_next_event(struct kbuffer *kbuf) 331{ 332 int type; 333 334 do { 335 kbuf->curr = kbuf->next; 336 if (kbuf->next >= kbuf->size) 337 return -1; 338 type = old_update_pointers(kbuf); 339 } while (type == OLD_RINGBUF_TYPE_TIME_EXTEND || type == OLD_RINGBUF_TYPE_PADDING); 340 341 return 0; 342} 343 344static unsigned int 345translate_data(struct kbuffer *kbuf, void *data, void **rptr, 346 unsigned long long *delta, int *length) 347{ 348 unsigned long long extend; 349 unsigned int type_len_ts; 350 unsigned int type_len; 351 352 type_len_ts = read_4(kbuf, data); 353 data += 4; 354 355 type_len = type_len4host(kbuf, type_len_ts); 356 *delta = ts4host(kbuf, type_len_ts); 357 358 switch (type_len) { 359 case KBUFFER_TYPE_PADDING: 360 *length = read_4(kbuf, data); 361 break; 362 363 case KBUFFER_TYPE_TIME_EXTEND: 364 case KBUFFER_TYPE_TIME_STAMP: 365 extend = read_4(kbuf, data); 366 data += 4; 367 extend <<= TS_SHIFT; 368 extend += *delta; 369 *delta = extend; 370 *length = 0; 371 break; 372 373 case 0: 374 *length = read_4(kbuf, data) - 4; 375 *length = (*length + 3) & ~3; 376 data += 4; 377 break; 378 default: 379 *length = type_len * 4; 380 break; 381 } 382 383 *rptr = data; 384 385 return type_len; 386} 387 388static unsigned int update_pointers(struct kbuffer *kbuf) 389{ 390 unsigned long long delta; 391 unsigned int type_len; 392 int length; 393 void *ptr = kbuf->data + kbuf->curr; 394 395 type_len = translate_data(kbuf, ptr, &ptr, &delta, &length); 396 397 if (type_len == KBUFFER_TYPE_TIME_STAMP) 398 kbuf->timestamp = delta; 399 else 400 kbuf->timestamp += delta; 401 402 kbuf->index = calc_index(kbuf, ptr); 403 kbuf->next = kbuf->index + length; 404 405 return type_len; 406} 407 408/** 409 * kbuffer_translate_data - read raw data to get a record 410 * @swap: Set to 1 if bytes in words need to be swapped when read 411 * @data: The raw data to read 412 * @size: Address to store the size of the event data. 413 * 414 * Returns a pointer to the event data. To determine the entire 415 * record size (record metadata + data) just add the difference between 416 * @data and the returned value to @size. 417 */ 418void *kbuffer_translate_data(int swap, void *data, unsigned int *size) 419{ 420 unsigned long long delta; 421 struct kbuffer kbuf; 422 int type_len; 423 int length; 424 void *ptr; 425 426 if (swap) { 427 kbuf.read_8 = __read_8_sw; 428 kbuf.read_4 = __read_4_sw; 429 kbuf.flags = host_is_bigendian() ? 0 : KBUFFER_FL_BIG_ENDIAN; 430 } else { 431 kbuf.read_8 = __read_8; 432 kbuf.read_4 = __read_4; 433 kbuf.flags = host_is_bigendian() ? KBUFFER_FL_BIG_ENDIAN: 0; 434 } 435 436 type_len = translate_data(&kbuf, data, &ptr, &delta, &length); 437 switch (type_len) { 438 case KBUFFER_TYPE_PADDING: 439 case KBUFFER_TYPE_TIME_EXTEND: 440 case KBUFFER_TYPE_TIME_STAMP: 441 return NULL; 442 } 443 444 *size = length; 445 446 return ptr; 447} 448 449static int __next_event(struct kbuffer *kbuf) 450{ 451 int type; 452 453 do { 454 kbuf->curr = kbuf->next; 455 if (kbuf->next >= kbuf->size) 456 return -1; 457 type = update_pointers(kbuf); 458 } while (type == KBUFFER_TYPE_TIME_EXTEND || 459 type == KBUFFER_TYPE_TIME_STAMP || 460 type == KBUFFER_TYPE_PADDING); 461 462 return 0; 463} 464 465static int next_event(struct kbuffer *kbuf) 466{ 467 return kbuf->next_event(kbuf); 468} 469 470/** 471 * kbuffer_next_event - increment the current pointer 472 * @kbuf: The kbuffer to read 473 * @ts: Address to store the next record's timestamp (may be NULL to ignore) 474 * 475 * Increments the pointers into the subbuffer of the kbuffer to point to the 476 * next event so that the next kbuffer_read_event() will return a 477 * new event. 478 * 479 * Returns the data of the next event if a new event exists on the subbuffer, 480 * NULL otherwise. 481 */ 482void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts) 483{ 484 int ret; 485 486 if (!kbuf || !kbuf->subbuffer) 487 return NULL; 488 489 ret = next_event(kbuf); 490 if (ret < 0) 491 return NULL; 492 493 if (ts) 494 *ts = kbuf->timestamp; 495 496 return kbuf->data + kbuf->index; 497} 498 499/** 500 * kbuffer_load_subbuffer - load a new subbuffer into the kbuffer 501 * @kbuf: The kbuffer to load 502 * @subbuffer: The subbuffer to load into @kbuf. 503 * 504 * Load a new subbuffer (page) into @kbuf. This will reset all 505 * the pointers and update the @kbuf timestamp. The next read will 506 * return the first event on @subbuffer. 507 * 508 * Returns 0 on succes, -1 otherwise. 509 */ 510int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer) 511{ 512 unsigned long long flags; 513 void *ptr = subbuffer; 514 515 if (!kbuf || !subbuffer) 516 return -1; 517 518 kbuf->subbuffer = subbuffer; 519 520 kbuf->timestamp = read_8(kbuf, ptr); 521 ptr += 8; 522 523 kbuf->curr = 0; 524 525 if (kbuf->flags & KBUFFER_FL_LONG_8) 526 kbuf->start = 16; 527 else 528 kbuf->start = 12; 529 530 kbuf->data = subbuffer + kbuf->start; 531 532 flags = read_long(kbuf, ptr); 533 kbuf->size = (unsigned int)flags & COMMIT_MASK; 534 535 if (flags & MISSING_EVENTS) { 536 if (flags & MISSING_STORED) { 537 ptr = kbuf->data + kbuf->size; 538 kbuf->lost_events = read_long(kbuf, ptr); 539 } else 540 kbuf->lost_events = -1; 541 } else 542 kbuf->lost_events = 0; 543 544 kbuf->index = 0; 545 kbuf->next = 0; 546 547 next_event(kbuf); 548 549 return 0; 550} 551 552/** 553 * kbuffer_subbuf_timestamp - read the timestamp from a sub buffer 554 * @kbuf: The kbuffer to load 555 * @subbuf: The subbuffer to read from. 556 * 557 * Return the timestamp from a subbuffer. 558 */ 559unsigned long long kbuffer_subbuf_timestamp(struct kbuffer *kbuf, void *subbuf) 560{ 561 return kbuf->read_8(subbuf); 562} 563 564/** 565 * kbuffer_ptr_delta - read the delta field from a record 566 * @kbuf: The kbuffer to load 567 * @ptr: The record in the buffe. 568 * 569 * Return the timestamp delta from a record 570 */ 571unsigned int kbuffer_ptr_delta(struct kbuffer *kbuf, void *ptr) 572{ 573 unsigned int type_len_ts; 574 575 type_len_ts = read_4(kbuf, ptr); 576 return ts4host(kbuf, type_len_ts); 577} 578 579 580/** 581 * kbuffer_read_event - read the next event in the kbuffer subbuffer 582 * @kbuf: The kbuffer to read from 583 * @ts: The address to store the timestamp of the event (may be NULL to ignore) 584 * 585 * Returns a pointer to the data part of the current event. 586 * NULL if no event is left on the subbuffer. 587 */ 588void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts) 589{ 590 if (!kbuf || !kbuf->subbuffer) 591 return NULL; 592 593 if (kbuf->curr >= kbuf->size) 594 return NULL; 595 596 if (ts) 597 *ts = kbuf->timestamp; 598 return kbuf->data + kbuf->index; 599} 600 601/** 602 * kbuffer_timestamp - Return the timestamp of the current event 603 * @kbuf: The kbuffer to read from 604 * 605 * Returns the timestamp of the current (next) event. 606 */ 607unsigned long long kbuffer_timestamp(struct kbuffer *kbuf) 608{ 609 return kbuf->timestamp; 610} 611 612/** 613 * kbuffer_read_at_offset - read the event that is at offset 614 * @kbuf: The kbuffer to read from 615 * @offset: The offset into the subbuffer 616 * @ts: The address to store the timestamp of the event (may be NULL to ignore) 617 * 618 * The @offset must be an index from the @kbuf subbuffer beginning. 619 * If @offset is bigger than the stored subbuffer, NULL will be returned. 620 * 621 * Returns the data of the record that is at @offset. Note, @offset does 622 * not need to be the start of the record, the offset just needs to be 623 * in the record (or beginning of it). 624 * 625 * Note, the kbuf timestamp and pointers are updated to the 626 * returned record. That is, kbuffer_read_event() will return the same 627 * data and timestamp, and kbuffer_next_event() will increment from 628 * this record. 629 */ 630void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, 631 unsigned long long *ts) 632{ 633 void *data; 634 635 if (offset < kbuf->start) 636 offset = 0; 637 else 638 offset -= kbuf->start; 639 640 /* Reset the buffer */ 641 kbuffer_load_subbuffer(kbuf, kbuf->subbuffer); 642 data = kbuffer_read_event(kbuf, ts); 643 644 while (kbuf->curr < offset) { 645 data = kbuffer_next_event(kbuf, ts); 646 if (!data) 647 break; 648 } 649 650 return data; 651} 652 653/** 654 * kbuffer_subbuffer_size - the size of the loaded subbuffer 655 * @kbuf: The kbuffer to read from 656 * 657 * Returns the size of the subbuffer. Note, this size is 658 * where the last event resides. The stored subbuffer may actually be 659 * bigger due to padding and such. 660 */ 661int kbuffer_subbuffer_size(struct kbuffer *kbuf) 662{ 663 return kbuf->size; 664} 665 666/** 667 * kbuffer_curr_index - Return the index of the record 668 * @kbuf: The kbuffer to read from 669 * 670 * Returns the index from the start of the data part of 671 * the subbuffer to the current location. Note this is not 672 * from the start of the subbuffer. An index of zero will 673 * point to the first record. Use kbuffer_curr_offset() for 674 * the actually offset (that can be used by kbuffer_read_at_offset()) 675 */ 676int kbuffer_curr_index(struct kbuffer *kbuf) 677{ 678 return kbuf->curr; 679} 680 681/** 682 * kbuffer_curr_offset - Return the offset of the record 683 * @kbuf: The kbuffer to read from 684 * 685 * Returns the offset from the start of the subbuffer to the 686 * current location. 687 */ 688int kbuffer_curr_offset(struct kbuffer *kbuf) 689{ 690 return kbuf->curr + kbuf->start; 691} 692 693/** 694 * kbuffer_event_size - return the size of the event data 695 * @kbuf: The kbuffer to read 696 * 697 * Returns the size of the event data (the payload not counting 698 * the meta data of the record) of the current event. 699 */ 700int kbuffer_event_size(struct kbuffer *kbuf) 701{ 702 return kbuf->next - kbuf->index; 703} 704 705/** 706 * kbuffer_curr_size - return the size of the entire record 707 * @kbuf: The kbuffer to read 708 * 709 * Returns the size of the entire record (meta data and payload) 710 * of the current event. 711 */ 712int kbuffer_curr_size(struct kbuffer *kbuf) 713{ 714 return kbuf->next - kbuf->curr; 715} 716 717/** 718 * kbuffer_missed_events - return the # of missed events from last event. 719 * @kbuf: The kbuffer to read from 720 * 721 * Returns the # of missed events (if recorded) before the current 722 * event. Note, only events on the beginning of a subbuffer can 723 * have missed events, all other events within the buffer will be 724 * zero. 725 */ 726int kbuffer_missed_events(struct kbuffer *kbuf) 727{ 728 /* Only the first event can have missed events */ 729 if (kbuf->curr) 730 return 0; 731 732 return kbuf->lost_events; 733} 734 735/** 736 * kbuffer_set_old_forma - set the kbuffer to use the old format parsing 737 * @kbuf: The kbuffer to set 738 * 739 * This is obsolete (or should be). The first kernels to use the 740 * new ring buffer had a slightly different ring buffer format 741 * (2.6.30 and earlier). It is still somewhat supported by kbuffer, 742 * but should not be counted on in the future. 743 */ 744void kbuffer_set_old_format(struct kbuffer *kbuf) 745{ 746 kbuf->flags |= KBUFFER_FL_OLD_FORMAT; 747 748 kbuf->next_event = __old_next_event; 749} 750 751/** 752 * kbuffer_start_of_data - return offset of where data starts on subbuffer 753 * @kbuf: The kbuffer 754 * 755 * Returns the location on the subbuffer where the data starts. 756 */ 757int kbuffer_start_of_data(struct kbuffer *kbuf) 758{ 759 return kbuf->start; 760} 761 762/** 763 * kbuffer_raw_get - get raw buffer info 764 * @kbuf: The kbuffer 765 * @subbuf: Start of mapped subbuffer 766 * @info: Info descriptor to fill in 767 * 768 * For debugging. This can return internals of the ring buffer. 769 * Expects to have info->next set to what it will read. 770 * The type, length and timestamp delta will be filled in, and 771 * @info->next will be updated to the next element. 772 * The @subbuf is used to know if the info is passed the end of 773 * data and NULL will be returned if it is. 774 */ 775struct kbuffer_raw_info * 776kbuffer_raw_get(struct kbuffer *kbuf, void *subbuf, struct kbuffer_raw_info *info) 777{ 778 unsigned long long flags; 779 unsigned long long delta; 780 unsigned int type_len; 781 unsigned int size; 782 int start; 783 int length; 784 void *ptr = info->next; 785 786 if (!kbuf || !subbuf) 787 return NULL; 788 789 if (kbuf->flags & KBUFFER_FL_LONG_8) 790 start = 16; 791 else 792 start = 12; 793 794 flags = read_long(kbuf, subbuf + 8); 795 size = (unsigned int)flags & COMMIT_MASK; 796 797 if (ptr < subbuf || ptr >= subbuf + start + size) 798 return NULL; 799 800 type_len = translate_data(kbuf, ptr, &ptr, &delta, &length); 801 802 info->next = ptr + length; 803 804 info->type = type_len; 805 info->delta = delta; 806 info->length = length; 807 808 return info; 809}