diff --git a/include/ChangeLog b/include/ChangeLog index 56922add8a..3ea7ac8660 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,12 @@ +2019-05-28 Nick Alcock + + * ctf-api.h (ctf_label_f): New. + (ctf_label_set): New. + (ctf_label_get): New. + (ctf_label_topmost): New. + (ctf_label_info): New. + (ctf_label_iter): New. + 2019-05-28 Nick Alcock * ctf-api.h (ctf_version): New. diff --git a/include/ctf-api.h b/include/ctf-api.h index 6ab754a184..c5ae38e6a4 100644 --- a/include/ctf-api.h +++ b/include/ctf-api.h @@ -213,6 +213,8 @@ typedef int ctf_member_f (const char *name, ctf_id_t membtype, typedef int ctf_enum_f (const char *name, int val, void *arg); typedef int ctf_variable_f (const char *name, ctf_id_t type, void *arg); typedef int ctf_type_f (ctf_id_t type, void *arg); +typedef int ctf_label_f (const char *name, const ctf_lblinfo_t *info, + void *arg); typedef int ctf_archive_member_f (ctf_file_t *fp, const char *name, void *arg); typedef int ctf_archive_raw_member_f (const char *name, const void *content, size_t len, void *arg); @@ -299,9 +301,16 @@ extern int ctf_array_info (ctf_file_t *, ctf_id_t, ctf_arinfo_t *); extern const char *ctf_enum_name (ctf_file_t *, ctf_id_t, int); extern int ctf_enum_value (ctf_file_t *, ctf_id_t, const char *, int *); +extern void ctf_label_set (ctf_file_t *, const char *); +extern const char *ctf_label_get (ctf_file_t *); + +extern const char *ctf_label_topmost (ctf_file_t *); +extern int ctf_label_info (ctf_file_t *, const char *, ctf_lblinfo_t *); + extern int ctf_member_iter (ctf_file_t *, ctf_id_t, ctf_member_f *, void *); extern int ctf_enum_iter (ctf_file_t *, ctf_id_t, ctf_enum_f *, void *); extern int ctf_type_iter (ctf_file_t *, ctf_type_f *, void *); +extern int ctf_label_iter (ctf_file_t *, ctf_label_f *, void *); extern int ctf_variable_iter (ctf_file_t *, ctf_variable_f *, void *); extern int ctf_archive_iter (const ctf_archive_t *, ctf_archive_member_f *, void *); diff --git a/libctf/ChangeLog b/libctf/ChangeLog index a6eb11ee30..e4976c40de 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,3 +1,7 @@ +2019-05-28 Nick Alcock + + * ctf-labels.c: New. + 2019-05-28 Nick Alcock * ctf-impl.h (_libctf_version): New declaration. diff --git a/libctf/ctf-labels.c b/libctf/ctf-labels.c new file mode 100644 index 0000000000..9b9fffea4e --- /dev/null +++ b/libctf/ctf-labels.c @@ -0,0 +1,138 @@ +/* Labelled ranges of type IDs. + Copyright (C) 2019 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 + . */ + +#include +#include + +static int +extract_label_info (ctf_file_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_file_t *fp) +{ + const ctf_lblent_t *ctlp = NULL; + const char *s; + uint32_t num_labels = 0; + + if (extract_label_info (fp, &ctlp, &num_labels) == CTF_ERR) + 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_file_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) == CTF_ERR) + return CTF_ERR; /* 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) + { + ctf_dprintf ("failed to decode label %u with " + "type %u\n", 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_file_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)) == CTF_ERR) + return rc; + + if (rc != 1) + return (ctf_set_errno (fp, ECTF_NOLABEL)); + + return 0; +}