Exemplo n.º 1
0
void
check_binary_file(char *filename)
{
    unsigned char *image;
    unsigned char *p;
    unsigned       idsize;
    int            nbytes;
    int            nrecords;

    image = get_binary_file_image(filename, &nbytes);
    if ( image == NULL ) {
        check_printf("No file image: %s\n", filename);
        return;
    }
    p = image;
    CHECK_FOR_ERROR(strcmp((char*)p, gdata->header)==0);
    check_printf("Filename=%s, nbytes=%d, header=\"%s\"\n",
                        filename, nbytes, p);
    p+=((int)strlen((char*)p)+1);
    idsize = read_u4(&p);
    CHECK_FOR_ERROR(idsize==sizeof(HprofId));
    (void)read_u4(&p);
    (void)read_u4(&p);
    /* LINTED */
    nrecords = check_tags(p, nbytes - (int)( p - image ) );
    check_printf("#%d total records found in %d bytes\n", nrecords, nbytes);
    HPROF_FREE(image);
}
Exemplo n.º 2
0
/* Read the entire file into memory */
static void *
get_binary_file_image(char *filename, int *pnbytes)
{
    unsigned char *image;
    int            fd;
    jlong          nbytes;
    int            nread;

    *pnbytes = 0;
    fd = md_open_binary(filename);
    CHECK_FOR_ERROR(fd>=0);
    if ( (nbytes = md_seek(fd, (jlong)-1)) == (jlong)-1 ) {
        HPROF_ERROR(JNI_TRUE, "Cannot md_seek() to end of file");
    }
    CHECK_FOR_ERROR(((jint)nbytes)>512);
    if ( md_seek(fd, (jlong)0) != (jlong)0 ) {
        HPROF_ERROR(JNI_TRUE, "Cannot md_seek() to start of file");
    }
    image = HPROF_MALLOC(((jint)nbytes)+1);
    CHECK_FOR_ERROR(image!=NULL);

    /* Read the entire file image into memory */
    nread = md_read(fd, image, (jint)nbytes);
    if ( nread <= 0 ) {
        HPROF_ERROR(JNI_TRUE, "System read failed.");
    }
    CHECK_FOR_ERROR(((jint)nbytes)==nread);
    md_close(fd);
    *pnbytes = (jint)nbytes;
    return image;
}
Exemplo n.º 3
0
/* Check all the heap tags in a heap dump */
static int
check_tags(unsigned char *pstart, int nbytes)
{
    unsigned char      *p;
    int                 nrecord;
    struct LookupTable *utab;
    UmapInfo            umap;

    check_printf("\nCHECK TAGS: starting\n");

    utab    = table_initialize("temp utf8 map", 64, 64, 512, sizeof(UmapInfo));

    /* Walk the tags, assumes UTF8 tags are defined before used */
    p       = pstart;
    nrecord = 0;
    while ( p < (pstart+nbytes) ) {
        unsigned     tag;
        unsigned     size;
        int          nheap_records;
        int          npos;
        char        *label;
        HprofId      id, nm, sg, so, gr, gn;
        int          i, li, num_elements;
        HprofType    ty;
        SerialNumber trace_serial_num;
        SerialNumber thread_serial_num;
        SerialNumber class_serial_num;
        unsigned     flags;
        unsigned     depth;
        float        cutoff;
        unsigned     temp;
        jint         nblive;
        jint         nilive;
        jlong        tbytes;
        jlong        tinsts;
        jint         total_samples;
        jint         trace_count;

        nrecord++;
        /*LINTED*/
        npos = (int)(p - pstart);
        tag = read_u1(&p);
        (void)read_u4(&p); /* microsecs */
        size = read_u4(&p);
        #define CASE_TAG(name) case name: label = #name;
        switch ( tag ) {
            CASE_TAG(HPROF_UTF8)
                CHECK_FOR_ERROR(size>=(int)sizeof(HprofId));
                id = read_id(&p);
                check_printf("#%d@%d: %s, sz=%d, name_id=0x%x, \"",
                                nrecord, npos, label, size, id);
                num_elements = size-(int)sizeof(HprofId);
                check_raw(p, num_elements);
                check_printf("\"\n");
                /* Create entry in umap */
                umap.str = HPROF_MALLOC(num_elements+1);
                (void)strncpy(umap.str, (char*)p, (size_t)num_elements);
                umap.str[num_elements] = 0;
                (void)table_create_entry(utab, &id, sizeof(id), &umap);
                p += num_elements;
                break;
            CASE_TAG(HPROF_LOAD_CLASS)
                CHECK_FOR_ERROR(size==2*4+2*(int)sizeof(HprofId));
                class_serial_num = read_u4(&p);
                CHECK_CLASS_SERIAL_NO(class_serial_num);
                id = read_id(&p);
                trace_serial_num = read_u4(&p);
                CHECK_TRACE_SERIAL_NO(trace_serial_num);
                nm = read_id(&p);
                check_printf("#%d@%d: %s, sz=%d, class_serial_num=%u,"
                             " id=0x%x, trace_serial_num=%u, name_id=0x%x\n",
                                nrecord, npos, label, size, class_serial_num,
                                id, trace_serial_num, nm);
                break;
            CASE_TAG(HPROF_UNLOAD_CLASS)
                CHECK_FOR_ERROR(size==4);
                class_serial_num = read_u4(&p);
                CHECK_CLASS_SERIAL_NO(class_serial_num);
                check_printf("#%d@%d: %s, sz=%d, class_serial_num=%u\n",
                                nrecord, npos, label, size, class_serial_num);
                break;
            CASE_TAG(HPROF_FRAME)
                CHECK_FOR_ERROR(size==2*4+4*(int)sizeof(HprofId));
                id = read_id(&p);
                nm = read_id(&p);
                sg = read_id(&p);
                so = read_id(&p);
                class_serial_num = read_u4(&p);
                CHECK_CLASS_SERIAL_NO(class_serial_num);
                li = read_u4(&p);
                check_printf("#%d@%d: %s, sz=%d, ", nrecord, npos, label, size);
                check_print_utf8(utab, "id=", id);
                check_printf(" name_id=0x%x, sig_id=0x%x, source_id=0x%x,"
                             " class_serial_num=%u, lineno=%d\n",
                                nm, sg, so, class_serial_num, li);
                break;
            CASE_TAG(HPROF_TRACE)
                CHECK_FOR_ERROR(size>=3*4);
                trace_serial_num = read_u4(&p);
                CHECK_TRACE_SERIAL_NO(trace_serial_num);
                thread_serial_num = read_u4(&p); /* Can be 0 */
                num_elements = read_u4(&p);
                check_printf("#%d@%d: %s, sz=%d, trace_serial_num=%u,"
                             " thread_serial_num=%u, nelems=%d [",
                                nrecord, npos, label, size,
                                trace_serial_num, thread_serial_num, num_elements);
                for(i=0; i< num_elements; i++) {
                    check_printf("0x%x,", read_id(&p));
                }
                check_printf("]\n");
                break;
            CASE_TAG(HPROF_ALLOC_SITES)
                CHECK_FOR_ERROR(size>=2+4*4+2*8);
                flags = read_u2(&p);
                temp  = read_u4(&p);
                cutoff = *((float*)&temp);
                nblive = read_u4(&p);
                nilive = read_u4(&p);
                tbytes = read_u8(&p);
                tinsts = read_u8(&p);
                num_elements     = read_u4(&p);
                check_printf("#%d@%d: %s, sz=%d, flags=0x%x, cutoff=%g,"
                             " nblive=%d, nilive=%d, tbytes=(%d,%d),"
                             " tinsts=(%d,%d), num_elements=%d\n",
                                nrecord, npos, label, size,
                                flags, cutoff, nblive, nilive,
                                jlong_high(tbytes), jlong_low(tbytes),
                                jlong_high(tinsts), jlong_low(tinsts),
                                num_elements);
                for(i=0; i< num_elements; i++) {
                    ty = read_u1(&p);
                    class_serial_num = read_u4(&p);
                    CHECK_CLASS_SERIAL_NO(class_serial_num);
                    trace_serial_num = read_u4(&p);
                    CHECK_TRACE_SERIAL_NO(trace_serial_num);
                    nblive = read_u4(&p);
                    nilive = read_u4(&p);
                    tbytes = read_u4(&p);
                    tinsts = read_u4(&p);
                    check_printf("\t %d: ty=%d, class_serial_num=%u,"
                                 " trace_serial_num=%u, nblive=%d, nilive=%d,"
                                 " tbytes=%d, tinsts=%d\n",
                                 i, ty, class_serial_num, trace_serial_num,
                                 nblive, nilive, (jint)tbytes, (jint)tinsts);
                }
                break;
            CASE_TAG(HPROF_HEAP_SUMMARY)
                CHECK_FOR_ERROR(size==2*4+2*8);
                nblive = read_u4(&p);
                nilive = read_u4(&p);
                tbytes = read_u8(&p);
                tinsts = read_u8(&p);
                check_printf("#%d@%d: %s, sz=%d,"
                             " nblive=%d, nilive=%d, tbytes=(%d,%d),"
                             " tinsts=(%d,%d)\n",
                                nrecord, npos, label, size,
                                nblive, nilive,
                                jlong_high(tbytes), jlong_low(tbytes),
                                jlong_high(tinsts), jlong_low(tinsts));
                break;
            CASE_TAG(HPROF_START_THREAD)
                CHECK_FOR_ERROR(size==2*4+4*(int)sizeof(HprofId));
                thread_serial_num = read_u4(&p);
                CHECK_THREAD_SERIAL_NO(thread_serial_num);
                id = read_id(&p);
                trace_serial_num = read_u4(&p);
                CHECK_TRACE_SERIAL_NO(trace_serial_num);
                nm = read_id(&p);
                gr = read_id(&p);
                gn = read_id(&p);
                check_printf("#%d@%d: %s, sz=%d, thread_serial_num=%u,"
                             " id=0x%x, trace_serial_num=%u, ",
                                nrecord, npos, label, size,
                                thread_serial_num, id, trace_serial_num);
                check_print_utf8(utab, "nm=", id);
                check_printf(" trace_serial_num=%u, nm=0x%x,"
                             " gr=0x%x, gn=0x%x\n",
                                trace_serial_num, nm, gr, gn);
                break;
            CASE_TAG(HPROF_END_THREAD)
                CHECK_FOR_ERROR(size==4);
                thread_serial_num = read_u4(&p);
                CHECK_THREAD_SERIAL_NO(thread_serial_num);
                check_printf("#%d@%d: %s, sz=%d, thread_serial_num=%u\n",
                                nrecord, npos, label, size, thread_serial_num);
                break;
            CASE_TAG(HPROF_HEAP_DUMP)
                check_printf("#%d@%d: BEGIN: %s, sz=%d\n",
                                nrecord, npos, label, size);
                nheap_records = check_heap_tags(utab, p, size);
                check_printf("#%d@%d: END: %s, sz=%d, nheap_recs=%d\n",
                                nrecord, npos, label, size, nheap_records);
                p += size;
                break;
            CASE_TAG(HPROF_HEAP_DUMP_SEGMENT) /* 1.0.2 */
                check_printf("#%d@%d: BEGIN SEGMENT: %s, sz=%d\n",
                                nrecord, npos, label, size);
                nheap_records = check_heap_tags(utab, p, size);
                check_printf("#%d@%d: END SEGMENT: %s, sz=%d, nheap_recs=%d\n",
                                nrecord, npos, label, size, nheap_records);
                p += size;
                break;
            CASE_TAG(HPROF_HEAP_DUMP_END) /* 1.0.2 */
                check_printf("#%d@%d: SEGMENT END: %s, sz=%d\n",
                                nrecord, npos, label, size);
                break;
            CASE_TAG(HPROF_CPU_SAMPLES)
                CHECK_FOR_ERROR(size>=2*4);
                total_samples = read_u4(&p);
                trace_count = read_u4(&p);
                check_printf("#%d@%d: %s, sz=%d, total_samples=%d,"
                             " trace_count=%d\n",
                                nrecord, npos, label, size,
                                total_samples, trace_count);
                for(i=0; i< trace_count; i++) {
                    num_elements = read_u4(&p);
                    trace_serial_num = read_u4(&p);
                    CHECK_TRACE_SERIAL_NO(trace_serial_num);
                    check_printf("\t %d: samples=%d, trace_serial_num=%u\n",
                                 trace_serial_num, num_elements);
                }
                break;
            CASE_TAG(HPROF_CONTROL_SETTINGS)
                CHECK_FOR_ERROR(size==4+2);
                flags = read_u4(&p);
                depth = read_u2(&p);
                check_printf("#%d@%d: %s, sz=%d, flags=0x%x, depth=%d\n",
                                nrecord, npos, label, size, flags, depth);
                break;
            default:
                label = "UNKNOWN";
                check_printf("#%d@%d: %s, sz=%d\n",
                                nrecord, npos, label, size);
                HPROF_ERROR(JNI_TRUE, "unknown record type");
                p += size;
                break;
        }
        CHECK_FOR_ERROR(p<=(pstart+nbytes));
    }
    check_flush();
    CHECK_FOR_ERROR(p==(pstart+nbytes));
    table_cleanup(utab, &utab_cleanup, NULL);
    return nrecord;
}
Exemplo n.º 4
0
/* Given the heap dump data and the utf8 map, check/write the heap dump. */
static int
check_heap_tags(struct LookupTable *utab, unsigned char *pstart, int nbytes)
{
    int                 nrecords;
    unsigned char      *p;
    unsigned char      *psave;
    struct LookupTable *ctab;
    CmapInfo            cmap;
    char               *label;
    unsigned            tag;
    HprofType           ty;
    HprofId             id, id2, fr, sup;
    int                 num_elements;
    int                 num_bytes;
    SerialNumber        trace_serial_num;
    SerialNumber        thread_serial_num;
    int                 npos;
    int                 i;
    int                 inst_size;

    ctab     = table_initialize("temp ctab", 64, 64, 512, sizeof(CmapInfo));

    /* First pass over heap records just fills in the CmapInfo table */
    nrecords = 0;
    p        = pstart;
    while ( p < (pstart+nbytes) ) {
        nrecords++;
        /*LINTED*/
        npos = (int)(p - pstart);
        tag  = read_u1(&p);
        switch ( tag ) {
            CASE_HEAP(HPROF_GC_ROOT_UNKNOWN)
                id = read_id(&p);
                break;
            CASE_HEAP(HPROF_GC_ROOT_JNI_GLOBAL)
                id  = read_id(&p);
                id2 = read_id(&p);
                break;
            CASE_HEAP(HPROF_GC_ROOT_JNI_LOCAL)
                id = read_id(&p);
                thread_serial_num = read_u4(&p);
                fr = read_u4(&p);
                break;
            CASE_HEAP(HPROF_GC_ROOT_JAVA_FRAME)
                id = read_id(&p);
                thread_serial_num = read_u4(&p);
                fr = read_u4(&p);
                break;
            CASE_HEAP(HPROF_GC_ROOT_NATIVE_STACK)
                id = read_id(&p);
                thread_serial_num = read_u4(&p);
                break;
            CASE_HEAP(HPROF_GC_ROOT_STICKY_CLASS)
                id = read_id(&p);
                break;
            CASE_HEAP(HPROF_GC_ROOT_THREAD_BLOCK)
                id = read_id(&p);
                thread_serial_num = read_u4(&p);
                break;
            CASE_HEAP(HPROF_GC_ROOT_MONITOR_USED)
                id = read_id(&p);
                break;
            CASE_HEAP(HPROF_GC_ROOT_THREAD_OBJ)
                id = read_id(&p);
                thread_serial_num = read_u4(&p);
                trace_serial_num = read_u4(&p);
                break;
            CASE_HEAP(HPROF_GC_CLASS_DUMP)
                (void)memset((void*)&cmap, 0, sizeof(cmap));
                id = read_id(&p);
                trace_serial_num = read_u4(&p);
                {
                    HprofId ld, si, pr, re1, re2;

                    sup      = read_id(&p);
                    ld       = read_id(&p);
                    si       = read_id(&p);
                    pr       = read_id(&p);
                    re1      = read_id(&p);
                    re2      = read_id(&p);
                    cmap.sup = sup;
                }
                inst_size = read_u4(&p);
                cmap.inst_size = inst_size;
                num_elements = read_u2(&p);
                for(i=0; i<num_elements; i++) {
                    (void)read_u2(&p);
                    ty = read_u1(&p);
                    (void)read_val(&p, ty);
                }
                num_elements = read_u2(&p);
                for(i=0; i<num_elements; i++) {
                    (void)read_id(&p);
                    ty = read_u1(&p);
                    (void)read_val(&p, ty);
                }
                num_elements = read_u2(&p);
                for(i=0; i<num_elements; i++) {
                    HprofType ty;
                    HprofId   id;

                    id = read_id(&p);
                    ty = read_u1(&p);
                    add_inst_field_to_cmap(&cmap, id, ty);
                }
                (void)table_create_entry(ctab, &id, sizeof(id), &cmap);
                break;
            CASE_HEAP(HPROF_GC_INSTANCE_DUMP)
                id = read_id(&p);
                trace_serial_num = read_u4(&p);
                id2 = read_id(&p); /* class id */
                num_bytes = read_u4(&p);
                p += num_bytes;
                break;
            CASE_HEAP(HPROF_GC_OBJ_ARRAY_DUMP)
                id = read_id(&p);
                trace_serial_num = read_u4(&p);
                num_elements = read_u4(&p);
                id2 = read_id(&p);
                p += num_elements*(int)sizeof(HprofId);
                break;
            CASE_HEAP(HPROF_GC_PRIM_ARRAY_DUMP)
                id = read_id(&p);
                trace_serial_num = read_u4(&p);
                num_elements = read_u4(&p);
                ty = read_u1(&p);
                p += type_size[ty]*num_elements;
                break;
            default:
                label = "UNKNOWN";
                check_printf("H#%d@%d %s: ERROR!\n",
                                nrecords, npos, label);
                HPROF_ERROR(JNI_TRUE, "unknown heap record type");
                break;
        }
    }
    CHECK_FOR_ERROR(p==pstart+nbytes);

    /* Scan again once we have our cmap */
    nrecords = 0;
    p        = pstart;
    while ( p < (pstart+nbytes) ) {
        nrecords++;
        /*LINTED*/
        npos = (int)(p - pstart);
        tag  = read_u1(&p);
        switch ( tag ) {
            CASE_HEAP(HPROF_GC_ROOT_UNKNOWN)
                id = read_id(&p);
                check_printf("H#%d@%d %s: id=0x%x\n",
                        nrecords, npos, label, id);
                break;
            CASE_HEAP(HPROF_GC_ROOT_JNI_GLOBAL)
                id = read_id(&p);
                id2 = read_id(&p);
                check_printf("H#%d@%d %s: id=0x%x, id2=0x%x\n",
                        nrecords, npos, label, id, id2);
                break;
            CASE_HEAP(HPROF_GC_ROOT_JNI_LOCAL)
                id = read_id(&p);
                thread_serial_num = read_u4(&p);
                fr = read_u4(&p);
                check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u, fr=0x%x\n",
                        nrecords, npos, label, id, thread_serial_num, fr);
                break;
            CASE_HEAP(HPROF_GC_ROOT_JAVA_FRAME)
                id = read_id(&p);
                thread_serial_num = read_u4(&p);
                fr = read_u4(&p);
                check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u, fr=0x%x\n",
                        nrecords, npos, label, id, thread_serial_num, fr);
                break;
            CASE_HEAP(HPROF_GC_ROOT_NATIVE_STACK)
                id = read_id(&p);
                thread_serial_num = read_u4(&p);
                check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u\n",
                        nrecords, npos, label, id, thread_serial_num);
                break;
            CASE_HEAP(HPROF_GC_ROOT_STICKY_CLASS)
                id = read_id(&p);
                check_printf("H#%d@%d %s: id=0x%x\n",
                        nrecords, npos, label, id);
                break;
            CASE_HEAP(HPROF_GC_ROOT_THREAD_BLOCK)
                id = read_id(&p);
                thread_serial_num = read_u4(&p);
                check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u\n",
                        nrecords, npos, label, id, thread_serial_num);
                break;
            CASE_HEAP(HPROF_GC_ROOT_MONITOR_USED)
                id = read_id(&p);
                check_printf("H#%d@%d %s: id=0x%x\n",
                        nrecords, npos, label, id);
                break;
            CASE_HEAP(HPROF_GC_ROOT_THREAD_OBJ)
                id = read_id(&p);
                thread_serial_num = read_u4(&p);
                trace_serial_num = read_u4(&p);
                CHECK_TRACE_SERIAL_NO(trace_serial_num);
                check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u,"
                             " trace_serial_num=%u\n",
                        nrecords, npos, label, id, thread_serial_num,
                        trace_serial_num);
                break;
            CASE_HEAP(HPROF_GC_CLASS_DUMP)
                id = read_id(&p);
                trace_serial_num = read_u4(&p);
                CHECK_TRACE_SERIAL_NO(trace_serial_num);
                check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u\n",
                        nrecords, npos, label, id, trace_serial_num);
                {
                    HprofId ld, si, pr, re1, re2;

                    sup = read_id(&p);
                    ld  = read_id(&p);
                    si  = read_id(&p);
                    pr  = read_id(&p);
                    re1 = read_id(&p);
                    re2 = read_id(&p);
                    check_printf("  su=0x%x, ld=0x%x, si=0x%x,"
                                 " pr=0x%x, re1=0x%x, re2=0x%x\n",
                        sup, ld, si, pr, re1, re2);
                }
                inst_size = read_u4(&p);
                check_printf("  instance_size=%d\n", inst_size);

                num_elements = read_u2(&p);
                for(i=0; i<num_elements; i++) {
                    HprofType ty;
                    unsigned  cpi;
                    jvalue    val;

                    cpi = read_u2(&p);
                    ty  = read_u1(&p);
                    val = read_val(&p, ty);
                    check_printf("  constant_pool %d: cpi=%d, ty=%d, val=",
                                i, cpi, ty);
                    check_printf_val(ty, val, 1);
                    check_printf("\n");
                }

                num_elements = read_u2(&p);
                check_printf("  static_field_count=%d\n", num_elements);
                for(i=0; i<num_elements; i++) {
                    HprofType ty;
                    HprofId   id;
                    jvalue    val;

                    id  = read_id(&p);
                    ty  = read_u1(&p);
                    val = read_val(&p, ty);
                    check_printf("  static field %d: ", i);
                    check_print_utf8(utab, "id=", id);
                    check_printf(", ty=%d, val=", ty);
                    check_printf_val(ty, val, 1);
                    check_printf("\n");
                }

                num_elements = read_u2(&p);
                check_printf("  instance_field_count=%d\n", num_elements);
                for(i=0; i<num_elements; i++) {
                    HprofType ty;
                    HprofId   id;

                    id = read_id(&p);
                    ty = read_u1(&p);
                    check_printf("  instance_field %d: ", i);
                    check_print_utf8(utab, "id=", id);
                    check_printf(", ty=%d\n", ty);
                }
                break;
            CASE_HEAP(HPROF_GC_INSTANCE_DUMP)
                id = read_id(&p);
                trace_serial_num = read_u4(&p);
                CHECK_TRACE_SERIAL_NO(trace_serial_num);
                id2 = read_id(&p); /* class id */
                num_bytes = read_u4(&p);
                check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u,"
                             " cid=0x%x, nbytes=%d\n",
                            nrecords, npos, label, id, trace_serial_num,
                            id2, num_bytes);
                /* This is a packed set of bytes for the instance fields */
                if ( num_bytes > 0 ) {
                    TableIndex cindex;
                    int        ifield;
                    CmapInfo  *map;

                    cindex = table_find_entry(ctab, &id2, sizeof(id2));
                    HPROF_ASSERT(cindex!=0);
                    map = (CmapInfo*)table_get_info(ctab, cindex);
                    HPROF_ASSERT(map!=NULL);
                    HPROF_ASSERT(num_bytes==map->inst_size);

                    psave  = p;
                    ifield = 0;

                    do {
                        for(i=0;i<map->n_finfo;i++) {
                            HprofType ty;
                            HprofId   id;
                            jvalue    val;

                            ty = map->finfo[i].ty;
                            id = map->finfo[i].id;
                            HPROF_ASSERT(ty!=0);
                            HPROF_ASSERT(id!=0);
                            val = read_val(&p, ty);
                            check_printf("  field %d: ", ifield);
                            check_print_utf8(utab, "id=", id);
                            check_printf(", ty=%d, val=", ty);
                            check_printf_val(ty, val, 1);
                            check_printf("\n");
                            ifield++;
                        }
                        id2    = map->sup;
                        map    = NULL;
                        cindex = 0;
                        if ( id2 != 0 ) {
                            cindex = table_find_entry(ctab, &id2, sizeof(id2));
                            HPROF_ASSERT(cindex!=0);
                            map = (CmapInfo*)table_get_info(ctab, cindex);
                            HPROF_ASSERT(map!=NULL);
                        }
                    } while ( map != NULL );
                    HPROF_ASSERT(num_bytes==(p-psave));
                }
                break;
            CASE_HEAP(HPROF_GC_OBJ_ARRAY_DUMP)
                id = read_id(&p);
                trace_serial_num = read_u4(&p);
                CHECK_TRACE_SERIAL_NO(trace_serial_num);
                num_elements = read_u4(&p);
                id2 = read_id(&p);
                check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u, nelems=%d, eid=0x%x\n",
                                nrecords, npos, label, id, trace_serial_num, num_elements, id2);
                for(i=0; i<num_elements; i++) {
                    HprofId id;

                    id = read_id(&p);
                    check_printf("  [%d]: id=0x%x\n", i, id);
                }
                break;
            CASE_HEAP(HPROF_GC_PRIM_ARRAY_DUMP)
                id = read_id(&p);
                trace_serial_num = read_u4(&p);
                CHECK_TRACE_SERIAL_NO(trace_serial_num);
                num_elements = read_u4(&p);
                ty = read_u1(&p);
                psave = p;
                check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u, "
                             "nelems=%d, ty=%d\n",
                                nrecords, npos, label, id, trace_serial_num, num_elements, ty);
                HPROF_ASSERT(HPROF_TYPE_IS_PRIMITIVE(ty));
                if ( num_elements > 0 ) {
                    int   count;
                    int   long_form;
                    int   max_count;
                    char *quote;

                    quote     = "";
                    long_form = 1;
                    max_count = 8;
                    count     = 0;
                    switch ( ty ) {
                        case HPROF_CHAR:
                            long_form = 0;
                            max_count = 72;
                            quote     = "\"";
                            /*FALLTHRU*/
                        case HPROF_INT:
                        case HPROF_DOUBLE:
                        case HPROF_LONG:
                        case HPROF_BYTE:
                        case HPROF_BOOLEAN:
                        case HPROF_SHORT:
                        case HPROF_FLOAT:
                            check_printf("  val=%s", quote);
                            for(i=0; i<num_elements; i++) {
                                jvalue val;

                                if ( i > 0 && count == 0 ) {
                                    check_printf("  %s", quote);
                                }
                                val = read_val(&p, ty);
                                check_printf_val(ty, val, long_form);
                                count += 1;
                                if ( count >= max_count ) {
                                    check_printf("\"\n");
                                    count = 0;
                                }
                            }
                            if ( count != 0 ) {
                                check_printf("%s\n", quote);
                            }
                            break;
                    }
                }
                HPROF_ASSERT(type_size[ty]*num_elements==(p-psave));
                break;
            default:
                label = "UNKNOWN";
                check_printf("H#%d@%d %s: ERROR!\n",
                                nrecords, npos, label);
                HPROF_ERROR(JNI_TRUE, "unknown heap record type");
                break;
        }
    }
    CHECK_FOR_ERROR(p==pstart+nbytes);

    table_cleanup(ctab, &cmap_cleanup, NULL);

    return nrecords;
}
static wiced_result_t smartbridge_att_cache_discover_all( bt_smartbridge_att_cache_t* cache, uint16_t connection_handle )
{
    /* This function performs the following:
     * 1. Primary Services discovery
     * 2. Relationship (Included Services) Discovery for every Primary Service
     * 3. Characteristic Discovery for every Primary Service
     * 4. Characteristic Value Read for every Charactertistic
     * 5. Characteristic Descriptor Discovery for every Characteristic
     */

    wiced_bt_smart_attribute_t**     primary_service_array    = NULL;
    wiced_bt_smart_attribute_t**     characteristic_array     = NULL;
    wiced_bt_smart_attribute_t*      characteristic_value     = NULL;
    wiced_bt_smart_attribute_t*      descriptor_with_no_value = NULL;
    wiced_bt_smart_attribute_t*      descriptor_with_value    = NULL;
    wiced_bt_smart_attribute_t*      iterator                 = NULL;
    wiced_result_t                   result                   = WICED_SUCCESS;
    wiced_result_t                   error_code_var           = WICED_ERROR;
    uint32_t                         i                        = 0;
    uint32_t                         j                        = 0;
    uint32_t                         primary_service_count    = 0;
    uint32_t                         characteristic_count     = 0;
    wiced_bt_smart_attribute_list_t  primary_service_list;
    wiced_bt_smart_attribute_list_t  included_service_list;
    wiced_bt_smart_attribute_list_t  characteristic_list;
    wiced_bt_smart_attribute_list_t  descriptor_list;

    if ( att_cache_manager == NULL )
    {
        return WICED_BT_ATT_CACHE_UNINITIALISED;
    }

    /* Initialise local variables */
    memset( &primary_service_list,  0, sizeof( primary_service_list  ) );
    memset( &included_service_list, 0, sizeof( included_service_list ) );
    memset( &characteristic_list,   0, sizeof( characteristic_list   ) );
    memset( &descriptor_list,       0, sizeof( descriptor_list       ) );

    wiced_rtos_lock_mutex( &cache->mutex );

    result = wiced_bt_smart_attribute_create_list( &primary_service_list );

    wiced_rtos_unlock_mutex( &cache->mutex );

    CHECK_FOR_ERROR( result != WICED_BT_SUCCESS, result );

    /**************************************************************************
     * Primary Services Discovery
     **************************************************************************/
    result = bt_smart_gatt_discover_all_primary_services( connection_handle, &primary_service_list );

    CHECK_FOR_ERROR( result != WICED_BT_SUCCESS, result );

    wiced_bt_smart_attribute_get_list_count( &primary_service_list, &primary_service_count );

    primary_service_array = (wiced_bt_smart_attribute_t**)malloc_named( "svc_array", primary_service_count * sizeof(wiced_bt_smart_attribute_t));

    CHECK_FOR_ERROR( primary_service_array == NULL, WICED_BT_OUT_OF_HEAP_SPACE );

    /* Keep the original pointers to the primary service list before the list gets merged */
    wiced_bt_smart_attribute_get_list_head( &primary_service_list, &iterator );

    for ( i = 0; i < primary_service_count; i++ )
    {
        primary_service_array[i] = iterator;
        iterator                 = iterator->next;
    }

    /* Check if characteristic is readable. If not readable, create a control-point attribute */
    for ( i = 0; i < primary_service_count; i++ )
    {
        /* Initialise variable for this iteration */
        memset( &characteristic_list,   0, sizeof( characteristic_list   ) );
        memset( &included_service_list, 0, sizeof( included_service_list ) );
        characteristic_array = NULL;

        /**********************************************************************
         * Relationship Discovery
         **********************************************************************/
        result = bt_smart_gatt_find_included_services( connection_handle, primary_service_array[i]->value.service.start_handle, primary_service_array[i]->value.service.start_handle, &included_service_list );

        CHECK_FOR_ERROR( result == WICED_BT_GATT_TIMEOUT, result );

        wiced_rtos_lock_mutex( &cache->mutex );

        result = wiced_bt_smart_attribute_merge_lists( &primary_service_list, &included_service_list );

        wiced_rtos_unlock_mutex( &cache->mutex );

        CHECK_FOR_ERROR( result != WICED_BT_SUCCESS, result );

        /**********************************************************************
         * Characteristic Discovery
         **********************************************************************/
        result = bt_smart_gatt_discover_all_characteristics_in_a_service( connection_handle, primary_service_array[i]->value.service.start_handle, primary_service_array[i]->value.service.end_handle, &characteristic_list );

        CHECK_FOR_ERROR( result == WICED_BT_GATT_TIMEOUT, result );

        wiced_bt_smart_attribute_get_list_count( &characteristic_list, &characteristic_count );

        characteristic_array = (wiced_bt_smart_attribute_t**)malloc_named( "char_array", characteristic_count * sizeof(characteristic_list));

        CHECK_FOR_ERROR( characteristic_array == NULL, WICED_BT_OUT_OF_HEAP_SPACE );

        /* Keep the original pointers to the characteristic list before the list gets merged. */
        wiced_bt_smart_attribute_get_list_head( &characteristic_list, &iterator );

        for ( j = 0; j < characteristic_count; j++ )
        {
            characteristic_array[j] = iterator;
            iterator                = iterator->next;
        }

        /* Traverse through all characteristics to perform Characteristic Value Read and Descriptors Discovery */
        for ( j = 0; j < characteristic_count; j++ )
        {
            /* Initialise local variables for this iteration */
            memset( &descriptor_list, 0, sizeof( descriptor_list ) );
            characteristic_value = NULL;

            /******************************************************************
             * Characteristic Value Read
             ******************************************************************/
            if ( ( characteristic_array[j]->value.characteristic.properties & 0x02 ) != 0 )
            {
                /* If characteristic is readable. If not readable, create a control-point attribute */
                result = bt_smart_gatt_read_characteristic_value( connection_handle, characteristic_array[j]->value.characteristic.value_handle, &characteristic_array[j]->value.characteristic.uuid, &characteristic_value );

                CHECK_FOR_ERROR( result == WICED_BT_GATT_TIMEOUT, result );
            }
            else
            {
                /* Failed to read. Let's enter a control-point attribute (dummy) here so when notification come, UUID is known. */
                result = wiced_bt_smart_attribute_create( &characteristic_value, WICED_ATTRIBUTE_TYPE_NO_VALUE, 0 );

                if ( result == WICED_BT_SUCCESS )
                {
                    characteristic_value->handle = characteristic_array[j]->value.characteristic.value_handle;
                    characteristic_value->type   = characteristic_array[j]->value.characteristic.uuid;
                }

                CHECK_FOR_ERROR( result != WICED_BT_SUCCESS, result );
            }

            if ( characteristic_value != NULL )
            {
                /* Add Characteristic Value to main list */
                wiced_rtos_lock_mutex( &cache->mutex );

                result = wiced_bt_smart_attribute_add_to_list( &primary_service_list, characteristic_value );

                wiced_rtos_unlock_mutex( &cache->mutex );

                CHECK_FOR_ERROR( result != WICED_BT_SUCCESS, result );
            }

            /******************************************************************
             * Characteristic Descriptor Discovery
             ******************************************************************/
            if ( characteristic_array[j]->value.characteristic.descriptor_start_handle <= characteristic_array[j]->value.characteristic.descriptor_end_handle )
            {
                result = bt_smart_gatt_discover_all_characteristic_descriptors( connection_handle, characteristic_array[j]->value.characteristic.descriptor_start_handle, characteristic_array[j]->value.characteristic.descriptor_end_handle, &descriptor_list );

                CHECK_FOR_ERROR( result == WICED_BT_GATT_TIMEOUT, result );

                wiced_bt_smart_attribute_get_list_head( &descriptor_list, &descriptor_with_no_value );

                /* Traverse through all descriptors */
                while ( descriptor_with_no_value != NULL )
                {
                    /* Initialise variable for this iteration */
                    descriptor_with_value = NULL;

                    result = bt_smart_gatt_read_characteristic_descriptor( connection_handle, descriptor_with_no_value->handle, &descriptor_with_no_value->type, &descriptor_with_value );

                    CHECK_FOR_ERROR( result == WICED_BT_GATT_TIMEOUT, result );

                    /* Add Descriptor with Value to main list */
                    result = wiced_bt_smart_attribute_add_to_list( &primary_service_list, descriptor_with_value );

                    CHECK_FOR_ERROR( result != WICED_BT_SUCCESS, result );

                    descriptor_with_no_value = descriptor_with_no_value->next;
                }

                /* Delete the empty descriptor list */
                result = wiced_bt_smart_attribute_delete_list( &descriptor_list );

                CHECK_FOR_ERROR( result != WICED_BT_SUCCESS, result );
            }
        }

        /* Merge Characteristics to main list */
        wiced_rtos_lock_mutex( &cache->mutex );

        result = wiced_bt_smart_attribute_merge_lists( &primary_service_list, &characteristic_list );

        wiced_rtos_unlock_mutex( &cache->mutex );

        CHECK_FOR_ERROR( result != WICED_BT_SUCCESS, result );

        /* Free primary service array */
        free( characteristic_array );
    }

    /* Free primary service array */
    free( primary_service_array );

    /* Successful. Now copy the primary service list to the cached attributes list */
    memcpy( &cache->attribute_list, &primary_service_list, sizeof( cache->attribute_list ) );

    return WICED_BT_SUCCESS;

    error:


    /* Delete all local attributes */
    if ( iterator != NULL )
    {
        wiced_bt_smart_attribute_delete( iterator );
    }

    if ( descriptor_with_no_value != NULL )
    {
        wiced_bt_smart_attribute_delete( descriptor_with_no_value );
    }

    if ( descriptor_with_value != NULL )
    {
        wiced_bt_smart_attribute_delete( descriptor_with_value );
    }

    if ( characteristic_value != NULL )
    {
        wiced_bt_smart_attribute_delete( characteristic_value );
    }

    if ( characteristic_array != NULL )
    {
        free( characteristic_array );
    }

    if ( primary_service_array != NULL )
    {
        free( primary_service_array );
    }

    wiced_bt_smart_attribute_delete_list( &descriptor_list );
    wiced_bt_smart_attribute_delete_list( &characteristic_list );
    wiced_bt_smart_attribute_delete_list( &included_service_list );
    wiced_bt_smart_attribute_delete_list( &primary_service_list );

    /* Return the error code to the caller */
    return error_code_var;
}
Exemplo n.º 6
0
static OSStatus smartbridge_att_cache_discover_all( bt_smartbridge_att_cache_t* cache, uint16_t connection_handle )
{
    /* This function performs the following:
     * 1. Primary Services discovery
     * 2. Relationship (Included Services) Discovery for every Primary Service
     * 3. Characteristic Discovery for every Primary Service
     * 4. Characteristic Value Read for every Charactertistic
     * 5. Characteristic Descriptor Discovery for every Characteristic
     */

    mico_bt_smart_attribute_t**     primary_service_array    = NULL;
    mico_bt_smart_attribute_t**     characteristic_array     = NULL;
    mico_bt_smart_attribute_t*      characteristic_value     = NULL;
    mico_bt_smart_attribute_t*      descriptor_with_no_value = NULL;
    mico_bt_smart_attribute_t*      descriptor_with_value    = NULL;
    mico_bt_smart_attribute_t*      iterator                 = NULL;
    OSStatus                         result                   = MICO_BT_SUCCESS;
    OSStatus                         error_code_var           = MICO_BT_ERROR;
    uint32_t                         i                        = 0;
    uint32_t                         j                        = 0;
    uint32_t                         primary_service_count    = 0;
    uint32_t                         characteristic_count     = 0;
    mico_bt_smart_attribute_list_t  primary_service_list;
    mico_bt_smart_attribute_list_t  branch_primary_service_list;
    mico_bt_smart_attribute_list_t  included_service_list;
    mico_bt_smart_attribute_list_t  characteristic_list;
    mico_bt_smart_attribute_list_t  descriptor_list;

    mico_bool_t characteristic_list_merged = MICO_FALSE;
    mico_bool_t included_service_list_merged = MICO_FALSE;

    if ( att_cache_manager == NULL )
    {
        return MICO_BT_ATT_CACHE_UNINITIALISED;
    }

    /* Initialise local variables */
    memset( &primary_service_list,          0, sizeof( primary_service_list  ) );
    memset( &branch_primary_service_list,   0, sizeof( primary_service_list  ) );
    memset( &included_service_list,         0, sizeof( included_service_list ) );
    memset( &characteristic_list,           0, sizeof( characteristic_list   ) );
    memset( &descriptor_list,               0, sizeof( descriptor_list       ) );

    mico_rtos_lock_mutex( &cache->mutex );

    result = mico_bt_smart_attribute_create_list( &primary_service_list );

    mico_rtos_unlock_mutex( &cache->mutex );

    CHECK_FOR_ERROR( result != MICO_BT_SUCCESS, result );

    /**************************************************************************
     * Primary Services Discovery
     **************************************************************************/
    if( att_cache_manager->att_cache_services_count == 0 )
    {
        result = smartbridge_bt_interface_discover_all_primary_services( connection_handle, &primary_service_list );
        CHECK_FOR_ERROR( result != MICO_BT_SUCCESS, result );
    }
    else
    {
        for ( i = 0; i < att_cache_manager->att_cache_services_count; i++ )
        {
            result = smartbridge_bt_interface_discover_primary_services_by_uuid( connection_handle, &att_cache_manager->att_cache_services[i], &branch_primary_service_list );
            CHECK_FOR_ERROR( result != MICO_BT_SUCCESS, result );
            result = mico_bt_smart_attribute_merge_lists( &primary_service_list, &branch_primary_service_list );
            CHECK_FOR_ERROR( result != MICO_BT_SUCCESS, result );
        }
    }

    mico_bt_smart_attribute_get_list_count( &primary_service_list, &primary_service_count );

    primary_service_array = (mico_bt_smart_attribute_t**)malloc_named( "svc_array", primary_service_count * sizeof(mico_bt_smart_attribute_t));

    CHECK_FOR_ERROR( primary_service_array == NULL, MICO_BT_OUT_OF_HEAP_SPACE );

    /* Keep the original pointers to the primary service list before the list gets merged */
    mico_bt_smart_attribute_get_list_head( &primary_service_list, &iterator );

    for ( i = 0; i < primary_service_count; i++ )
    {
        primary_service_array[i] = iterator;
        iterator                 = iterator->next;
    }

    bt_smartbridge_log( "[Cache] All services discovered. count: %u",(unsigned int) primary_service_count );

    /* Check if characteristic is readable. If not readable, create a control-point attribute */
    for ( i = 0; i < primary_service_count; i++ )
    {
        /* Initialise variable for this iteration */
        memset( &characteristic_list,   0, sizeof( characteristic_list   ) );
        memset( &included_service_list, 0, sizeof( included_service_list ) );
        characteristic_array = NULL;

        /**********************************************************************
         * Relationship Discovery
         **********************************************************************/
        /*result = bt_smart_gatt_find_included_services( connection_handle, primary_service_array[i]->value.service.start_handle, primary_service_array[i]->value.service.start_handle, &included_service_list );

        CHECK_FOR_ERROR( result == MICO_BT_GATT_TIMEOUT, result );

        mico_rtos_lock_mutex( &cache->mutex );

        result = mico_bt_smart_attribute_merge_lists( &primary_service_list, &included_service_list );

        if( result == MICO_BT_SUCCES )
        {
            included_service_list_merged = MICO_TRUE;
        }

        mico_rtos_unlock_mutex( &cache->mutex );

        CHECK_FOR_ERROR( result != MICO_BT_SUCCESS, result );
        */

        /**********************************************************************
         * Characteristic Discovery
         **********************************************************************/
        result = smartbridge_bt_interface_discover_all_characteristics_in_a_service( connection_handle, primary_service_array[i]->value.service.start_handle, primary_service_array[i]->value.service.end_handle, &characteristic_list );

        CHECK_FOR_ERROR( result == MICO_BT_GATT_TIMEOUT || result == MICO_BT_TIMEOUT, result );

        mico_bt_smart_attribute_get_list_count( &characteristic_list, &characteristic_count );


        characteristic_array = (mico_bt_smart_attribute_t**)malloc_named( "char_array", characteristic_count * sizeof(characteristic_list));

        CHECK_FOR_ERROR( characteristic_array == NULL, MICO_BT_OUT_OF_HEAP_SPACE );

        /* Keep the original pointers to the characteristic list before the list gets merged. */
        mico_bt_smart_attribute_get_list_head( &characteristic_list, &iterator );

        for ( j = 0; j < characteristic_count; j++ )
        {
            characteristic_array[j] = iterator;
            iterator                = iterator->next;
        }

        /* Traverse through all characteristics to perform Characteristic Value Read and Descriptors Discovery */
        for ( j = 0; j < characteristic_count; j++ )
        {
            /* Initialise local variables for this iteration */
            memset( &descriptor_list, 0, sizeof( descriptor_list ) );
            characteristic_value = NULL;

            /******************************************************************
             * Characteristic Value Read
             ******************************************************************/
            if ( ( characteristic_array[j]->value.characteristic.properties & 0x02 ) != 0 )
            {
                bt_smartbridge_log( "[Cache] Characteristic Read-Property IS set" );
                /* If characteristic is readable. If not readable, create a control-point attribute */
                result = smartbridge_bt_interface_read_characteristic_value( connection_handle, characteristic_array[j]->value.characteristic.value_handle, &characteristic_array[j]->value.characteristic.uuid, &characteristic_value );

                CHECK_FOR_ERROR( result == MICO_BT_GATT_TIMEOUT || result == MICO_BT_TIMEOUT, result );
            }
            else
            {
                bt_smartbridge_log( "[Cache] Characteristic Read-Properties is NOT set" );
                /* Failed to read. Let's enter a control-point attribute (dummy) here so when notification come, UUID is known. */
                result = mico_bt_smart_attribute_create( &characteristic_value, MICO_ATTRIBUTE_TYPE_NO_VALUE, 0 );

                if ( result == MICO_BT_SUCCESS )
                {
                    characteristic_value->handle = characteristic_array[j]->value.characteristic.value_handle;
                    characteristic_value->type   = characteristic_array[j]->value.characteristic.uuid;
                }

                CHECK_FOR_ERROR( result != MICO_BT_SUCCESS, result );
            }

            if ( characteristic_value != NULL )
            {
                /* Add Characteristic Value to main list */
                mico_rtos_lock_mutex( &cache->mutex );

                /* Add characteristic_value to main list */
                result = mico_bt_smart_attribute_add_to_list( &primary_service_list, characteristic_value );

                /* Merge success, it will be deleted by primary_service_list when error */
                if( result == MICO_BT_SUCCESS )
                {
                    characteristic_value = NULL;
                }

                mico_rtos_unlock_mutex( &cache->mutex );

                CHECK_FOR_ERROR( result != MICO_BT_SUCCESS, result );
            }
            /******************************************************************
             * Characteristic Descriptor Discovery
             ******************************************************************/
             
            /* If descriptor_start_handle is equal to the next characteristic's handle, stop, add by william  */
            if( (j < (characteristic_count - 1)) && (characteristic_array[j]->value.characteristic.descriptor_end_handle >= characteristic_array[j+1]->handle) )
                continue;

            /* If descriptor_start_handle is equal to the next service handle, stop, add by william  */
            if( (j == (characteristic_count - 1)) && (i < (primary_service_count - 1))&& (characteristic_array[j]->value.characteristic.descriptor_end_handle >= primary_service_array[i+1]->handle) )
                continue;


            if ( characteristic_array[j]->value.characteristic.descriptor_start_handle <= characteristic_array[j]->value.characteristic.descriptor_end_handle )
            {
                result = smartbridge_bt_interface_discover_all_characteristic_descriptors( connection_handle, characteristic_array[j]->value.characteristic.descriptor_start_handle, characteristic_array[j]->value.characteristic.descriptor_end_handle, &descriptor_list );

                CHECK_FOR_ERROR( result == MICO_BT_GATT_TIMEOUT || result == MICO_BT_TIMEOUT, result );

                mico_bt_smart_attribute_get_list_head( &descriptor_list, &descriptor_with_no_value );

                /* Traverse through all descriptors */
                while ( descriptor_with_no_value != NULL )
                {
                    /* Initialise variable for this iteration */
                    descriptor_with_value = NULL;

                    result = smartbridge_bt_interface_read_characteristic_descriptor( connection_handle, descriptor_with_no_value->handle, &descriptor_with_no_value->type, &descriptor_with_value );

                    CHECK_FOR_ERROR( result == MICO_BT_GATT_TIMEOUT || result == MICO_BT_TIMEOUT, result );

                    /* Add Descriptor with Value to main list */
                    result = mico_bt_smart_attribute_add_to_list( &primary_service_list, descriptor_with_value );

                    /* Merge success, it will be deleted by primary_service_list when error */
                    if( result == MICO_BT_SUCCESS )
                    {
                        descriptor_with_value = NULL;
                    }

                    CHECK_FOR_ERROR( result != MICO_BT_SUCCESS, result );

                    descriptor_with_no_value = descriptor_with_no_value->next;
                }

                /* Delete the empty descriptor list */
                result = mico_bt_smart_attribute_delete_list( &descriptor_list );

                CHECK_FOR_ERROR( result != MICO_BT_SUCCESS, result );
            }
        }

        /* Merge Characteristics to main list */
        mico_rtos_lock_mutex( &cache->mutex );

        result = mico_bt_smart_attribute_merge_lists( &primary_service_list, &characteristic_list );

        if( result == MICO_BT_SUCCESS )
        {
            characteristic_list_merged = MICO_TRUE;
        }

        mico_rtos_unlock_mutex( &cache->mutex );

        CHECK_FOR_ERROR( result != MICO_BT_SUCCESS, result );

        /* Free primary service array */
        free( characteristic_array );
    }

    /* Free primary service array */
    free( primary_service_array );

    /* Successful. Now copy the primary service list to the cached attributes list */
    memcpy( &cache->attribute_list, &primary_service_list, sizeof( cache->attribute_list ) );

    //mico_bt_smart_attribute_print_list( &(cache->attribute_list) );

    return MICO_BT_SUCCESS;

    error:


    /* Delete all local attributes */

    if ( descriptor_with_value != NULL )
    {
        mico_bt_smart_attribute_delete( descriptor_with_value );
    }

    if ( characteristic_value != NULL )
    {
        mico_bt_smart_attribute_delete( characteristic_value );
    }

    if ( characteristic_array != NULL )
    {
        free( characteristic_array );
    }

    if ( primary_service_array != NULL )
    {
        free( primary_service_array );
    }

    if( characteristic_list_merged == MICO_FALSE )
    {
        mico_bt_smart_attribute_delete_list( &characteristic_list );
    }

    if( included_service_list_merged == MICO_FALSE )
    {
        mico_bt_smart_attribute_delete_list( &included_service_list );
    }

    mico_bt_smart_attribute_delete_list( &descriptor_list );
    mico_bt_smart_attribute_delete_list( &primary_service_list );

    /* Return the error code to the caller */
    return error_code_var;
}