#include "cpumap.h"
 #include "print_binary.h"
 #include "stat.h"
+#include "mem-events.h"
 
 #if PY_MAJOR_VERSION < 3
 #define _PyUnicode_FromString(arg) \
        return pylist;
 }
 
+static PyObject *python_process_brstack(struct perf_sample *sample,
+                                       struct thread *thread)
+{
+       struct branch_stack *br = sample->branch_stack;
+       PyObject *pylist;
+       u64 i;
+
+       pylist = PyList_New(0);
+       if (!pylist)
+               Py_FatalError("couldn't create Python list");
+
+       if (!(br && br->nr))
+               goto exit;
+
+       for (i = 0; i < br->nr; i++) {
+               PyObject *pyelem;
+               struct addr_location al;
+               const char *dsoname;
+
+               pyelem = PyDict_New();
+               if (!pyelem)
+                       Py_FatalError("couldn't create Python dictionary");
+
+               pydict_set_item_string_decref(pyelem, "from",
+                   PyLong_FromUnsignedLongLong(br->entries[i].from));
+               pydict_set_item_string_decref(pyelem, "to",
+                   PyLong_FromUnsignedLongLong(br->entries[i].to));
+               pydict_set_item_string_decref(pyelem, "mispred",
+                   PyBool_FromLong(br->entries[i].flags.mispred));
+               pydict_set_item_string_decref(pyelem, "predicted",
+                   PyBool_FromLong(br->entries[i].flags.predicted));
+               pydict_set_item_string_decref(pyelem, "in_tx",
+                   PyBool_FromLong(br->entries[i].flags.in_tx));
+               pydict_set_item_string_decref(pyelem, "abort",
+                   PyBool_FromLong(br->entries[i].flags.abort));
+               pydict_set_item_string_decref(pyelem, "cycles",
+                   PyLong_FromUnsignedLongLong(br->entries[i].flags.cycles));
+
+               thread__find_map(thread, sample->cpumode,
+                                br->entries[i].from, &al);
+               dsoname = get_dsoname(al.map);
+               pydict_set_item_string_decref(pyelem, "from_dsoname",
+                                             _PyUnicode_FromString(dsoname));
+
+               thread__find_map(thread, sample->cpumode,
+                                br->entries[i].to, &al);
+               dsoname = get_dsoname(al.map);
+               pydict_set_item_string_decref(pyelem, "to_dsoname",
+                                             _PyUnicode_FromString(dsoname));
+
+               PyList_Append(pylist, pyelem);
+               Py_DECREF(pyelem);
+       }
+
+exit:
+       return pylist;
+}
+
+static unsigned long get_offset(struct symbol *sym, struct addr_location *al)
+{
+       unsigned long offset;
+
+       if (al->addr < sym->end)
+               offset = al->addr - sym->start;
+       else
+               offset = al->addr - al->map->start - sym->start;
+
+       return offset;
+}
+
+static int get_symoff(struct symbol *sym, struct addr_location *al,
+                     bool print_off, char *bf, int size)
+{
+       unsigned long offset;
+
+       if (!sym || !sym->name[0])
+               return scnprintf(bf, size, "%s", "[unknown]");
+
+       if (!print_off)
+               return scnprintf(bf, size, "%s", sym->name);
+
+       offset = get_offset(sym, al);
+
+       return scnprintf(bf, size, "%s+0x%x", sym->name, offset);
+}
+
+static int get_br_mspred(struct branch_flags *flags, char *bf, int size)
+{
+       if (!flags->mispred  && !flags->predicted)
+               return scnprintf(bf, size, "%s", "-");
+
+       if (flags->mispred)
+               return scnprintf(bf, size, "%s", "M");
+
+       return scnprintf(bf, size, "%s", "P");
+}
+
+static PyObject *python_process_brstacksym(struct perf_sample *sample,
+                                          struct thread *thread)
+{
+       struct branch_stack *br = sample->branch_stack;
+       PyObject *pylist;
+       u64 i;
+       char bf[512];
+       struct addr_location al;
+
+       pylist = PyList_New(0);
+       if (!pylist)
+               Py_FatalError("couldn't create Python list");
+
+       if (!(br && br->nr))
+               goto exit;
+
+       for (i = 0; i < br->nr; i++) {
+               PyObject *pyelem;
+
+               pyelem = PyDict_New();
+               if (!pyelem)
+                       Py_FatalError("couldn't create Python dictionary");
+
+               thread__find_symbol(thread, sample->cpumode,
+                                   br->entries[i].from, &al);
+               get_symoff(al.sym, &al, true, bf, sizeof(bf));
+               pydict_set_item_string_decref(pyelem, "from",
+                                             _PyUnicode_FromString(bf));
+
+               thread__find_symbol(thread, sample->cpumode,
+                                   br->entries[i].to, &al);
+               get_symoff(al.sym, &al, true, bf, sizeof(bf));
+               pydict_set_item_string_decref(pyelem, "to",
+                                             _PyUnicode_FromString(bf));
+
+               get_br_mspred(&br->entries[i].flags, bf, sizeof(bf));
+               pydict_set_item_string_decref(pyelem, "pred",
+                                             _PyUnicode_FromString(bf));
+
+               if (br->entries[i].flags.in_tx) {
+                       pydict_set_item_string_decref(pyelem, "in_tx",
+                                             _PyUnicode_FromString("X"));
+               } else {
+                       pydict_set_item_string_decref(pyelem, "in_tx",
+                                             _PyUnicode_FromString("-"));
+               }
+
+               if (br->entries[i].flags.abort) {
+                       pydict_set_item_string_decref(pyelem, "abort",
+                                             _PyUnicode_FromString("A"));
+               } else {
+                       pydict_set_item_string_decref(pyelem, "abort",
+                                             _PyUnicode_FromString("-"));
+               }
+
+               PyList_Append(pylist, pyelem);
+               Py_DECREF(pyelem);
+       }
+
+exit:
+       return pylist;
+}
+
 static PyObject *get_sample_value_as_tuple(struct sample_read_value *value)
 {
        PyObject *t;
        pydict_set_item_string_decref(dict_sample, "values", values);
 }
 
