2 /// \file m_jvmdebug.cc
3 /// Mode class for the JVMDebug mode
7 Copyright (C) 2005-2010, Net Direct Inc. (http://www.netdirect.ca/)
8 Copyright (C) 2008-2009, Nicolas VIVIEN
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "m_jvmdebug.h"
26 #include "protostructs.h"
31 #include "controller.h"
44 using namespace Barry::Protocol
;
48 ///////////////////////////////////////////////////////////////////////////////
49 // JDModulesList class
51 void JVMModulesList::Parse(const Data
&entry_packet
)
55 size_t size
= entry_packet
.GetSize();
57 while (count
< size
) {
60 const unsigned char *ptr
= (entry_packet
.GetData() + count
);
61 Protocol::JVMModulesEntry
*e
= (Protocol::JVMModulesEntry
*) ptr
;
63 len
= SB_JVMMODULES_ENTRY_HEADER_SIZE
+ be_btohs(e
->sizename
);
64 if( (count
+ len
) > size
)
67 JVMModulesEntry entry
;
69 entry
.Id
= be_btohl(e
->id
);
70 entry
.UniqueID
= be_btohl(e
->uniqueId
);
71 (entry
.Name
).assign((char *) (ptr
+ SB_JVMMODULES_ENTRY_HEADER_SIZE
), be_btohs(e
->sizename
));
80 void JVMModulesList::Dump(std::ostream
&os
) const
82 const_iterator i
= begin(), e
= end();
85 os
<< " UniqueID " << "|";
86 os
<< " Module Name" << endl
;
88 os
<< "------------+";
89 os
<< "------------+";
90 os
<< "-------------";
93 for( ; i
!= e
; ++i
) {
99 ///////////////////////////////////////////////////////////////////////////////
100 // JVMModulesEntry class
102 void JVMModulesEntry::Dump(std::ostream
&os
) const
104 os
<< " 0x" << setfill('0') << setw(8) << hex
<< Id
<< " |";
105 os
<< " 0x" << setfill('0') << setw(8) << hex
<< UniqueID
<< " |";
106 os
<< " " << Name
<< endl
;
110 ///////////////////////////////////////////////////////////////////////////////
111 // JVMThreadsList class
113 void JVMThreadsList::Parse(const Data
&entry_packet
)
117 size_t size
= entry_packet
.GetSize();
119 while (count
< size
) {
122 const unsigned char *ptr
= (entry_packet
.GetData() + count
);
123 uint32_t *e
= (uint32_t *) ptr
;
125 len
= sizeof(uint32_t);
126 if( (count
+ len
) > size
)
129 JVMThreadsEntry entry
;
131 entry
.Id
= be_btohl(*e
);
140 void JVMThreadsList::Dump(std::ostream
&os
) const
142 const_iterator i
= begin(), e
= end();
144 os
<< " Thread " << "|";
145 os
<< " Address " << "|";
146 os
<< " Byte " << "|";
147 os
<< " Unknown01 " << "|";
148 os
<< " Unknown02 " << "|";
149 os
<< " Unknown03 " << "|";
150 os
<< " Unknown04 " << "|";
151 os
<< " Unknown05 " << "|";
152 os
<< " Unknown06 " << "|";
154 os
<< "------------+";
155 os
<< "------------+";
157 os
<< "------------+";
158 os
<< "------------+";
159 os
<< "------------+";
160 os
<< "------------+";
161 os
<< "------------+";
162 os
<< "-------------";
165 for(int k
=0 ; i
!= e
; ++i
, k
++ ) {
171 void JVMThreadsEntry::Dump(std::ostream
&os
, int num
) const
173 os
<< " " << setfill(' ') << setw(8) << dec
<< num
<< " |";
174 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Id
) << " |";
175 os
<< " 0x" << setfill('0') << setw(2) << hex
<< (Byte
) << " |";
176 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Address
) << " |";
177 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown01
) << " |";
178 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown02
) << " |";
179 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown03
) << " |";
180 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown04
) << " |";
181 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown05
) << " |";
182 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown06
) << endl
;
188 ///////////////////////////////////////////////////////////////////////////////
189 // JVMDebug Mode class
191 JVMDebug::JVMDebug(Controller
&con
)
192 : Mode(con
, Controller::JVMDebug
)
197 JVMDebug::~JVMDebug()
203 ///////////////////////////////////////////////////////////////////////////////
207 ///////////////////////////////////////////////////////////////////////////////
210 void JVMDebug::OnOpen()
212 m_socket
->InitSequence();
215 // FIXME - is this necessary? and if it is, wouldn't it be better
216 // in the m_jvmdebug mode class? I'm not convinced that applications
217 // should have to bother with socket-level details.
218 void JVMDebug::Close()
230 /// These commands are sent to prepare the debug communication.
231 /// Must be called at the start of a JVMDebug session.
233 void JVMDebug::Attach()
240 /// Must be called at the end of a JVMDebug session. The JVM_GOODBYE
241 /// command is sent to the device.
243 void JVMDebug::Detach()
248 void JVMDebug::ThrowJVMError(const std::string
&msg
, uint8_t cmd
)
250 std::ostringstream oss
;
251 oss
<< msg
<< ": unexpected packet command code: 0x"
252 << std::hex
<< (unsigned int) cmd
;
253 throw Error(oss
.str());
260 void JVMDebug::Unknown01()
264 Data
command(-1, 8), response
;
265 JVMPacket
packet(command
, response
);
267 // Send the command packet
269 m_socket
->Packet(packet
);
270 expect
= packet
.Size();
275 // Read the data stream
276 m_socket
->ReceiveData(response
);
278 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
280 // Check the size read into the previous packet
281 if( expect
!= bytereceived
) {
282 ThrowJVMError("JVMDebug::Attach expect", expect
);
290 void JVMDebug::Unknown02()
294 Data
command(-1, 8), response
;
295 JVMPacket
packet(command
, response
);
297 // Send the command packet
299 m_socket
->Packet(packet
);
300 expect
= packet
.Size();
305 // Read the data stream
306 m_socket
->ReceiveData(response
);
308 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
310 // Check the size read into the previous packet
311 if( expect
!= bytereceived
) {
312 ThrowJVMError("JVMDebug::Attach expect", expect
);
320 void JVMDebug::Unknown03()
324 Data
command(-1, 8), response
;
325 JVMPacket
packet(command
, response
);
327 // Send the command packet
329 m_socket
->Packet(packet
);
330 expect
= packet
.Size();
335 // Read the data stream
336 m_socket
->ReceiveData(response
);
338 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
340 // Check the size read into the previous packet
341 if( expect
!= bytereceived
) {
342 ThrowJVMError("JVMDebug::Attach expect", expect
);
350 void JVMDebug::Unknown04()
354 Data
command(-1, 8), response
;
355 JVMPacket
packet(command
, response
);
357 // Send the command packet
359 m_socket
->Packet(packet
);
360 expect
= packet
.Size();
365 // Read the data stream
366 m_socket
->ReceiveData(response
);
368 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
370 // Check the size read into the previous packet
371 if( expect
!= bytereceived
) {
372 ThrowJVMError("JVMDebug::Attach expect", expect
);
380 void JVMDebug::Unknown05()
384 Data
command(-1, 8), response
;
385 JVMPacket
packet(command
, response
);
387 // Send the command packet
389 m_socket
->Packet(packet
);
390 expect
= packet
.Size();
395 // Read the data stream
396 m_socket
->ReceiveData(response
);
398 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
400 // Check the size read into the previous packet
401 if( expect
!= bytereceived
) {
402 ThrowJVMError("JVMDebug::Attach expect", expect
);
410 void JVMDebug::Unknown06()
414 Data
command(-1, 8), response
;
415 JVMPacket
packet(command
, response
);
417 // Send the command packet
419 m_socket
->Packet(packet
);
420 expect
= packet
.Size();
425 // Read the data stream
426 m_socket
->ReceiveData(response
);
428 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
430 // Check the size read into the previous packet
431 if( expect
!= bytereceived
) {
432 ThrowJVMError("JVMDebug::Attach expect", expect
);
440 void JVMDebug::Unknown07()
444 Data
command(-1, 8), response
;
445 JVMPacket
packet(command
, response
);
447 // Send the command packet
449 m_socket
->Packet(packet
);
450 expect
= packet
.Size();
455 // Read the data stream
456 m_socket
->ReceiveData(response
);
458 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
460 // Check the size read into the previous packet
461 if( expect
!= bytereceived
) {
462 ThrowJVMError("JVMDebug::Attach expect", expect
);
470 void JVMDebug::Unknown08()
474 Data
command(-1, 8), response
;
475 JVMPacket
packet(command
, response
);
477 // Send the command packet
479 m_socket
->Packet(packet
);
480 expect
= packet
.Size();
485 // Read the data stream
486 m_socket
->ReceiveData(response
);
488 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
490 // Check the size read into the previous packet
491 if( expect
!= bytereceived
) {
492 ThrowJVMError("JVMDebug::Attach expect", expect
);
500 void JVMDebug::Unknown09()
504 Data
command(-1, 8), response
;
505 JVMPacket
packet(command
, response
);
507 // Send the command packet
509 m_socket
->Packet(packet
);
510 expect
= packet
.Size();
515 // Read the data stream
516 m_socket
->ReceiveData(response
);
518 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
520 // Check the size read into the previous packet
521 if( expect
!= bytereceived
) {
522 ThrowJVMError("JVMDebug::Attach expect", expect
);
530 void JVMDebug::Unknown10()
534 Data
command(-1, 8), response
;
535 JVMPacket
packet(command
, response
);
537 // Send the command packet
539 m_socket
->Packet(packet
);
540 expect
= packet
.Size();
545 // Read the data stream
546 m_socket
->ReceiveData(response
);
548 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
550 // Check the size read into the previous packet
551 if( expect
!= bytereceived
) {
552 ThrowJVMError("JVMDebug::Attach expect", expect
);
560 bool JVMDebug::GetStatus(int &status
)
564 Data
command(-1, 8), response
;
565 JVMPacket
packet(command
, response
);
567 // Send the command packet
570 m_socket
->Packet(packet
);
572 expect
= packet
.Size();
577 // Read the data stream
578 m_socket
->ReceiveData(response
);
580 MAKE_JVMPACKET(dpack
, response
);
582 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
584 // Check the size read into the previous packet
585 if( expect
!= bytereceived
) {
586 ThrowJVMError("JVMDebug::GetModulesList expect", expect
);
589 // Make sure we have a header to read
590 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.status
));
593 status
= dpack
->u
.status
;
602 bool JVMDebug::WaitStatus(int &status
)
606 Data
command(-1, 8), response
;
607 JVMPacket
packet(command
, response
);
609 // Prepare the command packet
613 m_socket
->Receive(packet
.GetReceive(), 100);
614 } catch (Usb::Timeout
&to
) {
618 expect
= packet
.Size();
623 // Read the data stream
624 m_socket
->ReceiveData(response
);
626 MAKE_JVMPACKET(dpack
, response
);
628 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
630 // Check the size read into the previous packet
631 if( expect
!= bytereceived
) {
632 ThrowJVMError("JVMDebug::GetModulesList expect", expect
);
635 // Make sure we have a header to read
636 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.status
));
639 status
= dpack
->u
.status
;
646 // Get Console Message
647 // Sample, display the output of System.out.println(...) and all JVM messages output
649 // Return the length message or -1 if message doesn't exit or is empty
651 int JVMDebug::GetConsoleMessage(std::string
&message
)
655 Data
command(-1, 8), response
;
656 JVMPacket
packet(command
, response
);
658 // Send the command packet
659 packet
.GetConsoleMessage();
661 m_socket
->Packet(packet
);
663 expect
= packet
.Size();
668 // Read the data stream
669 m_socket
->ReceiveData(response
);
671 MAKE_JVMPACKET(dpack
, response
);
673 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
675 // Check the size read into the previous packet
676 if( expect
!= bytereceived
) {
677 ThrowJVMError("JVMDebug::GetModulesList expect", expect
);
680 // Make sure we have a header to read
681 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.msglength
));
684 uint16_t length
= be_btohs(dpack
->u
.msglength
);
689 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.msglength
) + length
);
691 // Parse the ID of nextmodules
692 const unsigned char *ptr
= (response
.GetData() + SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.msglength
));
694 message
.assign((char *) ptr
, length
);
701 // Get list of Java modules
703 void JVMDebug::GetModulesList(JVMModulesList
&mylist
)
710 Data
command(-1, 8), response
;
711 JVMPacket
packet(command
, response
);
714 // Send the command packet
715 packet
.GetModulesList(offset
);
717 m_socket
->Packet(packet
);
719 expect
= packet
.Size();
724 // Read the data stream
725 m_socket
->ReceiveData(response
);
727 MAKE_JVMPACKET(dpack
, response
);
729 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
731 // Check the size read into the previous packet
732 if( expect
!= bytereceived
) {
733 ThrowJVMError("JVMDebug::GetModulesList expect", expect
);
736 // Make sure there's enough for packet header + module list
737 // header + 4 bytes of ID
738 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMMODULES_LIST_HEADER_SIZE
+ 4);
740 // Number of modules entries in the list
741 count
= be_btohl(dpack
->u
.moduleslist
.nbr
);
743 // Size of modules list
744 // I remove the header of packet (contains the field 'number of modules')
745 // and 4 bytes (contains the field 'ID of next modules')
746 size
= bytereceived
- SB_JVMMODULES_LIST_HEADER_SIZE
- 4;
748 // Parse the modules list
749 mylist
.Parse(Data(response
.GetData() + SB_JVMPACKET_HEADER_SIZE
+ SB_JVMMODULES_LIST_HEADER_SIZE
, size
));
751 // Parse the ID of nextmodules
752 size_t id_offset
= SB_JVMPACKET_HEADER_SIZE
+ SB_JVMMODULES_LIST_HEADER_SIZE
+ size
;
753 const unsigned char *ptr
= (response
.GetData() + id_offset
);
754 CheckSize(response
, id_offset
+ sizeof(uint32_t));
755 uint32_t *poffset
= (uint32_t *) ptr
;
757 offset
= be_btohl(*poffset
);
758 } while (offset
!= 0); // When the offset != 0, there is some modules
763 // Get list of Java threads
765 void JVMDebug::GetThreadsList(JVMThreadsList
&mylist
)
771 Data
command(-1, 8), response
;
772 JVMPacket
packet(command
, response
);
774 // Send the command packet
775 packet
.GetThreadsList();
777 m_socket
->Packet(packet
);
779 expect
= packet
.Size();
784 // Read the data stream
785 m_socket
->ReceiveData(response
);
787 MAKE_JVMPACKET(dpack
, response
);
789 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
791 // Check the size read into the previous packet
792 if( expect
!= bytereceived
) {
793 ThrowJVMError("JVMDebug::GetThreadsList expect", expect
);
796 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMTHREADS_LIST_HEADER_SIZE
);
798 // Number of threads entries in the list
799 count
= be_btohl(dpack
->u
.threadslist
.nbr
);
801 // Size of threads list
802 // I remove the header of packet (contains the field 'number of threads')
803 size
= bytereceived
- SB_JVMTHREADS_LIST_HEADER_SIZE
;
805 // Parse the threads list
806 mylist
.Parse(Data(response
.GetData() + SB_JVMPACKET_HEADER_SIZE
+ SB_JVMTHREADS_LIST_HEADER_SIZE
, size
));
808 // Complete threads list
809 JVMThreadsList::iterator b
= mylist
.begin();
810 for( ; b
!= mylist
.end(); b
++ ) {
811 JVMThreadsEntry entry
= (*b
);
814 // Send the command packet
815 packet
.Unknown11(entry
.Id
);
817 m_socket
->Packet(packet
);
819 expect
= packet
.Size();
824 // Read the data stream
825 m_socket
->ReceiveData(response
);
827 MAKE_JVMPACKET(dpack
, response
);
829 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
831 // Check the size read into the previous packet
832 if( expect
!= bytereceived
) {
833 ThrowJVMError("JVMDebug::GetThreadsList (1) expect", expect
);
836 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMUNKNOWN01_HEADER_SIZE
);
839 entry
.Byte
= dpack
->u
.unknown01
.byte
;
840 entry
.Address
= be_btohl(dpack
->u
.unknown01
.address
);
843 if (entry
.Address
!= 0) {
844 // Send the command packet
845 packet
.Unknown12(entry
.Address
);
847 m_socket
->Packet(packet
);
849 expect
= packet
.Size();
854 // Read the data stream
855 m_socket
->ReceiveData(response
);
857 MAKE_JVMPACKET(dpack
, response
);
859 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
861 // Check the size read into the previous packet
862 if( expect
!= bytereceived
) {
863 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
868 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.address
));
869 entry
.Unknown01
= be_btohl(dpack
->u
.address
);
875 // Send the command packet
876 packet
.Unknown13(entry
.Id
);
878 m_socket
->Packet(packet
);
880 expect
= packet
.Size();
885 // Read the data stream
886 m_socket
->ReceiveData(response
);
888 dpack
= (const Protocol::JVMPacket
*) response
.GetData();
890 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
892 // Check the size read into the previous packet
893 if( expect
!= bytereceived
) {
894 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
898 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.address
));
899 entry
.Unknown02
= be_btohl(dpack
->u
.address
);
902 // Send the command packet
903 packet
.Unknown14(entry
.Id
);
905 m_socket
->Packet(packet
);
907 expect
= packet
.Size();
912 // Read the data stream
913 m_socket
->ReceiveData(response
);
915 dpack
= (const Protocol::JVMPacket
*) response
.GetData();
917 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
919 // Check the size read into the previous packet
920 if( expect
!= bytereceived
) {
921 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
925 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMUNKNOWN02_HEADER_SIZE
);
926 entry
.Unknown03
= be_btohl(dpack
->u
.unknown02
.address1
);
927 entry
.Unknown04
= be_btohl(dpack
->u
.unknown02
.address2
);
930 // Send the command packet
931 packet
.Unknown15(entry
.Id
);
933 m_socket
->Packet(packet
);
935 expect
= packet
.Size();
940 // Read the data stream
941 m_socket
->ReceiveData(response
);
943 dpack
= (const Protocol::JVMPacket
*) response
.GetData();
945 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
947 // Check the size read into the previous packet
948 if( expect
!= bytereceived
) {
949 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
953 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMUNKNOWN02_HEADER_SIZE
);
954 entry
.Unknown05
= be_btohl(dpack
->u
.unknown02
.address1
);
955 entry
.Unknown06
= be_btohl(dpack
->u
.unknown02
.address2
);
970 Data
command(-1, 8), response
;
971 JVMPacket
packet(command
, response
);
973 // Send the command packet
975 m_socket
->Packet(packet
);
976 expect
= packet
.Size();
978 while (expect
== 0) {
979 m_socket
->Receive(packet
.GetReceive());
981 expect
= packet
.Size();
984 // Read the data stream
985 m_socket
->ReceiveData(response
);
987 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
989 // Check the size read into the previous packet
990 if( expect
!= bytereceived
) {
991 ThrowJVMError("JVMDebug::Attach expect", expect
);
999 void JVMDebug::Stop()
1001 uint16_t expect
= 0;
1003 Data
command(-1, 8), response
;
1004 JVMPacket
packet(command
, response
);
1006 // Send the command packet
1008 m_socket
->Packet(packet
);
1009 expect
= packet
.Size();
1011 while (expect
== 0) {
1012 m_socket
->Receive(packet
.GetReceive());
1014 expect
= packet
.Size();
1017 // Read the data stream
1018 m_socket
->ReceiveData(response
);
1020 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
1022 // Check the size read into the previous packet
1023 if( expect
!= bytereceived
) {
1024 ThrowJVMError("JVMDebug::Attach expect", expect
);
1029 }} // namespace Barry::Mode