|  | /* Copyright (C) 2021-2025 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 <assert.h> | 
|  | #include <string.h> | 
|  | #include <ctype.h> | 
|  |  | 
|  | #include "util.h" | 
|  | #include "DbeSession.h" | 
|  | #include "Application.h" | 
|  | #include "DataObject.h" | 
|  | #include "Module.h" | 
|  | #include "debug.h" | 
|  |  | 
|  | DataObject::DataObject () | 
|  | { | 
|  | name = NULL; | 
|  | parent = NULL; | 
|  | master = NULL; | 
|  | _unannotated_name = NULL; | 
|  | _typename = NULL; | 
|  | _instname = NULL; | 
|  | scope = NULL; | 
|  | EAs = new Vector<DbeEA*>; | 
|  | size = 0; | 
|  | offset = (uint64_t) (-1); | 
|  | } | 
|  |  | 
|  | DataObject::~DataObject () | 
|  | { | 
|  | free (_unannotated_name); | 
|  | free (_typename); | 
|  | free (_instname); | 
|  | EAs->destroy (); | 
|  | delete EAs; | 
|  | } | 
|  |  | 
|  | // get_addr() doesn't return an actual address for a DataObject | 
|  | // but rather synthesises an address-like identifier tuple. | 
|  | // XXXX since an aggregate and its first element have identical tuples | 
|  | // may need to arrange for special-purpose sorting "by address" | 
|  | uint64_t | 
|  | DataObject::get_addr () | 
|  | { | 
|  | uint64_t addr; | 
|  | if (parent && parent->get_typename ()) | 
|  | addr = MAKE_ADDRESS (parent->id, offset);   // element | 
|  | else if (parent) | 
|  | addr = MAKE_ADDRESS (parent->id, id) | 0x8000000000000000ULL; // Scalar, Unknown | 
|  | else if (id == dbeSession->get_Scalars_DataObject ()->id) | 
|  | addr = MAKE_ADDRESS (id, 0) | 0x8000000000000000ULL;    // Scalar aggregate | 
|  | else if (id == dbeSession->get_Unknown_DataObject ()->id) | 
|  | addr = MAKE_ADDRESS (id, 0) | 0x8000000000000000ULL;    // Unknown aggregate | 
|  | else | 
|  | addr = MAKE_ADDRESS (id, 0);     // aggregate | 
|  | return addr; | 
|  | } | 
|  |  | 
|  | Histable * | 
|  | DataObject::convertto (Histable_type type, Histable *) | 
|  | { | 
|  | return type == DOBJECT ? this : NULL; | 
|  | } | 
|  |  | 
|  | char | 
|  | DataObject::get_offset_mark () | 
|  | { | 
|  | enum | 
|  | { | 
|  | blocksize = 32 | 
|  | }; | 
|  |  | 
|  | if (size == 0 || offset == -1) | 
|  | return '?';     // undefined | 
|  | if (size > blocksize) | 
|  | return '#';     // requires multiple blocks | 
|  | if (size == blocksize && (offset % blocksize == 0)) | 
|  | return '<';     // fits block entirely | 
|  | if (offset % blocksize == 0) | 
|  | return '/';     // starts block | 
|  | if ((offset + size) % blocksize == 0) | 
|  | return '\\';    // closes block | 
|  | if (offset / blocksize == ((offset + size) / blocksize)) | 
|  | return '|';     // inside block | 
|  | return 'X';       // crosses blocks unnecessarily | 
|  | } | 
|  |  | 
|  | char * | 
|  | DataObject::get_offset_name () | 
|  | { | 
|  | char *offset_name; | 
|  | if (parent && parent->get_typename ()) // element | 
|  | offset_name = dbe_sprintf (GTXT ("%c%+6lld .{%s %s}"), | 
|  | get_offset_mark (), (long long) offset, | 
|  | _typename ? _typename : GTXT ("NO_TYPE"), | 
|  | _instname ? _instname : GTXT ("-")); // "NO_NAME" | 
|  | else if ((offset != -1) && (offset > 0)) // filler | 
|  | offset_name = dbe_sprintf (GTXT ("%c%+6lld %s"), get_offset_mark (), | 
|  | (long long) offset, get_name ()); | 
|  | else if (parent) // Scalar/Unknown element | 
|  | offset_name = dbe_sprintf (GTXT ("        .%s"), get_unannotated_name ()); | 
|  | else // aggregate | 
|  | offset_name = dbe_strdup (get_name ()); | 
|  | return offset_name; | 
|  | } | 
|  |  | 
|  | void | 
|  | DataObject::set_dobjname (char *type_name, char *inst_name) | 
|  | { | 
|  | _unannotated_name = _typename = _instname = NULL; | 
|  | if (inst_name) | 
|  | _instname = dbe_strdup (inst_name); | 
|  |  | 
|  | char *buf; | 
|  | if (parent == dbeSession->get_Scalars_DataObject ()) | 
|  | { | 
|  | if (type_name) | 
|  | _typename = dbe_strdup (type_name); | 
|  | _unannotated_name = dbe_sprintf (NTXT ("{%s %s}"), type_name, | 
|  | inst_name ? inst_name : NTXT ("-")); | 
|  | buf = dbe_sprintf (NTXT ("%s.%s"), parent->get_name (), _unannotated_name); | 
|  | } | 
|  | else if (parent == dbeSession->get_Unknown_DataObject ()) | 
|  | { | 
|  | _unannotated_name = dbe_strdup (type_name); | 
|  | buf = dbe_sprintf (NTXT ("%s.%s"), parent->get_name (), _unannotated_name); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (type_name) | 
|  | _typename = dbe_strdup (type_name); | 
|  | if (parent && parent->get_typename ()) | 
|  | buf = dbe_sprintf (NTXT ("%s.{%s %s}"), | 
|  | parent->get_name () ? parent->get_name () : NTXT ("ORPHAN"), | 
|  | type_name ? type_name : NTXT ("NO_TYPE"), | 
|  | inst_name ? inst_name : NTXT ("-")); // "NO_NAME" | 
|  | else | 
|  | buf = dbe_sprintf (NTXT ("{%s %s}"), | 
|  | type_name ? type_name : NTXT ("NO_TYPE"), | 
|  | inst_name ? inst_name : NTXT ("-")); // "NO_NAME" | 
|  | } | 
|  | name = buf; | 
|  | dbeSession->dobj_updateHT (this); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataObject::set_name (char *string) | 
|  | { | 
|  | name = dbe_strdup (string); | 
|  | dbeSession->dobj_updateHT (this); | 
|  | } | 
|  |  | 
|  | DbeEA * | 
|  | DataObject::find_dbeEA (Vaddr EA) | 
|  | { | 
|  | DbeEA *dbeEA; | 
|  | int left = 0; | 
|  | int right = EAs->size () - 1; | 
|  | while (left <= right) | 
|  | { | 
|  | int index = (left + right) / 2; | 
|  | dbeEA = EAs->fetch (index); | 
|  | if (EA < dbeEA->eaddr) | 
|  | right = index - 1; | 
|  | else if (EA > dbeEA->eaddr) | 
|  | left = index + 1; | 
|  | else | 
|  | return dbeEA; | 
|  | } | 
|  |  | 
|  | // None found, create a new one | 
|  | dbeEA = new DbeEA (this, EA); | 
|  | EAs->insert (left, dbeEA); | 
|  | return dbeEA; | 
|  | } |