0001-CVE-2021-42574.patch 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001
  1. From b3aa80b45c4f46029efeb204bb9f2d2c4278a0e5 Mon Sep 17 00:00:00 2001
  2. From: Nick Clifton <nickc@redhat.com>
  3. Date: Tue, 9 Nov 2021 13:25:42 +0000
  4. Subject: [PATCH] Add --unicode option to control how unicode characters are
  5. handled by display tools.
  6. * nm.c: Add --unicode option to control how unicode characters are
  7. handled.
  8. * objdump.c: Likewise.
  9. * readelf.c: Likewise.
  10. * strings.c: Likewise.
  11. * binutils.texi: Document the new feature.
  12. * NEWS: Document the new feature.
  13. * testsuite/binutils-all/unicode.exp: New file.
  14. * testsuite/binutils-all/nm.hex.unicode
  15. * testsuite/binutils-all/strings.escape.unicode
  16. * testsuite/binutils-all/objdump.highlight.unicode
  17. * testsuite/binutils-all/readelf.invalid.unicode
  18. CVE: CVE-2021-42574
  19. Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=b3aa80b45c4f46029efeb204bb9f2d2c4278a0e5]
  20. RP: Added tweak uint -> unsigned int partial backport of
  21. https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=795588aec4f894206863c938bd6d716895886009
  22. Signed-off-by: pgowda <pgowda.cve@gmail.com>
  23. ---
  24. binutils/ChangeLog | 15 +
  25. binutils/NEWS | 9 +
  26. binutils/doc/binutils.texi | 78 ++++
  27. binutils/nm.c | 228 ++++++++++-
  28. binutils/objdump.c | 235 ++++++++++--
  29. binutils/readelf.c | 190 +++++++++-
  30. binutils/strings.c | 757 ++++++++++++++++++++++++++++++++++---
  31. 7 files changed, 1409 insertions(+), 103 deletions(-)
  32. diff --git a/binutils/ChangeLog b/binutils/ChangeLog
  33. --- a/binutils/ChangeLog 2021-12-19 19:00:27.038540406 -0800
  34. +++ b/binutils/ChangeLog 2021-12-19 19:28:42.733565078 -0800
  35. @@ -1,3 +1,18 @@
  36. +2021-11-09 Nick Clifton <nickc@redhat.com>
  37. +
  38. + * nm.c: Add --unicode option to control how unicode characters are
  39. + handled.
  40. + * objdump.c: Likewise.
  41. + * readelf.c: Likewise.
  42. + * strings.c: Likewise.
  43. + * binutils.texi: Document the new feature.
  44. + * NEWS: Document the new feature.
  45. + * testsuite/binutils-all/unicode.exp: New file.
  46. + * testsuite/binutils-all/nm.hex.unicode
  47. + * testsuite/binutils-all/strings.escape.unicode
  48. + * testsuite/binutils-all/objdump.highlight.unicode
  49. + * testsuite/binutils-all/readelf.invalid.unicode
  50. +
  51. 2021-07-16 Nick Clifton <nickc@redhat.com>
  52. * po/sv.po: Updated Swedish translation.
  53. diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
  54. --- a/binutils/doc/binutils.texi 2021-12-19 19:00:27.042540338 -0800
  55. +++ b/binutils/doc/binutils.texi 2021-12-19 19:27:56.526354667 -0800
  56. @@ -812,6 +812,7 @@ nm [@option{-A}|@option{-o}|@option{--pr
  57. [@option{-s}|@option{--print-armap}]
  58. [@option{-t} @var{radix}|@option{--radix=}@var{radix}]
  59. [@option{-u}|@option{--undefined-only}]
  60. + [@option{-U} @var{method}] [@option{--unicode=}@var{method}]
  61. [@option{-V}|@option{--version}]
  62. [@option{-X 32_64}]
  63. [@option{--defined-only}]
  64. @@ -1132,6 +1133,21 @@ Use @var{radix} as the radix for printin
  65. @cindex undefined symbols
  66. Display only undefined symbols (those external to each object file).
  67. +@item -U @var{[d|i|l|e|x|h]}
  68. +@itemx --unicode=@var{[default|invalid|locale|escape|hex|highlight]}
  69. +Controls the display of UTF-8 encoded mulibyte characters in strings.
  70. +The default (@option{--unicode=default}) is to give them no special
  71. +treatment. The @option{--unicode=locale} option displays the sequence
  72. +in the current locale, which may or may not support them. The options
  73. +@option{--unicode=hex} and @option{--unicode=invalid} display them as
  74. +hex byte sequences enclosed by either angle brackets or curly braces.
  75. +
  76. +The @option{--unicode=escape} option displays them as escape sequences
  77. +(@var{\uxxxx}) and the @option{--unicode=highlight} option displays
  78. +them as escape sequences highlighted in red (if supported by the
  79. +output device). The colouring is intended to draw attention to the
  80. +presence of unicode sequences where they might not be expected.
  81. +
  82. @item -V
  83. @itemx --version
  84. Show the version number of @command{nm} and exit.
  85. @@ -2247,6 +2263,7 @@ objdump [@option{-a}|@option{--archive-h
  86. [@option{--prefix-strip=}@var{level}]
  87. [@option{--insn-width=}@var{width}]
  88. [@option{--visualize-jumps[=color|=extended-color|=off]}
  89. + [@option{-U} @var{method}] [@option{--unicode=}@var{method}]
  90. [@option{-V}|@option{--version}]
  91. [@option{-H}|@option{--help}]
  92. @var{objfile}@dots{}
  93. @@ -2921,6 +2938,21 @@ When displaying symbols include those wh
  94. special in some way and which would not normally be of interest to the
  95. user.
  96. +@item -U @var{[d|i|l|e|x|h]}
  97. +@itemx --unicode=@var{[default|invalid|locale|escape|hex|highlight]}
  98. +Controls the display of UTF-8 encoded mulibyte characters in strings.
  99. +The default (@option{--unicode=default}) is to give them no special
  100. +treatment. The @option{--unicode=locale} option displays the sequence
  101. +in the current locale, which may or may not support them. The options
  102. +@option{--unicode=hex} and @option{--unicode=invalid} display them as
  103. +hex byte sequences enclosed by either angle brackets or curly braces.
  104. +
  105. +The @option{--unicode=escape} option displays them as escape sequences
  106. +(@var{\uxxxx}) and the @option{--unicode=highlight} option displays
  107. +them as escape sequences highlighted in red (if supported by the
  108. +output device). The colouring is intended to draw attention to the
  109. +presence of unicode sequences where they might not be expected.
  110. +
  111. @item -V
  112. @itemx --version
  113. Print the version number of @command{objdump} and exit.
  114. @@ -3197,6 +3229,7 @@ strings [@option{-afovV}] [@option{-}@va
  115. [@option{-n} @var{min-len}] [@option{--bytes=}@var{min-len}]
  116. [@option{-t} @var{radix}] [@option{--radix=}@var{radix}]
  117. [@option{-e} @var{encoding}] [@option{--encoding=}@var{encoding}]
  118. + [@option{-U} @var{method}] [@option{--unicode=}@var{method}]
  119. [@option{-}] [@option{--all}] [@option{--print-file-name}]
  120. [@option{-T} @var{bfdname}] [@option{--target=}@var{bfdname}]
  121. [@option{-w}] [@option{--include-all-whitespace}]
  122. @@ -3288,6 +3321,28 @@ single-8-bit-byte characters, @samp{b} =
  123. littleendian. Useful for finding wide character strings. (@samp{l}
  124. and @samp{b} apply to, for example, Unicode UTF-16/UCS-2 encodings).
  125. +@item -U @var{[d|i|l|e|x|h]}
  126. +@itemx --unicode=@var{[default|invalid|locale|escape|hex|highlight]}
  127. +Controls the display of UTF-8 encoded mulibyte characters in strings.
  128. +The default (@option{--unicode=default}) is to give them no special
  129. +treatment, and instead rely upon the setting of the
  130. +@option{--encoding} option. The other values for this option
  131. +automatically enable @option{--encoding=S}.
  132. +
  133. +The @option{--unicode=invalid} option treats them as non-graphic
  134. +characters and hence not part of a valid string. All the remaining
  135. +options treat them as valid string characters.
  136. +
  137. +The @option{--unicode=locale} option displays them in the current
  138. +locale, which may or may not support UTF-8 encoding. The
  139. +@option{--unicode=hex} option displays them as hex byte sequences
  140. +enclosed between @var{<>} characters. The @option{--unicode=escape}
  141. +option displays them as escape sequences (@var{\uxxxx}) and the
  142. +@option{--unicode=highlight} option displays them as escape sequences
  143. +highlighted in red (if supported by the output device). The colouring
  144. +is intended to draw attention to the presence of unicode sequences
  145. +where they might not be expected.
  146. +
  147. @item -T @var{bfdname}
  148. @itemx --target=@var{bfdname}
  149. @cindex object code format
  150. @@ -4796,6 +4851,7 @@ readelf [@option{-a}|@option{--all}]
  151. [@option{--demangle@var{=style}}|@option{--no-demangle}]
  152. [@option{--quiet}]
  153. [@option{--recurse-limit}|@option{--no-recurse-limit}]
  154. + [@option{-U} @var{method}|@option{--unicode=}@var{method}]
  155. [@option{-n}|@option{--notes}]
  156. [@option{-r}|@option{--relocs}]
  157. [@option{-u}|@option{--unwind}]
  158. @@ -4962,6 +5018,28 @@ necessary in order to demangle truly com
  159. that if the recursion limit is disabled then stack exhaustion is
  160. possible and any bug reports about such an event will be rejected.
  161. +@item -U @var{[d|i|l|e|x|h]}
  162. +@itemx --unicode=[default|invalid|locale|escape|hex|highlight]
  163. +Controls the display of non-ASCII characters in identifier names.
  164. +The default (@option{--unicode=locale} or @option{--unicode=default}) is
  165. +to treat them as multibyte characters and display them in the current
  166. +locale. All other versions of this option treat the bytes as UTF-8
  167. +encoded values and attempt to interpret them. If they cannot be
  168. +interpreted or if the @option{--unicode=invalid} option is used then
  169. +they are displayed as a sequence of hex bytes, encloses in curly
  170. +parethesis characters.
  171. +
  172. +Using the @option{--unicode=escape} option will display the characters
  173. +as as unicode escape sequences (@var{\uxxxx}). Using the
  174. +@option{--unicode=hex} will display the characters as hex byte
  175. +sequences enclosed between angle brackets.
  176. +
  177. +Using the @option{--unicode=highlight} will display the characters as
  178. +unicode escape sequences but it will also highlighted them in red,
  179. +assuming that colouring is supported by the output device. The
  180. +colouring is intended to draw attention to the presence of unicode
  181. +sequences when they might not be expected.
  182. +
  183. @item -e
  184. @itemx --headers
  185. Display all the headers in the file. Equivalent to @option{-h -l -S}.
  186. diff --git a/binutils/NEWS b/binutils/NEWS
  187. --- a/binutils/NEWS 2021-12-19 19:00:27.038540406 -0800
  188. +++ b/binutils/NEWS 2021-12-19 19:30:04.764162972 -0800
  189. @@ -1,5 +1,14 @@
  190. -*- text -*-
  191. +* Tools which display symbols or strings (readelf, strings, nm, objdump)
  192. + have a new command line option which controls how unicode characters are
  193. + handled. By default they are treated as normal for the tool. Using
  194. + --unicode=locale will display them according to the current locale.
  195. + Using --unicode=hex will display them as hex byte values, whilst
  196. + --unicode=escape will display them as escape sequences. In addition
  197. + using --unicode=highlight will display them as unicode escape sequences
  198. + highlighted in red (if supported by the output device).
  199. +
  200. Changes in 2.37:
  201. * The readelf tool has a new command line option which can be used to specify
  202. diff --git a/binutils/nm.c b/binutils/nm.c
  203. --- a/binutils/nm.c 2021-12-19 19:00:27.046540270 -0800
  204. +++ b/binutils/nm.c 2021-12-19 19:36:34.797491555 -0800
  205. @@ -38,6 +38,11 @@
  206. #include "bucomm.h"
  207. #include "plugin-api.h"
  208. #include "plugin.h"
  209. +#include "safe-ctype.h"
  210. +
  211. +#ifndef streq
  212. +#define streq(a,b) (strcmp ((a),(b)) == 0)
  213. +#endif
  214. /* When sorting by size, we use this structure to hold the size and a
  215. pointer to the minisymbol. */
  216. @@ -216,6 +221,18 @@ static const char *plugin_target = NULL;
  217. static bfd *lineno_cache_bfd;
  218. static bfd *lineno_cache_rel_bfd;
  219. +typedef enum unicode_display_type
  220. +{
  221. + unicode_default = 0,
  222. + unicode_locale,
  223. + unicode_escape,
  224. + unicode_hex,
  225. + unicode_highlight,
  226. + unicode_invalid
  227. +} unicode_display_type;
  228. +
  229. +static unicode_display_type unicode_display = unicode_default;
  230. +
  231. enum long_option_values
  232. {
  233. OPTION_TARGET = 200,
  234. @@ -260,6 +277,7 @@ static struct option long_options[] =
  235. {"target", required_argument, 0, OPTION_TARGET},
  236. {"defined-only", no_argument, &defined_only, 1},
  237. {"undefined-only", no_argument, &undefined_only, 1},
  238. + {"unicode", required_argument, NULL, 'U'},
  239. {"version", no_argument, &show_version, 1},
  240. {"with-symbol-versions", no_argument, &with_symbol_versions, 1},
  241. {"without-symbol-versions", no_argument, &with_symbol_versions, 0},
  242. @@ -313,6 +331,8 @@ usage (FILE *stream, int status)
  243. -t, --radix=RADIX Use RADIX for printing symbol values\n\
  244. --target=BFDNAME Specify the target object format as BFDNAME\n\
  245. -u, --undefined-only Display only undefined symbols\n\
  246. + -U {d|s|i|x|e|h} Specify how to treat UTF-8 encoded unicode characters\n\
  247. + --unicode={default|show|invalid|hex|escape|highlight}\n\
  248. --with-symbol-versions Display version strings after symbol names\n\
  249. -X 32_64 (ignored)\n\
  250. @FILE Read options from FILE\n\
  251. @@ -432,6 +452,187 @@ get_coff_symbol_type (const struct inter
  252. return bufp;
  253. }
  254. +/* Convert a potential UTF-8 encoded sequence in IN into characters in OUT.
  255. + The conversion format is controlled by the unicode_display variable.
  256. + Returns the number of characters added to OUT.
  257. + Returns the number of bytes consumed from IN in CONSUMED.
  258. + Always consumes at least one byte and displays at least one character. */
  259. +
  260. +static unsigned int
  261. +display_utf8 (const unsigned char * in, char * out, unsigned int * consumed)
  262. +{
  263. + char * orig_out = out;
  264. + unsigned int nchars = 0;
  265. + unsigned int j;
  266. +
  267. + if (unicode_display == unicode_default)
  268. + goto invalid;
  269. +
  270. + if (in[0] < 0xc0)
  271. + goto invalid;
  272. +
  273. + if ((in[1] & 0xc0) != 0x80)
  274. + goto invalid;
  275. +
  276. + if ((in[0] & 0x20) == 0)
  277. + {
  278. + nchars = 2;
  279. + goto valid;
  280. + }
  281. +
  282. + if ((in[2] & 0xc0) != 0x80)
  283. + goto invalid;
  284. +
  285. + if ((in[0] & 0x10) == 0)
  286. + {
  287. + nchars = 3;
  288. + goto valid;
  289. + }
  290. +
  291. + if ((in[3] & 0xc0) != 0x80)
  292. + goto invalid;
  293. +
  294. + nchars = 4;
  295. +
  296. + valid:
  297. + switch (unicode_display)
  298. + {
  299. + case unicode_locale:
  300. + /* Copy the bytes into the output buffer as is. */
  301. + memcpy (out, in, nchars);
  302. + out += nchars;
  303. + break;
  304. +
  305. + case unicode_invalid:
  306. + case unicode_hex:
  307. + out += sprintf (out, "%c", unicode_display == unicode_hex ? '<' : '{');
  308. + out += sprintf (out, "0x");
  309. + for (j = 0; j < nchars; j++)
  310. + out += sprintf (out, "%02x", in [j]);
  311. + out += sprintf (out, "%c", unicode_display == unicode_hex ? '>' : '}');
  312. + break;
  313. +
  314. + case unicode_highlight:
  315. + if (isatty (1))
  316. + out += sprintf (out, "\x1B[31;47m"); /* Red. */
  317. + /* Fall through. */
  318. + case unicode_escape:
  319. + switch (nchars)
  320. + {
  321. + case 2:
  322. + out += sprintf (out, "\\u%02x%02x",
  323. + ((in[0] & 0x1c) >> 2),
  324. + ((in[0] & 0x03) << 6) | (in[1] & 0x3f));
  325. + break;
  326. +
  327. + case 3:
  328. + out += sprintf (out, "\\u%02x%02x",
  329. + ((in[0] & 0x0f) << 4) | ((in[1] & 0x3c) >> 2),
  330. + ((in[1] & 0x03) << 6) | ((in[2] & 0x3f)));
  331. + break;
  332. +
  333. + case 4:
  334. + out += sprintf (out, "\\u%02x%02x%02x",
  335. + ((in[0] & 0x07) << 6) | ((in[1] & 0x3c) >> 2),
  336. + ((in[1] & 0x03) << 6) | ((in[2] & 0x3c) >> 2),
  337. + ((in[2] & 0x03) << 6) | ((in[3] & 0x3f)));
  338. + break;
  339. + default:
  340. + /* URG. */
  341. + break;
  342. + }
  343. +
  344. + if (unicode_display == unicode_highlight && isatty (1))
  345. + out += sprintf (out, "\033[0m"); /* Default colour. */
  346. + break;
  347. +
  348. + default:
  349. + /* URG */
  350. + break;
  351. + }
  352. +
  353. + * consumed = nchars;
  354. + return out - orig_out;
  355. +
  356. + invalid:
  357. + /* Not a valid UTF-8 sequence. */
  358. + *out = *in;
  359. + * consumed = 1;
  360. + return 1;
  361. +}
  362. +
  363. +/* Convert any UTF-8 encoded characters in NAME into the form specified by
  364. + unicode_display. Also converts control characters. Returns a static
  365. + buffer if conversion was necessary.
  366. + Code stolen from objdump.c:sanitize_string(). */
  367. +
  368. +static const char *
  369. +convert_utf8 (const char * in)
  370. +{
  371. + static char * buffer = NULL;
  372. + static size_t buffer_len = 0;
  373. + const char * original = in;
  374. + char * out;
  375. +
  376. + /* Paranoia. */
  377. + if (in == NULL)
  378. + return "";
  379. +
  380. + /* See if any conversion is necessary.
  381. + In the majority of cases it will not be needed. */
  382. + do
  383. + {
  384. + unsigned char c = *in++;
  385. +
  386. + if (c == 0)
  387. + return original;
  388. +
  389. + if (ISCNTRL (c))
  390. + break;
  391. +
  392. + if (unicode_display != unicode_default && c >= 0xc0)
  393. + break;
  394. + }
  395. + while (1);
  396. +
  397. + /* Copy the input, translating as needed. */
  398. + in = original;
  399. + if (buffer_len < (strlen (in) * 9))
  400. + {
  401. + free ((void *) buffer);
  402. + buffer_len = strlen (in) * 9;
  403. + buffer = xmalloc (buffer_len + 1);
  404. + }
  405. +
  406. + out = buffer;
  407. + do
  408. + {
  409. + unsigned char c = *in++;
  410. +
  411. + if (c == 0)
  412. + break;
  413. +
  414. + if (ISCNTRL (c))
  415. + {
  416. + *out++ = '^';
  417. + *out++ = c + 0x40;
  418. + }
  419. + else if (unicode_display != unicode_default && c >= 0xc0)
  420. + {
  421. + unsigned int num_consumed;
  422. +
  423. + out += display_utf8 ((const unsigned char *)(in - 1), out, & num_consumed);
  424. + in += num_consumed - 1;
  425. + }
  426. + else
  427. + *out++ = c;
  428. + }
  429. + while (1);
  430. +
  431. + *out = 0;
  432. + return buffer;
  433. +}
  434. +
  435. /* Print symbol name NAME, read from ABFD, with printf format FORM,
  436. demangling it if requested. */
  437. @@ -444,6 +645,7 @@ print_symname (const char *form, struct
  438. if (name == NULL)
  439. name = info->sinfo->name;
  440. +
  441. if (!with_symbol_versions
  442. && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
  443. {
  444. @@ -451,6 +653,7 @@ print_symname (const char *form, struct
  445. if (atver)
  446. *atver = 0;
  447. }
  448. +
  449. if (do_demangle && *name)
  450. {
  451. alloc = bfd_demangle (abfd, name, demangle_flags);
  452. @@ -458,6 +661,11 @@ print_symname (const char *form, struct
  453. name = alloc;
  454. }
  455. + if (unicode_display != unicode_default)
  456. + {
  457. + name = convert_utf8 (name);
  458. + }
  459. +
  460. if (info != NULL && info->elfinfo && with_symbol_versions)
  461. {
  462. const char *version_string;
  463. @@ -1807,7 +2015,7 @@ main (int argc, char **argv)
  464. fatal (_("fatal error: libbfd ABI mismatch"));
  465. set_default_bfd_target ();
  466. - while ((c = getopt_long (argc, argv, "aABCDef:gHhjJlnopPrSst:uvVvX:",
  467. + while ((c = getopt_long (argc, argv, "aABCDef:gHhjJlnopPrSst:uU:vVvX:",
  468. long_options, (int *) 0)) != EOF)
  469. {
  470. switch (c)
  471. @@ -1900,6 +2108,24 @@ main (int argc, char **argv)
  472. case 'u':
  473. undefined_only = 1;
  474. break;
  475. +
  476. + case 'U':
  477. + if (streq (optarg, "default") || streq (optarg, "d"))
  478. + unicode_display = unicode_default;
  479. + else if (streq (optarg, "locale") || streq (optarg, "l"))
  480. + unicode_display = unicode_locale;
  481. + else if (streq (optarg, "escape") || streq (optarg, "e"))
  482. + unicode_display = unicode_escape;
  483. + else if (streq (optarg, "invalid") || streq (optarg, "i"))
  484. + unicode_display = unicode_invalid;
  485. + else if (streq (optarg, "hex") || streq (optarg, "x"))
  486. + unicode_display = unicode_hex;
  487. + else if (streq (optarg, "highlight") || streq (optarg, "h"))
  488. + unicode_display = unicode_highlight;
  489. + else
  490. + fatal (_("invalid argument to -U/--unicode: %s"), optarg);
  491. + break;
  492. +
  493. case 'V':
  494. show_version = 1;
  495. break;
  496. diff --git a/binutils/objdump.c b/binutils/objdump.c
  497. --- a/binutils/objdump.c 2021-12-19 19:00:27.046540270 -0800
  498. +++ b/binutils/objdump.c 2021-12-19 19:43:09.438736729 -0800
  499. @@ -204,6 +204,18 @@ static const struct objdump_private_desc
  500. /* The list of detected jumps inside a function. */
  501. static struct jump_info *detected_jumps = NULL;
  502. +
  503. +typedef enum unicode_display_type
  504. +{
  505. + unicode_default = 0,
  506. + unicode_locale,
  507. + unicode_escape,
  508. + unicode_hex,
  509. + unicode_highlight,
  510. + unicode_invalid
  511. +} unicode_display_type;
  512. +
  513. +static unicode_display_type unicode_display = unicode_default;
  514. static void usage (FILE *, int) ATTRIBUTE_NORETURN;
  515. static void
  516. @@ -330,6 +342,9 @@ usage (FILE *stream, int status)
  517. fprintf (stream, _("\
  518. -w, --wide Format output for more than 80 columns\n"));
  519. fprintf (stream, _("\
  520. + -U[d|l|i|x|e|h] Controls the display of UTF-8 unicode characters\n\
  521. + --unicode=[default|locale|invalid|hex|escape|highlight]\n"));
  522. + fprintf (stream, _("\
  523. -z, --disassemble-zeroes Do not skip blocks of zeroes when disassembling\n"));
  524. fprintf (stream, _("\
  525. --start-address=ADDR Only process data whose address is >= ADDR\n"));
  526. @@ -420,17 +435,23 @@ static struct option long_options[]=
  527. {
  528. {"adjust-vma", required_argument, NULL, OPTION_ADJUST_VMA},
  529. {"all-headers", no_argument, NULL, 'x'},
  530. - {"private-headers", no_argument, NULL, 'p'},
  531. - {"private", required_argument, NULL, 'P'},
  532. {"architecture", required_argument, NULL, 'm'},
  533. {"archive-headers", no_argument, NULL, 'a'},
  534. +#ifdef ENABLE_LIBCTF
  535. + {"ctf", required_argument, NULL, OPTION_CTF},
  536. + {"ctf-parent", required_argument, NULL, OPTION_CTF_PARENT},
  537. +#endif
  538. {"debugging", no_argument, NULL, 'g'},
  539. {"debugging-tags", no_argument, NULL, 'e'},
  540. {"demangle", optional_argument, NULL, 'C'},
  541. {"disassemble", optional_argument, NULL, 'd'},
  542. {"disassemble-all", no_argument, NULL, 'D'},
  543. - {"disassembler-options", required_argument, NULL, 'M'},
  544. {"disassemble-zeroes", no_argument, NULL, 'z'},
  545. + {"disassembler-options", required_argument, NULL, 'M'},
  546. + {"dwarf", optional_argument, NULL, OPTION_DWARF},
  547. + {"dwarf-check", no_argument, 0, OPTION_DWARF_CHECK},
  548. + {"dwarf-depth", required_argument, 0, OPTION_DWARF_DEPTH},
  549. + {"dwarf-start", required_argument, 0, OPTION_DWARF_START},
  550. {"dynamic-reloc", no_argument, NULL, 'R'},
  551. {"dynamic-syms", no_argument, NULL, 'T'},
  552. {"endian", required_argument, NULL, OPTION_ENDIAN},
  553. @@ -440,16 +461,23 @@ static struct option long_options[]=
  554. {"full-contents", no_argument, NULL, 's'},
  555. {"headers", no_argument, NULL, 'h'},
  556. {"help", no_argument, NULL, 'H'},
  557. + {"include", required_argument, NULL, 'I'},
  558. {"info", no_argument, NULL, 'i'},
  559. + {"inlines", no_argument, 0, OPTION_INLINES},
  560. + {"insn-width", required_argument, NULL, OPTION_INSN_WIDTH},
  561. {"line-numbers", no_argument, NULL, 'l'},
  562. - {"no-show-raw-insn", no_argument, &show_raw_insn, -1},
  563. {"no-addresses", no_argument, &no_addresses, 1},
  564. - {"process-links", no_argument, &process_links, true},
  565. + {"no-recurse-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT},
  566. + {"no-recursion-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT},
  567. + {"no-show-raw-insn", no_argument, &show_raw_insn, -1},
  568. + {"prefix", required_argument, NULL, OPTION_PREFIX},
  569. {"prefix-addresses", no_argument, &prefix_addresses, 1},
  570. + {"prefix-strip", required_argument, NULL, OPTION_PREFIX_STRIP},
  571. + {"private", required_argument, NULL, 'P'},
  572. + {"private-headers", no_argument, NULL, 'p'},
  573. + {"process-links", no_argument, &process_links, true},
  574. {"recurse-limit", no_argument, NULL, OPTION_RECURSE_LIMIT},
  575. {"recursion-limit", no_argument, NULL, OPTION_RECURSE_LIMIT},
  576. - {"no-recurse-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT},
  577. - {"no-recursion-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT},
  578. {"reloc", no_argument, NULL, 'r'},
  579. {"section", required_argument, NULL, 'j'},
  580. {"section-headers", no_argument, NULL, 'h'},
  581. @@ -457,28 +485,16 @@ static struct option long_options[]=
  582. {"source", no_argument, NULL, 'S'},
  583. {"source-comment", optional_argument, NULL, OPTION_SOURCE_COMMENT},
  584. {"special-syms", no_argument, &dump_special_syms, 1},
  585. - {"include", required_argument, NULL, 'I'},
  586. - {"dwarf", optional_argument, NULL, OPTION_DWARF},
  587. -#ifdef ENABLE_LIBCTF
  588. - {"ctf", required_argument, NULL, OPTION_CTF},
  589. - {"ctf-parent", required_argument, NULL, OPTION_CTF_PARENT},
  590. -#endif
  591. {"stabs", no_argument, NULL, 'G'},
  592. {"start-address", required_argument, NULL, OPTION_START_ADDRESS},
  593. {"stop-address", required_argument, NULL, OPTION_STOP_ADDRESS},
  594. {"syms", no_argument, NULL, 't'},
  595. {"target", required_argument, NULL, 'b'},
  596. + {"unicode", required_argument, NULL, 'U'},
  597. {"version", no_argument, NULL, 'V'},
  598. - {"wide", no_argument, NULL, 'w'},
  599. - {"prefix", required_argument, NULL, OPTION_PREFIX},
  600. - {"prefix-strip", required_argument, NULL, OPTION_PREFIX_STRIP},
  601. - {"insn-width", required_argument, NULL, OPTION_INSN_WIDTH},
  602. - {"dwarf-depth", required_argument, 0, OPTION_DWARF_DEPTH},
  603. - {"dwarf-start", required_argument, 0, OPTION_DWARF_START},
  604. - {"dwarf-check", no_argument, 0, OPTION_DWARF_CHECK},
  605. - {"inlines", no_argument, 0, OPTION_INLINES},
  606. {"visualize-jumps", optional_argument, 0, OPTION_VISUALIZE_JUMPS},
  607. - {0, no_argument, 0, 0}
  608. + {"wide", no_argument, NULL, 'w'},
  609. + {NULL, no_argument, NULL, 0}
  610. };
  611. static void
  612. @@ -488,9 +504,121 @@ nonfatal (const char *msg)
  613. exit_status = 1;
  614. }
  615. +/* Convert a potential UTF-8 encoded sequence in IN into characters in OUT.
  616. + The conversion format is controlled by the unicode_display variable.
  617. + Returns the number of characters added to OUT.
  618. + Returns the number of bytes consumed from IN in CONSUMED.
  619. + Always consumes at least one byte and displays at least one character. */
  620. +
  621. +static unsigned int
  622. +display_utf8 (const unsigned char * in, char * out, unsigned int * consumed)
  623. +{
  624. + char * orig_out = out;
  625. + unsigned int nchars = 0;
  626. + unsigned int j;
  627. +
  628. + if (unicode_display == unicode_default)
  629. + goto invalid;
  630. +
  631. + if (in[0] < 0xc0)
  632. + goto invalid;
  633. +
  634. + if ((in[1] & 0xc0) != 0x80)
  635. + goto invalid;
  636. +
  637. + if ((in[0] & 0x20) == 0)
  638. + {
  639. + nchars = 2;
  640. + goto valid;
  641. + }
  642. +
  643. + if ((in[2] & 0xc0) != 0x80)
  644. + goto invalid;
  645. +
  646. + if ((in[0] & 0x10) == 0)
  647. + {
  648. + nchars = 3;
  649. + goto valid;
  650. + }
  651. +
  652. + if ((in[3] & 0xc0) != 0x80)
  653. + goto invalid;
  654. +
  655. + nchars = 4;
  656. +
  657. + valid:
  658. + switch (unicode_display)
  659. + {
  660. + case unicode_locale:
  661. + /* Copy the bytes into the output buffer as is. */
  662. + memcpy (out, in, nchars);
  663. + out += nchars;
  664. + break;
  665. +
  666. + case unicode_invalid:
  667. + case unicode_hex:
  668. + out += sprintf (out, "%c", unicode_display == unicode_hex ? '<' : '{');
  669. + out += sprintf (out, "0x");
  670. + for (j = 0; j < nchars; j++)
  671. + out += sprintf (out, "%02x", in [j]);
  672. + out += sprintf (out, "%c", unicode_display == unicode_hex ? '>' : '}');
  673. + break;
  674. +
  675. + case unicode_highlight:
  676. + if (isatty (1))
  677. + out += sprintf (out, "\x1B[31;47m"); /* Red. */
  678. + /* Fall through. */
  679. + case unicode_escape:
  680. + switch (nchars)
  681. + {
  682. + case 2:
  683. + out += sprintf (out, "\\u%02x%02x",
  684. + ((in[0] & 0x1c) >> 2),
  685. + ((in[0] & 0x03) << 6) | (in[1] & 0x3f));
  686. + break;
  687. +
  688. + case 3:
  689. + out += sprintf (out, "\\u%02x%02x",
  690. + ((in[0] & 0x0f) << 4) | ((in[1] & 0x3c) >> 2),
  691. + ((in[1] & 0x03) << 6) | ((in[2] & 0x3f)));
  692. + break;
  693. +
  694. + case 4:
  695. + out += sprintf (out, "\\u%02x%02x%02x",
  696. + ((in[0] & 0x07) << 6) | ((in[1] & 0x3c) >> 2),
  697. + ((in[1] & 0x03) << 6) | ((in[2] & 0x3c) >> 2),
  698. + ((in[2] & 0x03) << 6) | ((in[3] & 0x3f)));
  699. + break;
  700. + default:
  701. + /* URG. */
  702. + break;
  703. + }
  704. +
  705. + if (unicode_display == unicode_highlight && isatty (1))
  706. + out += sprintf (out, "\033[0m"); /* Default colour. */
  707. + break;
  708. +
  709. + default:
  710. + /* URG */
  711. + break;
  712. + }
  713. +
  714. + * consumed = nchars;
  715. + return out - orig_out;
  716. +
  717. + invalid:
  718. + /* Not a valid UTF-8 sequence. */
  719. + *out = *in;
  720. + * consumed = 1;
  721. + return 1;
  722. +}
  723. +
  724. /* Returns a version of IN with any control characters
  725. replaced by escape sequences. Uses a static buffer
  726. - if necessary. */
  727. + if necessary.
  728. +
  729. + If unicode display is enabled, then also handles the
  730. + conversion of unicode characters. */
  731. static const char *
  732. sanitize_string (const char * in)
  733. @@ -508,40 +636,50 @@ sanitize_string (const char * in)
  734. of cases it will not be needed. */
  735. do
  736. {
  737. - char c = *in++;
  738. + unsigned char c = *in++;
  739. if (c == 0)
  740. return original;
  741. if (ISCNTRL (c))
  742. break;
  743. +
  744. + if (unicode_display != unicode_default && c >= 0xc0)
  745. + break;
  746. }
  747. while (1);
  748. /* Copy the input, translating as needed. */
  749. in = original;
  750. - if (buffer_len < (strlen (in) * 2))
  751. + if (buffer_len < (strlen (in) * 9))
  752. {
  753. free ((void *) buffer);
  754. - buffer_len = strlen (in) * 2;
  755. + buffer_len = strlen (in) * 9;
  756. buffer = xmalloc (buffer_len + 1);
  757. }
  758. out = buffer;
  759. do
  760. {
  761. - char c = *in++;
  762. + unsigned char c = *in++;
  763. if (c == 0)
  764. break;
  765. - if (!ISCNTRL (c))
  766. - *out++ = c;
  767. - else
  768. + if (ISCNTRL (c))
  769. {
  770. *out++ = '^';
  771. *out++ = c + 0x40;
  772. }
  773. + else if (unicode_display != unicode_default && c >= 0xc0)
  774. + {
  775. + unsigned int num_consumed;
  776. +
  777. + out += display_utf8 ((const unsigned char *)(in - 1), out, & num_consumed);
  778. + in += num_consumed - 1;
  779. + }
  780. + else
  781. + *out++ = c;
  782. }
  783. while (1);
  784. @@ -4529,6 +4667,24 @@ dump_symbols (bfd *abfd ATTRIBUTE_UNUSED
  785. free (alloc);
  786. }
  787. }
  788. + else if (unicode_display != unicode_default
  789. + && name != NULL && *name != '\0')
  790. + {
  791. + const char * sanitized_name;
  792. +
  793. + /* If we want to sanitize the name, we do it here, and
  794. + temporarily clobber it while calling bfd_print_symbol.
  795. + FIXME: This is a gross hack. */
  796. + sanitized_name = sanitize_string (name);
  797. + if (sanitized_name != name)
  798. + (*current)->name = sanitized_name;
  799. + else
  800. + sanitized_name = NULL;
  801. + bfd_print_symbol (cur_bfd, stdout, *current,
  802. + bfd_print_symbol_all);
  803. + if (sanitized_name != NULL)
  804. + (*current)->name = name;
  805. + }
  806. else
  807. bfd_print_symbol (cur_bfd, stdout, *current,
  808. bfd_print_symbol_all);
  809. @@ -5212,7 +5368,7 @@ main (int argc, char **argv)
  810. set_default_bfd_target ();
  811. while ((c = getopt_long (argc, argv,
  812. - "pP:ib:m:M:VvCdDlfFaHhrRtTxsSI:j:wE:zgeGW::",
  813. + "CDE:FGHI:LM:P:RSTU:VW::ab:defghij:lm:prstvwxz",
  814. long_options, (int *) 0))
  815. != EOF)
  816. {
  817. @@ -5495,6 +5651,23 @@ main (int argc, char **argv)
  818. seenflag = true;
  819. break;
  820. + case 'U':
  821. + if (streq (optarg, "default") || streq (optarg, "d"))
  822. + unicode_display = unicode_default;
  823. + else if (streq (optarg, "locale") || streq (optarg, "l"))
  824. + unicode_display = unicode_locale;
  825. + else if (streq (optarg, "escape") || streq (optarg, "e"))
  826. + unicode_display = unicode_escape;
  827. + else if (streq (optarg, "invalid") || streq (optarg, "i"))
  828. + unicode_display = unicode_invalid;
  829. + else if (streq (optarg, "hex") || streq (optarg, "x"))
  830. + unicode_display = unicode_hex;
  831. + else if (streq (optarg, "highlight") || streq (optarg, "h"))
  832. + unicode_display = unicode_highlight;
  833. + else
  834. + fatal (_("invalid argument to -U/--unicode: %s"), optarg);
  835. + break;
  836. +
  837. case 'H':
  838. usage (stdout, 0);
  839. /* No need to set seenflag or to break - usage() does not return. */
  840. diff --git a/binutils/readelf.c b/binutils/readelf.c
  841. --- a/binutils/readelf.c 2021-12-19 19:00:27.058540065 -0800
  842. +++ b/binutils/readelf.c 2021-12-19 19:27:56.538354462 -0800
  843. @@ -328,6 +328,19 @@ typedef enum print_mode
  844. }
  845. print_mode;
  846. +typedef enum unicode_display_type
  847. +{
  848. + unicode_default = 0,
  849. + unicode_locale,
  850. + unicode_escape,
  851. + unicode_hex,
  852. + unicode_highlight,
  853. + unicode_invalid
  854. +} unicode_display_type;
  855. +
  856. +static unicode_display_type unicode_display = unicode_default;
  857. +
  858. +
  859. /* Versioned symbol info. */
  860. enum versioned_symbol_info
  861. {
  862. @@ -632,11 +645,18 @@ print_symbol (signed int width, const ch
  863. if (c == 0)
  864. break;
  865. - /* Do not print control characters directly as they can affect terminal
  866. - settings. Such characters usually appear in the names generated
  867. - by the assembler for local labels. */
  868. - if (ISCNTRL (c))
  869. + if (ISPRINT (c))
  870. + {
  871. + putchar (c);
  872. + width_remaining --;
  873. + num_printed ++;
  874. + }
  875. + else if (ISCNTRL (c))
  876. {
  877. + /* Do not print control characters directly as they can affect terminal
  878. + settings. Such characters usually appear in the names generated
  879. + by the assembler for local labels. */
  880. +
  881. if (width_remaining < 2)
  882. break;
  883. @@ -644,11 +664,137 @@ print_symbol (signed int width, const ch
  884. width_remaining -= 2;
  885. num_printed += 2;
  886. }
  887. - else if (ISPRINT (c))
  888. + else if (c == 0x7f)
  889. {
  890. - putchar (c);
  891. - width_remaining --;
  892. - num_printed ++;
  893. + if (width_remaining < 5)
  894. + break;
  895. + printf ("<DEL>");
  896. + width_remaining -= 5;
  897. + num_printed += 5;
  898. + }
  899. + else if (unicode_display != unicode_locale
  900. + && unicode_display != unicode_default)
  901. + {
  902. + /* Display unicode characters as something else. */
  903. + unsigned char bytes[4];
  904. + bool is_utf8;
  905. + unsigned int nbytes;
  906. +
  907. + bytes[0] = c;
  908. +
  909. + if (bytes[0] < 0xc0)
  910. + {
  911. + nbytes = 1;
  912. + is_utf8 = false;
  913. + }
  914. + else
  915. + {
  916. + bytes[1] = *symbol++;
  917. +
  918. + if ((bytes[1] & 0xc0) != 0x80)
  919. + {
  920. + is_utf8 = false;
  921. + /* Do not consume this character. It may only
  922. + be the first byte in the sequence that was
  923. + corrupt. */
  924. + --symbol;
  925. + nbytes = 1;
  926. + }
  927. + else if ((bytes[0] & 0x20) == 0)
  928. + {
  929. + is_utf8 = true;
  930. + nbytes = 2;
  931. + }
  932. + else
  933. + {
  934. + bytes[2] = *symbol++;
  935. +
  936. + if ((bytes[2] & 0xc0) != 0x80)
  937. + {
  938. + is_utf8 = false;
  939. + symbol -= 2;
  940. + nbytes = 1;
  941. + }
  942. + else if ((bytes[0] & 0x10) == 0)
  943. + {
  944. + is_utf8 = true;
  945. + nbytes = 3;
  946. + }
  947. + else
  948. + {
  949. + bytes[3] = *symbol++;
  950. +
  951. + nbytes = 4;
  952. +
  953. + if ((bytes[3] & 0xc0) != 0x80)
  954. + {
  955. + is_utf8 = false;
  956. + symbol -= 3;
  957. + nbytes = 1;
  958. + }
  959. + else
  960. + is_utf8 = true;
  961. + }
  962. + }
  963. + }
  964. +
  965. + if (unicode_display == unicode_invalid)
  966. + is_utf8 = false;
  967. +
  968. + if (unicode_display == unicode_hex || ! is_utf8)
  969. + {
  970. + unsigned int i;
  971. +
  972. + if (width_remaining < (nbytes * 2) + 2)
  973. + break;
  974. +
  975. + putchar (is_utf8 ? '<' : '{');
  976. + printf ("0x");
  977. + for (i = 0; i < nbytes; i++)
  978. + printf ("%02x", bytes[i]);
  979. + putchar (is_utf8 ? '>' : '}');
  980. + }
  981. + else
  982. + {
  983. + if (unicode_display == unicode_highlight && isatty (1))
  984. + printf ("\x1B[31;47m"); /* Red. */
  985. +
  986. + switch (nbytes)
  987. + {
  988. + case 2:
  989. + if (width_remaining < 6)
  990. + break;
  991. + printf ("\\u%02x%02x",
  992. + (bytes[0] & 0x1c) >> 2,
  993. + ((bytes[0] & 0x03) << 6) | (bytes[1] & 0x3f));
  994. + break;
  995. + case 3:
  996. + if (width_remaining < 6)
  997. + break;
  998. + printf ("\\u%02x%02x",
  999. + ((bytes[0] & 0x0f) << 4) | ((bytes[1] & 0x3c) >> 2),
  1000. + ((bytes[1] & 0x03) << 6) | (bytes[2] & 0x3f));
  1001. + break;
  1002. + case 4:
  1003. + if (width_remaining < 8)
  1004. + break;
  1005. + printf ("\\u%02x%02x%02x",
  1006. + ((bytes[0] & 0x07) << 6) | ((bytes[1] & 0x3c) >> 2),
  1007. + ((bytes[1] & 0x03) << 6) | ((bytes[2] & 0x3c) >> 2),
  1008. + ((bytes[2] & 0x03) << 6) | (bytes[3] & 0x3f));
  1009. +
  1010. + break;
  1011. + default:
  1012. + /* URG. */
  1013. + break;
  1014. + }
  1015. +
  1016. + if (unicode_display == unicode_highlight && isatty (1))
  1017. + printf ("\033[0m"); /* Default colour. */
  1018. + }
  1019. +
  1020. + if (bytes[nbytes - 1] == 0)
  1021. + break;
  1022. }
  1023. else
  1024. {
  1025. @@ -4668,6 +4814,7 @@ static struct option options[] =
  1026. {"syms", no_argument, 0, 's'},
  1027. {"silent-truncation",no_argument, 0, 'T'},
  1028. {"section-details", no_argument, 0, 't'},
  1029. + {"unicode", required_argument, NULL, 'U'},
  1030. {"unwind", no_argument, 0, 'u'},
  1031. {"version-info", no_argument, 0, 'V'},
  1032. {"version", no_argument, 0, 'v'},
  1033. @@ -4744,6 +4891,12 @@ usage (FILE * stream)
  1034. fprintf (stream, _("\
  1035. --no-recurse-limit Disable a demangling recursion limit\n"));
  1036. fprintf (stream, _("\
  1037. + -U[dlexhi] --unicode=[default|locale|escape|hex|highlight|invalid]\n\
  1038. + Display unicode characters as determined by the current locale\n\
  1039. + (default), escape sequences, \"<hex sequences>\", highlighted\n\
  1040. + escape sequences, or treat them as invalid and display as\n\
  1041. + \"{hex sequences}\"\n"));
  1042. + fprintf (stream, _("\
  1043. -n --notes Display the core notes (if present)\n"));
  1044. fprintf (stream, _("\
  1045. -r --relocs Display the relocations (if present)\n"));
  1046. @@ -4928,7 +5081,7 @@ parse_args (struct dump_data *dumpdata,
  1047. usage (stderr);
  1048. while ((c = getopt_long
  1049. - (argc, argv, "ACDHILNPR:STVWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF)
  1050. + (argc, argv, "ACDHILNPR:STU:VWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF)
  1051. {
  1052. switch (c)
  1053. {
  1054. @@ -5130,6 +5283,25 @@ parse_args (struct dump_data *dumpdata,
  1055. /* Ignored for backward compatibility. */
  1056. break;
  1057. + case 'U':
  1058. + if (optarg == NULL)
  1059. + error (_("Missing arg to -U/--unicode")); /* Can this happen ? */
  1060. + else if (streq (optarg, "default") || streq (optarg, "d"))
  1061. + unicode_display = unicode_default;
  1062. + else if (streq (optarg, "locale") || streq (optarg, "l"))
  1063. + unicode_display = unicode_locale;
  1064. + else if (streq (optarg, "escape") || streq (optarg, "e"))
  1065. + unicode_display = unicode_escape;
  1066. + else if (streq (optarg, "invalid") || streq (optarg, "i"))
  1067. + unicode_display = unicode_invalid;
  1068. + else if (streq (optarg, "hex") || streq (optarg, "x"))
  1069. + unicode_display = unicode_hex;
  1070. + else if (streq (optarg, "highlight") || streq (optarg, "h"))
  1071. + unicode_display = unicode_highlight;
  1072. + else
  1073. + error (_("invalid argument to -U/--unicode: %s"), optarg);
  1074. + break;
  1075. +
  1076. case OPTION_SYM_BASE:
  1077. sym_base = 0;
  1078. if (optarg != NULL)
  1079. diff --git a/binutils/strings.c b/binutils/strings.c
  1080. --- a/binutils/strings.c 2021-12-19 19:00:27.058540065 -0800
  1081. +++ b/binutils/strings.c 2021-12-19 19:48:26.205313218 -0800
  1082. @@ -55,6 +55,19 @@
  1083. -T {bfdname}
  1084. Specify a non-default object file format.
  1085. + --unicode={default|locale|invalid|hex|escape|highlight}
  1086. + -u {d|l|i|x|e|h}
  1087. + Determine how to handle UTF-8 unicode characters. The default
  1088. + is no special treatment. All other versions of this option
  1089. + only apply if the encoding is valid and enabling the option
  1090. + implies --encoding=S.
  1091. + The 'locale' option displays the characters according to the
  1092. + current locale. The 'invalid' option treats them as
  1093. + non-string characters. The 'hex' option displays them as hex
  1094. + byte sequences. The 'escape' option displays them as escape
  1095. + sequences and the 'highlight' option displays them as
  1096. + coloured escape sequences.
  1097. +
  1098. --output-separator=sep_string
  1099. -s sep_string String used to separate parsed strings in output.
  1100. Default is newline.
  1101. @@ -76,6 +89,22 @@
  1102. #include "safe-ctype.h"
  1103. #include "bucomm.h"
  1104. +#ifndef streq
  1105. +#define streq(a,b) (strcmp ((a),(b)) == 0)
  1106. +#endif
  1107. +
  1108. +typedef enum unicode_display_type
  1109. +{
  1110. + unicode_default = 0,
  1111. + unicode_locale,
  1112. + unicode_escape,
  1113. + unicode_hex,
  1114. + unicode_highlight,
  1115. + unicode_invalid
  1116. +} unicode_display_type;
  1117. +
  1118. +static unicode_display_type unicode_display = unicode_default;
  1119. +
  1120. #define STRING_ISGRAPHIC(c) \
  1121. ( (c) >= 0 \
  1122. && (c) <= 255 \
  1123. @@ -94,7 +123,7 @@ extern int errno;
  1124. static int address_radix;
  1125. /* Minimum length of sequence of graphic chars to trigger output. */
  1126. -static int string_min;
  1127. +static unsigned int string_min;
  1128. /* Whether or not we include all whitespace as a graphic char. */
  1129. static bool include_all_whitespace;
  1130. @@ -121,21 +150,22 @@ static char *output_separator;
  1131. static struct option long_options[] =
  1132. {
  1133. {"all", no_argument, NULL, 'a'},
  1134. + {"bytes", required_argument, NULL, 'n'},
  1135. {"data", no_argument, NULL, 'd'},
  1136. + {"encoding", required_argument, NULL, 'e'},
  1137. + {"help", no_argument, NULL, 'h'},
  1138. + {"include-all-whitespace", no_argument, NULL, 'w'},
  1139. + {"output-separator", required_argument, NULL, 's'},
  1140. {"print-file-name", no_argument, NULL, 'f'},
  1141. - {"bytes", required_argument, NULL, 'n'},
  1142. {"radix", required_argument, NULL, 't'},
  1143. - {"include-all-whitespace", no_argument, NULL, 'w'},
  1144. - {"encoding", required_argument, NULL, 'e'},
  1145. {"target", required_argument, NULL, 'T'},
  1146. - {"output-separator", required_argument, NULL, 's'},
  1147. - {"help", no_argument, NULL, 'h'},
  1148. + {"unicode", required_argument, NULL, 'U'},
  1149. {"version", no_argument, NULL, 'v'},
  1150. {NULL, 0, NULL, 0}
  1151. };
  1152. static bool strings_file (char *);
  1153. -static void print_strings (const char *, FILE *, file_ptr, int, int, char *);
  1154. +static void print_strings (const char *, FILE *, file_ptr, int, char *);
  1155. static void usage (FILE *, int) ATTRIBUTE_NORETURN;
  1156. int main (int, char **);
  1157. @@ -171,7 +201,7 @@ main (int argc, char **argv)
  1158. encoding = 's';
  1159. output_separator = NULL;
  1160. - while ((optc = getopt_long (argc, argv, "adfhHn:wot:e:T:s:Vv0123456789",
  1161. + while ((optc = getopt_long (argc, argv, "adfhHn:wot:e:T:s:U:Vv0123456789",
  1162. long_options, (int *) 0)) != EOF)
  1163. {
  1164. switch (optc)
  1165. @@ -244,6 +274,23 @@ main (int argc, char **argv)
  1166. output_separator = optarg;
  1167. break;
  1168. + case 'U':
  1169. + if (streq (optarg, "default") || streq (optarg, "d"))
  1170. + unicode_display = unicode_default;
  1171. + else if (streq (optarg, "locale") || streq (optarg, "l"))
  1172. + unicode_display = unicode_locale;
  1173. + else if (streq (optarg, "escape") || streq (optarg, "e"))
  1174. + unicode_display = unicode_escape;
  1175. + else if (streq (optarg, "invalid") || streq (optarg, "i"))
  1176. + unicode_display = unicode_invalid;
  1177. + else if (streq (optarg, "hex") || streq (optarg, "x"))
  1178. + unicode_display = unicode_hex;
  1179. + else if (streq (optarg, "highlight") || streq (optarg, "h"))
  1180. + unicode_display = unicode_highlight;
  1181. + else
  1182. + fatal (_("invalid argument to -U/--unicode: %s"), optarg);
  1183. + break;
  1184. +
  1185. case 'V':
  1186. case 'v':
  1187. print_version ("strings");
  1188. @@ -258,6 +305,9 @@ main (int argc, char **argv)
  1189. }
  1190. }
  1191. + if (unicode_display != unicode_default)
  1192. + encoding = 'S';
  1193. +
  1194. if (numeric_opt != 0)
  1195. {
  1196. string_min = (int) strtoul (argv[numeric_opt - 1] + 1, &s, 0);
  1197. @@ -293,14 +343,14 @@ main (int argc, char **argv)
  1198. {
  1199. datasection_only = false;
  1200. SET_BINARY (fileno (stdin));
  1201. - print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL);
  1202. + print_strings ("{standard input}", stdin, 0, 0, (char *) NULL);
  1203. files_given = true;
  1204. }
  1205. else
  1206. {
  1207. for (; optind < argc; ++optind)
  1208. {
  1209. - if (strcmp (argv[optind], "-") == 0)
  1210. + if (streq (argv[optind], "-"))
  1211. datasection_only = false;
  1212. else
  1213. {
  1214. @@ -342,7 +392,7 @@ strings_a_section (bfd *abfd, asection *
  1215. }
  1216. *got_a_section = true;
  1217. - print_strings (filename, NULL, sect->filepos, 0, sectsize, (char *) mem);
  1218. + print_strings (filename, NULL, sect->filepos, sectsize, (char *) mem);
  1219. free (mem);
  1220. }
  1221. @@ -427,7 +477,7 @@ strings_file (char *file)
  1222. return false;
  1223. }
  1224. - print_strings (file, stream, (file_ptr) 0, 0, 0, (char *) 0);
  1225. + print_strings (file, stream, (file_ptr) 0, 0, (char *) NULL);
  1226. if (fclose (stream) == EOF)
  1227. {
  1228. @@ -551,6 +601,626 @@ unget_part_char (long c, file_ptr *addre
  1229. }
  1230. }
  1231. }
  1232. +
  1233. +static void
  1234. +print_filename_and_address (const char * filename, file_ptr address)
  1235. +{
  1236. + if (print_filenames)
  1237. + printf ("%s: ", filename);
  1238. +
  1239. + if (! print_addresses)
  1240. + return;
  1241. +
  1242. + switch (address_radix)
  1243. + {
  1244. + case 8:
  1245. + if (sizeof (address) > sizeof (long))
  1246. + {
  1247. +#ifndef __MSVCRT__
  1248. + printf ("%7llo ", (unsigned long long) address);
  1249. +#else
  1250. + printf ("%7I64o ", (unsigned long long) address);
  1251. +#endif
  1252. + }
  1253. + else
  1254. + printf ("%7lo ", (unsigned long) address);
  1255. + break;
  1256. +
  1257. + case 10:
  1258. + if (sizeof (address) > sizeof (long))
  1259. + {
  1260. +#ifndef __MSVCRT__
  1261. + printf ("%7llu ", (unsigned long long) address);
  1262. +#else
  1263. + printf ("%7I64d ", (unsigned long long) address);
  1264. +#endif
  1265. + }
  1266. + else
  1267. + printf ("%7ld ", (long) address);
  1268. + break;
  1269. +
  1270. + case 16:
  1271. + if (sizeof (address) > sizeof (long))
  1272. + {
  1273. +#ifndef __MSVCRT__
  1274. + printf ("%7llx ", (unsigned long long) address);
  1275. +#else
  1276. + printf ("%7I64x ", (unsigned long long) address);
  1277. +#endif
  1278. + }
  1279. + else
  1280. + printf ("%7lx ", (unsigned long) address);
  1281. + break;
  1282. + }
  1283. +}
  1284. +
  1285. +/* Return non-zero if the bytes starting at BUFFER form a valid UTF-8 encoding.
  1286. + If the encoding is valid then returns the number of bytes it uses. */
  1287. +
  1288. +static unsigned int
  1289. +is_valid_utf8 (const unsigned char * buffer, unsigned long buflen)
  1290. +{
  1291. + if (buffer[0] < 0xc0)
  1292. + return 0;
  1293. +
  1294. + if (buflen < 2)
  1295. + return 0;
  1296. +
  1297. + if ((buffer[1] & 0xc0) != 0x80)
  1298. + return 0;
  1299. +
  1300. + if ((buffer[0] & 0x20) == 0)
  1301. + return 2;
  1302. +
  1303. + if (buflen < 3)
  1304. + return 0;
  1305. +
  1306. + if ((buffer[2] & 0xc0) != 0x80)
  1307. + return 0;
  1308. +
  1309. + if ((buffer[0] & 0x10) == 0)
  1310. + return 3;
  1311. +
  1312. + if (buflen < 4)
  1313. + return 0;
  1314. +
  1315. + if ((buffer[3] & 0xc0) != 0x80)
  1316. + return 0;
  1317. +
  1318. + return 4;
  1319. +}
  1320. +
  1321. +/* Display a UTF-8 encoded character in BUFFER according to the setting
  1322. + of unicode_display. The character is known to be valid.
  1323. + Returns the number of bytes consumed. */
  1324. +
  1325. +static unsigned int
  1326. +display_utf8_char (const unsigned char * buffer)
  1327. +{
  1328. + unsigned int j;
  1329. + unsigned int utf8_len;
  1330. +
  1331. + switch (buffer[0] & 0x30)
  1332. + {
  1333. + case 0x00:
  1334. + case 0x10:
  1335. + utf8_len = 2;
  1336. + break;
  1337. + case 0x20:
  1338. + utf8_len = 3;
  1339. + break;
  1340. + default:
  1341. + utf8_len = 4;
  1342. + }
  1343. +
  1344. + switch (unicode_display)
  1345. + {
  1346. + default:
  1347. + fprintf (stderr, "ICE: unexpected unicode display type\n");
  1348. + break;
  1349. +
  1350. + case unicode_escape:
  1351. + case unicode_highlight:
  1352. + if (unicode_display == unicode_highlight && isatty (1))
  1353. + printf ("\x1B[31;47m"); /* Red. */
  1354. +
  1355. + switch (utf8_len)
  1356. + {
  1357. + case 2:
  1358. + printf ("\\u%02x%02x",
  1359. + ((buffer[0] & 0x1c) >> 2),
  1360. + ((buffer[0] & 0x03) << 6) | (buffer[1] & 0x3f));
  1361. + break;
  1362. +
  1363. + case 3:
  1364. + printf ("\\u%02x%02x",
  1365. + ((buffer[0] & 0x0f) << 4) | ((buffer[1] & 0x3c) >> 2),
  1366. + ((buffer[1] & 0x03) << 6) | ((buffer[2] & 0x3f)));
  1367. + break;
  1368. +
  1369. + case 4:
  1370. + printf ("\\u%02x%02x%02x",
  1371. + ((buffer[0] & 0x07) << 6) | ((buffer[1] & 0x3c) >> 2),
  1372. + ((buffer[1] & 0x03) << 6) | ((buffer[2] & 0x3c) >> 2),
  1373. + ((buffer[2] & 0x03) << 6) | ((buffer[3] & 0x3f)));
  1374. + break;
  1375. + default:
  1376. + /* URG. */
  1377. + break;
  1378. + }
  1379. +
  1380. + if (unicode_display == unicode_highlight && isatty (1))
  1381. + printf ("\033[0m"); /* Default colour. */
  1382. + break;
  1383. +
  1384. + case unicode_hex:
  1385. + putchar ('<');
  1386. + printf ("0x");
  1387. + for (j = 0; j < utf8_len; j++)
  1388. + printf ("%02x", buffer [j]);
  1389. + putchar ('>');
  1390. + break;
  1391. +
  1392. + case unicode_locale:
  1393. + printf ("%.1s", buffer);
  1394. + break;
  1395. + }
  1396. +
  1397. + return utf8_len;
  1398. +}
  1399. +
  1400. +/* Display strings in BUFFER. Treat any UTF-8 encoded characters encountered
  1401. + according to the setting of the unicode_display variable. The buffer
  1402. + contains BUFLEN bytes.
  1403. +
  1404. + Display the characters as if they started at ADDRESS and are contained in
  1405. + FILENAME. */
  1406. +
  1407. +static void
  1408. +print_unicode_buffer (const char * filename,
  1409. + file_ptr address,
  1410. + const unsigned char * buffer,
  1411. + unsigned long buflen)
  1412. +{
  1413. + /* Paranoia checks... */
  1414. + if (filename == NULL
  1415. + || buffer == NULL
  1416. + || unicode_display == unicode_default
  1417. + || encoding != 'S'
  1418. + || encoding_bytes != 1)
  1419. + {
  1420. + fprintf (stderr, "ICE: bad arguments to print_unicode_buffer\n");
  1421. + return;
  1422. + }
  1423. +
  1424. + if (buflen == 0)
  1425. + return;
  1426. +
  1427. + /* We must only display strings that are at least string_min *characters*
  1428. + long. So we scan the buffer in two stages. First we locate the start
  1429. + of a potential string. Then we walk along it until we have found
  1430. + string_min characters. Then we go back to the start point and start
  1431. + displaying characters according to the unicode_display setting. */
  1432. +
  1433. + unsigned long start_point = 0;
  1434. + unsigned long i = 0;
  1435. + unsigned int char_len = 1;
  1436. + unsigned int num_found = 0;
  1437. +
  1438. + for (i = 0; i < buflen; i += char_len)
  1439. + {
  1440. + int c = buffer[i];
  1441. +
  1442. + char_len = 1;
  1443. +
  1444. + /* Find the first potential character of a string. */
  1445. + if (! STRING_ISGRAPHIC (c))
  1446. + {
  1447. + num_found = 0;
  1448. + continue;
  1449. + }
  1450. +
  1451. + if (c > 126)
  1452. + {
  1453. + if (c < 0xc0)
  1454. + {
  1455. + num_found = 0;
  1456. + continue;
  1457. + }
  1458. +
  1459. + if ((char_len = is_valid_utf8 (buffer + i, buflen - i)) == 0)
  1460. + {
  1461. + char_len = 1;
  1462. + num_found = 0;
  1463. + continue;
  1464. + }
  1465. +
  1466. + if (unicode_display == unicode_invalid)
  1467. + {
  1468. + /* We have found a valid UTF-8 character, but we treat it as non-graphic. */
  1469. + num_found = 0;
  1470. + continue;
  1471. + }
  1472. + }
  1473. +
  1474. + if (num_found == 0)
  1475. + /* We have found a potential starting point for a string. */
  1476. + start_point = i;
  1477. +
  1478. + ++ num_found;
  1479. +
  1480. + if (num_found >= string_min)
  1481. + break;
  1482. + }
  1483. +
  1484. + if (num_found < string_min)
  1485. + return;
  1486. +
  1487. + print_filename_and_address (filename, address + start_point);
  1488. +
  1489. + /* We have found string_min characters. Display them and any
  1490. + more that follow. */
  1491. + for (i = start_point; i < buflen; i += char_len)
  1492. + {
  1493. + int c = buffer[i];
  1494. +
  1495. + char_len = 1;
  1496. +
  1497. + if (! STRING_ISGRAPHIC (c))
  1498. + break;
  1499. + else if (c < 127)
  1500. + putchar (c);
  1501. + else if (! is_valid_utf8 (buffer + i, buflen - i))
  1502. + break;
  1503. + else if (unicode_display == unicode_invalid)
  1504. + break;
  1505. + else
  1506. + char_len = display_utf8_char (buffer + i);
  1507. + }
  1508. +
  1509. + if (output_separator)
  1510. + fputs (output_separator, stdout);
  1511. + else
  1512. + putchar ('\n');
  1513. +
  1514. + /* FIXME: Using tail recursion here is lazy programming... */
  1515. + print_unicode_buffer (filename, address + i, buffer + i, buflen - i);
  1516. +}
  1517. +
  1518. +static int
  1519. +get_unicode_byte (FILE * stream,
  1520. + unsigned char * putback,
  1521. + unsigned int * num_putback,
  1522. + unsigned int * num_read)
  1523. +{
  1524. + if (* num_putback > 0)
  1525. + {
  1526. + * num_putback = * num_putback - 1;
  1527. + return putback [* num_putback];
  1528. + }
  1529. +
  1530. + * num_read = * num_read + 1;
  1531. +
  1532. +#if defined(HAVE_GETC_UNLOCKED) && HAVE_DECL_GETC_UNLOCKED
  1533. + return getc_unlocked (stream);
  1534. +#else
  1535. + return getc (stream);
  1536. +#endif
  1537. +}
  1538. +
  1539. +/* Helper function for print_unicode_stream. */
  1540. +
  1541. +static void
  1542. +print_unicode_stream_body (const char * filename,
  1543. + file_ptr address,
  1544. + FILE * stream,
  1545. + unsigned char * putback_buf,
  1546. + unsigned int num_putback,
  1547. + unsigned char * print_buf)
  1548. +{
  1549. + /* It would be nice if we could just read the stream into a buffer
  1550. + and then process if with print_unicode_buffer. But the input
  1551. + might be huge or it might time-locked (eg stdin). So instead
  1552. + we go one byte at a time... */
  1553. +
  1554. + file_ptr start_point = 0;
  1555. + unsigned int num_read = 0;
  1556. + unsigned int num_chars = 0;
  1557. + unsigned int num_print = 0;
  1558. + int c = 0;
  1559. +
  1560. + /* Find a series of string_min characters. Put them into print_buf. */
  1561. + do
  1562. + {
  1563. + if (num_chars >= string_min)
  1564. + break;
  1565. +
  1566. + c = get_unicode_byte (stream, putback_buf, & num_putback, & num_read);
  1567. + if (c == EOF)
  1568. + break;
  1569. +
  1570. + if (! STRING_ISGRAPHIC (c))
  1571. + {
  1572. + num_chars = num_print = 0;
  1573. + continue;
  1574. + }
  1575. +
  1576. + if (num_chars == 0)
  1577. + start_point = num_read - 1;
  1578. +
  1579. + if (c < 127)
  1580. + {
  1581. + print_buf[num_print] = c;
  1582. + num_chars ++;
  1583. + num_print ++;
  1584. + continue;
  1585. + }
  1586. +
  1587. + if (c < 0xc0)
  1588. + {
  1589. + num_chars = num_print = 0;
  1590. + continue;
  1591. + }
  1592. +
  1593. + /* We *might* have a UTF-8 sequence. Time to start peeking. */
  1594. + char utf8[4];
  1595. +
  1596. + utf8[0] = c;
  1597. + c = get_unicode_byte (stream, putback_buf, & num_putback, & num_read);
  1598. + if (c == EOF)
  1599. + break;
  1600. + utf8[1] = c;
  1601. +
  1602. + if ((utf8[1] & 0xc0) != 0x80)
  1603. + {
  1604. + /* Invalid UTF-8. */
  1605. + putback_buf[num_putback++] = utf8[1];
  1606. + num_chars = num_print = 0;
  1607. + continue;
  1608. + }
  1609. + else if ((utf8[0] & 0x20) == 0)
  1610. + {
  1611. + /* A valid 2-byte UTF-8 encoding. */
  1612. + if (unicode_display == unicode_invalid)
  1613. + {
  1614. + putback_buf[num_putback++] = utf8[1];
  1615. + num_chars = num_print = 0;
  1616. + }
  1617. + else
  1618. + {
  1619. + print_buf[num_print ++] = utf8[0];
  1620. + print_buf[num_print ++] = utf8[1];
  1621. + num_chars ++;
  1622. + }
  1623. + continue;
  1624. + }
  1625. +
  1626. + c = get_unicode_byte (stream, putback_buf, & num_putback, & num_read);
  1627. + if (c == EOF)
  1628. + break;
  1629. + utf8[2] = c;
  1630. +
  1631. + if ((utf8[2] & 0xc0) != 0x80)
  1632. + {
  1633. + /* Invalid UTF-8. */
  1634. + putback_buf[num_putback++] = utf8[2];
  1635. + putback_buf[num_putback++] = utf8[1];
  1636. + num_chars = num_print = 0;
  1637. + continue;
  1638. + }
  1639. + else if ((utf8[0] & 0x10) == 0)
  1640. + {
  1641. + /* A valid 3-byte UTF-8 encoding. */
  1642. + if (unicode_display == unicode_invalid)
  1643. + {
  1644. + putback_buf[num_putback++] = utf8[2];
  1645. + putback_buf[num_putback++] = utf8[1];
  1646. + num_chars = num_print = 0;
  1647. + }
  1648. + else
  1649. + {
  1650. + print_buf[num_print ++] = utf8[0];
  1651. + print_buf[num_print ++] = utf8[1];
  1652. + print_buf[num_print ++] = utf8[2];
  1653. + num_chars ++;
  1654. + }
  1655. + continue;
  1656. + }
  1657. +
  1658. + c = get_unicode_byte (stream, putback_buf, & num_putback, & num_read);
  1659. + if (c == EOF)
  1660. + break;
  1661. + utf8[3] = c;
  1662. +
  1663. + if ((utf8[3] & 0xc0) != 0x80)
  1664. + {
  1665. + /* Invalid UTF-8. */
  1666. + putback_buf[num_putback++] = utf8[3];
  1667. + putback_buf[num_putback++] = utf8[2];
  1668. + putback_buf[num_putback++] = utf8[1];
  1669. + num_chars = num_print = 0;
  1670. + }
  1671. + /* We have a valid 4-byte UTF-8 encoding. */
  1672. + else if (unicode_display == unicode_invalid)
  1673. + {
  1674. + putback_buf[num_putback++] = utf8[3];
  1675. + putback_buf[num_putback++] = utf8[1];
  1676. + putback_buf[num_putback++] = utf8[2];
  1677. + num_chars = num_print = 0;
  1678. + }
  1679. + else
  1680. + {
  1681. + print_buf[num_print ++] = utf8[0];
  1682. + print_buf[num_print ++] = utf8[1];
  1683. + print_buf[num_print ++] = utf8[2];
  1684. + print_buf[num_print ++] = utf8[3];
  1685. + num_chars ++;
  1686. + }
  1687. + }
  1688. + while (1);
  1689. +
  1690. + if (num_chars >= string_min)
  1691. + {
  1692. + /* We know that we have string_min valid characters in print_buf,
  1693. + and there may be more to come in the stream. Start displaying
  1694. + them. */
  1695. +
  1696. + print_filename_and_address (filename, address + start_point);
  1697. +
  1698. + unsigned int i;
  1699. + for (i = 0; i < num_print;)
  1700. + {
  1701. + if (print_buf[i] < 127)
  1702. + putchar (print_buf[i++]);
  1703. + else
  1704. + i += display_utf8_char (print_buf + i);
  1705. + }
  1706. +
  1707. + /* OK so now we have to start read unchecked bytes. */
  1708. +
  1709. + /* Find a series of string_min characters. Put them into print_buf. */
  1710. + do
  1711. + {
  1712. + c = get_unicode_byte (stream, putback_buf, & num_putback, & num_read);
  1713. + if (c == EOF)
  1714. + break;
  1715. +
  1716. + if (! STRING_ISGRAPHIC (c))
  1717. + break;
  1718. +
  1719. + if (c < 127)
  1720. + {
  1721. + putchar (c);
  1722. + continue;
  1723. + }
  1724. +
  1725. + if (c < 0xc0)
  1726. + break;
  1727. +
  1728. + /* We *might* have a UTF-8 sequence. Time to start peeking. */
  1729. + unsigned char utf8[4];
  1730. +
  1731. + utf8[0] = c;
  1732. + c = get_unicode_byte (stream, putback_buf, & num_putback, & num_read);
  1733. + if (c == EOF)
  1734. + break;
  1735. + utf8[1] = c;
  1736. +
  1737. + if ((utf8[1] & 0xc0) != 0x80)
  1738. + {
  1739. + /* Invalid UTF-8. */
  1740. + putback_buf[num_putback++] = utf8[1];
  1741. + break;
  1742. + }
  1743. + else if ((utf8[0] & 0x20) == 0)
  1744. + {
  1745. + /* Valid 2-byte UTF-8. */
  1746. + if (unicode_display == unicode_invalid)
  1747. + {
  1748. + putback_buf[num_putback++] = utf8[1];
  1749. + break;
  1750. + }
  1751. + else
  1752. + {
  1753. + (void) display_utf8_char (utf8);
  1754. + continue;
  1755. + }
  1756. + }
  1757. +
  1758. + c = get_unicode_byte (stream, putback_buf, & num_putback, & num_read);
  1759. + if (c == EOF)
  1760. + break;
  1761. + utf8[2] = c;
  1762. +
  1763. + if ((utf8[2] & 0xc0) != 0x80)
  1764. + {
  1765. + /* Invalid UTF-8. */
  1766. + putback_buf[num_putback++] = utf8[2];
  1767. + putback_buf[num_putback++] = utf8[1];
  1768. + break;
  1769. + }
  1770. + else if ((utf8[0] & 0x10) == 0)
  1771. + {
  1772. + /* Valid 3-byte UTF-8. */
  1773. + if (unicode_display == unicode_invalid)
  1774. + {
  1775. + putback_buf[num_putback++] = utf8[2];
  1776. + putback_buf[num_putback++] = utf8[1];
  1777. + break;
  1778. + }
  1779. + else
  1780. + {
  1781. + (void) display_utf8_char (utf8);
  1782. + continue;
  1783. + }
  1784. + }
  1785. +
  1786. + c = get_unicode_byte (stream, putback_buf, & num_putback, & num_read);
  1787. + if (c == EOF)
  1788. + break;
  1789. + utf8[3] = c;
  1790. +
  1791. + if ((utf8[3] & 0xc0) != 0x80)
  1792. + {
  1793. + /* Invalid UTF-8. */
  1794. + putback_buf[num_putback++] = utf8[3];
  1795. + putback_buf[num_putback++] = utf8[2];
  1796. + putback_buf[num_putback++] = utf8[1];
  1797. + break;
  1798. + }
  1799. + else if (unicode_display == unicode_invalid)
  1800. + {
  1801. + putback_buf[num_putback++] = utf8[3];
  1802. + putback_buf[num_putback++] = utf8[2];
  1803. + putback_buf[num_putback++] = utf8[1];
  1804. + break;
  1805. + }
  1806. + else
  1807. + /* A valid 4-byte UTF-8 encoding. */
  1808. + (void) display_utf8_char (utf8);
  1809. + }
  1810. + while (1);
  1811. +
  1812. + if (output_separator)
  1813. + fputs (output_separator, stdout);
  1814. + else
  1815. + putchar ('\n');
  1816. + }
  1817. +
  1818. + if (c != EOF)
  1819. + /* FIXME: Using tail recursion here is lazy, but it works. */
  1820. + print_unicode_stream_body (filename, address + num_read, stream, putback_buf, num_putback, print_buf);
  1821. +}
  1822. +
  1823. +/* Display strings read in from STREAM. Treat any UTF-8 encoded characters
  1824. + encountered according to the setting of the unicode_display variable.
  1825. + The stream is positioned at ADDRESS and is attached to FILENAME. */
  1826. +
  1827. +static void
  1828. +print_unicode_stream (const char * filename,
  1829. + file_ptr address,
  1830. + FILE * stream)
  1831. +{
  1832. + /* Paranoia checks... */
  1833. + if (filename == NULL
  1834. + || stream == NULL
  1835. + || unicode_display == unicode_default
  1836. + || encoding != 'S'
  1837. + || encoding_bytes != 1)
  1838. + {
  1839. + fprintf (stderr, "ICE: bad arguments to print_unicode_stream\n");
  1840. + return;
  1841. + }
  1842. +
  1843. + /* Allocate space for string_min 4-byte utf-8 characters. */
  1844. + unsigned char * print_buf = xmalloc ((4 * string_min) + 1);
  1845. + /* We should never have to put back more than 4 bytes. */
  1846. + unsigned char putback_buf[5];
  1847. + unsigned int num_putback = 0;
  1848. +
  1849. + print_unicode_stream_body (filename, address, stream, putback_buf, num_putback, print_buf);
  1850. + free (print_buf);
  1851. +}
  1852. /* Find the strings in file FILENAME, read from STREAM.
  1853. Assume that STREAM is positioned so that the next byte read
  1854. @@ -566,20 +1236,29 @@ unget_part_char (long c, file_ptr *addre
  1855. static void
  1856. print_strings (const char *filename, FILE *stream, file_ptr address,
  1857. - int stop_point, int magiccount, char *magic)
  1858. + int magiccount, char *magic)
  1859. {
  1860. + if (unicode_display != unicode_default)
  1861. + {
  1862. + if (magic != NULL)
  1863. + print_unicode_buffer (filename, address,
  1864. + (const unsigned char *) magic, magiccount);
  1865. +
  1866. + if (stream != NULL)
  1867. + print_unicode_stream (filename, address, stream);
  1868. + return;
  1869. + }
  1870. +
  1871. char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1));
  1872. while (1)
  1873. {
  1874. file_ptr start;
  1875. - int i;
  1876. + unsigned int i;
  1877. long c;
  1878. /* See if the next `string_min' chars are all graphic chars. */
  1879. tryline:
  1880. - if (stop_point && address >= stop_point)
  1881. - break;
  1882. start = address;
  1883. for (i = 0; i < string_min; i++)
  1884. {
  1885. @@ -601,51 +1280,7 @@ print_strings (const char *filename, FIL
  1886. /* We found a run of `string_min' graphic characters. Print up
  1887. to the next non-graphic character. */
  1888. -
  1889. - if (print_filenames)
  1890. - printf ("%s: ", filename);
  1891. - if (print_addresses)
  1892. - switch (address_radix)
  1893. - {
  1894. - case 8:
  1895. - if (sizeof (start) > sizeof (long))
  1896. - {
  1897. -#ifndef __MSVCRT__
  1898. - printf ("%7llo ", (unsigned long long) start);
  1899. -#else
  1900. - printf ("%7I64o ", (unsigned long long) start);
  1901. -#endif
  1902. - }
  1903. - else
  1904. - printf ("%7lo ", (unsigned long) start);
  1905. - break;
  1906. -
  1907. - case 10:
  1908. - if (sizeof (start) > sizeof (long))
  1909. - {
  1910. -#ifndef __MSVCRT__
  1911. - printf ("%7llu ", (unsigned long long) start);
  1912. -#else
  1913. - printf ("%7I64d ", (unsigned long long) start);
  1914. -#endif
  1915. - }
  1916. - else
  1917. - printf ("%7ld ", (long) start);
  1918. - break;
  1919. -
  1920. - case 16:
  1921. - if (sizeof (start) > sizeof (long))
  1922. - {
  1923. -#ifndef __MSVCRT__
  1924. - printf ("%7llx ", (unsigned long long) start);
  1925. -#else
  1926. - printf ("%7I64x ", (unsigned long long) start);
  1927. -#endif
  1928. - }
  1929. - else
  1930. - printf ("%7lx ", (unsigned long) start);
  1931. - break;
  1932. - }
  1933. + print_filename_and_address (filename, start);
  1934. buf[i] = '\0';
  1935. fputs (buf, stdout);
  1936. @@ -697,6 +1332,8 @@ usage (FILE *stream, int status)
  1937. -T --target=<BFDNAME> Specify the binary file format\n\
  1938. -e --encoding={s,S,b,l,B,L} Select character size and endianness:\n\
  1939. s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\
  1940. + --unicode={default|show|invalid|hex|escape|highlight}\n\
  1941. + -u {d|s|i|x|e|h} Specify how to treat UTF-8 encoded unicode characters\n\
  1942. -s --output-separator=<string> String used to separate strings in output.\n\
  1943. @<file> Read options from <file>\n\
  1944. -h --help Display this information\n\