/src/ghostpdl/psi/idebug.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Debugging support for Ghostscript interpreter */ |
18 | | /* This file must always be compiled with DEBUG set. */ |
19 | | #undef DEBUG |
20 | | #define DEBUG |
21 | | #include "string_.h" |
22 | | #include "ghost.h" |
23 | | #include "gxalloc.h" /* for procs for getting struct type */ |
24 | | #include "idebug.h" /* defines interface */ |
25 | | #include "idict.h" |
26 | | #include "iname.h" |
27 | | #include "ipacked.h" |
28 | | #include "istack.h" |
29 | | #include "iutil.h" |
30 | | #include "ivmspace.h" |
31 | | #include "opdef.h" |
32 | | |
33 | | /* Table of type name strings */ |
34 | | static const char *const type_strings[] = { |
35 | | REF_TYPE_DEBUG_PRINT_STRINGS |
36 | | }; |
37 | | |
38 | | /* First unassigned type index */ |
39 | | extern const int tx_next_index; /* in interp.c */ |
40 | | |
41 | | /* Print a name. */ |
42 | | void |
43 | | debug_print_name(const gs_memory_t *mem, const ref * pnref) |
44 | 0 | { |
45 | 0 | ref sref; |
46 | |
|
47 | 0 | name_string_ref(mem, pnref, &sref); |
48 | 0 | debug_print_string(mem, sref.value.const_bytes, r_size(&sref)); |
49 | 0 | } |
50 | | void |
51 | | debug_print_name_index(const gs_memory_t *mem, name_index_t nidx) |
52 | 0 | { |
53 | 0 | ref nref; |
54 | |
|
55 | 0 | name_index_ref(mem, nidx, &nref); |
56 | 0 | debug_print_name(mem, &nref); |
57 | 0 | } |
58 | | |
59 | | /* Print a ref. */ |
60 | | static void |
61 | | debug_print_full_ref(const gs_memory_t *mem, const ref * pref) |
62 | 0 | { |
63 | 0 | uint size = r_size(pref); |
64 | 0 | ref nref; |
65 | |
|
66 | 0 | dmprintf1(mem, "(%x)", r_type_attrs(pref)); |
67 | 0 | switch (r_type(pref)) { |
68 | 0 | case t_array: |
69 | 0 | dmprintf2(mem, "array(%u)"PRI_INTPTR, size, (intptr_t)pref->value.refs); |
70 | 0 | break; |
71 | 0 | case t_astruct: |
72 | 0 | goto strct; |
73 | 0 | case t_boolean: |
74 | 0 | dmprintf1(mem, "boolean %x", pref->value.boolval); |
75 | 0 | break; |
76 | 0 | case t_device: |
77 | 0 | dmprintf1(mem, "device "PRI_INTPTR, (intptr_t) pref->value.pdevice->device); |
78 | 0 | break; |
79 | 0 | case t_dictionary: |
80 | 0 | dmprintf3(mem, "dict(%u/%u)"PRI_INTPTR, |
81 | 0 | dict_length(pref), dict_maxlength(pref), |
82 | 0 | (intptr_t)pref->value.pdict); |
83 | 0 | break; |
84 | 0 | case t_file: |
85 | 0 | dmprintf1(mem, "file "PRI_INTPTR, (intptr_t)pref->value.pfile); |
86 | 0 | break; |
87 | 0 | case t_fontID: |
88 | 0 | goto strct; |
89 | 0 | case t_integer: |
90 | 0 | dmprintf1(mem, "int %"PRIpsint, pref->value.intval); |
91 | 0 | break; |
92 | 0 | case t_mark: |
93 | 0 | dmprintf(mem, "mark"); |
94 | 0 | break; |
95 | 0 | case t_mixedarray: |
96 | 0 | dmprintf2(mem, "mixed packedarray(%u)"PRI_INTPTR"", size, |
97 | 0 | (intptr_t)pref->value.packed); |
98 | 0 | break; |
99 | 0 | case t_name: |
100 | 0 | dmprintf2(mem, "name("PRI_INTPTR"#%u)", (intptr_t)pref->value.pname, |
101 | 0 | name_index(mem, pref)); |
102 | 0 | debug_print_name(mem, pref); |
103 | 0 | break; |
104 | 0 | case t_null: |
105 | 0 | dmprintf(mem, "null"); |
106 | 0 | break; |
107 | 0 | case t_oparray: |
108 | 0 | dmprintf2(mem, "op_array(%u)"PRI_INTPTR":", size, (intptr_t) pref->value.const_refs); |
109 | 0 | { |
110 | 0 | const op_array_table *opt = get_op_array(mem, size); |
111 | |
|
112 | 0 | name_index_ref(mem, opt->nx_table[size - opt->base_index], &nref); |
113 | 0 | } |
114 | 0 | debug_print_name(mem, &nref); |
115 | 0 | break; |
116 | 0 | case t_operator: |
117 | 0 | dmprintf1(mem, "op(%u", size); |
118 | 0 | if (size > 0 && size < op_def_count) /* just in case */ |
119 | 0 | dmprintf1(mem, ":%s", (const char *)(op_index_def(size)->oname + 1)); |
120 | 0 | dmprintf1(mem, ")"PRI_INTPTR"", (intptr_t)pref->value.opproc); |
121 | 0 | break; |
122 | 0 | case t_real: |
123 | 0 | dmprintf1(mem, "real %f", pref->value.realval); |
124 | 0 | break; |
125 | 0 | case t_save: |
126 | 0 | dmprintf1(mem, "save %lu", pref->value.saveid); |
127 | 0 | break; |
128 | 0 | case t_shortarray: |
129 | 0 | dmprintf2(mem, "short packedarray(%u)"PRI_INTPTR"", size, |
130 | 0 | (intptr_t)pref->value.packed); |
131 | 0 | break; |
132 | 0 | case t_string: |
133 | 0 | dmprintf2(mem, "string(%u)"PRI_INTPTR"", size, (intptr_t)pref->value.bytes); |
134 | 0 | break; |
135 | 0 | case t_pdfctx: |
136 | 0 | case t_struct: |
137 | 0 | strct:{ |
138 | 0 | obj_header_t *obj = (obj_header_t *) pref->value.pstruct; |
139 | | /* HACK: We know this object was allocated with gsalloc.c. */ |
140 | 0 | gs_memory_type_ptr_t otype = |
141 | 0 | gs_ref_memory_procs.object_type(NULL, obj); |
142 | |
|
143 | 0 | dmprintf2(mem, "struct %s "PRI_INTPTR"", |
144 | 0 | (r_is_foreign(pref) ? "-foreign-" : |
145 | 0 | gs_struct_type_name_string(otype)), |
146 | 0 | (intptr_t)obj); |
147 | 0 | } |
148 | 0 | break; |
149 | 0 | default: |
150 | 0 | dmprintf1(mem, "type 0x%x", r_type(pref)); |
151 | 0 | } |
152 | 0 | } |
153 | | static void |
154 | | debug_print_packed_ref(const gs_memory_t *mem, const ref_packed *pref) |
155 | 0 | { |
156 | 0 | ushort elt = *pref & packed_value_mask; |
157 | 0 | ref nref; |
158 | |
|
159 | 0 | switch (*pref >> r_packed_type_shift) { |
160 | 0 | case pt_executable_operator: |
161 | 0 | dmprintf(mem, "<op_name>"); |
162 | 0 | op_index_ref(mem, elt, &nref); |
163 | 0 | debug_print_ref(mem, &nref); |
164 | 0 | break; |
165 | 0 | case pt_integer: |
166 | 0 | dmprintf1(mem, "<int> %d", (int)elt + packed_min_intval); |
167 | 0 | break; |
168 | 0 | case pt_literal_name: |
169 | 0 | dmprintf(mem, "<lit_name>"); |
170 | 0 | goto ptn; |
171 | 0 | case pt_executable_name: |
172 | 0 | dmprintf(mem, "<exec_name>"); |
173 | 0 | ptn: name_index_ref(mem, elt, &nref); |
174 | 0 | dmprintf2(mem, "("PRI_INTPTR"#%u)", (intptr_t) nref.value.pname, elt); |
175 | 0 | debug_print_name(mem, &nref); |
176 | 0 | break; |
177 | 0 | default: |
178 | 0 | dmprintf2(mem, "<packed_%d?>0x%x", *pref >> r_packed_type_shift, elt); |
179 | 0 | } |
180 | 0 | } |
181 | | void |
182 | | debug_print_ref_packed(const gs_memory_t *mem, const ref_packed *rpp) |
183 | 0 | { |
184 | 0 | if (r_is_packed(rpp)) |
185 | 0 | debug_print_packed_ref(mem, rpp); |
186 | 0 | else |
187 | 0 | debug_print_full_ref(mem, (const ref *)rpp); |
188 | 0 | dmflush(mem); |
189 | 0 | } |
190 | | void |
191 | | debug_print_ref(const gs_memory_t *mem, const ref * pref) |
192 | 0 | { |
193 | 0 | debug_print_ref_packed(mem, (const ref_packed *)pref); |
194 | 0 | } |
195 | | |
196 | | /* Dump one ref. */ |
197 | | static void print_ref_data(const gs_memory_t *mem, const ref *); |
198 | | void |
199 | | debug_dump_one_ref(const gs_memory_t *mem, const ref * p) |
200 | 0 | { |
201 | 0 | uint attrs = r_type_attrs(p); |
202 | 0 | uint type = r_type(p); |
203 | 0 | static const ref_attr_print_mask_t apm[] = { |
204 | 0 | REF_ATTR_PRINT_MASKS, |
205 | 0 | {0, 0, 0} |
206 | 0 | }; |
207 | 0 | const ref_attr_print_mask_t *ap = apm; |
208 | |
|
209 | 0 | if (type >= tx_next_index) |
210 | 0 | dmprintf1(mem, "0x%02x?? ", type); |
211 | 0 | else if (type >= t_next_index) |
212 | 0 | dmprintf(mem, "opr* "); |
213 | 0 | else |
214 | 0 | dmprintf1(mem, "%s ", type_strings[type]); |
215 | 0 | for (; ap->mask; ++ap) |
216 | 0 | if ((attrs & ap->mask) == ap->value) |
217 | 0 | dmputc(mem, ap->print); |
218 | 0 | dmprintf2(mem, " 0x%04x 0x%08lx", r_size(p), *(const ulong *)&p->value); |
219 | 0 | print_ref_data(mem, p); |
220 | 0 | dmflush(mem); |
221 | 0 | } |
222 | | static void |
223 | | print_ref_data(const gs_memory_t *mem, const ref *p) |
224 | 0 | { |
225 | 0 | #define BUF_SIZE 30 |
226 | 0 | byte buf[BUF_SIZE + 1]; |
227 | 0 | const byte *pchars; |
228 | 0 | uint plen; |
229 | |
|
230 | 0 | if (obj_cvs(mem, p, buf, countof(buf) - 1, &plen, &pchars) >= 0 && |
231 | 0 | pchars == buf && |
232 | 0 | ((buf[plen] = 0), strcmp((char *)buf, "--nostringval--")) |
233 | 0 | ) |
234 | 0 | dmprintf1(mem, " = %s", (char *)buf); |
235 | 0 | #undef BUF_SIZE |
236 | 0 | } |
237 | | |
238 | | /* Dump a region of memory containing refs. */ |
239 | | void |
240 | | debug_dump_refs(const gs_memory_t *mem, const ref * from, |
241 | | uint size, const char *msg) |
242 | 0 | { |
243 | 0 | const ref *p = from; |
244 | 0 | uint count = size; |
245 | |
|
246 | 0 | if (size && msg) |
247 | 0 | dmprintf2(mem, "%s at "PRI_INTPTR":\n", msg, (intptr_t)from); |
248 | 0 | while (count--) { |
249 | 0 | dmprintf2(mem, PRI_INTPTR": 0x%04x ", (intptr_t)p, r_type_attrs(p)); |
250 | 0 | debug_dump_one_ref(mem, p); |
251 | 0 | dmputc(mem, '\n'); |
252 | 0 | p++; |
253 | 0 | } |
254 | 0 | } |
255 | | |
256 | | /* Dump a stack. */ |
257 | | void |
258 | | debug_dump_stack(const gs_memory_t *mem, |
259 | | const ref_stack_t * pstack, const char *msg) |
260 | 0 | { |
261 | 0 | int i; |
262 | 0 | const char *m = msg; |
263 | |
|
264 | 0 | for (i = ref_stack_count(pstack); i > 0;) { |
265 | 0 | const ref *p = ref_stack_index(pstack, --i); |
266 | |
|
267 | 0 | if (m) { |
268 | 0 | dmprintf2(mem, "%s at "PRI_INTPTR":\n", m, (intptr_t)pstack); |
269 | 0 | m = NULL; |
270 | 0 | } |
271 | 0 | dmprintf2(mem, PRI_INTPTR": 0x%02x ", (intptr_t)p, r_type(p)); |
272 | 0 | debug_dump_one_ref(mem, p); |
273 | 0 | dmputc(mem, '\n'); |
274 | 0 | } |
275 | 0 | } |
276 | | |
277 | | /* Dump an array. */ |
278 | | void |
279 | | debug_dump_array(const gs_memory_t *mem, const ref * array) |
280 | 0 | { |
281 | 0 | const ref_packed *pp; |
282 | 0 | uint type = r_type(array); |
283 | 0 | uint len; |
284 | |
|
285 | 0 | switch (type) { |
286 | 0 | default: |
287 | 0 | dmprintf2(mem, "%s at "PRI_INTPTR" isn't an array.\n", |
288 | 0 | (type < countof(type_strings) ? |
289 | 0 | type_strings[type] : "????"), |
290 | 0 | (intptr_t)array); |
291 | 0 | return; |
292 | 0 | case t_oparray: |
293 | | /* This isn't really an array, but we'd like to see */ |
294 | | /* its contents anyway. */ |
295 | 0 | debug_dump_array(mem, array->value.const_refs); |
296 | 0 | return; |
297 | 0 | case t_array: |
298 | 0 | case t_mixedarray: |
299 | 0 | case t_shortarray: |
300 | 0 | ; |
301 | 0 | } |
302 | | |
303 | | /* This "packed" loop works for all array-types. */ |
304 | 0 | for (len = r_size(array), pp = array->value.packed; |
305 | 0 | len > 0; |
306 | 0 | len--, pp = packed_next(pp)) { |
307 | 0 | ref temp; |
308 | |
|
309 | 0 | packed_get(mem, pp, &temp); |
310 | 0 | if (r_is_packed(pp)) { |
311 | 0 | dmprintf2(mem, PRI_INTPTR"* 0x%04x ", (intptr_t)pp, (uint)*pp); |
312 | 0 | print_ref_data(mem, &temp); |
313 | 0 | } else { |
314 | 0 | dmprintf2(mem, PRI_INTPTR": 0x%02x ", (intptr_t)pp, r_type(&temp)); |
315 | 0 | debug_dump_one_ref(mem, &temp); |
316 | 0 | } |
317 | 0 | dmputc(mem, '\n'); |
318 | 0 | } |
319 | 0 | } |