static void fillThreadsAndLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { int n = 0, i = 0; // add threads n = get_num_threads(ph); for (i = 0; i < n; i++) { jobject thread; jobject threadList; lwpid_t lwpid; lwpid = get_lwp_id(ph, i); thread = (*env)->CallObjectMethod(env, this_obj, getThreadForThreadId_ID, (jlong)lwpid); CHECK_EXCEPTION; threadList = (*env)->GetObjectField(env, this_obj, threadList_ID); CHECK_EXCEPTION; (*env)->CallBooleanMethod(env, threadList, listAdd_ID, thread); CHECK_EXCEPTION; } // add load objects n = get_num_libs(ph); for (i = 0; i < n; i++) { uintptr_t base; const char* name; jobject loadObject; jobject loadObjectList; base = get_lib_base(ph, i); name = get_lib_name(ph, i); loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID, (*env)->NewStringUTF(env, name), (jlong)0, (jlong)base); CHECK_EXCEPTION; loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID); CHECK_EXCEPTION; (*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject); CHECK_EXCEPTION; } }
/* Parses gdb's stdout fd after requesting a backtrace. The result is stored in a linked list of FuncInfo structures. */ static List * parse_stack_trace (int gdb) { int i; int parentheses_are_off = 0; char c; char buf[4096]; List *stack = NULL; FuncInfo *f; List *libs = NULL; SharedLib *lib; enum { NONE, ADDR, FUNC, ARGS, FILE, LINE, LIB, QUOTE, FROMADDR, TOADDR, SYMS, SONAME } state = NONE, prev_state = NONE; while (read(gdb, &c, 1)) { switch (state) { case NONE: if (c == '#') { f = calloc(sizeof (FuncInfo), 1); while (read(gdb, &c, 1)) if (!isdigit(c)) break; while (read(gdb, &c, 1)) if (!isspace(c)) { buf[0] = c; i = 1; state = isdigit(c) ? ADDR : FUNC; break; } } else if (!stack && c == '0') { lib = calloc(sizeof (SharedLib), 1); state = FROMADDR; buf[0] = c; i = 1; } else if (stack && c == '(') { read(gdb, buf, 3); if (!strncmp(buf, "gdb", 3)) goto done; } else if (!stack && c == 'N') { read(gdb, buf, 7); if (!strncmp(buf, "o stack", 7)) goto done; } break; case FROMADDR: if (!isspace(c)) { buf[i++] = c; } else { buf[i] = 0; i = 0; sscanf(buf, "%p", &lib->from); read(gdb, buf, 1); state = TOADDR; } break; case TOADDR: if (!isspace(c)) { buf[i++] = c; } else { buf[i] = 0; i = 0; sscanf(buf, "%p", &lib->to); read(gdb, buf, 1); state = SYMS; } break; case SYMS: if (!isspace(c)) { buf[i++] = c; } else { buf[i] = 0; i = 0; if (eq(buf, "Yes")) lib->readsyms = 1; read(gdb, buf, 3); if (strncmp(buf, "(*)", 3)) lib->dbinfo = 1; while (read(gdb, &c, 1)) if (!isspace(c)) { buf[0] = c; i = 1; break; } state = SONAME; } break; case SONAME: if (c != '\n') { buf[i++] = c; } else { buf[i] = 0; i = 0; lib->name = strdup(buf); libs = list_push(libs, lib); state = NONE; } break; case ADDR: if (!isspace(c)) { buf[i++] = c; } else { buf[i] = 0; i = 0; sscanf(buf, "%p", &f->addr); f->lib = get_lib_name(libs, f->addr); read(gdb, buf, 3); state = FUNC; } break; case FUNC: if (!isspace(c)) { buf[i++] = c; } else { buf[i] = 0; i = 0; f->func = strdup(buf); state = ARGS; } break; case ARGS: buf[i++] = c; if (c == '(') parentheses_are_off++; else if (c == ')') { parentheses_are_off--; if (parentheses_are_off) continue; buf[i] = 0; i = 0; f->args = strdup(buf); read(gdb, &c, 1); if (c == '\n') { stack = list_push(stack, f); state = NONE; break; } read(gdb, buf, 3); if (!strncmp(buf, "at ", 3)) { state = FILE; } else if (!strncmp(buf, "fro", 3)) { state = LIB; read(gdb, buf, 2); } else { free(f); state = NONE; } } else if (c == '"') { prev_state = ARGS; state = QUOTE; } break; case QUOTE: buf[i++] = c; if (c == '\\') { read(gdb, &c, 1); buf[i++] = c; } else if (c == '"') state = prev_state; break; case LIB: if (!isspace(c)) { buf[i++] = c; } else { buf[i] = 0; i = 0; if (!f->lib) f->lib = strdup(buf); stack = list_push(stack, f); state = NONE; } break; case FILE: if (c != ':') { buf[i++] = c; } else { buf[i] = 0; i = 0; f->file = strdup(buf); state = LINE; } break; case LINE: if (isdigit(c)) { buf[i++] = c; } else { buf[i] = 0; i = 0; f->line = atoi(buf); stack = list_push(stack, f); state = NONE; } break; } } done: list_free(libs, shared_lib_free); return stack; }