/**
 * @file exo_osal_mem_management.c
 *
 * @brief This file contains function definitions for OS memory management.
 *
 * @copyright Copyright 2023 Antaris, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stdio.h>
#include "exo_osal_mem_management.h"
#include "exo_ral_mem_management.h"
#include "exo_common.h"
#ifndef LINUX_TEMP_PORT
#include "exo_types.h"
#include "FreeRTOSConfig.h"
#endif
#include "exo_io_al_sos_timer.h"
#include "exo_osal_mem_cpy.h"

#define CMALLOC_HEAP_MEM_CFG_SIZE    (30*1024)
#define HEAP_WARN_THRES (2)
volatile uint8_t mem_dbg_init = 0;
uint8_t print_mem_warn_flag = 0;

#ifndef LINUX_TEMP_PORT
static uint32_t cmalloc_free_bytes_start;
#endif

#ifdef MEM_DEBUG_ENB
uint32_t mem_alloc_track_idx=0;
uint32_t mem_free_track_idx=0;
s_mem_info mem_info;

#if defined(COREBOARD)
#define MAX_MALLOC_TRACK_CNT (1000)
#elif defined(LINUX_TEMP_PORT)
#define MAX_MALLOC_TRACK_CNT (10000)
#else
#define MAX_MALLOC_TRACK_CNT (100)
#endif

#ifdef MEM_TRAC_DRAM
s_mem_alloc_track PLACE_IN_EXT_RAM_MEM mem_alloc_info[MAX_MALLOC_TRACK_CNT];
s_mem_free_track PLACE_IN_EXT_RAM_MEM mem_free_info[MAX_MALLOC_TRACK_CNT];
#define MEM_TRACKER_DRAM_ALLOC_START_ADDRESS (&mem_alloc_info)
#define MEM_TRACKER_DRAM_FREE_START_ADDRESS (&mem_free_info)
#else
s_mem_alloc_track mem_alloc_info[MAX_MALLOC_TRACK_CNT];
s_mem_free_track mem_free_info[MAX_MALLOC_TRACK_CNT];
#define MEM_TRACKER_DRAM_ALLOC_START_ADDRESS (&mem_alloc_info)
#define MEM_TRACKER_DRAM_FREE_START_ADDRESS (&mem_free_info)
#endif

void vPortFree_eram( void *pv );
void *pvPortMalloc( size_t xWantedSize );


/**
 * @brief This API Initialize the memory debugging tracker.
 */
void mem_debug_tracker_init(void)
{
    mem_info.mem_alloc_info = (s_mem_alloc_track *)MEM_TRACKER_DRAM_ALLOC_START_ADDRESS;
    mem_info.mem_free_info = (s_mem_free_track *)MEM_TRACKER_DRAM_FREE_START_ADDRESS;
    mem_alloc_track_idx=0;
    mem_free_track_idx=0;
    memset(mem_info.mem_alloc_info, 0, MAX_MALLOC_TRACK_CNT*sizeof(s_mem_alloc_track));
    memset(mem_info.mem_free_info, 0, MAX_MALLOC_TRACK_CNT*sizeof(s_mem_free_track));
    mem_dbg_init = 1;
}

/**
 * @brief API to store the deallocation information to the structure.
 */
void append_mem_free_track(void *ptr, uint32_t len, uint8_t fail_sts)
{
    if(mem_info.mem_free_info != NULL)
    {
        mem_info.mem_free_info[mem_free_track_idx%MAX_MALLOC_TRACK_CNT].time_stamp = 10;
        mem_info.mem_free_info[mem_free_track_idx%MAX_MALLOC_TRACK_CNT].len = len | (fail_sts << FAIL_FLAG_OFST);
        mem_info.mem_free_info[mem_free_track_idx%MAX_MALLOC_TRACK_CNT].ptr = ptr;
        mem_free_track_idx++;
    }
}

/**
 * @brief API to store the allocation information to the structure.
 */
