205template<
typename atomic_var_t>
208 using guest_ptr_t =
typename std::make_unsigned_t<atomic_var_t>;
219 static DmesgMetadataRecord
220 read(
const TranslatingPortProxy & proxy,
222 guest_ptr_t data_offset_mask,
223 const ByteOrder & bo)
237 metadata.data_buffer.curr_offset & data_offset_mask;
239 metadata.data_buffer.next_offset & data_offset_mask;
255struct GEM5_PACKED DmesgInfoRecord
271 static DmesgInfoRecord
272 read(
const TranslatingPortProxy & proxy,
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>;
307template<
typename AtomicVarType>
308struct Metadata_Post_v5_18_0
310 using atomic_var_t = AtomicVarType;
312 typename std::make_unsigned_t<atomic_var_t>;
332template<
typename AtomicVarType,
typename MetadataStructType>
333struct GEM5_PACKED DmesgRingbuffer
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>;
360 static DmesgRingbuffer
361 read(
const TranslatingPortProxy & proxy,
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,
471 const TranslatingPortProxy & proxy,
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);
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);
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",
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>
545dumpDmesgImpl(ThreadContext *tc, std::ostream &
os)
547 using atomic_var_t =
typename ringbuffer_t::atomic_var_t;
548 using guest_ptr_t =
typename ringbuffer_t::guest_ptr_t;
550 System *
system = tc->getSystemPtr();
551 const ByteOrder
bo =
system->getGuestByteOrder();
552 const auto &symtab =
system->workload->symtab(tc);
553 TranslatingPortProxy proxy(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;
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;
630 iterateDataRingbuffer<ringbuffer_t>(
640 iterateDataRingbuffer<ringbuffer_t>(
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;
694extract_kernel_version(ThreadContext* tc) {
695 System *
system = tc->getSystemPtr();
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);
710 TranslatingPortProxy proxy(tc);
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 &) {
750 System *
system = tc->getSystemPtr();
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);