summaryrefslogtreecommitdiff
path: root/pttc/src/yasm.c
diff options
context:
space:
mode:
Diffstat (limited to 'pttc/src/yasm.c')
-rw-r--r--pttc/src/yasm.c902
1 files changed, 902 insertions, 0 deletions
diff --git a/pttc/src/yasm.c b/pttc/src/yasm.c
new file mode 100644
index 0000000000000..844a15528bc3b
--- /dev/null
+++ b/pttc/src/yasm.c
@@ -0,0 +1,902 @@
+/*
+ * Copyright (c) 2013-2019, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "errcode.h"
+#include "file.h"
+#include "util.h"
+#include "yasm.h"
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+# define snprintf _snprintf_c
+#endif
+
+
+static int create_section_label_name(char *label, size_t size,
+ const char *name, const char *attribute)
+{
+ int written;
+
+ written = snprintf(label, size, "section_%s_%s", name, attribute);
+ if ((written < 0) || (size <= (size_t) written))
+ return -err_no_mem;
+
+ return 0;
+}
+
+static int add_section_label(struct label *l, const char *name,
+ const char *attribute, uint64_t value,
+ struct label **length)
+{
+ char label[255];
+ int errcode;
+
+ errcode = create_section_label_name(label, sizeof(label), name,
+ attribute);
+ if (errcode < 0)
+ return errcode;
+
+ errcode = l_append(l, label, value);
+ if (errcode < 0)
+ return errcode;
+
+ if (length)
+ *length = l_find(l, label);
+
+ return 0;
+}
+
+static int parse_section_label(struct label *l, const char *name,
+ const char *attribute)
+{
+ uint64_t addr;
+ char *value;
+
+ value = strtok(NULL, " ]");
+ if (!value)
+ return -err_section_attribute_no_value;
+
+ if (sscanf(value, "%" PRIx64, &addr) != 1)
+ return -err_parse_int;
+
+ return add_section_label(l, name, attribute, addr, NULL);
+}
+
+static int parse_section(char *line, struct label *l, struct label **length)
+{
+ char *name, *attribute;
+ int errcode;
+
+ name = strtok(line, " ");
+ if (!name)
+ return -err_section_no_name;
+
+ /* we initialize the section's length to zero - it will be updated
+ * when we process the section's content.
+ */
+ errcode = add_section_label(l, name, "length", 0ull, length);
+ if (errcode < 0)
+ return errcode;
+
+ for (;;) {
+ attribute = strtok(NULL, " =]");
+ if (!attribute)
+ return 0;
+
+ if (strcmp(attribute, "start") == 0) {
+ errcode = parse_section_label(l, name, "start");
+ if (errcode < 0)
+ return errcode;
+ } else if (strcmp(attribute, "vstart") == 0) {
+ errcode = parse_section_label(l, name, "vstart");
+ if (errcode < 0)
+ return errcode;
+ } else
+ return -err_section_unknown_attribute;
+ }
+}
+
+static int lookup_section_label(struct label *l, const char *name,
+ const char *attribute, uint64_t *value)
+{
+ char label[255];
+ int errcode;
+
+ errcode = create_section_label_name(label, sizeof(label), name,
+ attribute);
+ if (errcode < 0)
+ return errcode;
+
+ return l_lookup(l, value, label);
+}
+
+static int lookup_section_vstart(struct label *l, char *line,
+ uint64_t *vstart)
+{
+ char *name;
+
+ name = strtok(line, " ");
+ if (!name)
+ return -err_section_no_name;
+
+ return lookup_section_label(l, name, "vstart", vstart);
+}
+
+static const char key_section[] = "[section";
+static const char key_org[] = "[org";
+
+int parse_yasm_labels(struct label *l, const struct text *t)
+{
+ int errcode, no_org_directive;
+ size_t i;
+ uint64_t base_addr;
+ char line[1024], *end;
+ struct label *length;
+
+ if (bug_on(!t))
+ return -err_internal;
+
+ base_addr = 0;
+ no_org_directive = 1;
+ length = NULL;
+ end = line + sizeof(line);
+
+ /* determine base address from org directive and insert special
+ * section labels.
+ */
+ for (i = 0; i < t->n; i++) {
+ char *tmp;
+
+ errcode = text_line(t, line, sizeof(line), i);
+ if (errcode < 0)
+ return errcode;
+
+ tmp = strstr(line, key_section);
+ if (tmp) {
+ tmp += sizeof(key_section) - 1;
+ errcode = parse_section(tmp, l, &length);
+ if (errcode < 0)
+ return errcode;
+ continue;
+ }
+
+ tmp = strstr(line, key_org);
+ if (tmp) {
+ char *org;
+
+ org = tmp + sizeof(key_org) - 1;
+ tmp = strstr(org, "]");
+ if (!tmp)
+ return -err_no_org_directive;
+
+ *tmp = 0;
+
+ errcode = str_to_uint64(org, &base_addr, 0);
+ if (errcode < 0)
+ return errcode;
+
+ errcode = l_append(l, "org", base_addr);
+ if (errcode < 0)
+ return errcode;
+
+ no_org_directive = 0;
+ continue;
+ }
+
+ /* update the section_<name>_length label, if we have one.
+ *
+ * this must be last; it destroys @line.
+ */
+ if (length) {
+ uint64_t value, size;
+
+ tmp = strtok(line, " ");
+ if (!tmp)
+ continue;
+
+ /* we expect a line number. */
+ errcode = str_to_uint64(tmp, &value, 10);
+ if (errcode < 0)
+ continue;
+
+ tmp = strtok(NULL, " ");
+ if (!tmp)
+ continue;
+
+ /* we expect an address. */
+ errcode = str_to_uint64(tmp, &value, 16);
+ if (errcode < 0)
+ continue;
+
+ tmp = strtok(NULL, " ");
+ if (!tmp)
+ continue;
+
+ /* we expect an opcode. */
+ errcode = str_to_uint64(tmp, &value, 16);
+ if (errcode < 0)
+ continue;
+
+ /* we got an opcode - let's compute it's size. */
+ for (size = 0; value != 0; value >>= 8)
+ size += 1;
+
+ /* update the section_<name>_length label. */
+ length->addr += size;
+ }
+ }
+
+ if (no_org_directive)
+ return -err_no_org_directive;
+
+ for (i = 0; i < t->n; i++) {
+ char *tmp;
+ uint64_t addr;
+
+ errcode = text_line(t, line, sizeof(line), i);
+ if (errcode < 0)
+ goto error;
+
+ /* Change the base on section switches. */
+ tmp = strstr(line, key_section);
+ if (tmp) {
+ tmp += sizeof(key_section) - 1;
+ errcode = lookup_section_vstart(l, tmp, &base_addr);
+ if (errcode < 0)
+ return errcode;
+ continue;
+ }
+
+ /* skip line number count. */
+ tmp = strtok(line, " ");
+ if (!tmp)
+ continue;
+
+ /* the label can now be on the same line as the memory
+ * address or on a line by its own.
+ * we look at the next token and (1) if it looks like a
+ * label, we search in the following lines for the
+ * corresponding address; or (2) if it looks like an
+ * address, we store it and see if the token after the
+ * opcode looks like a token; or (3) none of the above,
+ * we continue with the next line.
+ */
+
+ /* second token after the line number count. it's
+ * either an address; or a label.
+ */
+ tmp = strtok(NULL, " ");
+ if (!tmp)
+ continue;
+
+ if (!make_label(tmp, end)) {
+ uint64_t laddr;
+
+ /* get address in case we find a label later. */
+ if (sscanf(tmp, "%" PRIx64, &addr) != 1)
+ continue;
+
+ /* skip the opcode token. */
+ tmp = strtok(NULL, " ");
+ if (!tmp)
+ continue;
+
+ /* this might be a label now. */
+ tmp = strtok(NULL, " ");
+ if (!make_label(tmp, end))
+ continue;
+
+ laddr = addr + base_addr;
+ if (laddr < base_addr) {
+ errcode = -err_label_addr;
+ goto error;
+ }
+
+ errcode = l_append(l, tmp, laddr);
+ if (errcode < 0)
+ goto error;
+ continue;
+ }
+
+ /* there was a label so now an address needs to
+ * be found.
+ */
+ errcode = -err_label_addr;
+ for (i += 1; i < t->n; i++) {
+ int errcode_text;
+
+ errcode_text = text_line(t, line, sizeof(line), i);
+ if (errcode_text < 0) {
+ errcode = errcode_text;
+ break;
+ }
+ if (sscanf(line, "%*d %" PRIx64 " %*x %*s", &addr)
+ == 1) {
+ uint64_t laddr;
+
+ laddr = addr + base_addr;
+ if (laddr < base_addr) {
+ errcode = -err_label_addr;
+ break;
+ }
+
+ errcode = l_append(l, tmp, laddr);
+ break;
+ }
+ }
+ if (errcode == -err_label_addr)
+ fprintf(stderr, "label '%s' has no address\n", tmp);
+
+ if (errcode < 0)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ l_free(l->next);
+ free(l->name);
+ l->next = NULL;
+ l->name = NULL;
+ return errcode;
+}
+
+int make_label(char *s, const char *end)
+{
+ size_t n, size;
+
+ if (bug_on(!s))
+ return 0;
+
+ if (bug_on(end <= s))
+ return 0;
+
+ size = (size_t) ((uintptr_t) end - (uintptr_t) s);
+ n = strnlen(s, size);
+ if (size <= n)
+ return 0;
+
+ if (n == 0 || s[n-1] != ':')
+ return 0;
+
+ s[n-1] = '\0';
+ return 1;
+}
+
+struct state *st_alloc(void)
+{
+ return calloc(1, sizeof(struct state));
+}
+
+void st_free(struct state *st)
+{
+ if (!st)
+ return;
+
+ free(st->filename);
+ free(st->line);
+ free(st);
+}
+
+int st_print_err(const struct state *st, const char *s, int errcode)
+{
+ if (bug_on(!st))
+ return -err_internal;
+
+ if (bug_on(!(-err_max < errcode && errcode < 0)))
+ return -err_internal;
+
+ if (!s)
+ s = "";
+
+ fprintf(stderr, "%s:%d: error: %s (%s)\n", st->filename, st->n-1, s,
+ errstr[-errcode]);
+
+ return errcode;
+}
+
+/* Sets current @filename, increment (@inc) and line number (@n) in @st.
+ *
+ * Note that @filename, @inc and @n correspond to the yasm .lst file
+ * source file information.
+ *
+ * Returns 0 on success; a negative enum errcode otherwise.
+ */
+static int st_set_file(struct state *st, const char *filename, int inc, int n)
+{
+ int errcode;
+
+ if (bug_on(!st))
+ return -err_internal;
+
+ if (bug_on(!filename))
+ return -err_internal;
+
+ free(st->filename);
+ errcode = duplicate_name(&st->filename, filename, FILENAME_MAX);
+ if (errcode < 0)
+ return errcode;
+
+ st->inc = inc;
+ st->n = n;
+ return 0;
+}
+
+/* Sets current line in @st to @s and increases the line number.
+ *
+ * Returns 0 on success; a negative enum errcode otherwise.
+ */
+static int st_update(struct state *st, const char *s)
+{
+ int errcode;
+
+ free(st->line);
+ st->line = NULL;
+
+ errcode = duplicate_name(&st->line, s, FILENAME_MAX);
+ if (errcode < 0)
+ return errcode;
+
+ st->n += st->inc;
+ return 0;
+}
+
+struct pt_directive *pd_alloc(size_t n)
+{
+ struct pt_directive *pd;
+
+ pd = calloc(1, sizeof(*pd));
+ if (!pd)
+ return NULL;
+
+ pd->name = malloc(n);
+ if (!pd->name)
+ goto error;
+
+ pd->payload = malloc(n);
+ if (!pd->payload)
+ goto error;
+
+ pd->nlen = n;
+ pd->plen = n;
+
+ return pd;
+
+error:
+ pd_free(pd);
+ return NULL;
+}
+
+void pd_free(struct pt_directive *pd)
+{
+ if (!pd)
+ return;
+
+ free(pd->name);
+ free(pd->payload);
+ free(pd);
+}
+
+int pd_set(struct pt_directive *pd, enum pt_directive_kind kind,
+ const char *name, const char *payload)
+{
+ if (bug_on(!pd))
+ return -err_internal;
+
+ if (bug_on(!name))
+ return -err_internal;
+
+ if (bug_on(!payload))
+ return -err_internal;
+
+ pd->kind = kind;
+ strncpy(pd->name, name, pd->nlen);
+ if (pd->nlen > 0)
+ pd->name[pd->nlen - 1] = '\0';
+ strncpy(pd->payload, payload, pd->plen);
+ if (pd->plen > 0)
+ pd->payload[pd->plen - 1] = '\0';
+
+ return 0;
+}
+
+/* Magic annotation markers. */
+static const char pt_marker[] = "@pt ";
+
+#if defined(FEATURE_SIDEBAND)
+static const char sb_marker[] = "@sb ";
+#endif
+
+int pd_parse(struct pt_directive *pd, struct state *st)
+{
+ enum pt_directive_kind kind;
+ char *line, *comment, *openpar, *closepar, *directive, *payload;
+ int errcode;
+ char *c;
+
+ if (bug_on(!pd))
+ return -err_internal;
+
+ if (bug_on(!st))
+ return -err_internal;
+
+
+ errcode = duplicate_name(&line, st->line, FILENAME_MAX);
+ if (errcode < 0)
+ return errcode;
+
+ /* make line lower case. */
+ for (c = line; *c; ++c)
+ *c = (char) tolower(*c);
+
+ /* if the current line is not a comment or contains no magic marker
+ * -err_no_directive is returned.
+ */
+ errcode = -err_no_directive;
+
+ /* search where the comment begins. */
+ comment = strchr(line, ';');
+
+ /* if there is no comment in the line, we don't have anything to
+ * do.
+ */
+ if (!comment)
+ goto cleanup;
+
+ /* search for @pt marker. */
+ directive = strstr(comment+1, pt_marker);
+ if (directive) {
+ directive += sizeof(pt_marker) - 1;
+ kind = pdk_pt;
+ } else {
+#if defined(FEATURE_SIDEBAND)
+ /* search for @sb marker. */
+ directive = strstr(comment+1, sb_marker);
+ if (directive) {
+ directive += sizeof(sb_marker) - 1;
+ kind = pdk_sb;
+ } else
+#endif
+ goto cleanup;
+ }
+
+ /* skip leading whitespace. */
+ while (isspace(*directive))
+ directive += 1;
+
+ /* directive found, now parse the payload. */
+ errcode = 0;
+
+ /* find position of next '(', separating the directive and the
+ * payload.
+ */
+ openpar = strchr(directive, '(');
+ if (!openpar) {
+ errcode = -err_missing_openpar;
+ st_print_err(st, "invalid syntax", errcode);
+ goto cleanup;
+ }
+
+ /* find position of next ')', marking the end of the payload */
+ closepar = strchr(openpar, ')');
+ if (!closepar) {
+ errcode = -err_missing_closepar;
+ st_print_err(st, "invalid syntax", errcode);
+ goto cleanup;
+ }
+
+ /* make "multiple" strings by artifically terminating them with
+ * '\0' then get directive and payload substrings, which will
+ * have leading and trailing whitespace "removed".
+ */
+ *openpar = '\0';
+ *closepar = '\0';
+
+ payload = openpar+1;
+
+ errcode = pd_set(pd, kind, directive, payload);
+
+cleanup:
+ free(line);
+ return errcode;
+}
+
+static const char bin_suffix[] = ".bin";
+static const char lst_suffix[] = ".lst";
+static const char path_separator = '/';
+
+struct yasm *yasm_alloc(const char *pttfile)
+{
+ char *tmp;
+ size_t flen, binsize, lstsize;
+ struct yasm *y;
+ int errcode, len;
+
+ if (bug_on(!pttfile))
+ return NULL;
+
+ y = calloc(1, sizeof(*y));
+ if (!y)
+ return NULL;
+
+ y->fl = fl_alloc();
+ if (!y->fl)
+ goto error;
+
+ y->st_asm = st_alloc();
+ if (!y->st_asm)
+ goto error;
+
+ errcode = duplicate_name(&y->fileroot, pttfile, FILENAME_MAX);
+ if (errcode < 0)
+ goto error;
+
+ errcode = duplicate_name(&y->pttfile, pttfile, FILENAME_MAX);
+ if (errcode < 0)
+ goto error;
+
+ tmp = strrchr(y->fileroot, '.');
+ if (tmp)
+ *tmp = '\0';
+
+ tmp = strrchr(y->fileroot, path_separator);
+ if (tmp) {
+ tmp += 1;
+
+ flen = strnlen(tmp, FILENAME_MAX);
+ if (FILENAME_MAX <= flen)
+ goto error;
+
+ memmove(y->fileroot, tmp, flen);
+ y->fileroot[flen] = '\0';
+ }
+
+ flen = strnlen(y->fileroot, FILENAME_MAX);
+ if (FILENAME_MAX <= flen)
+ goto error;
+
+ binsize = flen + sizeof(bin_suffix);
+ lstsize = flen + sizeof(lst_suffix);
+
+ y->binfile = malloc(binsize);
+ if (!y->binfile)
+ goto error;
+
+ len = snprintf(y->binfile, binsize, "%s%s", y->fileroot, bin_suffix);
+ if ((len < 0) || ((size_t) len != (binsize - 1)))
+ goto error;
+
+ y->lstfile = malloc(lstsize);
+ if (!y->lstfile)
+ goto error;
+
+ len = snprintf(y->lstfile, lstsize, "%s%s", y->fileroot, lst_suffix);
+ if ((len < 0) || ((size_t) len != (lstsize - 1)))
+ goto error;
+
+ y->l = l_alloc();
+ if (!y->l)
+ goto error;
+
+ return y;
+
+error:
+ yasm_free(y);
+ return 0;
+}
+
+static int yasm_run(struct yasm *y)
+{
+ char *argv[] = {
+ "yasm",
+ "<pttfile>",
+ "-f", "bin",
+ "-o", "<binfile>",
+ "-L", "nasm",
+ "-l", "<lstfile>",
+ NULL,
+ };
+
+ argv[1] = y->pttfile;
+ argv[5] = y->binfile;
+ argv[9] = y->lstfile;
+
+ return run(argv[0], argv);
+}
+
+int yasm_parse(struct yasm *y)
+{
+ int errcode;
+ const struct text *t;
+
+ if (bug_on(!y))
+ return -err_internal;
+
+ errcode = yasm_run(y);
+ if (errcode < 0)
+ goto error;
+
+ errcode = fl_gettext(y->fl, &t, y->lstfile);
+ if (errcode < 0)
+ goto error;
+
+ errcode = parse_yasm_labels(y->l, t);
+ if (errcode < 0)
+ goto error;
+
+error:
+ return errcode;
+}
+
+void yasm_free(struct yasm *y)
+{
+ if (!y)
+ return;
+
+ free(y->fileroot);
+ free(y->pttfile);
+ free(y->lstfile);
+ free(y->binfile);
+ fl_free(y->fl);
+ st_free(y->st_asm);
+ l_free(y->l);
+ free(y);
+}
+
+int yasm_lookup_label(const struct yasm *y, uint64_t *addr,
+ const char *labelname)
+{
+ if (bug_on(!y))
+ return -err_internal;
+
+
+ return l_lookup(y->l, addr, labelname);
+}
+
+static int yasm_advance_next_line(struct yasm *y)
+{
+ char s[1024];
+ char filename[FILENAME_MAX];
+ int errcode;
+ int asm_line, asm_inc;
+
+ if (bug_on(!y))
+ return -err_internal;
+
+
+ for (;;) {
+ errcode = fl_getline(y->fl, s, sizeof(s), y->lstfile,
+ (size_t) y->lst_curr_line);
+ /* always advance in lst file. */
+ y->lst_curr_line += 1;
+
+ if (errcode < 0)
+ break;
+
+ /* if the current lst file line is a line directive, set
+ * state information to this file, line and increment
+ * and continue.
+ */
+ if (sscanf(s, "%*d %%line %d+%d %1023[^\r\n]", &asm_line,
+ &asm_inc, filename) == 3) {
+ st_set_file(y->st_asm, filename, asm_line, asm_inc);
+ continue;
+ }
+
+ /* if line number or increment in the previous line
+ * directive is <= 0, the current lst line has no
+ * corresponding line in the source file.
+ */
+ if (y->st_asm->n <= 0 || y->st_asm->inc <= 0)
+ continue;
+
+ /* finally the current line in the lst file can be
+ * correlated to the source file, so we retrieve the
+ * line from it and update the state.
+ */
+ errcode = fl_getline(y->fl, s, (size_t) sizeof(s),
+ y->st_asm->filename,
+ (size_t) y->st_asm->n - 1u);
+ if (errcode < 0)
+ break;
+
+ errcode = st_update(y->st_asm, s);
+ break;
+ }
+
+ return errcode;
+}
+
+int yasm_pd_parse(struct yasm *y, struct pt_directive *pd)
+{
+ return pd_parse(pd, y->st_asm);
+}
+
+int yasm_next_pt_directive(struct yasm *y, struct pt_directive *pd)
+{
+ int errcode;
+
+ for (;;) {
+ errcode = yasm_advance_next_line(y);
+ if (errcode < 0)
+ break;
+
+ errcode = pd_parse(pd, y->st_asm);
+ if (errcode != -err_no_directive)
+ return errcode;
+
+ }
+ if (errcode == -err_out_of_range)
+ errcode = -err_no_directive;
+
+ return errcode;
+}
+
+int yasm_next_line(struct yasm *y, char *dest, size_t destlen)
+{
+ int errcode;
+
+ if (!destlen)
+ return 0;
+
+ if (bug_on(!dest))
+ return -err_internal;
+
+ errcode = yasm_advance_next_line(y);
+ if (errcode < 0)
+ return errcode;
+
+ strncpy(dest, y->st_asm->line, destlen);
+ dest[destlen-1] = '\0';
+
+ return 0;
+}
+
+int yasm_print_err(const struct yasm *y, const char *s, int errcode)
+{
+ if (bug_on(!y))
+ return -err_internal;
+
+
+ return st_print_err(y->st_asm, s, errcode);
+}
+
+int yasm_lookup_section_label(const struct yasm *y, const char *name,
+ const char *attribute, uint64_t *value)
+{
+ if (bug_on(!y))
+ return -err_internal;
+
+ return lookup_section_label(y->l, name, attribute, value);
+}