#include <linux/log2.h>
 #include <linux/types.h>
 
+#include <opencsd/ocsd_if_types.h>
 #include <stdlib.h>
 
 #include "auxtrace.h"
        sample.stream_id = etmq->etm->instructions_id;
        sample.period = period;
        sample.cpu = etmq->packet->cpu;
-       sample.flags = 0;
+       sample.flags = etmq->prev_packet->flags;
        sample.insn_len = 1;
        sample.cpumode = event->sample.header.misc;
 
        sample.stream_id = etmq->etm->branches_id;
        sample.period = 1;
        sample.cpu = etmq->packet->cpu;
-       sample.flags = 0;
+       sample.flags = etmq->prev_packet->flags;
        sample.cpumode = event->sample.header.misc;
 
        /*
        return 0;
 }
 
+static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
+{
+       struct cs_etm_packet *packet = etmq->packet;
+
+       switch (packet->sample_type) {
+       case CS_ETM_RANGE:
+               /*
+                * Immediate branch instruction without neither link nor
+                * return flag, it's normal branch instruction within
+                * the function.
+                */
+               if (packet->last_instr_type == OCSD_INSTR_BR &&
+                   packet->last_instr_subtype == OCSD_S_INSTR_NONE) {
+                       packet->flags = PERF_IP_FLAG_BRANCH;
+
+                       if (packet->last_instr_cond)
+                               packet->flags |= PERF_IP_FLAG_CONDITIONAL;
+               }
+
+               /*
+                * Immediate branch instruction with link (e.g. BL), this is
+                * branch instruction for function call.
+                */
+               if (packet->last_instr_type == OCSD_INSTR_BR &&
+                   packet->last_instr_subtype == OCSD_S_INSTR_BR_LINK)
+                       packet->flags = PERF_IP_FLAG_BRANCH |
+                                       PERF_IP_FLAG_CALL;
+
+               /*
+                * Indirect branch instruction with link (e.g. BLR), this is
+                * branch instruction for function call.
+                */
+               if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
+                   packet->last_instr_subtype == OCSD_S_INSTR_BR_LINK)
+                       packet->flags = PERF_IP_FLAG_BRANCH |
+                                       PERF_IP_FLAG_CALL;
+
+               /*
+                * Indirect branch instruction with subtype of
+                * OCSD_S_INSTR_V7_IMPLIED_RET, this is explicit hint for
+                * function return for A32/T32.
+                */
+               if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
+                   packet->last_instr_subtype == OCSD_S_INSTR_V7_IMPLIED_RET)
+                       packet->flags = PERF_IP_FLAG_BRANCH |
+                                       PERF_IP_FLAG_RETURN;
+
+               /*
+                * Indirect branch instruction without link (e.g. BR), usually
+                * this is used for function return, especially for functions
+                * within dynamic link lib.
+                */
+               if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
+                   packet->last_instr_subtype == OCSD_S_INSTR_NONE)
+                       packet->flags = PERF_IP_FLAG_BRANCH |
+                                       PERF_IP_FLAG_RETURN;
+
+               /* Return instruction for function return. */
+               if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
+                   packet->last_instr_subtype == OCSD_S_INSTR_V8_RET)
+                       packet->flags = PERF_IP_FLAG_BRANCH |
+                                       PERF_IP_FLAG_RETURN;
+               break;
+       case CS_ETM_DISCONTINUITY:
+       case CS_ETM_EXCEPTION:
+       case CS_ETM_EXCEPTION_RET:
+       case CS_ETM_EMPTY:
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
 {
        struct cs_etm_auxtrace *etm = etmq->etm;
                                         */
                                        break;
 
+                               /*
+                                * Since packet addresses are swapped in packet
+                                * handling within below switch() statements,
+                                * thus setting sample flags must be called
+                                * prior to switch() statement to use address
+                                * information before packets swapping.
+                                */
+                               err = cs_etm__set_sample_flags(etmq);
+                               if (err < 0)
+                                       break;
+
                                switch (etmq->packet->sample_type) {
                                case CS_ETM_RANGE:
                                        /*