void append_mem_alloc_track(void *ptr, uint32_t len, uint8_t fail_sts, char* file_name, uint32_t line_num)
{
    if(mem_info.mem_alloc_info != NULL)
    {
        mem_info.mem_alloc_info[mem_alloc_track_idx%MAX_MALLOC_TRACK_CNT].time_stamp = get_crnt_time_date_in_epoch();
        mem_info.mem_alloc_info[mem_alloc_track_idx%MAX_MALLOC_TRACK_CNT].len = len | (fail_sts << FAIL_FLAG_OFST);
        mem_info.mem_alloc_info[mem_alloc_track_idx%MAX_MALLOC_TRACK_CNT].ptr = ptr;
        mem_info.mem_alloc_info[mem_alloc_track_idx%MAX_MALLOC_TRACK_CNT].file_name = file_name;
        mem_info.mem_alloc_info[mem_alloc_track_idx%MAX_MALLOC_TRACK_CNT].line_number = line_num;
        mem_alloc_track_idx++;
    }
}

#ifdef MEM_LEAK_TRACKER_ENB
/**
 * @brief This API use to update the free status flag to deallocate structure.
 */
void mem_free_flag_upd(void *ptr,uint8_t *file_name, uint32_t line)
{
    uint8_t upd_sts = 1;
    uint32_t idx = (mem_alloc_track_idx % MAX_MALLOC_TRACK_CNT) - 1;
    int i;
    for(i=idx; i>=0; i--)
    {
        if(mem_info.mem_alloc_info[i].time_stamp == 0)
        {
            break;
        }
        if(mem_info.mem_alloc_info[i].ptr == ptr)
        {
            if(mem_info.mem_alloc_info[i].len >> FREE_STS_FLAG_OFST)
            {
                DEBUG_CPRINT(("WARN Already ptr may be freed %p idx %d LEN %lu File %s ",ptr,i,(unsigned long int)line,file_name));
            }
            else
            {
                mem_info.mem_alloc_info[i].len |= (1 << FREE_STS_FLAG_OFST);
                upd_sts =0;
                break;
            }
        }
    }
    if(upd_sts)
    {
        for(i=MAX_MALLOC_TRACK_CNT-1; i>idx; i--)
        {
            if(mem_info.mem_alloc_info[i].time_stamp == 0)
            {
                break;
            }
            if(mem_info.mem_alloc_info[i].ptr == ptr)
            {
                if(mem_info.mem_alloc_info[i].len >> FREE_STS_FLAG_OFST)
                {
                    DEBUG_CPRINT(("WARN Already ptr may be freed %p idx %d LEN %lu File %s ",ptr,i,(unsigned long int)line,file_name));
                }
                else
                {
                    mem_info.mem_alloc_info[i].len |= (1 << FREE_STS_FLAG_OFST);
                    upd_sts =0;
                    break;
                }
            }

        }
    }
    if(upd_sts)
    {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
        DEBUG_CPRINT(("WARN Freed ptr may not be allocated or already freed %p LEN %d File %s ",ptr,line, file_name));
#pragma GCC diagnostic pop
    }
}

/**
 * @brief This API use to print the memory leak information.
 */
void print_mem_leak(void)
{
    uint8_t upd_sts = 1;
    uint32_t idx = (mem_alloc_track_idx % MAX_MALLOC_TRACK_CNT) - 1;
    int i;
    for(i=idx; i>=0; i--)
    {
        if(mem_info.mem_alloc_info[i].time_stamp)
        {
            if(0 == (mem_info.mem_alloc_info[i].len & (1 << FREE_STS_FLAG_OFST)))
            {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
                DEBUG_CPRINT(("\r\n MLEAK ts:%d ptr:%p, siz:%d file_name:%s line_num:%ld", \
                        mem_info.mem_alloc_info[i].time_stamp , \
                        mem_info.mem_alloc_info[i].ptr, \
                        mem_info.mem_alloc_info[i].len,mem_info.mem_alloc_info[i].file_name,mem_info.mem_alloc_info[i].line_number));
#pragma GCC diagnostic pop
            }
        }
        else
        {
            upd_sts =0;
            break;
        }
    }
    if(upd_sts)
    {
        for(i=MAX_MALLOC_TRACK_CNT-1; i>idx; i--)
        {
            if(mem_info.mem_alloc_info[i].time_stamp)
            {
                if(0 == (mem_info.mem_alloc_info[i].len & (1 << FREE_STS_FLAG_OFST)))
                {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
                    DEBUG_CPRINT(("\r\n MLEAK ts:%d ptr:%p, siz:%d file_name:%s line_num:%ld", \
                            mem_info.mem_alloc_info[i].time_stamp , \
                            mem_info.mem_alloc_info[i].ptr, \
                            mem_info.mem_alloc_info[i].len,mem_info.mem_alloc_info[i].file_name,mem_info.mem_alloc_info[i].line_number));
#pragma GCC diagnostic pop
                }
            }
            else
            {
                upd_sts =0;
                break;
            }
        }
    }
}
#else
void print_mem_leak(void)
{
    DEBUG_CPRINT(("No MEM leak analyzer enabled"));
}
#endif

