xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/CompCom.cc (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Copyright (C) 2021-2024 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 
CompComment(Elf * _elf,int _compcom)37 CompComment::CompComment (Elf *_elf, int _compcom)
38 {
39   elf = _elf;
40   compcom = _compcom;
41   elf_cls = elf->elf_getclass ();
42 }
43 
~CompComment()44 CompComment::~CompComment () { }
45 
46 int
get_align(int64_t offset,int align)47 CompComment::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  */
61 int
compcom_open(CheckSrcName check_src)62 CompComment::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 
105 char *
get_demangle_name(char * fname)106 CompComment::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  */
116 char *
compcom_format(int index,compmsg * msg,int & visible)117 CompComment::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)
309 	    free (parms[i]);
310 	}
311     }
312   return mbuf;
313 }
314