gem5 v24.0.0.0
Loading...
Searching...
No Matches
helpers.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016, 2022-2023 Arm Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#include "kern/linux/helpers.hh"
39
40/* The following pragmas are to fix a bug in GCC \w the CPP standard library,
41 * outlined here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105562.
42 * This ignores the 'maybe-unitialized' warning when importing regex for
43 * GCC 12.1.
44 */
45
46// ignore 'maybe-uniitialized' warnings for GCC 12.1.
47#if __GNUC__ && __GNUC__ == 12 && __GNUC_MINOR__ == 1
48 #define SUPPRESSING_MAYBE_UNINITIALIZED_WARNING
49 // save diagnostic state.
50 #pragma GCC diagnostic push
51 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
52#endif
53#include <regex>
54#ifdef SUPPRESSING_MAYBE_UNINITIALIZED_WARNING
55 // restore the diagnostic state.
56 #pragma GCC diagnostic pop
57#endif
58
59#include <string>
60#include <type_traits>
61#include <vector>
62
63#include "base/compiler.hh"
65#include "cpu/thread_context.hh"
66#include "mem/port_proxy.hh"
68#include "sim/byteswap.hh"
69#include "sim/system.hh"
70
71namespace gem5 {
72
73namespace linux {
74
75namespace {
76
77namespace pre5_10 {
78
80struct GEM5_PACKED DmesgEntry
81{
82 uint64_t ts_nsec;
83 uint16_t len;
84 uint16_t text_len;
85 uint16_t dict_len;
86 uint8_t facility;
87 uint8_t flags;
88};
89
91static int
92dumpDmesgEntry(const uint8_t *base, const uint8_t *end,
93 const ByteOrder bo,
94 std::ostream &os)
95{
96 const size_t max_length = end - base;
97 DmesgEntry de;
98
99 if (max_length < sizeof(de)) {
100 warn("Malformed dmesg entry\n");
101 return -1;
102 }
103
104 memcpy(&de, base, sizeof(de));
105 de.ts_nsec = gtoh(de.ts_nsec, bo);
106 de.len = gtoh(de.len, bo);
107 de.text_len = gtoh(de.text_len, bo);
108
109 if (de.len < sizeof(de) ||
110 max_length < de.len ||
111 max_length < sizeof(DmesgEntry) + de.text_len) {
112
113 warn("Malformed dmesg entry:\n");
114 warn("\tMax length: %i\n", max_length);
115 warn("\tde.len: %i\n", de.len);
116 warn("\tde.text_len: %i\n", de.text_len);
117 return -1;
118 }
119
120 ccprintf(os, "[%.6f] ", de.ts_nsec * 10e-9);
121 os.write((char *)base + sizeof(de), de.text_len);
122 os << std::endl;
123
124 return de.len;
125}
126
128void
129dumpDmesg(ThreadContext *tc, std::ostream &os)
130{
131 System *system = tc->getSystemPtr();
132 const ByteOrder bo = system->getGuestByteOrder();
133 const auto &symtab = system->workload->symtab(tc);
134 TranslatingPortProxy proxy(tc);
135
136 auto lb = symtab.find("__log_buf");
137 auto lb_len = symtab.find("log_buf_len");
138 auto first = symtab.find("log_first_idx");
139 auto next = symtab.find("log_next_idx");
140
141 auto end_it = symtab.end();
142
143 if (lb == end_it || lb_len == end_it ||
144 first == end_it || next == end_it) {
145 warn("Failed to find kernel dmesg symbols.\n");
146 return;
147 }
148
149 uint32_t log_buf_len = proxy.read<uint32_t>(lb_len->address(), bo);
150 uint32_t log_first_idx = proxy.read<uint32_t>(first->address(), bo);
151 uint32_t log_next_idx = proxy.read<uint32_t>(next->address(), bo);
152
153 if (log_first_idx >= log_buf_len || log_next_idx >= log_buf_len) {
154 warn("dmesg pointers/length corrupted\n");
155 return;
156 }
157
158 // Normalize and read the dmesg ring buffer
159 std::vector<uint8_t> log_buf(log_buf_len);
160 int length;
161 if (log_first_idx < log_next_idx) {
162 length = log_next_idx - log_first_idx;
163 if (length < 0 || length > log_buf.size()) {
164 warn("Unexpected dmesg buffer length\n");
165 return;
166 }
167 proxy.readBlob(lb->address() + log_first_idx, log_buf.data(), length);
168 } else {
169 const int length_2 = log_buf_len - log_first_idx;
170 if (length_2 < 0 || length_2 + log_next_idx > log_buf.size()) {
171 warn("Unexpected dmesg buffer length\n");
172 return;
173 }
174 length = log_buf_len;
175 proxy.readBlob(
176 lb->address() + log_first_idx, log_buf.data(), length_2);
177 proxy.readBlob(
178 lb->address(), log_buf.data() + length_2, log_next_idx);
179 }
180
181 // Print dmesg buffer content
182 const uint8_t *cur = log_buf.data(), *end = log_buf.data() + length;
183 while (cur < end) {
184 int ret = dumpDmesgEntry(cur, end, bo, os);
185 if (ret < 0)
186 return;
187 cur += ret;
188 }
189}
190
191} // namespace pre5_10
192
193namespace post5_10 {
194
205template<typename atomic_var_t>
206struct GEM5_PACKED DmesgMetadataRecord
207{
208 using guest_ptr_t = typename std::make_unsigned_t<atomic_var_t>;
209
210 // Struct data members
211 atomic_var_t state;
212 struct
213 {
214 guest_ptr_t curr_offset;
215 guest_ptr_t next_offset;
217
219 static DmesgMetadataRecord
220 read(const TranslatingPortProxy & proxy,
221 Addr address,
222 guest_ptr_t data_offset_mask,
223 const ByteOrder & bo)
224 {
225 DmesgMetadataRecord metadata;
226 proxy.readBlob(address, &metadata, sizeof(metadata));
227
228 // Convert members to host byte order
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);
234
235 // Mask the offsets
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;
240
241 return metadata;
242 }
243};
244
255struct GEM5_PACKED DmesgInfoRecord
256{
257 // Struct data members
258 uint64_t unused1;
259 uint64_t ts_nsec;
260 uint16_t message_size;
261 uint8_t unused2;
262 uint8_t unused3;
263 uint32_t unused4;
264 struct
265 {
266 char unused5_1[16];
267 char unused5_2[48];
269
271 static DmesgInfoRecord
272 read(const TranslatingPortProxy & proxy,
273 Addr address,
274 const ByteOrder & bo)
275 {
276 DmesgInfoRecord info;
277 proxy.readBlob(address, &info, sizeof(info));
278
279 // Convert members to host byte order
280 info.ts_nsec = gtoh(info.ts_nsec, bo);
281 info.message_size = gtoh(info.message_size, bo);
282
283 return info;
284 }
285};
286
290template<typename AtomicVarType>
291struct Metadata_Pre_v5_18_0
292{
293 using atomic_var_t = AtomicVarType;
294 using guest_ptr_t =
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;
301};
302
303
307template<typename AtomicVarType>
308struct Metadata_Post_v5_18_0
309{
310 using atomic_var_t = AtomicVarType;
311 using guest_ptr_t =
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;
319};
320
321
332template<typename AtomicVarType, typename MetadataStructType>
333struct GEM5_PACKED DmesgRingbuffer
334{
335 static_assert(
336 std::disjunction<
337 std::is_same<AtomicVarType, int32_t>,
338 std::is_same<AtomicVarType, int64_t>
339 >::value,
340 "AtomicVarType must be int32_t or int64_t");
341
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>;
345
346 // Struct data members
347
348 // Metadata struct size depends on the Linux Kernel Version
349 MetadataStructType metadata;
350 struct
351 {
352 unsigned int mask_bits;
353 guest_ptr_t data_ring_ptr;
354 atomic_var_t head_offset;
355 atomic_var_t tail_offset;
357 atomic_var_t fail;
358
360 static DmesgRingbuffer
361 read(const TranslatingPortProxy & proxy,
362 const Addr address,
363 const ByteOrder & bo)
364 {
365 DmesgRingbuffer rb;
366 proxy.readBlob(address, &rb, sizeof(rb));
367
368 // Convert members to host byte order
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);
375
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);
380
381 // Mask offsets to the correct number of bits
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);
386
387 return rb;
388 }
389
393 template<typename as_type>
394 static as_type
395 make_offset_mask_as(const unsigned int mask_bits)
396 {
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);
403 }
404
406 template<typename metadata_offset_t>
407 metadata_offset_t
408 make_metadata_offset_mask() const
409 {
410 return make_offset_mask_as<metadata_offset_t>(metadata.mask_bits);
411 }
412
414 template<typename data_offset_t>
415 data_offset_t
416 make_data_offset_mask() const
417 {
418 return make_offset_mask_as<data_offset_t>(data.mask_bits);
419 }
420
423 template<typename metadata_offset_t>
424 metadata_offset_t
425 mask_metadata_offset(const metadata_offset_t metadata_offset) const
426 {
427 const atomic_var_t MASK =
428 make_metadata_offset_mask<metadata_offset_t>();
429 return metadata_offset & MASK;
430 }
431
433 template<typename data_offset_t>
434 data_offset_t
435 mask_data_offset(const data_offset_t data_offset) const
436 {
437 const atomic_var_t MASK = make_data_offset_mask<data_offset_t>();
438 return data_offset & MASK;
439 }
440};
441
442// Aliases for the types of Ringbuffer that could be used.
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>>;
447
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>>;
452
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>
469atomic_var_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,
475 const ByteOrder bo)
476{
477 using metadata_record_t = typename ringbuffer_t::metadata_record_t;
478
479 constexpr size_t METADATA_RECORD_SIZE =
480 sizeof(typename ringbuffer_t::metadata_record_t);
481 constexpr size_t INFO_RECORD_SIZE = sizeof(DmesgInfoRecord);
482
483 const guest_ptr_t DATA_OFFSET_MASK =
484 rb.template make_data_offset_mask<guest_ptr_t>();
485
486 // Read the offset of the metadata record from the beginning of
487 // the data record.
488 guest_ptr_t metadata_info_offset = rb.mask_metadata_offset(
489 proxy.read<guest_ptr_t>(rb.data.data_ring_ptr + offset, bo));
490
491 // If the metadata offset of the block is the same as the metadata
492 // offset of the first block of the data ringbuffer, then this
493 // data block is unsused (padding), and the iteration can wrap
494 // around to the beginning of the data ringbuffer (offset == 0).
495 if (metadata_info_offset == first_metadata_offset) {
496 return static_cast<atomic_var_t>(0);
497 }
498
499 // Read the metadata record from the metadata ringbuffer.
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);
505
506 // Read the info record from the info ringbuffer.
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);
512
513 // The metadata record should point back to the same data record
514 // in the data ringbuffer.
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);
520 }
521
522 // Read the message from the data record. This is placed
523 // immediately after the `guest_ptr_t` sized metadata offset at
524 // the beginning of the record.
525 std::vector<uint8_t> message(info.message_size);
526 proxy.readBlob(rb.data.data_ring_ptr + offset + sizeof(guest_ptr_t),
527 message.data(), info.message_size);
528
529 // Print the record
530 ccprintf(os, "[%.6f] ", info.ts_nsec * 10e-9);
531 os.write((char *)message.data(), info.message_size);
532 os << "\n";
533
534 // Return the offset of the next data record in the data
535 // ringbuffer.
536 return metadata.data_buffer.next_offset;
537}
538
543template <typename ringbuffer_t>
544void
545dumpDmesgImpl(ThreadContext *tc, std::ostream &os)
546{
547 using atomic_var_t = typename ringbuffer_t::atomic_var_t;
548 using guest_ptr_t = typename ringbuffer_t::guest_ptr_t;
549
550 System *system = tc->getSystemPtr();
551 const ByteOrder bo = system->getGuestByteOrder();
552 const auto &symtab = system->workload->symtab(tc);
553 TranslatingPortProxy proxy(tc);
554
555 auto symtab_end_it = symtab.end();
556
557 // Read the dynamic ringbuffer structure from guest memory, if present.
558 ringbuffer_t dynamic_rb;
559 auto dynamic_rb_symbol = symtab.find("printk_rb_dynamic");
560 if (dynamic_rb_symbol != symtab_end_it) {
561 dynamic_rb =
562 ringbuffer_t::read(proxy, dynamic_rb_symbol->address(), bo);
563 } else {
564 warn("Failed to find required dmesg symbols.\n");
565 return;
566 }
567
568 // Read the static ringbuffer structure from guest memory, if present.
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);
573 } else {
574 warn("Failed to find required dmesg symbols.\n");
575 return;
576 }
577
578 // Read the pointer to the active ringbuffer structure from guest
579 // memory. This should point to one of the two ringbuffer
580 // structures already read from guest memory.
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(),
586 bo);
587 } else {
588 warn("Failed to find required dmesg symbols.\n");
589 return;
590 }
591
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");
596 return;
597 }
598
599 ringbuffer_t & rb =
600 (active_ringbuffer_ptr == dynamic_rb_symbol->address())
601 ? dynamic_rb : static_rb;
602
603 atomic_var_t head_offset = rb.data.head_offset;
604 atomic_var_t tail_offset = rb.data.tail_offset;
605
606 // Get some marker offsets into the data ringbuffer which will be
607 // used as end values to control the iteration.
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;
612
613 // Iterate over the active ringbuffer, printing each message to
614 // `os`. Use the maximum number of possible info records plus one
615 // (invalid_metadata_offset) as an escape counter to make sure the
616 // process doesn't iterate infinitely if the kernel data
617 // structures have been corrupted.
618
619 // When head is behind tail, read to the end of the ringbuffer,
620 // then loop back to the begining.
621 //
622 // iterateDataRingbuffer will return offset at the beginning of
623 // the data ringbuffer when it loops back.
624 //
625 // `first_metadata_offset` is used to detect cases where the final data
626 // block is unused.
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);
632 ++count;
633 }
634
635 // When tail is behind head, read forwards from the tail offset to
636 // the head offset.
637 count = 0;
638 while (tail_offset < head_offset && count < invalid_metadata_offset) {
640 iterateDataRingbuffer<ringbuffer_t>(
641 os, proxy, rb, tail_offset, invalid_metadata_offset, bo);
642 ++count;
643 }
644}
645
651extract_printable_strings(const std::vector<uint8_t> buffer)
652{
654 std::string result;
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) {
661 if (byte == '\0') {
662 results.push_back(result);
663 }
664 result.clear();
665 reading_printable = false;
666 }
667 }
668 return results;
669}
670
693uint32_t
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();
698
699 auto symbol = symtab.find("init_uts_ns");
700 if (symbol == symtab_end_it) {
701 return 0x0;
702 }
703
704 // Use size of `init_uts_ns` in Linux v5.18.0 as a default.
705 // (e.g. for upgraded checkpoints.)
706 const size_t INIT_UTS_NS_SIZE_DEFAULT = 432;
707 const size_t BUFFER_SIZE =
708 symbol->sizeOrDefault(INIT_UTS_NS_SIZE_DEFAULT);
709
710 TranslatingPortProxy proxy(tc);
711 std::vector<uint8_t> buffer(BUFFER_SIZE);
712 proxy.readBlob(
713 symbol->address(), buffer.data(), buffer.size() * sizeof(uint8_t));
714 auto strings = extract_printable_strings(buffer);
715
716 const std::regex version_re {"^(\\d+)\\.(\\d+)\\.(\\d)+$"};
717 std::smatch match;
718 for (const auto& string: strings) {
719 if (std::regex_search(string, match, version_re)) {
720 try {
721 int major = std::stoi(match[1]);
722 int minor = std::stoi(match[2]);
723 int point = std::stoi(match[3]);
724 return (
725 (major & 0xFF) << 16
726 | (minor & 0xFF) << 8
727 | std::min(point, 255));
728 }
729 catch (const std::invalid_argument &) {
730 // This shouldn't be possible if the regex matched.
731 continue;
732 }
733 catch (const std::out_of_range &) {
734 continue;
735 }
736 }
737 }
738
739 return 0x0;
740}
741
747void
748dumpDmesg(ThreadContext *tc, std::ostream &os)
749{
750 System *system = tc->getSystemPtr();
751 const bool os_is_64_bit = loader::archIs64Bit(system->workload->getArch());
752 const uint32_t kernel_version = extract_kernel_version(tc);
753 const uint32_t KERNEL_5_18_0 = 0x00051200;
754
755 if (kernel_version == 0x0) {
756 warn("Could not determine Linux Kernel version. "
757 "Assuming post-v5.18.0\n");
758 }
759
760 if (kernel_version == 0x0 || kernel_version >= KERNEL_5_18_0) {
761 if (os_is_64_bit) {
762 dumpDmesgImpl<Linux64_Ringbuffer_Post_v5_18_0>(tc, os);
763 } else {
764 dumpDmesgImpl<Linux32_Ringbuffer_Post_v5_18_0>(tc, os);
765 }
766 } else {
767 if (os_is_64_bit) {
768 dumpDmesgImpl<Linux64_Ringbuffer_Pre_v5_18_0>(tc, os);
769 } else {
770 dumpDmesgImpl<Linux32_Ringbuffer_Pre_v5_18_0>(tc, os);
771 }
772 }
773}
774
775} // namespace post5_10
776
777} // anonymous namespace
778
779void
780dumpDmesg(ThreadContext *tc, std::ostream &os)
781{
782 System *system = tc->getSystemPtr();
783 const auto &symtab = system->workload->symtab(tc);
784
785 auto end_it = symtab.end();
786
787 // Search for symbols associated with the Kernel Dmesg ringbuffer,
788 // pre-v5.10.
789 auto lb = symtab.find("__log_buf");
790 auto lb_len = symtab.find("log_buf_len");
791 auto first = symtab.find("log_first_idx");
792 auto next = symtab.find("log_next_idx");
793
794 if (lb != end_it && lb_len != end_it &&
795 first != end_it && next != end_it) {
796 linux::pre5_10::dumpDmesg(tc, os);
797 return;
798 }
799
800 // Search for symbols associated with the Kernel Dmesg ringbuffer,
801 // post-v5.10.
802 auto printk_rb_static = symtab.find("printk_rb_static");
803 auto printk_rb_dynamic = symtab.find("printk_rb_dynamic");
804
805 if (printk_rb_dynamic != end_it || printk_rb_static != end_it) {
806 linux::post5_10::dumpDmesg(tc, os);
807 return;
808 }
809
810 // Required symbols relating to the Kernel Dmesg buffer were not
811 // found for any supported version of Linux.
812 warn("Failed to find kernel dmesg symbols.\n");
813}
814
815} // namespace linux
816
817} // namespace gem5
const char data[]
Workload * workload
OS kernel.
Definition system.hh:326
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual System * getSystemPtr()=0
virtual const loader::SymbolTable & symtab(ThreadContext *tc)=0
const_iterator end() const
Definition symtab.hh:278
STL vector class.
Definition stl.hh:37
uint8_t unused3
Definition helpers.cc:262
uint64_t ts_nsec
Definition helpers.cc:82
uint32_t unused4
Definition helpers.cc:263
struct gem5::linux::@1425::post5_10::DmesgInfoRecord::@368 unused5
uint64_t unused1
Definition helpers.cc:258
uint8_t facility
Definition helpers.cc:86
unsigned int mask_bits
Definition helpers.cc:296
atomic_var_t state
Definition helpers.cc:211
char unused5_1[16]
Definition helpers.cc:266
atomic_var_t head_offset
Definition helpers.cc:354
struct gem5::linux::@1425::post5_10::DmesgMetadataRecord::@367 data_buffer
guest_ptr_t next_offset
Definition helpers.cc:215
uint16_t message_size
Definition helpers.cc:260
guest_ptr_t curr_offset
Definition helpers.cc:214
uint16_t len
Definition helpers.cc:83
uint8_t unused2
Definition helpers.cc:261
uint8_t flags
Definition helpers.cc:87
MetadataStructType metadata
Definition helpers.cc:349
uint16_t dict_len
Definition helpers.cc:85
guest_ptr_t metadata_ring_ptr
Definition helpers.cc:297
guest_ptr_t info_ring_ptr
Definition helpers.cc:298
atomic_var_t tail_offset
Definition helpers.cc:355
char unused5_2[48]
Definition helpers.cc:267
guest_ptr_t data_ring_ptr
Definition helpers.cc:353
atomic_var_t fail
Definition helpers.cc:357
uint16_t text_len
Definition helpers.cc:84
#define warn(...)
Definition logging.hh:256
#define warn_once(...)
Definition logging.hh:260
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 9 > e
Definition misc_types.hh:65
Bitfield< 25, 21 > bo
Definition types.hh:82
Bitfield< 15 > system
Definition misc.hh:1032
Bitfield< 51, 12 > base
Definition pagetable.hh:141
Bitfield< 17 > os
Definition misc.hh:838
Bitfield< 3 > de
Definition misc.hh:652
void dumpDmesg(ThreadContext *tc, std::ostream &os)
Dump Linux's dmesg log buffer to the an output stream.
Definition helpers.cc:780
bool archIs64Bit(const loader::Arch arch)
Determine whether the loader::Arch is 64-bit or 32-bit.
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
T gtoh(T value, ByteOrder guest_byte_order)
Definition byteswap.hh:194
void ccprintf(cp::Print &print)
Definition cprintf.hh:130
Minor contains all the definitions within the MinorCPU apart from the CPU class itself.
PortProxy Object Declaration.
PM4 packets.

Generated on Tue Jun 18 2024 16:24:04 for gem5 by doxygen 1.11.0