/**
 * @brief This API use to print the allocated memory information.
 */
void print_mem_alloc_info(void)
{
    int32_t idx=  (mem_alloc_track_idx % MAX_MALLOC_TRACK_CNT) - 1;
    uint8_t buff_full = 0;
    if(idx+1 <MAX_MALLOC_TRACK_CNT )
    {
        if(mem_info.mem_alloc_info[idx+1].time_stamp)
        {
            buff_full=1;
        }
    }
    /*for(int i=idx; i>=0;i--)
      {
      if(0 == (mem_info.mem_alloc_info[i].len & (1 << FREE_STS_FLAG_OFST)))
      {
      DEBUG_CPRINT(\r\nMEM_AINFO ts:%d ptr:%p, siz:%d file_name:%s line_num:%ld", \
      mem_info.mem_alloc_info[i].time_stamp , \
      mem_info.mem_alloc_info[i].ptr, \
      mem_info.mem_alloc_info[i].len,mem_info.mem_alloc_info[i].file_name,mem_info.mem_alloc_info[i].line_number));
      }
      }*/
    if(buff_full)
    {
        /*for(i=MAX_MALLOC_TRACK_CNT-1; i>idx;i--)
          {
          if(0 == (mem_info.mem_alloc_info[i].len & (1 << FREE_STS_FLAG_OFST)))
          {
          DEBUG_CPRINT(\r\nMEM_AINFO ts:%d ptr:%p, siz:%d file_name:%s line_num:%ld", \
          mem_info.mem_alloc_info[i].time_stamp , \
          mem_info.mem_alloc_info[i].ptr, \
          mem_info.mem_alloc_info[i].len,mem_info.mem_alloc_info[i].file_name,mem_info.mem_alloc_info[i].line_number));
          }
          }*/
    }
}

/**
 * @brief This API use to print the deallocated memory information.
 */
void print_mem_free_info(void)
{
    int32_t idx=  (mem_free_track_idx % MAX_MALLOC_TRACK_CNT) -1;
    uint8_t buff_full = 0;
    if(idx+1 <MAX_MALLOC_TRACK_CNT )
    {
        if(mem_info.mem_free_info[idx+1].time_stamp)
        {
            buff_full=1;
        }
    }
    /*for(int i=idx; i>=0;i--)
      {
      DEBUG_CPRINT(\r\nMEM_FINFO ts:%d ptr:%p, siz:%d idx %d", \
      mem_info.mem_free_info[i].time_stamp , \
      mem_info.mem_free_info[i].ptr, \
      mem_info.mem_free_info[i].len,i));
      }*/
    if(buff_full)
    {
        /*for(i=MAX_MALLOC_TRACK_CNT-1; i>idx;i--)
          {
          DEBUG_CPRINT(\r\nMEM_FINFO ts:%d ptr:%p, siz:%d idx %d", \
          mem_info.mem_free_info[i].time_stamp , \
          mem_info.mem_free_info[i].ptr, \
          mem_info.mem_free_info[i].len,i));
          }*/
    }
}
#endif

/**
 * @brief This API allocate and reset the memory then store allocation
 *         information to the structure.
 */
void *os_calloc_debug(uint32_t nmemb,uint32_t byte_size,char *file_name, uint32_t line_num)
{
    void * ptr =  os_malloc_debug(nmemb * byte_size,file_name, line_num);
    if(ptr)
    {
        os_memset((uint8_t *)ptr,0,byte_size);
    }
    return ptr;
}

/**
 * @brief This API allocate the memory in eram then store allocation
 *         information to the structure.
 */
