gem5 [DEVELOP-FOR-25.1]
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// clang-format off
47// ignore 'maybe-uniitialized' warnings for GCC >= 12.
48#if __GNUC__ && __GNUC__ >= 12
49 #define SUPPRESSING_MAYBE_UNINITIALIZED_WARNING
50 // save diagnostic state.
51 #pragma GCC diagnostic push
52 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
53#endif
54#include <regex>
55#ifdef SUPPRESSING_MAYBE_UNINITIALIZED_WARNING
56 // restore the diagnostic state.
57 #pragma GCC diagnostic pop
58#endif
59// clang-format on
60
61#include <string>
62#include <type_traits>
63#include <vector>
64
65#include "base/compiler.hh"
67#include "cpu/thread_context.hh"
68#include "mem/port_proxy.hh"
70#include "sim/byteswap.hh"
71#include "sim/system.hh"
72
73namespace gem5 {
74
75namespace linux {
76
77namespace {
78
79namespace pre5_10 {
80
82struct GEM5_PACKED DmesgEntry
83{
84 uint64_t ts_nsec;
85 uint16_t len;
86 uint16_t text_len;
87 uint16_t dict_len;
88 uint8_t facility;
89 uint8_t flags;
90};
91
93static int
94dumpDmesgEntry(const uint8_t *base, const uint8_t *end,
95 const ByteOrder bo,
96 std::ostream &os)
97{
98 const size_t max_length = end - base;
99 DmesgEntry de;
100
101 if (max_length < sizeof(de)) {
102 warn("Malformed dmesg entry\n");
103 return -1;
104 }
105
106 memcpy(&de, base, sizeof(de));
107 de.ts_nsec = gtoh(de.ts_nsec, bo);
108 de.len = gtoh(de.len, bo);
109 de.text_len = gtoh(de.text_len, bo);
110
111 if (de.len < sizeof(de) ||
112 max_length < de.len ||
113 max_length < sizeof(DmesgEntry) + de.text_len) {
114
115 warn("Malformed dmesg entry:\n");
116 warn("\tMax length: %i\n", max_length);
117 warn("\tde.len: %i\n", de.len);
118 warn("\tde.text_len: %i\n", de.text_len);
119 return -1;
120 }
121
122 ccprintf(os, "[%.6f] ", de.ts_nsec * 10e-9);
123 os.write((char *)base + sizeof(de), de.text_len);
124 os << std::endl;
125
126 return de.len;
127}
128
130void
131dumpDmesg(ThreadContext *tc, std::ostream &os)
132{
133 System *system = tc->getSystemPtr();
134 const ByteOrder bo = system->getGuestByteOrder();
135 const auto &symtab = system->workload->symtab(tc);
136 TranslatingPortProxy proxy(tc);
137
138 auto lb = symtab.find("__log_buf");
139 auto lb_len = symtab.find("log_buf_len");
140 auto first = symtab.find("log_first_idx");
141 auto next = symtab.find("log_next_idx");
142
143 auto end_it = symtab.end();
144
145 if (lb == end_it || lb_len == end_it ||
146 first == end_it || next == end_it) {
147 warn("Failed to find kernel dmesg symbols.\n");
148 return;
149 }
150
151 uint32_t log_buf_len = proxy.read<uint32_t>(lb_len->address(), bo);
152 uint32_t log_first_idx = proxy.read<uint32_t>(first->address(), bo);
153 uint32_t log_next_idx = proxy.read<uint32_t>(next->address(), bo);
154
155 if (log_first_idx >= log_buf_len || log_next_idx >= log_buf_len) {
156 warn("dmesg pointers/length corrupted\n");
157 return;
158 }
159
160 // Normalize and read the dmesg ring buffer
161 std::vector<uint8_t> log_buf(log_buf_len);
162 int length;
163 if (log_first_idx < log_next_idx) {
164 length = log_next_idx - log_first_idx;
165 if (length < 0 || length > log_buf.size()) {
166 warn("Unexpected dmesg buffer length\n");
167 return;
168 }
169 proxy.readBlob(lb->address() + log_first_idx, log_buf.data(), length);
170 } else {
171 const int length_2 = log_buf_len - log_first_idx;
172 if (length_2 < 0 || length_2 + log_next_idx > log_buf.size()) {
173 warn("Unexpected dmesg buffer length\n");
174 return;
175 }
176 length = log_buf_len;
177 proxy.readBlob(
178 lb->address() + log_first_idx, log_buf.data(), length_2);
179 proxy.readBlob(
180 lb->address(), log_buf.data() + length_2, log_next_idx);
181 }
182
183 // Print dmesg buffer content
184 const uint8_t *cur = log_buf.data(), *end = log_buf.data() + length;
185 while (cur < end) {
186 int ret = dumpDmesgEntry(cur, end, bo, os);
187 if (ret < 0)
188 return;
189 cur += ret;
190 }
191}
192
193} // namespace pre5_10
194
195namespace post5_10 {
196
207template<typename atomic_var_t>
208struct GEM5_PACKED DmesgMetadataRecord
209{
210 using guest_ptr_t = typename std::make_unsigned_t<atomic_var_t>;
211
212 // Struct data members
213 atomic_var_t state;
214 struct
215 {
216 guest_ptr_t curr_offset;
217 guest_ptr_t next_offset;
218 } data_buffer;
219
221 static DmesgMetadataRecord
222 read(const TranslatingPortProxy & proxy,
223 Addr address,
224 guest_ptr_t data_offset_mask,
225 const ByteOrder & bo)
226 {
227 DmesgMetadataRecord metadata;
228 proxy.readBlob(address, &metadata, sizeof(metadata));
229
230 // Convert members to host byte order
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);
236
237 // Mask the offsets
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;
242
243 return metadata;
244 }
245};
246
257struct GEM5_PACKED DmesgInfoRecord
258{
259 // Struct data members
260 uint64_t unused1;
261 uint64_t ts_nsec;
262 uint16_t message_size;
263 uint8_t unused2;
264 uint8_t unused3;
265 uint32_t unused4;
266 struct
267 {
268 char unused5_1[16];
269 char unused5_2[48];
270 } unused5;
271
273 static DmesgInfoRecord
274 read(const TranslatingPortProxy & proxy,
275 Addr address,
276 const ByteOrder & bo)
277 {
278 DmesgInfoRecord info;
279 proxy.readBlob(address, &info, sizeof(info));
280
281 // Convert members to host byte order
282 info.ts_nsec = gtoh(info.ts_nsec, bo);
283 info.message_size = gtoh(info.message_size, bo);
284
285 return info;
286 }
287};
288
292template<typename AtomicVarType>
293struct Metadata_Pre_v5_18_0
294{
295 using atomic_var_t = AtomicVarType;
296 using guest_ptr_t =
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;
303};
304
305
309template<typename AtomicVarType>
310struct Metadata_Post_v5_18_0
311{
312 using atomic_var_t = AtomicVarType;
313 using guest_ptr_t =
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;
321};
322
323
334template<typename AtomicVarType, typename MetadataStructType>
335struct GEM5_PACKED DmesgRingbuffer
336{
337 static_assert(
338 std::disjunction<
339 std::is_same<AtomicVarType, int32_t>,
340 std::is_same<AtomicVarType, int64_t>
341 >::value,
342 "AtomicVarType must be int32_t or int64_t");
343
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>;
347
348 // Struct data members
349
350 // Metadata struct size depends on the Linux Kernel Version
351 MetadataStructType metadata;
352 struct
353 {
354 unsigned int mask_bits;
355 guest_ptr_t data_ring_ptr;
356 atomic_var_t head_offset;
357 atomic_var_t tail_offset;
358 } data;
359 atomic_var_t fail;
360
362 static DmesgRingbuffer
363 read(const TranslatingPortProxy & proxy,
364 const Addr address,
365 const ByteOrder & bo)
366 {
367 DmesgRingbuffer rb;
368 proxy.readBlob(address, &rb, sizeof(rb));
369
370 // Convert members to host byte order
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);
377
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);
382
383 // Mask offsets to the correct number of bits
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);
388
389 return rb;
390 }
391
395 template<typename as_type>
396 static as_type
397 make_offset_mask_as(const unsigned int mask_bits)
398 {
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);
405 }
406
408 template<typename metadata_offset_t>
409 metadata_offset_t
410 make_metadata_offset_mask() const
411 {
412 return make_offset_mask_as<metadata_offset_t>(metadata.mask_bits);
413 }
414
416 template<typename data_offset_t>
417 data_offset_t
418 make_data_offset_mask() const
419 {
420 return make_offset_mask_as<data_offset_t>(data.mask_bits);
421 }
422
425 template<typename metadata_offset_t>
426 metadata_offset_t
427 mask_metadata_offset(const metadata_offset_t metadata_offset) const
428 {
429 const atomic_var_t MASK =
430 make_metadata_offset_mask<metadata_offset_t>();
431 return metadata_offset & MASK;
432 }
433
435 template<typename data_offset_t>
436 data_offset_t
437 mask_data_offset(const data_offset_t data_offset) const
438 {
439 const atomic_var_t MASK = make_data_offset_mask<data_offset_t>();
440 return data_offset & MASK;
441 }
442};
443
444// Aliases for the types of Ringbuffer that could be used.
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>>;
449
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>>;
454
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>
471atomic_var_t
472iterateDataRingbuffer(std::ostream & os,
473 const TranslatingPortProxy & proxy,
474 const ringbuffer_t & rb,
475 const atomic_var_t offset,
476 const guest_ptr_t first_metadata_offset,
477 const ByteOrder bo)
478{
479 using metadata_record_t = typename ringbuffer_t::metadata_record_t;
480
481 constexpr size_t METADATA_RECORD_SIZE =
482 sizeof(typename ringbuffer_t::metadata_record_t);
483 constexpr size_t INFO_RECORD_SIZE = sizeof(DmesgInfoRecord);
484
485 const guest_ptr_t DATA_OFFSET_MASK =
486 rb.template make_data_offset_mask<guest_ptr_t>();
487
488 // Read the offset of the metadata record from the beginning of
489 // the data record.
490 guest_ptr_t metadata_info_offset = rb.mask_metadata_offset(
491 proxy.read<guest_ptr_t>(rb.data.data_ring_ptr + offset, bo));
492
493 // If the metadata offset of the block is the same as the metadata
494 // offset of the first block of the data ringbuffer, then this
495 // data block is unsused (padding), and the iteration can wrap
496 // around to the beginning of the data ringbuffer (offset == 0).
497 if (metadata_info_offset == first_metadata_offset) {
498 return static_cast<atomic_var_t>(0);
499 }
500
501 // Read the metadata record from the metadata ringbuffer.
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);
507
508 // Read the info record from the info ringbuffer.
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);
514
515 // The metadata record should point back to the same data record
516 // in the data ringbuffer.
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);
522 }
523
524 // Read the message from the data record. This is placed
525 // immediately after the `guest_ptr_t` sized metadata offset at
526 // the beginning of the record.
527 std::vector<uint8_t> message(info.message_size);
528 proxy.readBlob(rb.data.data_ring_ptr + offset + sizeof(guest_ptr_t),
529 message.data(), info.message_size);
530
531 // Print the record
532 ccprintf(os, "[%.6f] ", info.ts_nsec * 10e-9);
533 os.write((char *)message.data(), info.message_size);
534 os << "\n";
535
536 // Return the offset of the next data record in the data
537 // ringbuffer.
538 return metadata.data_buffer.next_offset;
539}
540
545template <typename ringbuffer_t>
546void
547dumpDmesgImpl(ThreadContext *tc, std::ostream &os)
548{
549 using atomic_var_t = typename ringbuffer_t::atomic_var_t;
550 using guest_ptr_t = typename ringbuffer_t::guest_ptr_t;
551
552 System *system = tc->getSystemPtr();
553 const ByteOrder bo = system->getGuestByteOrder();
554 const auto &symtab = system->workload->symtab(tc);
555 TranslatingPortProxy proxy(tc);
556
557 auto symtab_end_it = symtab.end();
558
559 // Read the dynamic ringbuffer structure from guest memory, if present.
560 ringbuffer_t dynamic_rb;
561 auto dynamic_rb_symbol = symtab.find("printk_rb_dynamic");
562 if (dynamic_rb_symbol != symtab_end_it) {
563 dynamic_rb =
564 ringbuffer_t::read(proxy, dynamic_rb_symbol->address(), bo);
565 } else {
566 warn("Failed to find required dmesg symbols.\n");
567 return;
568 }
569
570 // Read the static ringbuffer structure from guest memory, if present.
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);
575 } else {
576 warn("Failed to find required dmesg symbols.\n");
577 return;
578 }
579
580 // Read the pointer to the active ringbuffer structure from guest
581 // memory. This should point to one of the two ringbuffer
582 // structures already read from guest memory.
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(),
588 bo);
589 } else {
590 warn("Failed to find required dmesg symbols.\n");
591 return;
592 }
593
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");
598 return;
599 }
600
601 ringbuffer_t & rb =
602 (active_ringbuffer_ptr == dynamic_rb_symbol->address())
603 ? dynamic_rb : static_rb;
604
605 atomic_var_t head_offset = rb.data.head_offset;
606 atomic_var_t tail_offset = rb.data.tail_offset;
607
608 // Get some marker offsets into the data ringbuffer which will be
609 // used as end values to control the iteration.
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;
614
615 // Iterate over the active ringbuffer, printing each message to
616 // `os`. Use the maximum number of possible info records plus one
617 // (invalid_metadata_offset) as an escape counter to make sure the
618 // process doesn't iterate infinitely if the kernel data
619 // structures have been corrupted.
620
621 // When head is behind tail, read to the end of the ringbuffer,
622 // then loop back to the begining.
623 //
624 // iterateDataRingbuffer will return offset at the beginning of
625 // the data ringbuffer when it loops back.
626 //
627 // `first_metadata_offset` is used to detect cases where the final data
628 // block is unused.
629 guest_ptr_t count = 0;
630 while (head_offset < tail_offset && count < invalid_metadata_offset) {
631 tail_offset =
632 iterateDataRingbuffer<ringbuffer_t>(
633 os, proxy, rb, tail_offset, first_metadata_offset, bo);
634 ++count;
635 }
636
637 // When tail is behind head, read forwards from the tail offset to
638 // the head offset.
639 count = 0;
640 while (tail_offset < head_offset && count < invalid_metadata_offset) {
641 tail_offset =
642 iterateDataRingbuffer<ringbuffer_t>(
643 os, proxy, rb, tail_offset, invalid_metadata_offset, bo);
644 ++count;
645 }
646}
647
653extract_printable_strings(const std::vector<uint8_t> buffer)
654{
656 std::string result;
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) {
663 if (byte == '\0') {
664 results.push_back(result);
665 }
666 result.clear();
667 reading_printable = false;
668 }
669 }
670 return results;
671}
672
695uint32_t
696extract_kernel_version(ThreadContext* tc) {
697 System *system = tc->getSystemPtr();
698 const auto &symtab = system->workload->symtab(tc);
699 auto symtab_end_it = symtab.end();
700
701 auto symbol = symtab.find("init_uts_ns");
702 if (symbol == symtab_end_it) {
703 return 0x0;
704 }
705
706 // Use size of `init_uts_ns` in Linux v5.18.0 as a default.
707 // (e.g. for upgraded checkpoints.)
708 const size_t INIT_UTS_NS_SIZE_DEFAULT = 432;
709 const size_t BUFFER_SIZE =
710 symbol->sizeOrDefault(INIT_UTS_NS_SIZE_DEFAULT);
711
712 TranslatingPortProxy proxy(tc);
713 std::vector<uint8_t> buffer(BUFFER_SIZE);
714 proxy.readBlob(
715 symbol->address(), buffer.data(), buffer.size() * sizeof(uint8_t));
716 auto strings = extract_printable_strings(buffer);
717
718 const std::regex version_re {"^(\\d+)\\.(\\d+)\\.(\\d)+$"};
719 std::smatch match;
720 for (const auto& string: strings) {
721 if (std::regex_search(string, match, version_re)) {
722 try {
723 int major = std::stoi(match[1]);
724 int minor = std::stoi(match[2]);
725 int point = std::stoi(match[3]);
726 return (
727 (major & 0xFF) << 16
728 | (minor & 0xFF) << 8
729 | std::min(point, 255));
730 }
731 catch (const std::invalid_argument &) {
732 // This shouldn't be possible if the regex matched.
733 continue;
734 }
735 catch (const std::out_of_range &) {
736 continue;
737 }
738 }
739 }
740
741 return 0x0;
742}
743
749void
750dumpDmesg(ThreadContext *tc, std::ostream &os)
751{
752 System *system = tc->getSystemPtr();
753 const bool os_is_64_bit = loader::archIs64Bit(system->workload->getArch());
754 const uint32_t kernel_version = extract_kernel_version(tc);
755 const uint32_t KERNEL_5_18_0 = 0x00051200;
756
757 if (kernel_version == 0x0) {
758 warn("Could not determine Linux Kernel version. "
759 "Assuming post-v5.18.0\n");
760 }
761
762 if (kernel_version == 0x0 || kernel_version >= KERNEL_5_18_0) {
763 if (os_is_64_bit) {
764 dumpDmesgImpl<Linux64_Ringbuffer_Post_v5_18_0>(tc, os);
765 } else {
766 dumpDmesgImpl<Linux32_Ringbuffer_Post_v5_18_0>(tc, os);
767 }
768 } else {
769 if (os_is_64_bit) {
770 dumpDmesgImpl<Linux64_Ringbuffer_Pre_v5_18_0>(tc, os);
771 } else {
772 dumpDmesgImpl<Linux32_Ringbuffer_Pre_v5_18_0>(tc, os);
773 }
774 }
775}
776
777} // namespace post5_10
778
779} // anonymous namespace
780
781void
782dumpDmesg(ThreadContext *tc, std::ostream &os)
783{
784 System *system = tc->getSystemPtr();
785 const auto &symtab = system->workload->symtab(tc);
786
787 auto end_it = symtab.end();
788
789 // Search for symbols associated with the Kernel Dmesg ringbuffer,
790 // pre-v5.10.
791 auto lb = symtab.find("__log_buf");
792 auto lb_len = symtab.find("log_buf_len");
793 auto first = symtab.find("log_first_idx");
794 auto next = symtab.find("log_next_idx");
795
796 if (lb != end_it && lb_len != end_it &&
797 first != end_it && next != end_it) {
798 linux::pre5_10::dumpDmesg(tc, os);
799 return;
800 }
801
802 // Search for symbols associated with the Kernel Dmesg ringbuffer,
803 // post-v5.10.
804 auto printk_rb_static = symtab.find("printk_rb_static");
805 auto printk_rb_dynamic = symtab.find("printk_rb_dynamic");
806
807 if (printk_rb_dynamic != end_it || printk_rb_static != end_it) {
808 linux::post5_10::dumpDmesg(tc, os);
809 return;
810 }
811
812 // Required symbols relating to the Kernel Dmesg buffer were not
813 // found for any supported version of Linux.
814 warn("Failed to find kernel dmesg symbols.\n");
815}
816
817} // namespace linux
818
819} // namespace gem5
const char data[]
void readBlob(Addr addr, void *p, uint64_t size) const
Higher level interfaces based on the above.
T read(Addr address) const
Read sizeof(T) bytes from address and return as object T.
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual System * getSystemPtr()=0
This proxy attempts to translate virtual addresses using the TLBs.
STL vector class.
Definition stl.hh:37
#define warn(...)
Definition logging.hh:288
#define warn_once(...)
Definition logging.hh:292
Bitfield< 18, 16 > len
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< 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:782
bool archIs64Bit(const loader::Arch arch)
Determine whether the loader::Arch is 64-bit or 32-bit.
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
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 Mon Oct 27 2025 04:13:02 for gem5 by doxygen 1.14.0