+static void set_sample_datasrc_in_dict(PyObject *dict,
+                                      struct perf_sample *sample)
+{
+       struct mem_info mi = { .data_src.val = sample->data_src };
+       char decode[100];
+
+       pydict_set_item_string_decref(dict, "datasrc",
+                       PyLong_FromUnsignedLongLong(sample->data_src));
+
+       perf_script__meminfo_scnprintf(decode, 100, &mi);
+
+       pydict_set_item_string_decref(dict, "datasrc_decode",
+                       _PyUnicode_FromString(decode));
+}
+
+static int regs_map(struct regs_dump *regs, uint64_t mask, char *bf, int size)
+{
+       unsigned int i = 0, r;
+       int printed = 0;
+
+       bf[0] = 0;
+
+       for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) {
+               u64 val = regs->regs[i++];
+
+               printed += scnprintf(bf + printed, size - printed,
+                                    "%5s:0x%" PRIx64 " ",
+                                    perf_reg_name(r), val);
+       }
+
+       return printed;
+}
+
+static void set_regs_in_dict(PyObject *dict,
+                            struct perf_sample *sample,
+                            struct perf_evsel *evsel)
+{
+       struct perf_event_attr *attr = &evsel->attr;
+       char bf[512];
+
+       regs_map(&sample->intr_regs, attr->sample_regs_intr, bf, sizeof(bf));
+
+       pydict_set_item_string_decref(dict, "iregs",
+                       _PyUnicode_FromString(bf));
+
+       regs_map(&sample->user_regs, attr->sample_regs_user, bf, sizeof(bf));
+
+       pydict_set_item_string_decref(dict, "uregs",
+                       _PyUnicode_FromString(bf));
+}
+
 static PyObject *get_perf_sample_dict(struct perf_sample *sample,
                                         struct perf_evsel *evsel,
                                         struct addr_location *al,
                                         PyObject *callchain)
 {
-       PyObject *dict, *dict_sample;
+       PyObject *dict, *dict_sample, *brstack, *brstacksym;
 
        dict = PyDict_New();
        if (!dict)
        pydict_set_item_string_decref(dict_sample, "addr",
                        PyLong_FromUnsignedLongLong(sample->addr));
        set_sample_read_in_dict(dict_sample, sample, evsel);
+       pydict_set_item_string_decref(dict_sample, "weight",
+                       PyLong_FromUnsignedLongLong(sample->weight));
+       pydict_set_item_string_decref(dict_sample, "transaction",
+                       PyLong_FromUnsignedLongLong(sample->transaction));
+       set_sample_datasrc_in_dict(dict_sample, sample);
        pydict_set_item_string_decref(dict, "sample", dict_sample);
 
        pydict_set_item_string_decref(dict, "raw_buf", _PyBytes_FromStringAndSize(
 
        pydict_set_item_string_decref(dict, "callchain", callchain);
 
+       brstack = python_process_brstack(sample, al->thread);
+       pydict_set_item_string_decref(dict, "brstack", brstack);
+
+       brstacksym = python_process_brstacksym(sample, al->thread);
+       pydict_set_item_string_decref(dict, "brstacksym", brstacksym);
+
+       set_regs_in_dict(dict, sample, evsel);
+
        return dict;
 }