void *os_malloc_eram_debug(uint32_t byte_size,char *file_name, uint32_t line_num)
{
    void * ptr = NULL;
    ptr = os_malloc_eram_api(byte_size);
#ifdef MEM_DEBUG_ENB
#ifndef LINUX_TEMP_PORT
#if 0
    uint32_t remain_heap_size =xPortGetFreeHeapSize();
    if(remain_heap_size <  (configTOTAL_HEAP_SIZE>>HEAP_WARN_THRES))
    {
        DEBUG_CPRINT(("\r\n MEM 75% More used, Last allocated memory F_N: %s Ln: %ld Le: %d Remain %d ",\
        		 file_name,line_num,byte_size,remain_heap_size));
        if(print_mem_warn_flag == 0)
        {
#ifdef MEM_LEAK_TRACKER_ENB
         print_mem_leak();
#endif
         print_mem_warn_flag = 1;
        }
     }
#endif
#endif

    if(mem_dbg_init)
    {
        if(ptr)
        {
            append_mem_alloc_track(ptr,byte_size,0,file_name,line_num);
        }
        else
        {
            append_mem_alloc_track(ptr,byte_size,1,file_name,line_num);
            DEBUG_CPRINT(("\r\nM_F F_N: %s Ln: %ld Le: %lu ",file_name,(unsigned long int)line_num,(unsigned long int)byte_size));
#ifdef MEM_LEAK_TRACKER_ENB
            print_mem_leak();
#endif
        }
    }

#endif
    return ptr;
}
/**
 * @brief This API allocate the memory then store allocation
 *         information to the structure.
 */
void *os_malloc_debug(uint32_t byte_size,char *file_name, uint32_t line_num)
{
    void * ptr = NULL;
    ptr = os_malloc_api(byte_size);
#ifdef MEM_DEBUG_ENB
#ifndef LINUX_TEMP_PORT
#if 0
    uint32_t remain_heap_size =xPortGetFreeHeapSize();
    if(remain_heap_size <  (configTOTAL_HEAP_SIZE>>HEAP_WARN_THRES))
    {
        DEBUG_CPRINT(("\r\n MEM 75% More used, Last allocated memory F_N: %s Ln: %ld Le: %d Remain %d ",\
        		 file_name,line_num,byte_size,remain_heap_size));
        if(print_mem_warn_flag == 0)
        {
#ifdef MEM_LEAK_TRACKER_ENB
         print_mem_leak();
#endif
         print_mem_warn_flag = 1;
        }
     }
#endif
#endif

    if(mem_dbg_init)
    {
        if(ptr)
        {
            append_mem_alloc_track(ptr,byte_size,0,file_name,line_num);
        }
        else
        {
            append_mem_alloc_track(ptr,byte_size,1,file_name,line_num);
            DEBUG_CPRINT(("\r\nM_F F_N: %s Ln: %ld Le: %lu ",file_name,(unsigned long int)line_num,(unsigned long int)byte_size));
#ifdef MEM_LEAK_TRACKER_ENB
            print_mem_leak();
#endif
        }
    }

#endif
    return ptr;
}

/**
 * @brief This API allocate and reset the memory.
 */
void *os_calloc_api(uint32_t nmemb,uint32_t byte_size)
{
    void * ptr =  os_malloc_api(nmemb * byte_size);
    if(ptr)
    {
        os_memset((uint8_t *)ptr,0,byte_size);
    }
    return ptr;
}

/**
 * @brief This API allocate the memory in eram.
 */
void *os_malloc_eram_api(uint32_t byte_size)
{
    void * ptr = NULL;
#ifdef LINUX_TEMP_PORT
    ptr = malloc(byte_size);
#else
    if(byte_size % 4)
    {
        byte_size = (((byte_size +4) >>2) << 2);
    }
    ptr = (void *)ral_malloc_eram(byte_size);
#endif
     mallocASSERT(ptr);
    return ptr;
}
/**
 * @brief This API allocate the memory.
 */
void *os_malloc_api(uint32_t byte_size)
{
    void * ptr = NULL;
#ifdef LINUX_TEMP_PORT
    ptr = malloc(byte_size);
#else
    if(byte_size % 4)
    {
        byte_size = (((byte_size +4) >>2) << 2);
    }
    ptr = (void *)ral_malloc(byte_size);
#endif
    mallocASSERT(ptr);
    return ptr;
}

