Breakpoints, don't skip prologue of ifunc resolvers with debug info
[deliverable/binutils-gdb.git] / gdb / common / format.c
CommitLineData
d3ce09f5
SS
1/* Parse a printf-style format string.
2
e2882c85 3 Copyright (C) 1986-2018 Free Software Foundation, Inc.
d3ce09f5
SS
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
727605ca 20#include "common-defs.h"
d3ce09f5
SS
21#include "format.h"
22
8e481c3b 23format_pieces::format_pieces (const char **arg)
d3ce09f5 24{
bbc13ae3
KS
25 const char *s;
26 char *f, *string;
27 const char *prev_start;
28 const char *percent_loc;
d3ce09f5 29 char *sub_start, *current_substring;
d3ce09f5
SS
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
224c3ddb 98 current_substring = (char *) xmalloc (strlen (string) * 2 + 1000);
8e481c3b 99 m_storage.reset (current_substring);
d3ce09f5
SS
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
8e481c3b 129 m_pieces.emplace_back (sub_start, literal_piece);
d3ce09f5
SS
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. */
5ea5559b 140 while (*f != '\0' && strchr ("0-+ #", *f))
d3ce09f5
SS
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. */
5ea5559b 154 while (*f != '\0' && strchr ("0123456789", *f))
d3ce09f5
SS
155 f++;
156
157 /* The next part of a format specifier is a precision. */
158 if (*f == '.')
159 {
160 seen_prec = 1;
161 f++;
5ea5559b 162 while (*f != '\0' && strchr ("0123456789", *f))
d3ce09f5
SS
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;
4ff3ce77
DE
230
231 if (seen_big_l)
232 bad = 1;
233 break;
d3ce09f5
SS
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;
5c30d39a
AB
247 if (seen_prec)
248 bad = 1;
249 if (seen_hash || seen_zero || seen_space || seen_plus)
d3ce09f5
SS
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':
16e812b2
UW
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;
d3ce09f5
SS
272 else if (seen_big_l)
273 this_argclass = long_double_arg;
274 else
275 this_argclass = double_arg;
276
4ff3ce77
DE
277 if (lcount || seen_h)
278 bad = 1;
279 break;
d3ce09f5
SS
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
8e481c3b 335 m_pieces.emplace_back (sub_start, this_argclass);
d3ce09f5
SS
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
8e481c3b 346 m_pieces.emplace_back (sub_start, literal_piece);
d3ce09f5 347}
This page took 0.432023 seconds and 4 git commands to generate.