/* Jitter: data locations: header. Copyright (C) 2019, 2020, 2021 Luca Saiu Written by Luca Saiu This file is part of Jitter. Jitter is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jitter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jitter. If not, see . */ #ifndef JITTER_DATA_LOCATIONS_H_ #define JITTER_DATA_LOCATIONS_H_ #include #include #include #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT) # include #endif // #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT) #include #include /* Low-level debugging features relying on assembly: data locations. * ************************************************************************** */ /* Information about where a certain datum is held at run time in the executor. */ struct jitter_data_location { /* The datum name. */ const char *name; /* The datum location, as text, in assembly notation as emitted by GCC. */ const char *location; /* Non-false iff the datum is held in a register. */ bool register_; }; /* An array of data locations, with a field holding its size. */ struct jitter_data_locations { /* An array of data, as elements of the struct above. */ struct jitter_data_location *data_locations; /* How many data there are. */ size_t data_location_no; /* Non-false iff the information contained in data_locations is known to be reliable. The information may not be reliable if some datum is not accessible from a register or as a single memory operand, and instead requires additional loads. That would be a symptom of some problem. */ bool reliable; }; /* Given a pointer to the VM data structure, return a pointer to a freshly allocated struct jitter_data_location_data object. This function is used by machine-generated code. */ struct jitter_data_locations * jitter_make_data_locations (const struct jitter_vm *vm) __attribute__ ((nonnull (1), returns_nonnull)); /* Destroy the data structure allocated from the previous function. */ void jitter_destroy_data_locations (struct jitter_data_locations *locations) __attribute__ ((nonnull (1))); /* Data locations: human-readable output. * ************************************************************************** */ /* Output a human-readable message about data locations for the pointed VM to the given print context. */ void jitter_dump_data_locations (jitter_print_context ctx, const struct jitter_vm *vm) __attribute__ ((nonnull (1, 2))); /* Data location macros. * ************************************************************************** */ /* The following macros provide a way of emitting information about specific data, as registers or register-based memory locations, *as strings* in a separate subsection, all as part of the definition of a global symbol visible from C as a global variable. This can be useful to read from memory and print out to help the user follow VM instruction disassemblies. This functionality is used by machine-generated code. */ /* This functionality is not actually available if the host binary format is not supported. In that case, define compatibility stubs. */ #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT) /* Data locations are actually supported. */ /* The name of the global variable holding data prefixes. */ # define JITTER_DATA_LOCATION_NAME(_jitter_vm_the_prefix) \ JITTER_CONCATENATE_TWO(_jitter_vm_the_prefix, _data_locations) /* The subsection number for data locations. */ # define JITTER_ASM_DATA_LOCATION_SUBSECTION \ "12" /* Begin the global definition for data locations for the VM with the given vmprefix. This temporarily enters the appropriate subsection, emits a symbol definition, and pops back to the previous subsection. Between a call to this macro and a call to JITTER_DATA_LOCATION_FOOTER the user is supposed to emit location data for every datum, in some predictable order. The defined global is only one. */ # define JITTER_DATA_LOCATION_HEADER(_jitter_vm_the_prefix) \ asm (/* Generate the identifier definition in assembly. */ \ JITTER_ASM_OPEN_DEFINITION (JITTER_ASM_DATA_LOCATION_SUBSECTION, \ JITTER_DATA_LOCATION_NAME \ (_jitter_vm_the_prefix))) /* End the global definition for data locations, for the VM with the given vmprefix. This enters, and then exits, the appropriate subsection. */ # define JITTER_DATA_LOCATION_FOOTER(_jitter_vm_the_prefix) \ asm (/* Emit the final empty string as "\0". */ \ JITTER_ASM_ENTER_SUBSECTION( JITTER_ASM_DATA_LOCATION_SUBSECTION) \ ".byte 0\n\t" \ JITTER_ASM_EXIT_SUBSECTION \ /* Close the identifier definition in assembly. */ \ JITTER_ASM_CLOSE_DEFINITION (JITTER_ASM_DATA_LOCATION_SUBSECTION, \ JITTER_DATA_LOCATION_NAME \ (_jitter_vm_the_prefix))) /* Emit the location for the given datum with the given name as two '\0'-terminated strings, in the data location subsection. For example, if foo is a local variable currently kept in some hardware register named $r10, then the macro call JITTER_DATA_LOCATION_DATUM("the foo variable", foo); will emit .asciz "the foo variable" .asciz "$r10" in the data location subsection. Notice that: - name_as_string is emitted as is in an extended-asm template, therefore any '%' character must be escaped as "%%"; - name_as_string_literal must never be an empty string, since an empty string terminates the entire data structure. */ # define JITTER_DATA_LOCATION_DATUM(name_as_string_literal, datum) \ asm volatile (JITTER_ASM_ENTER_SUBSECTION( \ JITTER_ASM_DATA_LOCATION_SUBSECTION) \ "\n" JITTER_ASM_COMMENT_PREFIX \ name_as_string_literal " " JITTER_STRINGIFY(datum) "\n" \ ".asciz \"" name_as_string_literal "\"\n" \ ".asciz \"%[datum_from_asm]\"\n\t" \ JITTER_ASM_EXIT_SUBSECTION \ : /* outputs */ \ : [datum_from_asm] "X" (datum) /* inputs */) #else // ! defined (JITTER_HAVE_KNOWN_BINARY_FORMAT) /* Use dummy macros emitting no data locations, for compatibility. */ # define JITTER_DATA_LOCATION_HEADER(_jitter_vm_the_prefix) /* Nothing. */ # define JITTER_DATA_LOCATION_FOOTER(_jitter_vm_the_prefix) /* Nothing. */ # define JITTER_DATA_LOCATION_DATUM(name_as_string_literal, datum) /* Nothing. */ #endif // #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT) #endif // #ifndef JITTER_DATA_LOCATIONS_H_