/**
 * @brief This API use to release the allocated memory
 */
void os_free_debug(void *ptr,char *file_name, uint32_t line_num)
{
    if(ptr)
    {
#ifdef LINUX_TEMP_PORT
        free(ptr);
#ifdef MEM_DEBUG_ENB
            append_mem_free_track(ptr,0,0);
#ifdef MEM_LEAK_TRACKER_ENB
            mem_free_flag_upd(ptr,(uint8_t*)file_name, line_num);
#endif
#endif
    }
#else
        if( 1 == is_valid_addr_heap_range(ptr))
        {
            ral_free(ptr);
            uint32_t remain_heap_size =xPortGetFreeHeapSize();
            if(remain_heap_size >=  (configTOTAL_HEAP_SIZE>>HEAP_WARN_THRES))
                {
            	print_mem_warn_flag=0;
                }
#ifdef MEM_DEBUG_ENB
            append_mem_free_track(ptr,0,0);
#ifdef MEM_LEAK_TRACKER_ENB
            mem_free_flag_upd(ptr,(uint8_t*)file_name, line_num);
#endif
#endif
        }
        else if (1 == is_valid_addr_eram_heap_range(ptr))
        {
            vPortFree_eram(ptr);
#ifdef MEM_DEBUG_ENB
            append_mem_free_track(ptr,0,0);
#ifdef MEM_LEAK_TRACKER_ENB
            mem_free_flag_upd(ptr,(uint8_t*)file_name, line_num);
#endif
#endif
        }
        else
        {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
            DEBUG_CPRINT(("Err Invalid Free Pointer called %p Line %d File %s ", ptr,line_num, file_name ));
#pragma GCC diagnostic pop
        }
}
#endif
    else
    {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
        DEBUG_CPRINT(("Err NULL Pointer free called Line %d File %s",line_num, file_name));
#pragma GCC diagnostic pop
        //    append_mem_free_track(ptr,0,1);
    }
}

/**
 * @brief This API use to load the memory block with given value
 */
void* os_memset(void *ptr, int val, size_t num_bytes)
{
    return(memset(ptr, val, num_bytes));
}

/**
 * @brief This API to copy data from one memory location to another
 *        memory location
 */
void* os_memcpy(void * destination_ptr, const void * src_ptr, size_t num_bytes)
{
    return(memcpy(destination_ptr,src_ptr, num_bytes));
}
/**
 * @brief This function get the heap memory information
 */
void get_os_heap_mem_info(os_heap_memory_info_s *mem_data)
{
	get_ral_heap_mem_info((ral_heap_memory_info_s *) mem_data);

}
    

#ifndef LINUX_TEMP_PORT

int32_t get_available_cmalloc_free(void)
{

	int32_t end_address;
	uint8_t *temp;
	end_address = cmalloc_free_bytes_start + CMALLOC_HEAP_MEM_CFG_SIZE;
	temp = malloc(4096);

	if(temp != NULL)
	{
		if((uint32_t)temp < end_address)
		{
			end_address =  (end_address - (uint32_t)temp);
		}
		else
		{
			end_address = -2;
		}

		free(temp);

	}
	else
	{
		end_address = -1;
	}

	return end_address;

}



static void set_available_cmalloc_free(uint32_t set)
{

	cmalloc_free_bytes_start = set;
}




void cmalloc_track_init(void)
{


	uint8_t *temp = malloc(4);
	set_available_cmalloc_free((uint32_t)temp);
	free(temp);

}

#endif

#define MEM_LEAK_MAX_INST_CNT   (100)

/**
 * @brief This API use to print the memory leak information.
 */
