| /* Labelled ranges of type IDs. | 
 |    Copyright (C) 2019-2024 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of libctf. | 
 |  | 
 |    libctf 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; see the file COPYING.  If not see | 
 |    <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include <ctf-impl.h> | 
 | #include <string.h> | 
 |  | 
 | static int | 
 | extract_label_info (ctf_dict_t *fp, const ctf_lblent_t **ctl, | 
 | 		    uint32_t *num_labels) | 
 | { | 
 |   const ctf_header_t *h; | 
 |  | 
 |   h = (const ctf_header_t *) fp->ctf_data.cts_data; | 
 |  | 
 |   *ctl = (const ctf_lblent_t *) (fp->ctf_buf + h->cth_lbloff); | 
 |   *num_labels = (h->cth_objtoff - h->cth_lbloff) / sizeof (ctf_lblent_t); | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Returns the topmost label, or NULL if any errors are encountered.  */ | 
 |  | 
 | const char * | 
 | ctf_label_topmost (ctf_dict_t *fp) | 
 | { | 
 |   const ctf_lblent_t *ctlp = NULL; | 
 |   const char *s; | 
 |   uint32_t num_labels = 0; | 
 |  | 
 |   if (extract_label_info (fp, &ctlp, &num_labels) < 0) | 
 |     return NULL;				/* errno is set for us.  */ | 
 |  | 
 |   if (num_labels == 0) | 
 |     { | 
 |       (void) ctf_set_errno (fp, ECTF_NOLABELDATA); | 
 |       return NULL; | 
 |     } | 
 |  | 
 |   if ((s = ctf_strraw (fp, (ctlp + num_labels - 1)->ctl_label)) == NULL) | 
 |     (void) ctf_set_errno (fp, ECTF_CORRUPT); | 
 |  | 
 |   return s; | 
 | } | 
 |  | 
 | /* Iterate over all labels.  We pass the label string and the lblinfo_t struct | 
 |    to the specified callback function.  */ | 
 | int | 
 | ctf_label_iter (ctf_dict_t *fp, ctf_label_f *func, void *arg) | 
 | { | 
 |   const ctf_lblent_t *ctlp = NULL; | 
 |   uint32_t i; | 
 |   uint32_t num_labels = 0; | 
 |   ctf_lblinfo_t linfo; | 
 |   const char *lname; | 
 |   int rc; | 
 |  | 
 |   if (extract_label_info (fp, &ctlp, &num_labels) < 0) | 
 |     return -1;			/* errno is set for us.  */ | 
 |  | 
 |   if (num_labels == 0) | 
 |     return (ctf_set_errno (fp, ECTF_NOLABELDATA)); | 
 |  | 
 |   for (i = 0; i < num_labels; i++, ctlp++) | 
 |     { | 
 |       if ((lname = ctf_strraw (fp, ctlp->ctl_label)) == NULL) | 
 | 	{ | 
 | 	  /* Not marked for translation: label code not used yet.  */ | 
 | 	  ctf_err_warn (fp, 0, ECTF_CORRUPT, | 
 | 			"failed to decode label %u with type %u", | 
 | 			ctlp->ctl_label, ctlp->ctl_type); | 
 | 	  return (ctf_set_errno (fp, ECTF_CORRUPT)); | 
 | 	} | 
 |  | 
 |       linfo.ctb_type = ctlp->ctl_type; | 
 |       if ((rc = func (lname, &linfo, arg)) != 0) | 
 | 	return rc; | 
 |     } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | typedef struct linfo_cb_arg | 
 | { | 
 |   const char *lca_name;		/* Label we want to retrieve info for.  */ | 
 |   ctf_lblinfo_t *lca_info;	/* Where to store the info about the label.  */ | 
 | } linfo_cb_arg_t; | 
 |  | 
 | static int | 
 | label_info_cb (const char *lname, const ctf_lblinfo_t *linfo, void *arg) | 
 | { | 
 |   /* If lname matches the label we are looking for, copy the | 
 |     lblinfo_t struct for the caller.  */ | 
 |  | 
 |   if (strcmp (lname, ((linfo_cb_arg_t *) arg)->lca_name) == 0) | 
 |     { | 
 |       /* * Allow caller not to allocate storage to test if label exists.  */ | 
 |  | 
 |       if (((linfo_cb_arg_t *) arg)->lca_info != NULL) | 
 | 	memcpy (((linfo_cb_arg_t *) arg)->lca_info, linfo, | 
 | 	       sizeof (ctf_lblinfo_t)); | 
 |       return 1;		/* Indicate we found a match.  */ | 
 |     } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Retrieve information about the label with name "lname". */ | 
 | int | 
 | ctf_label_info (ctf_dict_t *fp, const char *lname, ctf_lblinfo_t *linfo) | 
 | { | 
 |   linfo_cb_arg_t cb_arg; | 
 |   int rc; | 
 |  | 
 |   cb_arg.lca_name = lname; | 
 |   cb_arg.lca_info = linfo; | 
 |  | 
 |   if ((rc = ctf_label_iter (fp, label_info_cb, &cb_arg)) < 0) | 
 |     return rc; | 
 |  | 
 |   if (rc != 1) | 
 |     return (ctf_set_errno (fp, ECTF_NOLABEL)); | 
 |  | 
 |   return 0; | 
 | } |