1717 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20- #if ! TREZOR_EMULATOR || PYOPT
20+ #if PYOPT
2121#define MEMINFO_DICT_ENTRIES /* empty */
2222
2323#else
3838#include "embed/rust/librust.h"
3939#include "embed/upymod/trezorobj.h"
4040
41+ #if !TREZOR_EMULATOR
42+ #define fopen (path , mode ) &mp_plat_print
43+ #define fprintf mp_printf
44+ #define fflush (f )
45+ #define fclose (f )
46+ #define FILE const mp_print_t
47+ #endif
48+
4149#define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / MP_BYTES_PER_OBJ_WORD)
4250#define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK)
4351
@@ -149,24 +157,38 @@ bool is_short(mp_const_obj_t value) {
149157 mp_obj_is_small_int (value ) || !VERIFY_PTR (value );
150158}
151159
160+ static void escape_and_dump_string (FILE * out , const char * unescaped ) {
161+ fprintf (out , "\"" );
162+ for (; * unescaped ; ++ unescaped ) {
163+ char c = * unescaped ;
164+ if (c == '\n' ) {
165+ fprintf (out , "\\n" );
166+ } else if (c == '\r' ) {
167+ fprintf (out , "\\r" );
168+ } else if (c == '\"' ) {
169+ fprintf (out , "\\\"" );
170+ } else if (c == '\\' ) {
171+ fprintf (out , "\\\\" );
172+ } else if (c >= 0x20 && c < 0x7F ) {
173+ fprintf (out , "%c" , c );
174+ } else {
175+ fprintf (out , "\\u%04x" , c );
176+ }
177+ }
178+ fprintf (out , "\"" );
179+ }
180+
152181static void print_type (FILE * out , const char * typename , const char * shortval ,
153182 const void * ptr , bool end ) {
154- static char unescaped [1000 ];
155183 size_t size = 0 ;
156184 if (!is_short (ptr )) {
157185 size = find_allocated_size (ptr );
158186 }
159187 fprintf (out , "{\"type\": \"%s\", \"alloc\": %ld, \"ptr\": \"%p\"" , typename ,
160188 size , ptr );
161189 if (shortval ) {
162- assert (strlen (shortval ) < 1000 );
163- char * c = unescaped ;
164- while (* shortval ) {
165- if (* shortval == '\\' || * shortval == '"' ) * c ++ = '\\' ;
166- * c ++ = * shortval ++ ;
167- }
168- * c = 0 ;
169- fprintf (out , ", \"shortval\": \"%s\"" , unescaped );
190+ fprintf (out , ", \"shortval\": " );
191+ escape_and_dump_string (out , shortval );
170192 } else {
171193 fprintf (out , ", \"shortval\": null" );
172194 }
@@ -199,7 +221,7 @@ void dump_short(FILE *out, mp_const_obj_t value) {
199221
200222 } else if (mp_obj_is_small_int (value )) {
201223 static char num_buf [100 ];
202- snprintf (num_buf , 100 , "%ld" , MP_OBJ_SMALL_INT_VALUE (value ));
224+ snprintf (num_buf , 100 , INT_FMT , MP_OBJ_SMALL_INT_VALUE (value ));
203225 print_type (out , "smallint" , num_buf , NULL , true);
204226
205227 } else if (!VERIFY_PTR (value )) {
@@ -680,10 +702,11 @@ void dump_qstr_pool(FILE *out, const qstr_pool_t *pool) {
680702 for (const char * const * q = pool -> qstrs , * const * q_top =
681703 pool -> qstrs + pool -> len ;
682704 q < q_top ; q ++ ) {
705+ escape_and_dump_string (out , Q_GET_DATA (* q ));
683706 if (q < (q_top - 1 ))
684- fprintf (out , "\"%s\" ,\n" , Q_GET_DATA ( * q ) );
707+ fprintf (out , ",\n" );
685708 else
686- fprintf (out , "\"%s\" ]\n" , Q_GET_DATA ( * q ) );
709+ fprintf (out , "]\n" );
687710 }
688711 fprintf (out , "},\n" );
689712 for (const char * const * q = pool -> qstrs , * const * q_top =
@@ -709,15 +732,19 @@ void dump_qstrdata(FILE *out) {
709732 }
710733}
711734
712- /// def meminfo(filename: str) -> None:
713- /// """Dumps map of micropython GC arena to a file.
714- /// The JSON file can be decoded by analyze-memory-dump.py
715- /// Only available in the emulator.
716- /// """
717- STATIC mp_obj_t mod_trezorutils_meminfo (mp_obj_t filename ) {
718- size_t fn_len ;
719- FILE * out = fopen (mp_obj_str_get_data (filename , & fn_len ), "w" );
720- fprintf (out , "[" );
735+ static void dump_meminfo_json (FILE * out ) {
736+ bool should_close = true;
737+ if (out == NULL ) {
738+ should_close = false;
739+ #if TREZOR_EMULATOR
740+ out = stdout ;
741+ #else
742+ out = & mp_plat_print ;
743+ #endif
744+ }
745+ fprintf (out , "\n[\n[" UINT_FMT ", " UINT_FMT ", " UINT_FMT "],\n" ,
746+ (mp_uint_t )MP_STATE_MEM (gc_pool_start ),
747+ (mp_uint_t )MP_STATE_MEM (gc_pool_end ), BYTES_PER_BLOCK );
721748
722749 // void **ptrs = (void **)(void *)&mp_state_ctx;
723750 // size_t root_start = offsetof(mp_state_ctx_t, thread.dict_locals);
@@ -768,8 +795,12 @@ STATIC mp_obj_t mod_trezorutils_meminfo(mp_obj_t filename) {
768795 pool = pool -> prev ;
769796 }
770797
771- fprintf (out , "null]\n" );
772- fclose (out );
798+ fprintf (out , "null\n]\n" );
799+ if (should_close ) {
800+ fclose (out );
801+ } else {
802+ fflush (out );
803+ }
773804 for (size_t block = 0 ;
774805 block < MP_STATE_MEM (gc_alloc_table_byte_len ) * BLOCKS_PER_ATB ;
775806 block ++ ) {
@@ -779,6 +810,19 @@ STATIC mp_obj_t mod_trezorutils_meminfo(mp_obj_t filename) {
779810 }
780811
781812 gc_dump_alloc_table ();
813+ }
814+
815+ /// def meminfo(filename: str | None) -> None:
816+ /// """Dumps map of micropython GC arena to a file.
817+ /// The JSON file can be decoded by analyze-memory-dump.py
818+ /// """
819+ STATIC mp_obj_t mod_trezorutils_meminfo (mp_obj_t filename ) {
820+ size_t fn_len ;
821+ FILE * out = (filename == mp_const_none )
822+ ? NULL
823+ : fopen (mp_obj_str_get_data (filename , & fn_len ), "w" );
824+ (void )fn_len ;
825+ dump_meminfo_json (out );
782826 return mp_const_none ;
783827}
784828STATIC MP_DEFINE_CONST_FUN_OBJ_1 (mod_trezorutils_meminfo_obj ,
0 commit comments