1/* Copyright (C) 2021 Free Software Foundation, Inc.
2   Contributed by Oracle.
3
4   This file is part of GNU Binutils.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3, or (at your option)
9   any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, 51 Franklin Street - Fifth Floor, Boston,
19   MA 02110-1301, USA.  */
20
21#include "config.h"
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25#include <locale.h>
26#include <sys/param.h>
27
28#include "demangle.h"
29#include "gp-defs.h"
30#include "StringBuilder.h"
31#include "CompCom.h"
32#include "Elf.h"
33#include "util.h"
34#include "i18n.h"
35#include "comp_com.c"
36
37CompComment::CompComment (Elf *_elf, int _compcom)
38{
39  elf = _elf;
40  compcom = _compcom;
41  elf_cls = elf->elf_getclass ();
42}
43
44CompComment::~CompComment () { }
45
46int
47CompComment::get_align (int64_t offset, int align)
48{
49  int val = (int) (offset % align);
50  if (val)
51    val = align - val;
52  return val;
53}
54
55/*
56 * Preprocesses the header structure, builds a table of messages with the line
57 * numbers, PCoffsets, original index, and compmsg pointer for each message.
58 * If the show_bits field is not in the message, this routine would fill it in
59 * from the mapping from COMPMSG_ID
60 */
61int
62CompComment::compcom_open (CheckSrcName check_src)
63{
64  if (check_src == NULL)
65    return 0;
66  Elf_Data *data = elf->elf_getdata (compcom);
67  uint64_t b_offset = data->d_off;
68  if (get_align (b_offset, 4))   // not align 4
69    return 0;
70  char *CommData = (char *) data->d_buf;
71  uint64_t offset = b_offset;
72  for (uint64_t e_offset = b_offset + data->d_size; offset < e_offset;)
73    {
74      offset += get_align (offset, (int) data->d_align);
75      if (offset >= e_offset)
76	return 0;
77      compcomhdr *hdr = (compcomhdr *) (CommData + (offset - b_offset));
78      int hdr_msgcount = elf->decode (hdr->msgcount);
79      int hdr_srcname = elf->decode (hdr->srcname);
80      int hdr_stringlen = elf->decode (hdr->stringlen);
81      int hdr_paramcount = elf->decode (hdr->paramcount);
82      size_t length = sizeof (compcomhdr) + hdr_msgcount * sizeof (compmsg) +
83	      hdr_paramcount * sizeof (int32_t);
84      if (offset + length + hdr_stringlen > e_offset || hdr_srcname < 0
85	  || hdr_srcname >= hdr_stringlen)
86	return 0;
87
88      // check source file
89      char *src_name = (char *) (((char*) hdr) + length + hdr_srcname);
90      if (check_src (src_name))
91	{
92	  msgs = (compmsg *) (((char *) hdr) + sizeof (compcomhdr));
93	  params = (int32_t *) ((char *) msgs + hdr_msgcount * sizeof (compmsg));
94	  strs = (char *) ((char *) params + hdr_paramcount * sizeof (int32_t));
95
96	  // initialize the I18N/L10N strings & set the visible table
97	  ccm_vis_init ();
98	  return hdr_msgcount;
99	}
100      offset += (length + hdr_stringlen);
101    }
102  return 0;
103}
104
105char *
106CompComment::get_demangle_name (char *fname)
107{
108  if (*fname == '_')
109    return cplus_demangle (fname, DMGL_PARAMS);
110  return NULL;
111}
112
113/*
114 * takes the message, and returns the I18N string for the message.
115 */
116char *
117CompComment::compcom_format (int index, compmsg *msg, int &visible)
118{
119  compmsg *p = msgs + index;
120  msg->instaddr = elf->decode (p->instaddr);
121  msg->lineno = elf->decode (p->lineno);
122  msg->msg_type = elf->decode (p->msg_type);
123  msg->nparam = elf->decode (p->nparam);
124  msg->param_index = elf->decode (p->param_index);
125
126  int vindex = ccm_vis_index (msg->msg_type);
127  char *mbuf;
128  Ccm_Primtype_t prim_ty;
129  visible = ccm_attrs[vindex].vis;
130  if (ccm_attrs[vindex].msg == NULL)
131    {
132      /* Print CCM_UNKNOWN message */
133      int uindex = ccm_vis_index (CCM_UNKNOWN);
134      visible = ccm_attrs[uindex].vis;
135      return dbe_sprintf (ccm_attrs[uindex].msg, vindex);
136    }
137
138  /*
139   * Construct the output buffer based on the primitive types of the
140   * message parameters.
141   *
142   * Parameter lists have to be handled carefully -- the 1 parameter
143   * is built up of all the elements separated by ", ".
144   *
145   * Old way: Case by message format string.
146   */
147  int *ind = params + msg->param_index;
148  int plist_idx = ccm_paramlist_index (msg->msg_type);
149  if (plist_idx <= 0)
150    {
151      /* No parameter list to handle; 0 parameters case is handled */
152
153      enum
154      {
155	MAX_COMPCOM_ARGS = 13
156      };
157      char *parms[MAX_COMPCOM_ARGS];
158      if (msg->nparam >= MAX_COMPCOM_ARGS)
159	{
160	  fprintf (stderr,
161		   GTXT ("Warning: improperly formatted compiler commentary message (%d parameters >= %d);\n  please report this bug against the compiler\n"),
162		   msg->nparam, MAX_COMPCOM_ARGS);
163	  return NULL;
164	}
165      for (int i = 0; i < MAX_COMPCOM_ARGS; i++)
166	parms[i] = NULL; // initialize array
167      int prm_cnt = ccm_num_params (msg->msg_type);
168      if (prm_cnt != msg->nparam)
169	{
170	  fprintf (stderr,
171		   GTXT ("Warning, improperly formatted compiler commentary message (parameter count mismatch = %d, param# = %d, msg_type = %x, `%s');\n  please report this bug against the compiler\n"),
172		   prm_cnt, msg->nparam, msg->msg_type, ccm_attrs[vindex].msg);
173	  return NULL;
174	}
175      for (int i = 0; i < msg->nparam; i++)
176	{
177	  /* Parameters in message-type numbered from '1' */
178	  prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
179	  if (prim_ty == CCM_PRIMTYPE_INTEGER)
180	    {
181	      unsigned long v = elf->decode (ind[i]);
182	      parms[i] = (char*) v;
183	    }
184	  else if (prim_ty == CCM_PRIMTYPE_STRING)
185	    {
186	      char *fname = strs + elf->decode (ind[i]);
187	      char *demName = get_demangle_name (fname);
188	      parms[i] = demName ? demName : dbe_strdup (fname);
189	    }
190	  else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
191	    parms[i] = dbe_sprintf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
192				    (unsigned long long) msg->instaddr);
193	  else
194	    {
195	      fprintf (stderr,
196		       GTXT ("Warning, improperly formatted compiler commentary message (unexpected primitive type %d);\n  please report this bug against the compiler\n"),
197		       prim_ty);
198	      // Dummy code to avoid compiler's warning: static function ccm_param_hightype is not used
199	      Ccm_Hitype_t hightype = CCM_HITYPE_NONE;
200	      if (hightype != CCM_HITYPE_NONE)
201		hightype = ccm_param_hightype (msg->msg_type, i + 1);
202	      return NULL;
203	    }
204	}
205
206      /*
207       * Must make sure to pass _ALL_ params; may pass more because
208       * the format won't access the 'extra' parameters if all the
209       * rules for messages have been followed.
210       */
211      mbuf = dbe_sprintf (ccm_attrs[vindex].msg, parms[0], parms[1], parms[2],
212			  parms[3], parms[4], parms[5], parms[6], parms[7],
213			  parms[8], parms[9], parms[10], parms[11]);
214      // Cleanup allocated memory.
215      for (int i = 0; i < msg->nparam; i++)
216	{
217	  prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
218	  if (prim_ty == CCM_PRIMTYPE_STRING || prim_ty == CCM_PRIMTYPE_HEXSTRING)
219	    free (parms[i]);
220	}
221    }
222  else
223    {
224      /*
225       * Parameter list messages never have 0 parameters; the
226       * primitive type for the parameter list elements is always
227       * the same.  And as of 22-Sep-2006, it was always
228       * CCM_PRIMTYPE_STRING.
229       *
230       * Account for different bases of parameter indices and
231       * 'nparam' count (1 and 0, respectively).
232       */
233      char *parms[3];
234      if (plist_idx > (int) ((sizeof (parms) / sizeof (char*))))
235	{
236	  fprintf (stderr,
237		   GTXT ("Warning: improperly formatted compiler commentary message (msg->nparam=%d plist_idx=%d);\n  please report this bug against the compiler\n"),
238		   msg->nparam, plist_idx);
239	  return NULL;
240	}
241      for (size_t i = 0; i < (sizeof (parms) / sizeof (char*)); i++)
242	parms[i] = NULL; // initialize array
243
244      StringBuilder sb;
245      prim_ty = ccm_param_primtype (msg->msg_type, plist_idx);
246      for (int i = plist_idx - 1; i < msg->nparam; i++)
247	{
248	  if (i != plist_idx - 1)
249	    sb.append (GTXT (", "));
250	  if (prim_ty == CCM_PRIMTYPE_INTEGER)
251	    sb.append (elf->decode (ind[i]));
252	  else if (prim_ty == CCM_PRIMTYPE_STRING)
253	    {
254	      char *fname = strs + elf->decode (ind[i]);
255	      char *demName = get_demangle_name (fname);
256	      if (demName)
257		{
258		  sb.append (demName);
259		  delete demName;
260		}
261	      else
262		sb.append (fname);
263	    }
264	  else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
265	    sb.appendf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
266			(unsigned long long) msg->instaddr);
267	}
268      parms[plist_idx - 1] = sb.toString ();
269
270      for (int i = 0; i < plist_idx - 1; i++)
271	{
272	  prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
273	  if (prim_ty == CCM_PRIMTYPE_INTEGER)
274	    {
275	      unsigned long v = elf->decode (ind[i]);
276	      parms[i] = (char*) v;
277	    }
278	  else if (prim_ty == CCM_PRIMTYPE_STRING)
279	    {
280	      char *fname = strs + elf->decode (ind[i]);
281	      char *demName = get_demangle_name (fname);
282	      parms[i] = demName ? demName : dbe_strdup (fname);
283	    }
284	  else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
285	    parms[i] = dbe_sprintf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
286				    (unsigned long long) msg->instaddr);
287	  else
288	    {
289	      fprintf (stderr,
290		       GTXT ("Warning, improperly formatted compiler commentary message (unexpected primitive type %d);\n  please report this bug against the compiler\n"),
291		       prim_ty);
292	      return NULL;
293	    }
294	}
295
296      /*
297       * We have reduced the parameter list to a single string (as
298       * the printf format specifier requires), so only have
299       * 'plist_idx' parameters.
300       */
301      mbuf = dbe_sprintf (ccm_attrs[vindex].msg, parms[0], parms[1], parms[2]);
302
303      // Cleanup allocated memory.
304      free (parms[plist_idx - 1]);
305      for (int i = 0; i < plist_idx - 1; i++)
306	{
307	  prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
308	  if (prim_ty == CCM_PRIMTYPE_STRING || prim_ty == CCM_PRIMTYPE_STRING)
309	    free (parms[i]);
310	}
311    }
312  return mbuf;
313}
314