summaryrefslogtreecommitdiff
path: root/extension_eppic.c
diff options
context:
space:
mode:
Diffstat (limited to 'extension_eppic.c')
-rw-r--r--extension_eppic.c468
1 files changed, 468 insertions, 0 deletions
diff --git a/extension_eppic.c b/extension_eppic.c
new file mode 100644
index 0000000..45bc032
--- /dev/null
+++ b/extension_eppic.c
@@ -0,0 +1,468 @@
+/*
+ * extension_eppic.c
+ *
+ * Created by: Aravinda Prasad <aravinda@linux.vnet.ibm.com>
+ *
+ * Copyright (C) 2012, 2013 IBM Corporation
+ *
+ * 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 2 of the License, 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.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dwarf.h>
+
+#include "makedumpfile.h"
+#include "extension_eppic.h"
+
+static int apigetctype(int, char *, type_t *);
+
+/*
+ * Most of the functions included in this file performs similar
+ * functionality as in the applications/crash/eppic.c file part of
+ * eppic, but uses DWARF instead of gdb. Few of the functions are
+ * reused directly which are acknowledged in the comment before the
+ * function.
+ */
+
+/*
+ * This is the call back function called when a new eppic macro is
+ * loaded. This will execute the loaded eppic macro.
+ *
+ * "fname" is considered as the entry point of an eppic macro only if
+ * the following functions are defined:
+ *
+ * fname_help()
+ * fname_usage()
+ *
+ * These functions have no relevance in makedumpfile context as
+ * makedumpfile automatically executes the eppic macro by calling the
+ * entry point and user will not have any option to execute the usage
+ * or help functions. However they are required to identify the entry
+ * points in the eppic macro.
+ */
+void
+reg_callback(char *name, int load)
+{
+ char fname[MAX_SYMNAMELEN];
+
+ /* Nothing to process for unload request */
+ if (!load)
+ return;
+
+ snprintf(fname, sizeof(fname), "%s_help", name);
+ if (eppic_chkfname(fname, 0)) {
+ snprintf(fname, sizeof(fname), "%s_usage", name);
+ if (eppic_chkfname(fname, 0))
+ eppic_cmd(name, NULL, 0);
+ }
+ return;
+}
+
+/*
+ * This function is a copy of eppic_setupidx() function in
+ * applications/crash/eppic.c file from eppic source code
+ * repository.
+ *
+ * set idx value to actual array indexes from specified size
+ */
+static void
+eppic_setupidx(TYPE_S *t, int ref, int nidx, int *idxlst)
+{
+ /* put the idxlst in index size format */
+ if (nidx) {
+ int i;
+ for (i = 0; i < nidx - 1; i++) {
+ /* kludge for array dimensions of [1] */
+ if (idxlst[i + 1] == 0)
+ idxlst[i + 1] = 1;
+ idxlst[i] = idxlst[i] / idxlst[i + 1];
+ }
+
+ /* divide by element size for last element bound */
+ if (ref)
+ idxlst[i] /= eppic_defbsize();
+ else
+ idxlst[i] /= eppic_type_getsize(t);
+ eppic_type_setidxlst(t, idxlst);
+ }
+}
+
+/*
+ * Call back functions for eppic to query the dump image
+ */
+
+static int
+apigetmem(ull iaddr, void *p, int nbytes)
+{
+ return READMEM(VADDR, iaddr, p, nbytes);
+}
+
+static int
+apiputmem(ull iaddr, void *p, int nbytes)
+{
+ return 1;
+}
+
+/*
+ * Drill down the type of the member and update eppic with information
+ * about the member
+ */
+static char *
+drilldown(ull offset, type_t *t)
+{
+ int type_flag, len = 0, t_len = 0, nidx = 0;
+ int fctflg = 0, ref = 0, *idxlst = 0;
+ ull die_off = offset, t_die_off;
+ char *tstr = NULL, *tstr_dup = NULL;
+
+ while (GET_DIE_ATTR_TYPE(die_off, &type_flag, &t_die_off)) {
+ switch (type_flag) {
+ /* typedef inserts a level of reference to the actual type */
+ case DW_TAG_pointer_type:
+ ref++;
+ die_off = t_die_off;
+ /*
+ * This could be a void *, in which case the drill
+ * down stops here
+ */
+ if (!GET_DIE_ATTR_TYPE(die_off, &type_flag,
+ &t_die_off)) {
+ /* make it a char* */
+ eppic_parsetype("char", t, ref);
+ return eppic_strdup("");
+ }
+ break;
+ /* Handle pointer to function */
+ case DW_TAG_subroutine_type:
+ fctflg = 1;
+ die_off = t_die_off;
+ break;
+ /* Handle arrays */
+ case DW_TAG_array_type:
+ if (!idxlst) {
+ idxlst = eppic_calloc(sizeof(int) * \
+ (MAX_ARRAY_DIMENSION + 1));
+ if (!idxlst) {
+ ERRMSG("Out of memory\n");
+ return NULL;
+ }
+ }
+ if (nidx >= MAX_ARRAY_DIMENSION) {
+ ERRMSG("Too many array indexes. Max=%d\n",
+ MAX_ARRAY_DIMENSION);
+ return NULL;
+ }
+
+ /* handle multi-dimensional array */
+ len = GET_DIE_LENGTH(die_off, FALSE);
+ t_len = GET_DIE_LENGTH(t_die_off, FALSE);
+ if (len > 0 && t_len > 0)
+ idxlst[nidx++] = len / t_len;
+ die_off = t_die_off;
+ break;
+ /* Handle typedef */
+ case DW_TAG_typedef:
+ die_off = t_die_off;
+ break;
+ case DW_TAG_base_type:
+ eppic_parsetype(tstr = GET_DIE_NAME(t_die_off), t, 0);
+ goto out;
+ case DW_TAG_union_type:
+ eppic_type_mkunion(t);
+ goto label;
+ case DW_TAG_enumeration_type:
+ eppic_type_mkenum(t);
+ goto label;
+ case DW_TAG_structure_type:
+ eppic_type_mkstruct(t);
+label:
+ eppic_type_setsize(t, GET_DIE_LENGTH(t_die_off, TRUE));
+ eppic_type_setidx(t, (ull)t_die_off);
+ tstr = GET_DIE_NAME(t_die_off);
+ /* Drill down further */
+ if (tstr)
+ apigetctype(V_STRUCT, tstr, t);
+ die_off = 0;
+ break;
+ /* Unknown TAG ? */
+ default:
+ die_off = t_die_off;
+ break;
+ }
+ }
+
+out:
+ eppic_setupidx(t, ref, nidx, idxlst);
+ if (fctflg)
+ eppic_type_setfct(t, 1);
+ eppic_pushref(t, ref + (nidx ? 1 : 0));
+ tstr_dup = (tstr) ? eppic_strdup(tstr) : eppic_strdup("");
+ /* Free the memory allocated by makedumpfile. */
+ free(tstr);
+ return tstr_dup;
+}
+
+/*
+ * Get the type, size and position information for a member of a structure.
+ */
+static char *
+apimember(char *mname, ull idx, type_t *tm, member_t *m, ull *last_index)
+{
+ int index, nfields = -1, size;
+ int nbits = 0, fbits = 0;
+ long offset;
+ ull m_die, die_off = idx;
+ char *name = NULL;
+
+ nfields = GET_DIE_NFIELDS_ALL(die_off);
+ /*
+ * GET_DIE_NFIELDS() returns < 0 if the die is not structure type
+ * or union type
+ */
+ if (nfields <= 0)
+ return NULL;
+
+ /* if we're being asked the next member in a getfirst/getnext
+ * sequence
+ */
+ if (mname && !mname[0] && last_index && (*last_index))
+ index = *last_index;
+ else
+ index = 0;
+
+ while (index < nfields) {
+ size = GET_DIE_MEMBER_ALL(die_off, index, &offset, &name,
+ &nbits, &fbits, &m_die);
+
+ if (size < 0)
+ return NULL;
+
+ if (!mname || !mname[0] || !strcmp(mname, name)) {
+ eppic_member_ssize(m, size);
+ if (name) {
+ eppic_member_sname(m, name);
+ /*
+ * Free the memory allocated by makedumpfile.
+ */
+ free(name);
+ }
+ else
+ eppic_member_sname(m, "");
+ eppic_member_soffset(m, offset);
+ eppic_member_snbits(m, nbits);
+ eppic_member_sfbit(m, fbits);
+ *last_index = index + 1;
+ return drilldown(m_die, tm);
+ }
+ index++;
+ }
+ return NULL;
+}
+
+static int
+apigetctype(int ctype, char *name, type_t *tout)
+{
+ long size = 0;
+ unsigned long long die = 0;
+
+ switch (ctype) {
+ case V_TYPEDEF:
+ size = GET_DOMAIN_ALL(name, DWARF_INFO_GET_DOMAIN_TYPEDEF,
+ &die);
+ break;
+ case V_STRUCT:
+ size = GET_DOMAIN_ALL(name, DWARF_INFO_GET_DOMAIN_STRUCT, &die);
+ break;
+ case V_UNION:
+ size = GET_DOMAIN_ALL(name, DWARF_INFO_GET_DOMAIN_UNION, &die);
+ break;
+ /* TODO
+ * Implement for all the domains
+ */
+ }
+
+ if (size <= 0 || !die)
+ return 0;
+
+ /* populate */
+ eppic_type_settype(tout, ctype);
+ eppic_type_setsize(tout, size);
+ eppic_type_setidx(tout, (ull)(unsigned long)die);
+ eppic_pushref(tout, 0);
+ return 1;
+}
+
+static char *
+apigetrtype(ull idx, type_t *t)
+{
+ return drilldown(idx, t);
+}
+
+static int
+apialignment(ull idx)
+{
+ return 0;
+}
+
+int
+apigetval(char *name, ull *val, VALUE_S *value)
+{
+ ull ptr = 0;
+
+ ptr = GET_SYMBOL_ADDR_ALL(name);
+
+ if (!ptr)
+ return 0;
+
+ *val = ptr;
+
+ if (!value)
+ return 1;
+
+ /* Support for fully typed symbol access */
+ ull type;
+ TYPE_S *stype;
+
+ type = GET_DIE_OFFSET(name);
+ stype = eppic_gettype(value);
+
+ apigetrtype(type, stype);
+
+ eppic_pushref(stype, 1);
+ eppic_setmemaddr(value, *val);
+ eppic_do_deref(1, value, value);
+
+ *val = eppic_getval(value);
+
+ if (!eppic_typeislocal(stype) && eppic_type_getidx(stype) > 100) {
+ char *tname = GET_DIE_NAME(eppic_type_getidx(stype));
+ if (tname) {
+ eppic_chktype(stype, tname);
+ /* Free the memory allocated by makedumpfile. */
+ free(tname);
+ }
+ }
+ return 1;
+}
+
+static enum_t *
+apigetenum(char *name)
+{
+ return 0;
+}
+
+static def_t *
+apigetdefs(void)
+{
+ return 0;
+}
+
+static uint8_t
+apigetuint8(void *ptr)
+{
+ uint8_t val;
+ if (!READMEM(VADDR, (unsigned long)ptr, (char *)&val, sizeof(val)))
+ return (uint8_t) -1;
+ return val;
+}
+
+static uint16_t
+apigetuint16(void *ptr)
+{
+ uint16_t val;
+ if (!READMEM(VADDR, (unsigned long)ptr, (char *)&val, sizeof(val)))
+ return (uint16_t) -1;
+ return val;
+}
+
+static uint32_t
+apigetuint32(void *ptr)
+{
+ uint32_t val;
+ if (!READMEM(VADDR, (unsigned long)ptr, (char *)&val, sizeof(val)))
+ return (uint32_t) -1;
+ return val;
+}
+
+static uint64_t
+apigetuint64(void *ptr)
+{
+ uint64_t val;
+ if (!READMEM(VADDR, (unsigned long)ptr, (char *)&val, sizeof(val)))
+ return (uint64_t) -1;
+ return val;
+}
+
+static char *
+apifindsym(char *p)
+{
+ return NULL;
+}
+
+apiops icops = {
+ apigetmem,
+ apiputmem,
+ apimember,
+ apigetctype,
+ apigetrtype,
+ apialignment,
+ apigetval,
+ apigetenum,
+ apigetdefs,
+ apigetuint8,
+ apigetuint16,
+ apigetuint32,
+ apigetuint64,
+ apifindsym
+};
+
+/* Extensions to built-in functions */
+VALUE_S *
+eppic_memset(VALUE_S *vaddr, VALUE_S *vch, VALUE_S *vlen)
+{
+ ull addr = eppic_getval(vaddr);
+ int len = eppic_getval(vlen);
+ int ch = eppic_getval(vch);
+
+ /*
+ * Set the value at address from iaddr till iaddr + nbytes
+ * to the value specified in variable ch
+ */
+ UPDATE_FILTER_INFO_RAW(addr, ch, len);
+ return eppic_makebtype(1);
+}
+
+
+/* Initialize eppic */
+int
+eppic_init(void *fun_ptr)
+{
+ cb = (struct call_back *)fun_ptr;
+
+ if (eppic_open() >= 0) {
+
+ /* Register call back functions */
+ eppic_apiset(&icops, 3, sizeof(long), 0);
+
+ /* set the new function callback */
+ eppic_setcallback(reg_callback);
+
+ /* Extend built-in functions to include memset */
+ eppic_builtin("int memset(char *, int, int)",
+ (bf_t *)eppic_memset);
+
+ return 0;
+ }
+ return 1;
+}
+