1 /* Jitter: data locations: header.
2 
3    Copyright (C) 2019, 2020, 2021 Luca Saiu
4    Written by Luca Saiu
5 
6    This file is part of Jitter.
7 
8    Jitter is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation, either version 3 of the License, or
11    (at your option) any later version.
12 
13    Jitter is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with Jitter.  If not, see <http://www.gnu.org/licenses/>. */
20 
21 
22 #ifndef JITTER_DATA_LOCATIONS_H_
23 #define JITTER_DATA_LOCATIONS_H_
24 
25 #include <stdio.h>
26 #include <stdbool.h>
27 
28 #include <jitter/jitter.h>
29 #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT)
30 # include <jitter/jitter-sections.h>
31 #endif // #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT)
32 #include <jitter/jitter-print.h>
33 #include <jitter/jitter-vm.h>
34 
35 
36 /* Low-level debugging features relying on assembly: data locations.
37  * ************************************************************************** */
38 
39 /* Information about where a certain datum is held at run time in the
40    executor. */
41 struct jitter_data_location
42 {
43   /* The datum name. */
44   const char *name;
45 
46   /* The datum location, as text, in assembly notation as emitted by GCC. */
47   const char *location;
48 
49   /* Non-false iff the datum is held in a register. */
50   bool register_;
51 };
52 
53 /* An array of data locations, with a field holding its size. */
54 struct jitter_data_locations
55 {
56   /* An array of data, as elements of the struct above. */
57   struct jitter_data_location *data_locations;
58 
59   /* How many data there are. */
60   size_t data_location_no;
61 
62   /* Non-false iff the information contained in data_locations is known to be
63      reliable.  The information may not be reliable if some datum is not
64      accessible from a register or as a single memory operand, and instead
65      requires additional loads.  That would be a symptom of some problem. */
66   bool reliable;
67 };
68 
69 /* Given a pointer to the VM data structure, return a pointer to a freshly
70    allocated struct jitter_data_location_data object.  This function is used by
71    machine-generated code. */
72 struct jitter_data_locations *
73 jitter_make_data_locations (const struct jitter_vm *vm)
74   __attribute__ ((nonnull (1), returns_nonnull));
75 
76 /* Destroy the data structure allocated from the previous function. */
77 void
78 jitter_destroy_data_locations (struct jitter_data_locations *locations)
79   __attribute__ ((nonnull (1)));
80 
81 
82 
83 
84 /* Data locations: human-readable output.
85  * ************************************************************************** */
86 
87 /* Output a human-readable message about data locations for the pointed VM to
88    the given print context. */
89 void
90 jitter_dump_data_locations (jitter_print_context ctx, const struct jitter_vm *vm)
91   __attribute__ ((nonnull (1, 2)));
92 
93 
94 
95 
96 /* Data location macros.
97  * ************************************************************************** */
98 
99 /* The following macros provide a way of emitting information about specific
100    data, as registers or register-based memory locations, *as strings* in a
101    separate subsection, all as part of the definition of a global symbol visible
102    from C as a global variable.  This can be useful to read from memory and
103    print out to help the user follow VM instruction disassemblies.
104 
105    This functionality is used by machine-generated code. */
106 
107 /* This functionality is not actually available if the host binary format is not
108    supported.  In that case, define compatibility stubs. */
109 #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT)
110   /* Data locations are actually supported. */
111 
112   /* The name of the global variable holding data prefixes. */
113 # define JITTER_DATA_LOCATION_NAME(_jitter_vm_the_prefix)  \
114     JITTER_CONCATENATE_TWO(_jitter_vm_the_prefix, _data_locations)
115 
116   /* The subsection number for data locations. */
117 # define JITTER_ASM_DATA_LOCATION_SUBSECTION  \
118     "12"
119 
120   /* Begin the global definition for data locations for the VM with the given
121      vmprefix.  This temporarily enters the appropriate subsection, emits a symbol
122      definition, and pops back to the previous subsection.  Between a call to this
123      macro and a call to JITTER_DATA_LOCATION_FOOTER the user is supposed to emit
124      location data for every datum, in some predictable order.  The defined global
125      is only one. */
126 # define JITTER_DATA_LOCATION_HEADER(_jitter_vm_the_prefix)                \
127     asm (/* Generate the identifier definition in assembly. */             \
128          JITTER_ASM_OPEN_DEFINITION (JITTER_ASM_DATA_LOCATION_SUBSECTION,  \
129                                      JITTER_DATA_LOCATION_NAME             \
130                                         (_jitter_vm_the_prefix)))
131 
132   /* End the global definition for data locations, for the VM with the given
133      vmprefix.  This enters, and then exits, the appropriate subsection. */
134 # define JITTER_DATA_LOCATION_FOOTER(_jitter_vm_the_prefix)                 \
135     asm (/* Emit the final empty string as "\0". */                         \
136          JITTER_ASM_ENTER_SUBSECTION( JITTER_ASM_DATA_LOCATION_SUBSECTION)  \
137          ".byte 0\n\t"                                                      \
138          JITTER_ASM_EXIT_SUBSECTION                                         \
139          /* Close the identifier definition in assembly. */                 \
140          JITTER_ASM_CLOSE_DEFINITION (JITTER_ASM_DATA_LOCATION_SUBSECTION,  \
141                                       JITTER_DATA_LOCATION_NAME             \
142                                          (_jitter_vm_the_prefix)))
143 
144   /* Emit the location for the given datum with the given name as two
145      '\0'-terminated strings, in the data location subsection.
146      For example, if foo is a local variable currently kept in some hardware
147      register named $r10, then the macro call
148        JITTER_DATA_LOCATION_DATUM("the foo variable", foo);
149      will emit
150        .asciz "the foo variable"
151        .asciz "$r10"
152      in the data location subsection.
153      Notice that:
154      - name_as_string is emitted as is in an extended-asm template,
155        therefore any '%' character must be escaped as "%%";
156      - name_as_string_literal must never be an empty string, since an
157        empty string terminates the entire data structure. */
158 # define JITTER_DATA_LOCATION_DATUM(name_as_string_literal, datum)             \
159     asm volatile (JITTER_ASM_ENTER_SUBSECTION(                                 \
160                      JITTER_ASM_DATA_LOCATION_SUBSECTION)                      \
161                   "\n" JITTER_ASM_COMMENT_PREFIX                               \
162                        name_as_string_literal " " JITTER_STRINGIFY(datum) "\n" \
163                   ".asciz \"" name_as_string_literal "\"\n"                    \
164                   ".asciz \"%[datum_from_asm]\"\n\t"                           \
165                   JITTER_ASM_EXIT_SUBSECTION                                   \
166                   : /* outputs */                                              \
167                   : [datum_from_asm] "X" (datum) /* inputs */)
168 #else // ! defined (JITTER_HAVE_KNOWN_BINARY_FORMAT)
169   /* Use dummy macros emitting no data locations, for compatibility. */
170 # define JITTER_DATA_LOCATION_HEADER(_jitter_vm_the_prefix)         /* Nothing. */
171 # define JITTER_DATA_LOCATION_FOOTER(_jitter_vm_the_prefix)         /* Nothing. */
172 # define JITTER_DATA_LOCATION_DATUM(name_as_string_literal, datum)  /* Nothing. */
173 #endif // #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT)
174 
175 
176 #endif // #ifndef JITTER_DATA_LOCATIONS_H_
177