Breakpoints, don't skip prologue of ifunc resolvers with debug info
[deliverable/binutils-gdb.git] / gdb / common / format.c
1 /* Parse a printf-style format string.
2
3 Copyright (C) 1986-2018 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20 #include "common-defs.h"
21 #include "format.h"
22
23 format_pieces::format_pieces (const char **arg)
24 {
25 const char *s;
26 char *f, *string;
27 const char *prev_start;
28 const char *percent_loc;
29 char *sub_start, *current_substring;
30 enum argclass this_argclass;
31
32 s = *arg;
33
34 /* Parse the format-control string and copy it into the string STRING,
35 processing some kinds of escape sequence. */
36
37 f = string = (char *) alloca (strlen (s) + 1);
38
39 while (*s != '"' && *s != '\0')
40 {
41 int c = *s++;
42 switch (c)
43 {
44 case '\0':
45 continue;
46
47 case '\\':
48 switch (c = *s++)
49 {
50 case '\\':
51 *f++ = '\\';
52 break;
53 case 'a':
54 *f++ = '\a';
55 break;
56 case 'b':
57 *f++ = '\b';
58 break;
59 case 'f':
60 *f++ = '\f';
61 break;
62 case 'n':
63 *f++ = '\n';
64 break;
65 case 'r':
66 *f++ = '\r';
67 break;
68 case 't':
69 *f++ = '\t';
70 break;
71 case 'v':
72 *f++ = '\v';
73 break;
74 case '"':
75 *f++ = '"';
76 break;
77 default:
78 /* ??? TODO: handle other escape sequences. */
79 error (_("Unrecognized escape character \\%c in format string."),
80 c);
81 }
82 break;
83
84 default:
85 *f++ = c;
86 }
87 }
88
89 /* Terminate our escape-processed copy. */
90 *f++ = '\0';
91
92 /* Whether the format string ended with double-quote or zero, we're
93 done with it; it's up to callers to complain about syntax. */
94 *arg = s;
95
96 /* Need extra space for the '\0's. Doubling the size is sufficient. */
97
98 current_substring = (char *) xmalloc (strlen (string) * 2 + 1000);
99 m_storage.reset (current_substring);
100
101 /* Now scan the string for %-specs and see what kinds of args they want.
102 argclass classifies the %-specs so we can give printf-type functions
103 something of the right size. */
104
105 f = string;
106 prev_start = string;
107 while (*f)
108 if (*f++ == '%')
109 {
110 int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0;
111 int seen_space = 0, seen_plus = 0;
112 int seen_big_l = 0, seen_h = 0, seen_big_h = 0;
113 int seen_big_d = 0, seen_double_big_d = 0;
114 int bad = 0;
115
116 /* Skip over "%%", it will become part of a literal piece. */
117 if (*f == '%')
118 {
119 f++;
120 continue;
121 }
122
123 sub_start = current_substring;
124
125 strncpy (current_substring, prev_start, f - 1 - prev_start);
126 current_substring += f - 1 - prev_start;
127 *current_substring++ = '\0';
128
129 m_pieces.emplace_back (sub_start, literal_piece);
130
131 percent_loc = f - 1;
132
133 /* Check the validity of the format specifier, and work
134 out what argument it expects. We only accept C89
135 format strings, with the exception of long long (which
136 we autoconf for). */
137
138 /* The first part of a format specifier is a set of flag
139 characters. */
140 while (*f != '\0' && strchr ("0-+ #", *f))
141 {
142 if (*f == '#')
143 seen_hash = 1;
144 else if (*f == '0')
145 seen_zero = 1;
146 else if (*f == ' ')
147 seen_space = 1;
148 else if (*f == '+')
149 seen_plus = 1;
150 f++;
151 }
152
153 /* The next part of a format specifier is a width. */
154 while (*f != '\0' && strchr ("0123456789", *f))
155 f++;
156
157 /* The next part of a format specifier is a precision. */
158 if (*f == '.')
159 {
160 seen_prec = 1;
161 f++;
162 while (*f != '\0' && strchr ("0123456789", *f))
163 f++;
164 }
165
166 /* The next part of a format specifier is a length modifier. */
167 if (*f == 'h')
168 {
169 seen_h = 1;
170 f++;
171 }
172 else if (*f == 'l')
173 {
174 f++;
175 lcount++;
176 if (*f == 'l')
177 {
178 f++;
179 lcount++;
180 }
181 }
182 else if (*f == 'L')
183 {
184 seen_big_l = 1;
185 f++;
186 }
187 /* Decimal32 modifier. */
188 else if (*f == 'H')
189 {
190 seen_big_h = 1;
191 f++;
192 }
193 /* Decimal64 and Decimal128 modifiers. */
194 else if (*f == 'D')
195 {
196 f++;
197
198 /* Check for a Decimal128. */
199 if (*f == 'D')
200 {
201 f++;
202 seen_double_big_d = 1;
203 }
204 else
205 seen_big_d = 1;
206 }
207
208 switch (*f)
209 {
210 case 'u':
211 if (seen_hash)
212 bad = 1;
213 /* FALLTHROUGH */
214
215 case 'o':
216 case 'x':
217 case 'X':
218 if (seen_space || seen_plus)
219 bad = 1;
220 /* FALLTHROUGH */
221
222 case 'd':
223 case 'i':
224 if (lcount == 0)
225 this_argclass = int_arg;
226 else if (lcount == 1)
227 this_argclass = long_arg;
228 else
229 this_argclass = long_long_arg;
230
231 if (seen_big_l)
232 bad = 1;
233 break;
234
235 case 'c':
236 this_argclass = lcount == 0 ? int_arg : wide_char_arg;
237 if (lcount > 1 || seen_h || seen_big_l)
238 bad = 1;
239 if (seen_prec || seen_zero || seen_space || seen_plus)
240 bad = 1;
241 break;
242
243 case 'p':
244 this_argclass = ptr_arg;
245 if (lcount || seen_h || seen_big_l)
246 bad = 1;
247 if (seen_prec)
248 bad = 1;
249 if (seen_hash || seen_zero || seen_space || seen_plus)
250 bad = 1;
251 break;
252
253 case 's':
254 this_argclass = lcount == 0 ? string_arg : wide_string_arg;
255 if (lcount > 1 || seen_h || seen_big_l)
256 bad = 1;
257 if (seen_zero || seen_space || seen_plus)
258 bad = 1;
259 break;
260
261 case 'e':
262 case 'f':
263 case 'g':
264 case 'E':
265 case 'G':
266 if (seen_double_big_d)
267 this_argclass = dec128float_arg;
268 else if (seen_big_d)
269 this_argclass = dec64float_arg;
270 else if (seen_big_h)
271 this_argclass = dec32float_arg;
272 else if (seen_big_l)
273 this_argclass = long_double_arg;
274 else
275 this_argclass = double_arg;
276
277 if (lcount || seen_h)
278 bad = 1;
279 break;
280
281 case '*':
282 error (_("`*' not supported for precision or width in printf"));
283
284 case 'n':
285 error (_("Format specifier `n' not supported in printf"));
286
287 case '\0':
288 error (_("Incomplete format specifier at end of format string"));
289
290 default:
291 error (_("Unrecognized format specifier '%c' in printf"), *f);
292 }
293
294 if (bad)
295 error (_("Inappropriate modifiers to "
296 "format specifier '%c' in printf"),
297 *f);
298
299 f++;
300
301 sub_start = current_substring;
302
303 if (lcount > 1 && USE_PRINTF_I64)
304 {
305 /* Windows' printf does support long long, but not the usual way.
306 Convert %lld to %I64d. */
307 int length_before_ll = f - percent_loc - 1 - lcount;
308
309 strncpy (current_substring, percent_loc, length_before_ll);
310 strcpy (current_substring + length_before_ll, "I64");
311 current_substring[length_before_ll + 3] =
312 percent_loc[length_before_ll + lcount];
313 current_substring += length_before_ll + 4;
314 }
315 else if (this_argclass == wide_string_arg
316 || this_argclass == wide_char_arg)
317 {
318 /* Convert %ls or %lc to %s. */
319 int length_before_ls = f - percent_loc - 2;
320
321 strncpy (current_substring, percent_loc, length_before_ls);
322 strcpy (current_substring + length_before_ls, "s");
323 current_substring += length_before_ls + 2;
324 }
325 else
326 {
327 strncpy (current_substring, percent_loc, f - percent_loc);
328 current_substring += f - percent_loc;
329 }
330
331 *current_substring++ = '\0';
332
333 prev_start = f;
334
335 m_pieces.emplace_back (sub_start, this_argclass);
336 }
337
338 /* Record the remainder of the string. */
339
340 sub_start = current_substring;
341
342 strncpy (current_substring, prev_start, f - prev_start);
343 current_substring += f - prev_start;
344 *current_substring++ = '\0';
345
346 m_pieces.emplace_back (sub_start, literal_piece);
347 }
This page took 0.037885 seconds and 4 git commands to generate.