/* Copyright (C) 2021 Free Software Foundation, Inc. Contributed by Oracle. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #include #include #include #include "demangle.h" #include "gp-defs.h" #include "StringBuilder.h" #include "CompCom.h" #include "Elf.h" #include "util.h" #include "i18n.h" #include "comp_com.c" CompComment::CompComment (Elf *_elf, int _compcom) { elf = _elf; compcom = _compcom; elf_cls = elf->elf_getclass (); } CompComment::~CompComment () { } int CompComment::get_align (int64_t offset, int align) { int val = (int) (offset % align); if (val) val = align - val; return val; } /* * Preprocesses the header structure, builds a table of messages with the line * numbers, PCoffsets, original index, and compmsg pointer for each message. * If the show_bits field is not in the message, this routine would fill it in * from the mapping from COMPMSG_ID */ int CompComment::compcom_open (CheckSrcName check_src) { if (check_src == NULL) return 0; Elf_Data *data = elf->elf_getdata (compcom); uint64_t b_offset = data->d_off; if (get_align (b_offset, 4)) // not align 4 return 0; char *CommData = (char *) data->d_buf; uint64_t offset = b_offset; for (uint64_t e_offset = b_offset + data->d_size; offset < e_offset;) { offset += get_align (offset, (int) data->d_align); if (offset >= e_offset) return 0; compcomhdr *hdr = (compcomhdr *) (CommData + (offset - b_offset)); int hdr_msgcount = elf->decode (hdr->msgcount); int hdr_srcname = elf->decode (hdr->srcname); int hdr_stringlen = elf->decode (hdr->stringlen); int hdr_paramcount = elf->decode (hdr->paramcount); size_t length = sizeof (compcomhdr) + hdr_msgcount * sizeof (compmsg) + hdr_paramcount * sizeof (int32_t); if (offset + length + hdr_stringlen > e_offset || hdr_srcname < 0 || hdr_srcname >= hdr_stringlen) return 0; // check source file char *src_name = (char *) (((char*) hdr) + length + hdr_srcname); if (check_src (src_name)) { msgs = (compmsg *) (((char *) hdr) + sizeof (compcomhdr)); params = (int32_t *) ((char *) msgs + hdr_msgcount * sizeof (compmsg)); strs = (char *) ((char *) params + hdr_paramcount * sizeof (int32_t)); // initialize the I18N/L10N strings & set the visible table ccm_vis_init (); return hdr_msgcount; } offset += (length + hdr_stringlen); } return 0; } char * CompComment::get_demangle_name (char *fname) { if (*fname == '_') return cplus_demangle (fname, DMGL_PARAMS); return NULL; } /* * takes the message, and returns the I18N string for the message. */ char * CompComment::compcom_format (int index, compmsg *msg, int &visible) { compmsg *p = msgs + index; msg->instaddr = elf->decode (p->instaddr); msg->lineno = elf->decode (p->lineno); msg->msg_type = elf->decode (p->msg_type); msg->nparam = elf->decode (p->nparam); msg->param_index = elf->decode (p->param_index); int vindex = ccm_vis_index (msg->msg_type); char *mbuf; Ccm_Primtype_t prim_ty; visible = ccm_attrs[vindex].vis; if (ccm_attrs[vindex].msg == NULL) { /* Print CCM_UNKNOWN message */ int uindex = ccm_vis_index (CCM_UNKNOWN); visible = ccm_attrs[uindex].vis; return dbe_sprintf (ccm_attrs[uindex].msg, vindex); } /* * Construct the output buffer based on the primitive types of the * message parameters. * * Parameter lists have to be handled carefully -- the 1 parameter * is built up of all the elements separated by ", ". * * Old way: Case by message format string. */ int *ind = params + msg->param_index; int plist_idx = ccm_paramlist_index (msg->msg_type); if (plist_idx <= 0) { /* No parameter list to handle; 0 parameters case is handled */ enum { MAX_COMPCOM_ARGS = 13 }; char *parms[MAX_COMPCOM_ARGS]; if (msg->nparam >= MAX_COMPCOM_ARGS) { fprintf (stderr, GTXT ("Warning: improperly formatted compiler commentary message (%d parameters >= %d);\n please report this bug against the compiler\n"), msg->nparam, MAX_COMPCOM_ARGS); return NULL; } for (int i = 0; i < MAX_COMPCOM_ARGS; i++) parms[i] = NULL; // initialize array int prm_cnt = ccm_num_params (msg->msg_type); if (prm_cnt != msg->nparam) { fprintf (stderr, 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"), prm_cnt, msg->nparam, msg->msg_type, ccm_attrs[vindex].msg); return NULL; } for (int i = 0; i < msg->nparam; i++) { /* Parameters in message-type numbered from '1' */ prim_ty = ccm_param_primtype (msg->msg_type, i + 1); if (prim_ty == CCM_PRIMTYPE_INTEGER) { unsigned long v = elf->decode (ind[i]); parms[i] = (char*) v; } else if (prim_ty == CCM_PRIMTYPE_STRING) { char *fname = strs + elf->decode (ind[i]); char *demName = get_demangle_name (fname); parms[i] = demName ? demName : dbe_strdup (fname); } else if (prim_ty == CCM_PRIMTYPE_HEXSTRING) parms[i] = dbe_sprintf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"), (unsigned long long) msg->instaddr); else { fprintf (stderr, GTXT ("Warning, improperly formatted compiler commentary message (unexpected primitive type %d);\n please report this bug against the compiler\n"), prim_ty); // Dummy code to avoid compiler's warning: static function ccm_param_hightype is not used Ccm_Hitype_t hightype = CCM_HITYPE_NONE; if (hightype != CCM_HITYPE_NONE) hightype = ccm_param_hightype (msg->msg_type, i + 1); return NULL; } } /* * Must make sure to pass _ALL_ params; may pass more because * the format won't access the 'extra' parameters if all the * rules for messages have been followed. */ mbuf = dbe_sprintf (ccm_attrs[vindex].msg, parms[0], parms[1], parms[2], parms[3], parms[4], parms[5], parms[6], parms[7], parms[8], parms[9], parms[10], parms[11]); // Cleanup allocated memory. for (int i = 0; i < msg->nparam; i++) { prim_ty = ccm_param_primtype (msg->msg_type, i + 1); if (prim_ty == CCM_PRIMTYPE_STRING || prim_ty == CCM_PRIMTYPE_HEXSTRING) free (parms[i]); } } else { /* * Parameter list messages never have 0 parameters; the * primitive type for the parameter list elements is always * the same. And as of 22-Sep-2006, it was always * CCM_PRIMTYPE_STRING. * * Account for different bases of parameter indices and * 'nparam' count (1 and 0, respectively). */ char *parms[3]; if (plist_idx > (int) ((sizeof (parms) / sizeof (char*)))) { fprintf (stderr, GTXT ("Warning: improperly formatted compiler commentary message (msg->nparam=%d plist_idx=%d);\n please report this bug against the compiler\n"), msg->nparam, plist_idx); return NULL; } for (size_t i = 0; i < (sizeof (parms) / sizeof (char*)); i++) parms[i] = NULL; // initialize array StringBuilder sb; prim_ty = ccm_param_primtype (msg->msg_type, plist_idx); for (int i = plist_idx - 1; i < msg->nparam; i++) { if (i != plist_idx - 1) sb.append (GTXT (", ")); if (prim_ty == CCM_PRIMTYPE_INTEGER) sb.append (elf->decode (ind[i])); else if (prim_ty == CCM_PRIMTYPE_STRING) { char *fname = strs + elf->decode (ind[i]); char *demName = get_demangle_name (fname); if (demName) { sb.append (demName); delete demName; } else sb.append (fname); } else if (prim_ty == CCM_PRIMTYPE_HEXSTRING) sb.appendf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"), (unsigned long long) msg->instaddr); } parms[plist_idx - 1] = sb.toString (); for (int i = 0; i < plist_idx - 1; i++) { prim_ty = ccm_param_primtype (msg->msg_type, i + 1); if (prim_ty == CCM_PRIMTYPE_INTEGER) { unsigned long v = elf->decode (ind[i]); parms[i] = (char*) v; } else if (prim_ty == CCM_PRIMTYPE_STRING) { char *fname = strs + elf->decode (ind[i]); char *demName = get_demangle_name (fname); parms[i] = demName ? demName : dbe_strdup (fname); } else if (prim_ty == CCM_PRIMTYPE_HEXSTRING) parms[i] = dbe_sprintf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"), (unsigned long long) msg->instaddr); else { fprintf (stderr, GTXT ("Warning, improperly formatted compiler commentary message (unexpected primitive type %d);\n please report this bug against the compiler\n"), prim_ty); return NULL; } } /* * We have reduced the parameter list to a single string (as * the printf format specifier requires), so only have * 'plist_idx' parameters. */ mbuf = dbe_sprintf (ccm_attrs[vindex].msg, parms[0], parms[1], parms[2]); // Cleanup allocated memory. free (parms[plist_idx - 1]); for (int i = 0; i < plist_idx - 1; i++) { prim_ty = ccm_param_primtype (msg->msg_type, i + 1); if (prim_ty == CCM_PRIMTYPE_STRING || prim_ty == CCM_PRIMTYPE_STRING) free (parms[i]); } } return mbuf; }