207template<
typename atomic_var_t>
210 using guest_ptr_t =
typename std::make_unsigned_t<atomic_var_t>;
216 guest_ptr_t curr_offset;
217 guest_ptr_t next_offset;
221 static DmesgMetadataRecord
224 guest_ptr_t data_offset_mask,
225 const ByteOrder &
bo)
227 DmesgMetadataRecord metadata;
228 proxy.
readBlob(address, &metadata,
sizeof(metadata));
231 metadata.state =
gtoh(metadata.state,
bo);
232 metadata.data_buffer.curr_offset =
233 gtoh(metadata.data_buffer.curr_offset,
bo);
234 metadata.data_buffer.next_offset =
235 gtoh(metadata.data_buffer.next_offset,
bo);
238 metadata.data_buffer.curr_offset =
239 metadata.data_buffer.curr_offset & data_offset_mask;
240 metadata.data_buffer.next_offset =
241 metadata.data_buffer.next_offset & data_offset_mask;
262 uint16_t message_size;
273 static DmesgInfoRecord
276 const ByteOrder &
bo)
278 DmesgInfoRecord info;
279 proxy.
readBlob(address, &info,
sizeof(info));
282 info.ts_nsec =
gtoh(info.ts_nsec,
bo);
283 info.message_size =
gtoh(info.message_size,
bo);
292template<
typename AtomicVarType>
293struct Metadata_Pre_v5_18_0
295 using atomic_var_t = AtomicVarType;
297 typename std::make_unsigned_t<atomic_var_t>;
298 unsigned int mask_bits;
299 guest_ptr_t metadata_ring_ptr;
300 guest_ptr_t info_ring_ptr;
301 atomic_var_t unused1;
302 atomic_var_t unused2;
309template<
typename AtomicVarType>
310struct Metadata_Post_v5_18_0
312 using atomic_var_t = AtomicVarType;
314 typename std::make_unsigned_t<atomic_var_t>;
315 unsigned int mask_bits;
316 guest_ptr_t metadata_ring_ptr;
317 guest_ptr_t info_ring_ptr;
318 atomic_var_t unused1;
319 atomic_var_t unused2;
320 atomic_var_t unused3;
334template<
typename AtomicVarType,
typename MetadataStructType>
339 std::is_same<AtomicVarType, int32_t>,
340 std::is_same<AtomicVarType, int64_t>
342 "AtomicVarType must be int32_t or int64_t");
344 using atomic_var_t = AtomicVarType;
345 using guest_ptr_t =
typename std::make_unsigned_t<atomic_var_t>;
346 using metadata_record_t = DmesgMetadataRecord<atomic_var_t>;
351 MetadataStructType metadata;
354 unsigned int mask_bits;
355 guest_ptr_t data_ring_ptr;
356 atomic_var_t head_offset;
357 atomic_var_t tail_offset;
362 static DmesgRingbuffer
365 const ByteOrder &
bo)
368 proxy.
readBlob(address, &rb,
sizeof(rb));
371 rb.metadata.mask_bits =
372 gtoh(rb.metadata.mask_bits,
bo);
373 rb.metadata.metadata_ring_ptr =
374 gtoh(rb.metadata.metadata_ring_ptr,
bo);
375 rb.metadata.info_ring_ptr =
376 gtoh(rb.metadata.info_ring_ptr,
bo);
378 rb.data.mask_bits =
gtoh(rb.data.mask_bits,
bo);
379 rb.data.data_ring_ptr =
gtoh(rb.data.data_ring_ptr,
bo);
380 rb.data.head_offset =
gtoh(rb.data.head_offset,
bo);
381 rb.data.tail_offset =
gtoh(rb.data.tail_offset,
bo);
384 rb.data.head_offset =
385 rb.mask_data_offset(rb.data.head_offset);
386 rb.data.tail_offset =
387 rb.mask_data_offset(rb.data.tail_offset);
395 template<
typename as_type>
397 make_offset_mask_as(
const unsigned int mask_bits)
399 using unsigned_atomic_var_t =
400 typename std::make_unsigned<atomic_var_t>::type;
401 const atomic_var_t offset_mask =
402 static_cast<atomic_var_t
>(
403 (
static_cast<unsigned_atomic_var_t
>(1) << mask_bits) - 1);
404 return static_cast<as_type
>(offset_mask);
408 template<
typename metadata_offset_t>
410 make_metadata_offset_mask()
const
412 return make_offset_mask_as<metadata_offset_t>(metadata.mask_bits);
416 template<
typename data_offset_t>
418 make_data_offset_mask()
const
420 return make_offset_mask_as<data_offset_t>(
data.mask_bits);
425 template<
typename metadata_offset_t>
427 mask_metadata_offset(
const metadata_offset_t metadata_offset)
const
429 const atomic_var_t MASK =
430 make_metadata_offset_mask<metadata_offset_t>();
431 return metadata_offset & MASK;
435 template<
typename data_offset_t>
437 mask_data_offset(
const data_offset_t data_offset)
const
439 const atomic_var_t MASK = make_data_offset_mask<data_offset_t>();
440 return data_offset & MASK;
445using Linux64_Ringbuffer_Pre_v5_18_0 =
446 DmesgRingbuffer<int64_t, Metadata_Pre_v5_18_0<int64_t>>;
447using Linux32_Ringbuffer_Pre_v5_18_0 =
448 DmesgRingbuffer<int32_t, Metadata_Pre_v5_18_0<int32_t>>;
450using Linux64_Ringbuffer_Post_v5_18_0 =
451 DmesgRingbuffer<int64_t, Metadata_Post_v5_18_0<int64_t>>;
452using Linux32_Ringbuffer_Post_v5_18_0 =
453 DmesgRingbuffer<int32_t, Metadata_Post_v5_18_0<int32_t>>;
468template <
typename ringbuffer_t,
469 typename atomic_var_t=
typename ringbuffer_t::atomic_var_t,
470 typename guest_ptr_t=
typename ringbuffer_t::guest_ptr_t>
472iterateDataRingbuffer(std::ostream &
os,
474 const ringbuffer_t & rb,
475 const atomic_var_t
offset,
476 const guest_ptr_t first_metadata_offset,
479 using metadata_record_t =
typename ringbuffer_t::metadata_record_t;
481 constexpr size_t METADATA_RECORD_SIZE =
482 sizeof(
typename ringbuffer_t::metadata_record_t);
483 constexpr size_t INFO_RECORD_SIZE =
sizeof(DmesgInfoRecord);
485 const guest_ptr_t DATA_OFFSET_MASK =
486 rb.template make_data_offset_mask<guest_ptr_t>();
490 guest_ptr_t metadata_info_offset = rb.mask_metadata_offset(
491 proxy.
read<guest_ptr_t>(rb.data.data_ring_ptr +
offset,
bo));
497 if (metadata_info_offset == first_metadata_offset) {
498 return static_cast<atomic_var_t
>(0);
502 guest_ptr_t metadata_address =
503 rb.metadata.metadata_ring_ptr +
504 (metadata_info_offset * METADATA_RECORD_SIZE);
505 metadata_record_t metadata =
506 metadata_record_t::read(proxy, metadata_address, DATA_OFFSET_MASK,
bo);
509 guest_ptr_t info_address =
510 rb.metadata.info_ring_ptr +
511 (metadata_info_offset * INFO_RECORD_SIZE);
512 DmesgInfoRecord info =
513 DmesgInfoRecord::read(proxy, info_address,
bo);
517 if (metadata.data_buffer.curr_offset !=
offset) {
518 warn_once(
"Dmesg dump: metadata record (at 0x%08x) does not point "
519 "back to the correponding data record (at 0x%08x). Dmesg "
520 "buffer may be corrupted",
521 metadata.data_buffer.next_offset,
offset);
528 proxy.
readBlob(rb.data.data_ring_ptr +
offset +
sizeof(guest_ptr_t),
529 message.data(), info.message_size);
533 os.write((
char *)message.data(), info.message_size);
538 return metadata.data_buffer.next_offset;
545template <
typename ringbuffer_t>
549 using atomic_var_t =
typename ringbuffer_t::atomic_var_t;
550 using guest_ptr_t =
typename ringbuffer_t::guest_ptr_t;
553 const ByteOrder
bo =
system->getGuestByteOrder();
554 const auto &symtab =
system->workload->symtab(tc);
557 auto symtab_end_it = symtab.end();
560 ringbuffer_t dynamic_rb;
561 auto dynamic_rb_symbol = symtab.find(
"printk_rb_dynamic");
562 if (dynamic_rb_symbol != symtab_end_it) {
564 ringbuffer_t::read(proxy, dynamic_rb_symbol->address(),
bo);
566 warn(
"Failed to find required dmesg symbols.\n");
571 ringbuffer_t static_rb;
572 auto static_rb_symbol = symtab.find(
"printk_rb_static");
573 if (static_rb_symbol != symtab_end_it) {
574 static_rb = ringbuffer_t::read(proxy, static_rb_symbol->address(),
bo);
576 warn(
"Failed to find required dmesg symbols.\n");
583 guest_ptr_t active_ringbuffer_ptr = 0x0;
584 auto active_ringbuffer_ptr_symbol = symtab.find(
"prb");
585 if (active_ringbuffer_ptr_symbol != symtab_end_it) {
586 active_ringbuffer_ptr =
587 proxy.
read<guest_ptr_t>(active_ringbuffer_ptr_symbol->address(),
590 warn(
"Failed to find required dmesg symbols.\n");
594 if (active_ringbuffer_ptr == 0 ||
595 (active_ringbuffer_ptr != dynamic_rb_symbol->address() &&
596 active_ringbuffer_ptr != static_rb_symbol->address())) {
597 warn(
"Kernel Dmesg ringbuffer appears to be invalid.\n");
602 (active_ringbuffer_ptr == dynamic_rb_symbol->address())
603 ? dynamic_rb : static_rb;
605 atomic_var_t head_offset = rb.data.head_offset;
606 atomic_var_t tail_offset = rb.data.tail_offset;
610 const guest_ptr_t first_metadata_offset = rb.mask_metadata_offset(
611 proxy.
read<guest_ptr_t>(rb.data.data_ring_ptr,
bo));
612 const guest_ptr_t invalid_metadata_offset =
613 rb.template make_metadata_offset_mask<guest_ptr_t>() + 1;
629 guest_ptr_t
count = 0;
630 while (head_offset < tail_offset &&
count < invalid_metadata_offset) {
632 iterateDataRingbuffer<ringbuffer_t>(
633 os, proxy, rb, tail_offset, first_metadata_offset,
bo);
640 while (tail_offset < head_offset &&
count < invalid_metadata_offset) {
642 iterateDataRingbuffer<ringbuffer_t>(
643 os, proxy, rb, tail_offset, invalid_metadata_offset,
bo);
657 bool reading_printable =
false;
658 for (
const uint8_t
byte: buffer) {
659 if (std::isprint(
byte)) {
660 result +=
static_cast<char>(byte);
661 reading_printable =
true;
662 }
else if (reading_printable) {
664 results.push_back(result);
667 reading_printable =
false;
698 const auto &symtab =
system->workload->symtab(tc);
699 auto symtab_end_it = symtab.end();
701 auto symbol = symtab.find(
"init_uts_ns");
702 if (symbol == symtab_end_it) {
708 const size_t INIT_UTS_NS_SIZE_DEFAULT = 432;
709 const size_t BUFFER_SIZE =
710 symbol->sizeOrDefault(INIT_UTS_NS_SIZE_DEFAULT);
715 symbol->address(), buffer.data(), buffer.size() *
sizeof(uint8_t));
716 auto strings = extract_printable_strings(buffer);
718 const std::regex version_re {
"^(\\d+)\\.(\\d+)\\.(\\d)+$"};
720 for (
const auto&
string: strings) {
721 if (std::regex_search(
string, match, version_re)) {
723 int major = std::stoi(match[1]);
724 int minor = std::stoi(match[2]);
725 int point = std::stoi(match[3]);
728 | (
minor & 0xFF) << 8
729 | std::min(point, 255));
731 catch (
const std::invalid_argument &) {
735 catch (
const std::out_of_range &) {
754 const uint32_t kernel_version = extract_kernel_version(tc);
755 const uint32_t KERNEL_5_18_0 = 0x00051200;
757 if (kernel_version == 0x0) {
758 warn(
"Could not determine Linux Kernel version. "
759 "Assuming post-v5.18.0\n");
762 if (kernel_version == 0x0 || kernel_version >= KERNEL_5_18_0) {
764 dumpDmesgImpl<Linux64_Ringbuffer_Post_v5_18_0>(tc,
os);
766 dumpDmesgImpl<Linux32_Ringbuffer_Post_v5_18_0>(tc,
os);
770 dumpDmesgImpl<Linux64_Ringbuffer_Pre_v5_18_0>(tc,
os);
772 dumpDmesgImpl<Linux32_Ringbuffer_Pre_v5_18_0>(tc,
os);