uint16_t get_mem_leak_info(uint8_t **tm_data)
{
    int32_t idx = (mem_alloc_track_idx % MAX_MALLOC_TRACK_CNT) - 1;
    uint32_t data_len = 0;
    uint8_t *data = NULL;
    uint32_t data_idx = 0;
    uint32_t alct_mem_len = 0;
    uint8_t file_name_len = 0;
    uint16_t inst_cnt = 0;
    uint16_t cpy_inst_cnt = 0;
    for(int i = 0; i < MAX_MALLOC_TRACK_CNT; i++)
    {
        if(inst_cnt >= MEM_LEAK_MAX_INST_CNT)
        {
            break;
        }
        if(mem_info.mem_alloc_info[idx].time_stamp)
        {
            if(0 == (mem_info.mem_alloc_info[idx].len & (1 << FREE_STS_FLAG_OFST)))
            {
                data_len += sizeof(s_mem_leak_info) - sizeof(char*);
                if(strcmp("src/", mem_info.mem_alloc_info[idx].file_name)) 
                {
                    data_len += strlen(mem_info.mem_alloc_info[idx].file_name) - 4;
                }
                else
                {
                    data_len += strlen(mem_info.mem_alloc_info[idx].file_name);
                }
                inst_cnt++;
            }
        }
        else
        {
            break;
        }
        idx--;
        if(idx < 0)
        {
            idx = MAX_MALLOC_TRACK_CNT - 1;
        }
    }
    idx = (mem_alloc_track_idx % MAX_MALLOC_TRACK_CNT) - 1;
    // Add Instance count size
    data_len = data_len + sizeof(inst_cnt);
    data = os_malloc(data_len);

    // Copy instance count to data stream
    os_memcpy(data, &inst_cnt, sizeof(inst_cnt));
    data_idx += sizeof(inst_cnt);
    for(int i = 0; i < MAX_MALLOC_TRACK_CNT; i++)
    {
        if(cpy_inst_cnt >= inst_cnt)
        {
            break;
        }
        if(mem_info.mem_alloc_info[idx].time_stamp)
        {
            if(0 == (mem_info.mem_alloc_info[idx].len & (1 << FREE_STS_FLAG_OFST)))
            {
                // Copy Time stamp into data stream
                os_memcpy(&data[data_idx], &mem_info.mem_alloc_info[idx].time_stamp,\
                        sizeof(mem_info.mem_alloc_info[idx].time_stamp));
                data_idx += sizeof(mem_info.mem_alloc_info[idx].time_stamp);
                // Copy Allocated length into data stream
                alct_mem_len = mem_info.mem_alloc_info[idx].len & 0x3FFFFFFF;

#ifndef LINUX_TEMP_PORT
                if(1 == is_valid_addr_eram_heap_range(mem_info.mem_alloc_info[idx].ptr))
                {
                    alct_mem_len |= E_RAM << MEM_TYPE_FLAG_OFST;
                }
#endif
                os_memcpy(&data[data_idx], &alct_mem_len, sizeof(alct_mem_len));
                data_idx += sizeof(alct_mem_len);

                if(strcmp("src/", mem_info.mem_alloc_info[idx].file_name)) 
                {
                    // Remove src/ length Copy file name length into data stream
                    file_name_len = strlen(mem_info.mem_alloc_info[idx].file_name) - 4;
                    os_memcpy(&data[data_idx], &file_name_len, sizeof(file_name_len));
                    data_idx += sizeof(file_name_len);
                    // Copy file name into data stream without src/
                    os_memcpy(&data[data_idx], &mem_info.mem_alloc_info[idx].file_name[4],\
                            file_name_len); 
                    data_idx += file_name_len;
                }
                else
                {
                    // Copy file name length into data stream
                    file_name_len = strlen(mem_info.mem_alloc_info[idx].file_name);
                    os_memcpy(&data[data_idx], &file_name_len, sizeof(file_name_len));
                    data_idx += sizeof(file_name_len);
                    // Copy file name into data stream
                    os_memcpy(&data[data_idx], mem_info.mem_alloc_info[idx].file_name, file_name_len); 
                    data_idx += file_name_len;
                }
                // Copy line number into data stream
                os_memcpy(&data[data_idx], &mem_info.mem_alloc_info[idx].line_number, sizeof(uint16_t));
                data_idx += sizeof(uint16_t);
                cpy_inst_cnt++;
            }
        }
        else
        {
            break;
        }
        idx--;
        if(idx < 0)
        {
            idx = MAX_MALLOC_TRACK_CNT - 1;
        }
    }
    *tm_data = data;
    return data_len;
}
