1111
1212#include "binary_io.h"
1313#include "_remote_debugging.h"
14+ #include "pycore_bitutils.h" /* _Py_bswap32, _Py_bswap64 for cross-endian reading */
1415#include <string.h>
1516
1617#ifdef HAVE_ZSTD
@@ -49,7 +50,13 @@ reader_parse_header(BinaryReader *reader, const uint8_t *data, size_t file_size)
4950 memcpy (& magic , & data [0 ], sizeof (magic ));
5051 memcpy (& version , & data [4 ], sizeof (version ));
5152
52- if (magic != BINARY_FORMAT_MAGIC ) {
53+ /* Detect endianness from magic number */
54+ if (magic == BINARY_FORMAT_MAGIC ) {
55+ reader -> needs_swap = 0 ;
56+ } else if (magic == BINARY_FORMAT_MAGIC_SWAPPED ) {
57+ reader -> needs_swap = 1 ;
58+ version = _Py_bswap32 (version );
59+ } else {
5360 PyErr_Format (PyExc_ValueError , "Invalid magic number: 0x%08x" , magic );
5461 return -1 ;
5562 }
@@ -77,13 +84,26 @@ reader_parse_header(BinaryReader *reader, const uint8_t *data, size_t file_size)
7784 reader -> py_major = data [HDR_OFF_PY_MAJOR ];
7885 reader -> py_minor = data [HDR_OFF_PY_MINOR ];
7986 reader -> py_micro = data [HDR_OFF_PY_MICRO ];
80- memcpy (& reader -> start_time_us , & data [HDR_OFF_START_TIME ], HDR_SIZE_START_TIME );
81- memcpy (& reader -> sample_interval_us , & data [HDR_OFF_INTERVAL ], HDR_SIZE_INTERVAL );
82- memcpy (& reader -> sample_count , & data [HDR_OFF_SAMPLES ], HDR_SIZE_SAMPLES );
83- memcpy (& reader -> thread_count , & data [HDR_OFF_THREADS ], HDR_SIZE_THREADS );
84- memcpy (& reader -> string_table_offset , & data [HDR_OFF_STR_TABLE ], HDR_SIZE_STR_TABLE );
85- memcpy (& reader -> frame_table_offset , & data [HDR_OFF_FRAME_TABLE ], HDR_SIZE_FRAME_TABLE );
86- memcpy (& reader -> compression_type , & data [HDR_OFF_COMPRESSION ], HDR_SIZE_COMPRESSION );
87+
88+ /* Read header fields with byte-swapping if needed */
89+ uint64_t start_time_us , sample_interval_us , string_table_offset , frame_table_offset ;
90+ uint32_t sample_count , thread_count , compression_type ;
91+
92+ memcpy (& start_time_us , & data [HDR_OFF_START_TIME ], HDR_SIZE_START_TIME );
93+ memcpy (& sample_interval_us , & data [HDR_OFF_INTERVAL ], HDR_SIZE_INTERVAL );
94+ memcpy (& sample_count , & data [HDR_OFF_SAMPLES ], HDR_SIZE_SAMPLES );
95+ memcpy (& thread_count , & data [HDR_OFF_THREADS ], HDR_SIZE_THREADS );
96+ memcpy (& string_table_offset , & data [HDR_OFF_STR_TABLE ], HDR_SIZE_STR_TABLE );
97+ memcpy (& frame_table_offset , & data [HDR_OFF_FRAME_TABLE ], HDR_SIZE_FRAME_TABLE );
98+ memcpy (& compression_type , & data [HDR_OFF_COMPRESSION ], HDR_SIZE_COMPRESSION );
99+
100+ reader -> start_time_us = SWAP64_IF (reader -> needs_swap , start_time_us );
101+ reader -> sample_interval_us = SWAP64_IF (reader -> needs_swap , sample_interval_us );
102+ reader -> sample_count = SWAP32_IF (reader -> needs_swap , sample_count );
103+ reader -> thread_count = SWAP32_IF (reader -> needs_swap , thread_count );
104+ reader -> string_table_offset = SWAP64_IF (reader -> needs_swap , string_table_offset );
105+ reader -> frame_table_offset = SWAP64_IF (reader -> needs_swap , frame_table_offset );
106+ reader -> compression_type = (int )SWAP32_IF (reader -> needs_swap , compression_type );
87107
88108 return 0 ;
89109}
@@ -98,8 +118,12 @@ reader_parse_footer(BinaryReader *reader, const uint8_t *data, size_t file_size)
98118
99119 const uint8_t * footer = data + file_size - FILE_FOOTER_SIZE ;
100120 /* Use memcpy to avoid strict aliasing violations */
101- memcpy (& reader -> strings_count , & footer [0 ], sizeof (reader -> strings_count ));
102- memcpy (& reader -> frames_count , & footer [4 ], sizeof (reader -> frames_count ));
121+ uint32_t strings_count , frames_count ;
122+ memcpy (& strings_count , & footer [0 ], sizeof (strings_count ));
123+ memcpy (& frames_count , & footer [4 ], sizeof (frames_count ));
124+
125+ reader -> strings_count = SWAP32_IF (reader -> needs_swap , strings_count );
126+ reader -> frames_count = SWAP32_IF (reader -> needs_swap , frames_count );
103127
104128 return 0 ;
105129}
@@ -857,15 +881,18 @@ binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progre
857881 break ; /* End of data */
858882 }
859883
860- /* Use memcpy to avoid strict aliasing violations */
861- uint64_t thread_id ;
862- uint32_t interpreter_id ;
863- memcpy (& thread_id , & reader -> sample_data [offset ], sizeof (thread_id ));
884+ /* Use memcpy to avoid strict aliasing violations, then byte-swap if needed */
885+ uint64_t thread_id_raw ;
886+ uint32_t interpreter_id_raw ;
887+ memcpy (& thread_id_raw , & reader -> sample_data [offset ], sizeof (thread_id_raw ));
864888 offset += 8 ;
865889
866- memcpy (& interpreter_id , & reader -> sample_data [offset ], sizeof (interpreter_id ));
890+ memcpy (& interpreter_id_raw , & reader -> sample_data [offset ], sizeof (interpreter_id_raw ));
867891 offset += 4 ;
868892
893+ uint64_t thread_id = SWAP64_IF (reader -> needs_swap , thread_id_raw );
894+ uint32_t interpreter_id = SWAP32_IF (reader -> needs_swap , interpreter_id_raw );
895+
869896 /* Get or create thread state for reconstruction */
870897 ReaderThreadState * ts = reader_get_or_create_thread_state (reader , thread_id , interpreter_id );
871898 if (!ts ) {
0 commit comments