205template<
typename atomic_var_t>
208 using guest_ptr_t =
typename std::make_unsigned_t<atomic_var_t>;
214 guest_ptr_t curr_offset;
215 guest_ptr_t next_offset;
219 static DmesgMetadataRecord
222 guest_ptr_t data_offset_mask,
223 const ByteOrder &
bo)
225 DmesgMetadataRecord metadata;
226 proxy.
readBlob(address, &metadata,
sizeof(metadata));
229 metadata.state =
gtoh(metadata.state,
bo);
230 metadata.data_buffer.curr_offset =
231 gtoh(metadata.data_buffer.curr_offset,
bo);
232 metadata.data_buffer.next_offset =
233 gtoh(metadata.data_buffer.next_offset,
bo);
236 metadata.data_buffer.curr_offset =
237 metadata.data_buffer.curr_offset & data_offset_mask;
238 metadata.data_buffer.next_offset =
239 metadata.data_buffer.next_offset & data_offset_mask;
260 uint16_t message_size;
271 static DmesgInfoRecord
274 const ByteOrder &
bo)
276 DmesgInfoRecord info;
277 proxy.
readBlob(address, &info,
sizeof(info));
280 info.ts_nsec =
gtoh(info.ts_nsec,
bo);
281 info.message_size =
gtoh(info.message_size,
bo);
290template<
typename AtomicVarType>
291struct Metadata_Pre_v5_18_0
293 using atomic_var_t = AtomicVarType;
295 typename std::make_unsigned_t<atomic_var_t>;
296 unsigned int mask_bits;
297 guest_ptr_t metadata_ring_ptr;
298 guest_ptr_t info_ring_ptr;
299 atomic_var_t unused1;
300 atomic_var_t unused2;
307template<
typename AtomicVarType>
308struct Metadata_Post_v5_18_0
310 using atomic_var_t = AtomicVarType;
312 typename std::make_unsigned_t<atomic_var_t>;
313 unsigned int mask_bits;
314 guest_ptr_t metadata_ring_ptr;
315 guest_ptr_t info_ring_ptr;
316 atomic_var_t unused1;
317 atomic_var_t unused2;
318 atomic_var_t unused3;
332template<
typename AtomicVarType,
typename MetadataStructType>
337 std::is_same<AtomicVarType, int32_t>,
338 std::is_same<AtomicVarType, int64_t>
340 "AtomicVarType must be int32_t or int64_t");
342 using atomic_var_t = AtomicVarType;
343 using guest_ptr_t =
typename std::make_unsigned_t<atomic_var_t>;
344 using metadata_record_t = DmesgMetadataRecord<atomic_var_t>;
349 MetadataStructType metadata;
352 unsigned int mask_bits;
353 guest_ptr_t data_ring_ptr;
354 atomic_var_t head_offset;
355 atomic_var_t tail_offset;
360 static DmesgRingbuffer
363 const ByteOrder &
bo)
366 proxy.
readBlob(address, &rb,
sizeof(rb));
369 rb.metadata.mask_bits =
370 gtoh(rb.metadata.mask_bits,
bo);
371 rb.metadata.metadata_ring_ptr =
372 gtoh(rb.metadata.metadata_ring_ptr,
bo);
373 rb.metadata.info_ring_ptr =
374 gtoh(rb.metadata.info_ring_ptr,
bo);
376 rb.data.mask_bits =
gtoh(rb.data.mask_bits,
bo);
377 rb.data.data_ring_ptr =
gtoh(rb.data.data_ring_ptr,
bo);
378 rb.data.head_offset =
gtoh(rb.data.head_offset,
bo);
379 rb.data.tail_offset =
gtoh(rb.data.tail_offset,
bo);
382 rb.data.head_offset =
383 rb.mask_data_offset(rb.data.head_offset);
384 rb.data.tail_offset =
385 rb.mask_data_offset(rb.data.tail_offset);
393 template<
typename as_type>
395 make_offset_mask_as(
const unsigned int mask_bits)
397 using unsigned_atomic_var_t =
398 typename std::make_unsigned<atomic_var_t>::type;
399 const atomic_var_t offset_mask =
400 static_cast<atomic_var_t
>(
401 (
static_cast<unsigned_atomic_var_t
>(1) << mask_bits) - 1);
402 return static_cast<as_type
>(offset_mask);
406 template<
typename metadata_offset_t>
408 make_metadata_offset_mask()
const
410 return make_offset_mask_as<metadata_offset_t>(metadata.mask_bits);
414 template<
typename data_offset_t>
416 make_data_offset_mask()
const
418 return make_offset_mask_as<data_offset_t>(
data.mask_bits);
423 template<
typename metadata_offset_t>
425 mask_metadata_offset(
const metadata_offset_t metadata_offset)
const
427 const atomic_var_t MASK =
428 make_metadata_offset_mask<metadata_offset_t>();
429 return metadata_offset & MASK;
433 template<
typename data_offset_t>
435 mask_data_offset(
const data_offset_t data_offset)
const
437 const atomic_var_t MASK = make_data_offset_mask<data_offset_t>();
438 return data_offset & MASK;
443using Linux64_Ringbuffer_Pre_v5_18_0 =
444 DmesgRingbuffer<int64_t, Metadata_Pre_v5_18_0<int64_t>>;
445using Linux32_Ringbuffer_Pre_v5_18_0 =
446 DmesgRingbuffer<int32_t, Metadata_Pre_v5_18_0<int32_t>>;
448using Linux64_Ringbuffer_Post_v5_18_0 =
449 DmesgRingbuffer<int64_t, Metadata_Post_v5_18_0<int64_t>>;
450using Linux32_Ringbuffer_Post_v5_18_0 =
451 DmesgRingbuffer<int32_t, Metadata_Post_v5_18_0<int32_t>>;
466template <
typename ringbuffer_t,
467 typename atomic_var_t=
typename ringbuffer_t::atomic_var_t,
468 typename guest_ptr_t=
typename ringbuffer_t::guest_ptr_t>
470iterateDataRingbuffer(std::ostream &
os,
472 const ringbuffer_t & rb,
473 const atomic_var_t
offset,
474 const guest_ptr_t first_metadata_offset,
477 using metadata_record_t =
typename ringbuffer_t::metadata_record_t;
479 constexpr size_t METADATA_RECORD_SIZE =
480 sizeof(
typename ringbuffer_t::metadata_record_t);
481 constexpr size_t INFO_RECORD_SIZE =
sizeof(DmesgInfoRecord);
483 const guest_ptr_t DATA_OFFSET_MASK =
484 rb.template make_data_offset_mask<guest_ptr_t>();
488 guest_ptr_t metadata_info_offset = rb.mask_metadata_offset(
489 proxy.
read<guest_ptr_t>(rb.data.data_ring_ptr +
offset,
bo));
495 if (metadata_info_offset == first_metadata_offset) {
496 return static_cast<atomic_var_t
>(0);
500 guest_ptr_t metadata_address =
501 rb.metadata.metadata_ring_ptr +
502 (metadata_info_offset * METADATA_RECORD_SIZE);
503 metadata_record_t metadata =
504 metadata_record_t::read(proxy, metadata_address, DATA_OFFSET_MASK,
bo);
507 guest_ptr_t info_address =
508 rb.metadata.info_ring_ptr +
509 (metadata_info_offset * INFO_RECORD_SIZE);
510 DmesgInfoRecord info =
511 DmesgInfoRecord::read(proxy, info_address,
bo);
515 if (metadata.data_buffer.curr_offset !=
offset) {
516 warn_once(
"Dmesg dump: metadata record (at 0x%08x) does not point "
517 "back to the correponding data record (at 0x%08x). Dmesg "
518 "buffer may be corrupted",
519 metadata.data_buffer.next_offset,
offset);
526 proxy.
readBlob(rb.data.data_ring_ptr +
offset +
sizeof(guest_ptr_t),
527 message.data(), info.message_size);
531 os.write((
char *)message.data(), info.message_size);
536 return metadata.data_buffer.next_offset;
543template <
typename ringbuffer_t>
547 using atomic_var_t =
typename ringbuffer_t::atomic_var_t;
548 using guest_ptr_t =
typename ringbuffer_t::guest_ptr_t;
551 const ByteOrder
bo =
system->getGuestByteOrder();
552 const auto &symtab =
system->workload->symtab(tc);
555 auto symtab_end_it = symtab.end();
558 ringbuffer_t dynamic_rb;
559 auto dynamic_rb_symbol = symtab.find(
"printk_rb_dynamic");
560 if (dynamic_rb_symbol != symtab_end_it) {
562 ringbuffer_t::read(proxy, dynamic_rb_symbol->address(),
bo);
564 warn(
"Failed to find required dmesg symbols.\n");
569 ringbuffer_t static_rb;
570 auto static_rb_symbol = symtab.find(
"printk_rb_static");
571 if (static_rb_symbol != symtab_end_it) {
572 static_rb = ringbuffer_t::read(proxy, static_rb_symbol->address(),
bo);
574 warn(
"Failed to find required dmesg symbols.\n");
581 guest_ptr_t active_ringbuffer_ptr = 0x0;
582 auto active_ringbuffer_ptr_symbol = symtab.find(
"prb");
583 if (active_ringbuffer_ptr_symbol != symtab_end_it) {
584 active_ringbuffer_ptr =
585 proxy.
read<guest_ptr_t>(active_ringbuffer_ptr_symbol->address(),
588 warn(
"Failed to find required dmesg symbols.\n");
592 if (active_ringbuffer_ptr == 0 ||
593 (active_ringbuffer_ptr != dynamic_rb_symbol->address() &&
594 active_ringbuffer_ptr != static_rb_symbol->address())) {
595 warn(
"Kernel Dmesg ringbuffer appears to be invalid.\n");
600 (active_ringbuffer_ptr == dynamic_rb_symbol->address())
601 ? dynamic_rb : static_rb;
603 atomic_var_t head_offset = rb.data.head_offset;
604 atomic_var_t tail_offset = rb.data.tail_offset;
608 const guest_ptr_t first_metadata_offset = rb.mask_metadata_offset(
609 proxy.
read<guest_ptr_t>(rb.data.data_ring_ptr,
bo));
610 const guest_ptr_t invalid_metadata_offset =
611 rb.template make_metadata_offset_mask<guest_ptr_t>() + 1;
627 guest_ptr_t
count = 0;
628 while (head_offset < tail_offset &&
count < invalid_metadata_offset) {
630 iterateDataRingbuffer<ringbuffer_t>(
631 os, proxy, rb, tail_offset, first_metadata_offset,
bo);
638 while (tail_offset < head_offset &&
count < invalid_metadata_offset) {
640 iterateDataRingbuffer<ringbuffer_t>(
641 os, proxy, rb, tail_offset, invalid_metadata_offset,
bo);
655 bool reading_printable =
false;
656 for (
const uint8_t
byte: buffer) {
657 if (std::isprint(
byte)) {
658 result +=
static_cast<char>(byte);
659 reading_printable =
true;
660 }
else if (reading_printable) {
662 results.push_back(result);
665 reading_printable =
false;
696 const auto &symtab =
system->workload->symtab(tc);
697 auto symtab_end_it = symtab.end();
699 auto symbol = symtab.find(
"init_uts_ns");
700 if (symbol == symtab_end_it) {
706 const size_t INIT_UTS_NS_SIZE_DEFAULT = 432;
707 const size_t BUFFER_SIZE =
708 symbol->sizeOrDefault(INIT_UTS_NS_SIZE_DEFAULT);
713 symbol->address(), buffer.data(), buffer.size() *
sizeof(uint8_t));
714 auto strings = extract_printable_strings(buffer);
716 const std::regex version_re {
"^(\\d+)\\.(\\d+)\\.(\\d)+$"};
718 for (
const auto&
string: strings) {
719 if (std::regex_search(
string, match, version_re)) {
721 int major = std::stoi(match[1]);
722 int minor = std::stoi(match[2]);
723 int point = std::stoi(match[3]);
726 | (
minor & 0xFF) << 8
727 | std::min(point, 255));
729 catch (
const std::invalid_argument &) {
733 catch (
const std::out_of_range &) {
752 const uint32_t kernel_version = extract_kernel_version(tc);
753 const uint32_t KERNEL_5_18_0 = 0x00051200;
755 if (kernel_version == 0x0) {
756 warn(
"Could not determine Linux Kernel version. "
757 "Assuming post-v5.18.0\n");
760 if (kernel_version == 0x0 || kernel_version >= KERNEL_5_18_0) {
762 dumpDmesgImpl<Linux64_Ringbuffer_Post_v5_18_0>(tc,
os);
764 dumpDmesgImpl<Linux32_Ringbuffer_Post_v5_18_0>(tc,
os);
768 dumpDmesgImpl<Linux64_Ringbuffer_Pre_v5_18_0>(tc,
os);
770 dumpDmesgImpl<Linux32_Ringbuffer_Pre_v5_18_0>(tc,
os);