From deb012d919ea6c5e79702a39a03a85be2ffcf406 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sat, 18 Feb 2012 16:41:31 +0000 Subject: Retrieved the frames stack from the running process. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@235 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 30 +++++++++ plugins/pyoida/debug/debugger.c | 40 ++++++++++-- plugins/python/exectracer/exectracer.py | 10 +++ src/debug/debugger-int.h | 4 ++ src/debug/debugger.c | 31 +++++++++ src/debug/debugger.h | 14 +++++ src/debug/jdwp/debugger.c | 79 +++++++++++++++++++++++ src/debug/jdwp/jdwp_def.h | 42 +++++++++++++ src/debug/jdwp/misc/Makefile.am | 1 + src/debug/jdwp/misc/location.c | 64 +++++++++++++++++++ src/debug/jdwp/misc/location.h | 40 ++++++++++++ src/debug/jdwp/sets/list.c | 7 +++ src/debug/jdwp/sets/list.h | 2 + src/debug/jdwp/sets/thread.c | 108 +++++++++++++++++++++++++++++++- src/debug/jdwp/sets/thread.h | 9 +++ 15 files changed, 475 insertions(+), 6 deletions(-) create mode 100644 src/debug/jdwp/misc/location.c create mode 100644 src/debug/jdwp/misc/location.h diff --git a/ChangeLog b/ChangeLog index 4db2e5b..6e6735a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +12-02-18 Cyrille Bagard + + * plugins/pyoida/debug/debugger.c: + * plugins/python/exectracer/exectracer.py: + * src/debug/debugger.c: + * src/debug/debugger.h: + * src/debug/debugger-int.h: + * src/debug/jdwp/debugger.c: + Retrieve the frames stack from the running process. + + * src/debug/jdwp/jdwp_def.h: + Support the Frames command. + + * src/debug/jdwp/misc/location.c: + * src/debug/jdwp/misc/location.h: + New entries: load JVM locations. + + * src/debug/jdwp/misc/Makefile.am: + Add the location.[ch] files to libdebugjdwpmisc_la_SOURCES. + + * src/debug/jdwp/sets/list.c: + * src/debug/jdwp/sets/list.h: + Extend the payload with new requests/replies. + + * src/debug/jdwp/sets/thread.c: + Fix a bug when getting a thread name. Get all frames of a given thread. + + * src/debug/jdwp/sets/thread.h: + Get all frames of a given thread. + 12-02-17 Cyrille Bagard * plugins/pyoida/debug/debugger.c: diff --git a/plugins/pyoida/debug/debugger.c b/plugins/pyoida/debug/debugger.c index 75de6d8..3e42ab7 100644 --- a/plugins/pyoida/debug/debugger.c +++ b/plugins/pyoida/debug/debugger.c @@ -25,6 +25,7 @@ #include "debugger.h" +#include #include @@ -36,7 +37,7 @@ static PyObject *py_binary_debugger_list_all_threads(PyObject *, PyObject *); /* Fournit la pile d'exécution courante via un débogueur. */ -static PyObject *py_binary_debugger_get_current_stack(PyObject *, PyObject *); +static PyObject *py_binary_debugger_get_frames_stack(PyObject *, PyObject *); @@ -171,9 +172,38 @@ static PyObject *py_binary_debugger_list_all_threads(PyObject *self, PyObject *a * * ******************************************************************************/ -static PyObject *py_binary_debugger_get_current_stack(PyObject *self, PyObject *args) +static PyObject *py_binary_debugger_get_frames_stack(PyObject *self, PyObject *args) { - return PyLong_FromLong(23); + PyObject *result; /* Trouvailles à retourner */ + GBinaryDebugger *debugger; /* Version native */ + unsigned long thread; /* Identifiant du thread visé */ + size_t count; /* Taille de cette liste */ + dbg_frame_t *frames; /* Frames courantes trouvées */ + size_t i; /* Boucle de parcours */ + PyObject *frame; /* Détails sur une frame */ + + debugger = G_BINARY_DEBUGGER(pygobject_get(self)); + + if (!PyArg_ParseTuple(args, "k", &thread)) + return Py_None; + + frames = g_binary_debugger_get_frames_stack(debugger, thread, &count); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { + frame = PyTuple_New(1); + PyTuple_SetItem(result, i, frame); + + PyTuple_SetItem(frame, 0, PyLong_FromUnsignedLongLong(frames[i].addr)); + + } + + if (frames != NULL) + free(frames); + + return result; } @@ -205,8 +235,8 @@ bool register_python_binary_debugger(PyObject *module) "List all current active threads." }, { - "get_current_stack", (PyCFunction)py_binary_debugger_get_current_stack, - METH_NOARGS, + "get_frames_stack", (PyCFunction)py_binary_debugger_get_frames_stack, + METH_VARARGS, "Provide the current callstack using a debugger." }, { NULL } diff --git a/plugins/python/exectracer/exectracer.py b/plugins/python/exectracer/exectracer.py index 898f0be..76e2ce4 100644 --- a/plugins/python/exectracer/exectracer.py +++ b/plugins/python/exectracer/exectracer.py @@ -21,3 +21,13 @@ class ExecTracer(Plugin): for i in debugger.list_all_threads(): print "Thread %d '%s'" % (i[0], i[1]) + + frames = debugger.get_frames_stack(i[0]) + + for frame in frames: + print " 0x%08x" % frame[0] + + if len(frames) == 0: + print " -" + + diff --git a/src/debug/debugger-int.h b/src/debug/debugger-int.h index 490b35c..f6f51ad 100644 --- a/src/debug/debugger-int.h +++ b/src/debug/debugger-int.h @@ -44,6 +44,9 @@ typedef bool (* resume_debugger_fc) (GBinaryDebugger *); /* Fournit les identifiants de tous les threads actifs. */ typedef pid_t * (* dbg_list_all_threads_fc) (GBinaryDebugger *, char ***, size_t *); +/* Fournit la liste des frames courantes d'un thread donné. */ +typedef dbg_frame_t * (* dbg_get_frames_stack_fc) (GBinaryDebugger *, pid_t, size_t *); + /* Fournit la valeur des registres de l'architecture. */ typedef register_value * (* get_register_values_fc) (GBinaryDebugger *, size_t *); @@ -63,6 +66,7 @@ struct _GBinaryDebugger basic_debugger_fc kill; /* Tue le débogueur */ dbg_list_all_threads_fc all_threads; /* Liste des threads actifs */ + dbg_get_frames_stack_fc frames_stack; /* Pile des frames courantes */ get_register_values_fc get_reg_values; /* Obtient les valeurs de reg. */ diff --git a/src/debug/debugger.c b/src/debug/debugger.c index ce62625..73b8719 100644 --- a/src/debug/debugger.c +++ b/src/debug/debugger.c @@ -261,6 +261,37 @@ pid_t *g_binary_debugger_list_all_threads(GBinaryDebugger *debugger, char ***nam /****************************************************************************** * * +* Paramètres : debugger = instance du module de débogage chargé. * +* thread = thread concerné par l'analyse. * +* count = nombre de frames en place. [OUT] * +* * +* Description : Fournit la liste des frames courantes d'un thread donné. * +* * +* Retour : Liste des frames trouvées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +dbg_frame_t *g_binary_debugger_get_frames_stack(GBinaryDebugger *debugger, pid_t thread, size_t *count) +{ + dbg_frame_t *result; /* Liste à retourner */ + + if (debugger->frames_stack != NULL) + result = debugger->frames_stack(debugger, thread, count); + else + { + *count = 0; + result = NULL; + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : debugger = débogueur à manipuler ici. * * count = nombre de transmissions effetuées. * * * diff --git a/src/debug/debugger.h b/src/debug/debugger.h index 362f8a1..7a6459b 100644 --- a/src/debug/debugger.h +++ b/src/debug/debugger.h @@ -31,6 +31,7 @@ #include "../analysis/binary.h" +#include "../arch/archbase.h" @@ -46,6 +47,16 @@ typedef enum _DebuggerType } DebuggerType; +/* Définition d'une frame */ +typedef struct _dbg_frame_t +{ + + vmpa_t addr; /* Position dans le code */ + +} dbg_frame_t; + + + /* Transmission des valeurs des registres */ typedef struct _register_value { @@ -91,6 +102,9 @@ void g_binary_debugger_kill(GBinaryDebugger *); /* Fournit les identifiants de tous les threads actifs. */ pid_t *g_binary_debugger_list_all_threads(GBinaryDebugger *, char ***, size_t *); +/* Fournit la liste des frames courantes d'un thread donné. */ +dbg_frame_t *g_binary_debugger_get_frames_stack(GBinaryDebugger *, pid_t, size_t *); + /* Fournit la valeur des registres de l'architecture. */ register_value *g_binary_debugger_get_registers(GBinaryDebugger *, size_t *); diff --git a/src/debug/jdwp/debugger.c b/src/debug/jdwp/debugger.c index 51a0db8..b416840 100644 --- a/src/debug/jdwp/debugger.c +++ b/src/debug/jdwp/debugger.c @@ -24,7 +24,10 @@ #include "debugger.h" +#include #include + + #include @@ -70,6 +73,9 @@ static bool g_java_debugger_attach(GJavaDebugger *); /* Fournit les identifiants de tous les threads actifs. */ static pid_t *g_java_debugger_list_all_threads(GJavaDebugger *, char ***, size_t *); +/* Fournit la liste des frames courantes d'un thread donné. */ +static dbg_frame_t *g_java_debugger_get_frames_stack(GJavaDebugger *, pid_t, size_t *); + /* Indique le type défini par la GLib pour le débogueur java. */ @@ -116,6 +122,7 @@ static void g_java_debugger_init(GJavaDebugger *debugger) parent->attach = (attach_debugger_fc)g_java_debugger_attach; parent->all_threads = (dbg_list_all_threads_fc)g_java_debugger_list_all_threads; + parent->frames_stack = (dbg_get_frames_stack_fc)g_java_debugger_get_frames_stack; #if 0 parent->run = (basic_debugger_fc)g_java_debugger_run; @@ -364,3 +371,75 @@ static pid_t *g_java_debugger_list_all_threads(GJavaDebugger *debugger, char *** return result; } + + +/****************************************************************************** +* * +* Paramètres : debugger = instance du module de débogage chargé. * +* thread = thread concerné par l'analyse. * +* count = nombre de frames en place. [OUT] * +* * +* Description : Fournit la liste des frames courantes d'un thread donné. * +* * +* Retour : Liste des frames trouvées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static dbg_frame_t *g_java_debugger_get_frames_stack(GJavaDebugger *debugger, pid_t thread, size_t *count) +{ + dbg_frame_t *result; /* Bilan à retourner */ + GDebugPacket *req; /* Requête à formuler */ + jdwp_cmd_thread_frames_request frames; /* Ciblage du thread désiré */ + GDebugPacket *ret; /* Obtention de la réponse */ + jdwp_payload *payload; /* Charge utile d'une réponse */ + size_t i; /* Boucle de parcours */ + + result = NULL; + *count = 0; + + req = g_debug_stream_get_free_packet(debugger->stream); + + g_jdwp_packet_set_request_header(G_JDWP_PACKET(req), + JDWP_CST_THREAD_REFERENCE, JDWP_CMD_THREAD_FRAMES); + + frames.id = thread; + frames.start = 0; + frames.length = ALL_FRAMES; + g_jdwp_packet_set_payload(G_JDWP_PACKET(req), (jdwp_payload *)&frames); + + if (!g_debug_stream_send_packet(debugger->stream, req)) + goto gjdgsf_req_error; + + ret = g_debug_stream_recv_packet(debugger->stream, + (filter_packet_fc)g_jdwp_packet_is_reply, req); + if (!ret) goto gjdgsf_req_error; + + if (!g_jdwp_packet_parse_payload(G_JDWP_PACKET(ret), + JDWP_CST_THREAD_REFERENCE, JDWP_CMD_THREAD_FRAMES)) + goto gjdgsf_ret_error; + + payload = g_jdwp_packet_get_payload(G_JDWP_PACKET(ret)); + + *count = payload->th_frames.count; + result = (dbg_frame_t *)calloc(*count, sizeof(dbg_frame_t)); + + for (i = 0; i < *count; i++) + { + /* TODO */ + result[i].addr = payload->th_frames.frames[i].location.index; + + } + + gjdgsf_ret_error: + + g_debug_stream_mark_packet_as_free(debugger->stream, ret); + + gjdgsf_req_error: + + g_debug_stream_mark_packet_as_free(debugger->stream, req); + + return result; + +} diff --git a/src/debug/jdwp/jdwp_def.h b/src/debug/jdwp/jdwp_def.h index 7f13f8c..17df081 100644 --- a/src/debug/jdwp/jdwp_def.h +++ b/src/debug/jdwp/jdwp_def.h @@ -99,6 +99,17 @@ typedef uint64_t jdwp_dynsized_id; +/* "location" */ +typedef struct _jdwp_location +{ + jdwp_type_tag tag; /* Classe ou interface ? */ + + jdwp_dynsized_id class_id; /* Identifiant correspondant */ + jdwp_dynsized_id method_id; /* Méthode concernée */ + uint64_t index; /* Position dans le code */ + +} jdwp_location; + /* "string" */ typedef struct _jdwp_string @@ -111,6 +122,10 @@ typedef struct _jdwp_string + + + + /** * Jeux de commandes. */ @@ -137,6 +152,7 @@ typedef struct _jdwp_string /* ThreadReference Command Set */ #define JDWP_CMD_THREAD_NAME 1 +#define JDWP_CMD_THREAD_FRAMES 6 /** @@ -190,6 +206,32 @@ typedef struct _jdwp_cmd_thread_name_reply } jdwp_cmd_thread_name_reply; +/* JDWP_CMD_THREAD_FRAMES */ + +typedef struct _jdwp_cmd_thread_frames_request +{ + jdwp_dynsized_id id; /* Identifiant du thread visé */ + uint32_t start; /* Première frame à traiter */ + uint32_t length; /* Longueur de la liste ou -1 */ + +} jdwp_cmd_thread_frames_request; + +#define ALL_FRAMES 0xffffffff + +typedef struct _jdwp_thread_frame +{ + jdwp_dynsized_id frame_id; /* Identifiant de la frame */ + jdwp_location location; /* Localisation de la frame */ + +} jdwp_thread_frame; + +typedef struct _jdwp_cmd_thread_frames_reply +{ + uint32_t count; /* Taille de la liste */ + jdwp_thread_frame *frames; /* Liste de frames */ + +} jdwp_cmd_thread_frames_reply; + #endif /* _DEBUG_JDWP_JDWP_DEF_H */ diff --git a/src/debug/jdwp/misc/Makefile.am b/src/debug/jdwp/misc/Makefile.am index 44c6224..f955501 100644 --- a/src/debug/jdwp/misc/Makefile.am +++ b/src/debug/jdwp/misc/Makefile.am @@ -4,6 +4,7 @@ noinst_LTLIBRARIES = libdebugjdwpmisc.la libdebugjdwpmisc_la_SOURCES = \ header.h header.c \ id.h id.c \ + location.h location.c \ types.h types.c libdebugjdwpmisc_la_LDFLAGS = diff --git a/src/debug/jdwp/misc/location.c b/src/debug/jdwp/misc/location.c new file mode 100644 index 0000000..3fd95cb --- /dev/null +++ b/src/debug/jdwp/misc/location.c @@ -0,0 +1,64 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * location.c - constitution des localisations d'instructions courantes + * + * Copyright (C) 2012 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see . + */ + + +#include "location.h" + + +#include "id.h" +#include "../../../common/endianness.h" + + + +/****************************************************************************** +* * +* Paramètres : blob = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* len = taille totale des données à analyser. * +* sizes = référence pour la taille utilisée. * +* loc = localisation à fournir. [OUT] * +* * +* Description : Lit une localisation d'instruction courante dans l'exécution.* +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool get_jdwp_location(const bin_t *blob, off_t *pos, off_t len, const jdwp_cmd_vm_id_sizes_reply *sizes, jdwp_location *loc) +{ + if (!read_u8(&loc->tag, blob, pos, len, SRE_BIG)) + return false; + + if (!get_jdwp_class_id(blob, pos, len, sizes, &loc->class_id)) + return false; + + if (!get_jdwp_method_id(blob, pos, len, sizes, &loc->method_id)) + return false; + + if (!read_u64(&loc->index, blob, pos, len, SRE_BIG)) + return false; + + return true; + +} diff --git a/src/debug/jdwp/misc/location.h b/src/debug/jdwp/misc/location.h new file mode 100644 index 0000000..a594bac --- /dev/null +++ b/src/debug/jdwp/misc/location.h @@ -0,0 +1,40 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * location.h - prototypes pour la constitution des localisations d'instructions courantes + * + * Copyright (C) 2012 Cyrille Bagard + * + * This file is part of OpenIDA. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see . + */ + + +#ifndef _DEBUG_JDWP_MISC_LOCATION_H +#define _DEBUG_JDWP_MISC_LOCATION_H + + +#include + + +#include "../jdwp_def.h" +#include "../../../arch/archbase.h" + + +/* Lit une localisation d'instruction courante dans l'exécution. */ +bool get_jdwp_location(const bin_t *, off_t *, off_t, const jdwp_cmd_vm_id_sizes_reply *, jdwp_location *); + + + +#endif /* _DEBUG_JDWP_MISC_LOCATION_H */ diff --git a/src/debug/jdwp/sets/list.c b/src/debug/jdwp/sets/list.c index 84c6ac0..ba96917 100644 --- a/src/debug/jdwp/sets/list.c +++ b/src/debug/jdwp/sets/list.c @@ -87,6 +87,13 @@ static jdwp_command _commands[][256] = { .free_set_payload = (free_jdwp_payload_fc)NULL, .get_payload = (get_jdwp_payload_fc)get_jdwp_thread_name, .free_got_payload = (free_jdwp_payload_fc)free_jdwp_thread_name_reply + }, + + [JDWP_CMD_THREAD_FRAMES] = { + .set_payload = (set_jdwp_payload_fc)set_jdwp_thread_frames, + .free_set_payload = (free_jdwp_payload_fc)NULL, + .get_payload = (get_jdwp_payload_fc)get_jdwp_thread_frames, + .free_got_payload = (free_jdwp_payload_fc)free_jdwp_thread_frames_reply } } diff --git a/src/debug/jdwp/sets/list.h b/src/debug/jdwp/sets/list.h index 9880e69..ba66842 100644 --- a/src/debug/jdwp/sets/list.h +++ b/src/debug/jdwp/sets/list.h @@ -42,6 +42,8 @@ typedef union _jdwp_payload jdwp_cmd_thread_name_request th_ident; /* Identification d'un thread */ jdwp_cmd_thread_name_reply th_name; /* Désignation d'un thread */ + jdwp_cmd_thread_frames_request __nu0; /* Inutilisé */ + jdwp_cmd_thread_frames_reply th_frames; /* Pile des frames courantes */ bin_t padding[500]; diff --git a/src/debug/jdwp/sets/thread.c b/src/debug/jdwp/sets/thread.c index 9391ff6..ea60bc6 100644 --- a/src/debug/jdwp/sets/thread.c +++ b/src/debug/jdwp/sets/thread.c @@ -24,10 +24,12 @@ #include "thread.h" +#include #include #include "../misc/id.h" +#include "../misc/location.h" #include "../misc/types.h" #include "../../../common/endianness.h" @@ -87,7 +89,7 @@ bool get_jdwp_thread_name(const bin_t *blob, off_t len, const jdwp_cmd_vm_id_siz off_t pos; /* Tête de lecture */ pos = 0; - memset(reply, 0, sizeof(jdwp_cmd_vm_version_reply)); + memset(reply, 0, sizeof(jdwp_cmd_thread_name_reply)); result = get_jdwp_string(blob, &pos, len, &reply->name); if (!result) return false; @@ -114,3 +116,107 @@ void free_jdwp_thread_name_reply(jdwp_cmd_thread_name_reply *reply) free_jdwp_string(&reply->name); } + + +/****************************************************************************** +* * +* Paramètres : req = structure de réponse à constituer. * +* sizes = références pour la valeur des tailles dynamiques. * +* blob = ensemble de données binaires brutes. [OUT] * +* len = quantité de données disponibles, puis écrites. [OUT] * +* * +* Description : Prépare une requête demandant les frames d'un thread. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool set_jdwp_thread_frames(const jdwp_cmd_thread_frames_request *req, const jdwp_cmd_vm_id_sizes_reply *sizes, bin_t *blob, off_t *len) +{ + bool result; /* Bilan à retourner */ + off_t pos; /* Tête de lecture */ + + pos = 0; + memset(blob, 0, sizeof(jdwp_cmd_thread_frames_request)); + + result = set_jdwp_frame_id(&req->id, sizes, blob, &pos, *len); + if (!result) return false; + + result = write_u32(&req->start, blob, &pos, *len, SRE_BIG); + if (!result) return false; + + result = write_u32(&req->length, blob, &pos, *len, SRE_BIG); + if (!result) return false; + + *len = pos; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : blob = ensemble de données binaires brutes. * +* len = quantité de données valides. * +* sizes = références pour la valeur des tailles dynamiques. * +* reply = structure de réponse à constituer. [OUT] * +* * +* Description : Reconstitue une réponse fournissant les frames d'un thread. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool get_jdwp_thread_frames(const bin_t *blob, off_t len, const jdwp_cmd_vm_id_sizes_reply *sizes, jdwp_cmd_thread_frames_reply *reply) +{ + bool result; /* Bilan à retourner */ + off_t pos; /* Tête de lecture */ + uint32_t i; /* Boucle de parcours */ + + pos = 0; + memset(reply, 0, sizeof(jdwp_cmd_thread_frames_reply)); + + result = read_u32(&reply->count, blob, &pos, len, SRE_BIG); + if (!result) return false; + + reply->frames = (jdwp_thread_frame *)calloc(reply->count, sizeof(jdwp_thread_frame)); + + for (i = 0; i < reply->count && result; i++) + { + result = get_jdwp_frame_id(blob, &pos, len, sizes, &reply->frames[i].frame_id); + + result &= get_jdwp_location(blob, &pos, len, sizes, &reply->frames[i].location); + + } + + if (!result) + free_jdwp_thread_frames_reply(reply); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : reply = structure de réponse à supprimer de la mémoire. * +* * +* Description : Libère une liste de frames d'un thread. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void free_jdwp_thread_frames_reply(jdwp_cmd_thread_frames_reply *reply) +{ + if (reply->frames != NULL) + free(reply->frames); + +} diff --git a/src/debug/jdwp/sets/thread.h b/src/debug/jdwp/sets/thread.h index f8c3abe..a304cc0 100644 --- a/src/debug/jdwp/sets/thread.h +++ b/src/debug/jdwp/sets/thread.h @@ -41,6 +41,15 @@ bool get_jdwp_thread_name(const bin_t *, off_t, const jdwp_cmd_vm_id_sizes_reply /* Libère le nom donné à un thread. */ void free_jdwp_thread_name_reply(jdwp_cmd_thread_name_reply *); +/* Prépare une requête demandant les frames d'un thread. */ +bool set_jdwp_thread_frames(const jdwp_cmd_thread_frames_request *, const jdwp_cmd_vm_id_sizes_reply *, bin_t *, off_t *); + +/* Reconstitue une réponse fournissant les frames d'un thread. */ +bool get_jdwp_thread_frames(const bin_t *, off_t, const jdwp_cmd_vm_id_sizes_reply *, jdwp_cmd_thread_frames_reply *); + +/* Libère une liste de frames d'un thread. */ +void free_jdwp_thread_frames_reply(jdwp_cmd_thread_frames_reply *); + #endif /* _DEBUG_JDWP_SETS_THREAD_H */ -- cgit v0.11.2-87-g4458