2 /// \file m_jvmdebug.cc
3 /// Mode class for the JVMDebug mode
7 Copyright (C) 2005-2011, 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"
40 #include "ios_state.h"
45 using namespace Barry::Protocol
;
49 ///////////////////////////////////////////////////////////////////////////////
50 // JDModulesList class
52 void JVMModulesList::Parse(const Data
&entry_packet
)
56 size_t size
= entry_packet
.GetSize();
58 while (count
< size
) {
61 const unsigned char *ptr
= (entry_packet
.GetData() + count
);
62 Protocol::JVMModulesEntry
*e
= (Protocol::JVMModulesEntry
*) ptr
;
64 len
= SB_JVMMODULES_ENTRY_HEADER_SIZE
+ be_btohs(e
->sizename
);
65 if( (count
+ len
) > size
)
68 JVMModulesEntry entry
;
70 entry
.Id
= be_btohl(e
->id
);
71 entry
.UniqueID
= be_btohl(e
->uniqueId
);
72 (entry
.Name
).assign((char *) (ptr
+ SB_JVMMODULES_ENTRY_HEADER_SIZE
), be_btohs(e
->sizename
));
81 void JVMModulesList::Dump(std::ostream
&os
) const
83 ios_format_state
state(os
);
85 const_iterator i
= begin(), e
= end();
88 os
<< " UniqueID " << "|";
89 os
<< " Module Name" << endl
;
91 os
<< "------------+";
92 os
<< "------------+";
93 os
<< "-------------";
96 for( ; i
!= e
; ++i
) {
102 ///////////////////////////////////////////////////////////////////////////////
103 // JVMModulesEntry class
105 void JVMModulesEntry::Dump(std::ostream
&os
) const
107 ios_format_state
state(os
);
109 os
<< " 0x" << setfill('0') << setw(8) << hex
<< Id
<< " |";
110 os
<< " 0x" << setfill('0') << setw(8) << hex
<< UniqueID
<< " |";
111 os
<< " " << Name
<< endl
;
115 ///////////////////////////////////////////////////////////////////////////////
116 // JVMThreadsList class
118 void JVMThreadsList::Parse(const Data
&entry_packet
)
122 size_t size
= entry_packet
.GetSize();
124 while (count
< size
) {
127 const unsigned char *ptr
= (entry_packet
.GetData() + count
);
128 uint32_t *e
= (uint32_t *) ptr
;
130 len
= sizeof(uint32_t);
131 if( (count
+ len
) > size
)
134 JVMThreadsEntry entry
;
136 entry
.Id
= be_btohl(*e
);
145 void JVMThreadsList::Dump(std::ostream
&os
) const
147 ios_format_state
state(os
);
149 const_iterator i
= begin(), e
= end();
151 os
<< " Thread " << "|";
152 os
<< " Address " << "|";
153 os
<< " Byte " << "|";
154 os
<< " Unknown01 " << "|";
155 os
<< " Unknown02 " << "|";
156 os
<< " Unknown03 " << "|";
157 os
<< " Unknown04 " << "|";
158 os
<< " Unknown05 " << "|";
159 os
<< " Unknown06 " << "|";
161 os
<< "------------+";
162 os
<< "------------+";
164 os
<< "------------+";
165 os
<< "------------+";
166 os
<< "------------+";
167 os
<< "------------+";
168 os
<< "------------+";
169 os
<< "-------------";
172 for(int k
=0 ; i
!= e
; ++i
, k
++ ) {
178 void JVMThreadsEntry::Dump(std::ostream
&os
, int num
) const
180 ios_format_state
state(os
);
182 os
<< " " << setfill(' ') << setw(8) << dec
<< num
<< " |";
183 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Id
) << " |";
184 os
<< " 0x" << setfill('0') << setw(2) << hex
<< (Byte
) << " |";
185 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Address
) << " |";
186 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown01
) << " |";
187 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown02
) << " |";
188 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown03
) << " |";
189 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown04
) << " |";
190 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown05
) << " |";
191 os
<< " 0x" << setfill('0') << setw(8) << hex
<< (Unknown06
) << endl
;
197 ///////////////////////////////////////////////////////////////////////////////
198 // JVMDebug Mode class
200 JVMDebug::JVMDebug(Controller
&con
)
201 : Mode(con
, Controller::JVMDebug
)
206 JVMDebug::~JVMDebug()
212 ///////////////////////////////////////////////////////////////////////////////
216 ///////////////////////////////////////////////////////////////////////////////
219 void JVMDebug::OnOpen()
223 // FIXME - is this necessary? and if it is, wouldn't it be better
224 // in the m_jvmdebug mode class? I'm not convinced that applications
225 // should have to bother with socket-level details.
226 void JVMDebug::Close()
238 /// These commands are sent to prepare the debug communication.
239 /// Must be called at the start of a JVMDebug session.
241 void JVMDebug::Attach()
248 /// Must be called at the end of a JVMDebug session. The JVM_GOODBYE
249 /// command is sent to the device.
251 void JVMDebug::Detach()
256 void JVMDebug::ThrowJVMError(const std::string
&msg
, uint8_t cmd
)
258 std::ostringstream oss
;
259 oss
<< msg
<< ": unexpected packet command code: 0x"
260 << std::hex
<< (unsigned int) cmd
;
261 throw Error(oss
.str());
268 void JVMDebug::Unknown01()
272 Data
command(-1, 8), response
;
273 JVMPacket
packet(command
, response
);
275 // Send the command packet
277 m_socket
->Packet(packet
);
278 expect
= packet
.Size();
283 // Read the data stream
284 m_socket
->Receive(response
);
286 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
288 // Check the size read into the previous packet
289 if( expect
!= bytereceived
) {
290 ThrowJVMError("JVMDebug::Attach expect", expect
);
298 void JVMDebug::Unknown02()
302 Data
command(-1, 8), response
;
303 JVMPacket
packet(command
, response
);
305 // Send the command packet
307 m_socket
->Packet(packet
);
308 expect
= packet
.Size();
313 // Read the data stream
314 m_socket
->Receive(response
);
316 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
318 // Check the size read into the previous packet
319 if( expect
!= bytereceived
) {
320 ThrowJVMError("JVMDebug::Attach expect", expect
);
328 void JVMDebug::Unknown03()
332 Data
command(-1, 8), response
;
333 JVMPacket
packet(command
, response
);
335 // Send the command packet
337 m_socket
->Packet(packet
);
338 expect
= packet
.Size();
343 // Read the data stream
344 m_socket
->Receive(response
);
346 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
348 // Check the size read into the previous packet
349 if( expect
!= bytereceived
) {
350 ThrowJVMError("JVMDebug::Attach expect", expect
);
358 void JVMDebug::Unknown04()
362 Data
command(-1, 8), response
;
363 JVMPacket
packet(command
, response
);
365 // Send the command packet
367 m_socket
->Packet(packet
);
368 expect
= packet
.Size();
373 // Read the data stream
374 m_socket
->Receive(response
);
376 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
378 // Check the size read into the previous packet
379 if( expect
!= bytereceived
) {
380 ThrowJVMError("JVMDebug::Attach expect", expect
);
388 void JVMDebug::Unknown05()
392 Data
command(-1, 8), response
;
393 JVMPacket
packet(command
, response
);
395 // Send the command packet
397 m_socket
->Packet(packet
);
398 expect
= packet
.Size();
403 // Read the data stream
404 m_socket
->Receive(response
);
406 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
408 // Check the size read into the previous packet
409 if( expect
!= bytereceived
) {
410 ThrowJVMError("JVMDebug::Attach expect", expect
);
418 void JVMDebug::Unknown06()
422 Data
command(-1, 8), response
;
423 JVMPacket
packet(command
, response
);
425 // Send the command packet
427 m_socket
->Packet(packet
);
428 expect
= packet
.Size();
433 // Read the data stream
434 m_socket
->Receive(response
);
436 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
438 // Check the size read into the previous packet
439 if( expect
!= bytereceived
) {
440 ThrowJVMError("JVMDebug::Attach expect", expect
);
448 void JVMDebug::Unknown07()
452 Data
command(-1, 8), response
;
453 JVMPacket
packet(command
, response
);
455 // Send the command packet
457 m_socket
->Packet(packet
);
458 expect
= packet
.Size();
463 // Read the data stream
464 m_socket
->Receive(response
);
466 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
468 // Check the size read into the previous packet
469 if( expect
!= bytereceived
) {
470 ThrowJVMError("JVMDebug::Attach expect", expect
);
478 void JVMDebug::Unknown08()
482 Data
command(-1, 8), response
;
483 JVMPacket
packet(command
, response
);
485 // Send the command packet
487 m_socket
->Packet(packet
);
488 expect
= packet
.Size();
493 // Read the data stream
494 m_socket
->Receive(response
);
496 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
498 // Check the size read into the previous packet
499 if( expect
!= bytereceived
) {
500 ThrowJVMError("JVMDebug::Attach expect", expect
);
508 void JVMDebug::Unknown09()
512 Data
command(-1, 8), response
;
513 JVMPacket
packet(command
, response
);
515 // Send the command packet
517 m_socket
->Packet(packet
);
518 expect
= packet
.Size();
523 // Read the data stream
524 m_socket
->Receive(response
);
526 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
528 // Check the size read into the previous packet
529 if( expect
!= bytereceived
) {
530 ThrowJVMError("JVMDebug::Attach expect", expect
);
538 void JVMDebug::Unknown10()
542 Data
command(-1, 8), response
;
543 JVMPacket
packet(command
, response
);
545 // Send the command packet
547 m_socket
->Packet(packet
);
548 expect
= packet
.Size();
553 // Read the data stream
554 m_socket
->Receive(response
);
556 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
558 // Check the size read into the previous packet
559 if( expect
!= bytereceived
) {
560 ThrowJVMError("JVMDebug::Attach expect", expect
);
568 bool JVMDebug::GetStatus(int &status
)
572 Data
command(-1, 8), response
;
573 JVMPacket
packet(command
, response
);
575 // Send the command packet
578 m_socket
->Packet(packet
);
580 expect
= packet
.Size();
585 // Read the data stream
586 m_socket
->Receive(response
);
588 MAKE_JVMPACKET(dpack
, response
);
590 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
592 // Check the size read into the previous packet
593 if( expect
!= bytereceived
) {
594 ThrowJVMError("JVMDebug::GetModulesList expect", expect
);
597 // Make sure we have a header to read
598 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.status
));
601 status
= dpack
->u
.status
;
610 bool JVMDebug::WaitStatus(int &status
)
614 Data
command(-1, 8), response
;
615 JVMPacket
packet(command
, response
);
617 // Prepare the command packet
621 m_socket
->Receive(packet
.GetReceive(), 100);
622 } catch (Usb::Timeout
&to
) {
626 expect
= packet
.Size();
631 // Read the data stream
632 m_socket
->Receive(response
);
634 MAKE_JVMPACKET(dpack
, response
);
636 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
638 // Check the size read into the previous packet
639 if( expect
!= bytereceived
) {
640 ThrowJVMError("JVMDebug::GetModulesList expect", expect
);
643 // Make sure we have a header to read
644 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.status
));
647 status
= dpack
->u
.status
;
654 // Get Console Message
655 // Sample, display the output of System.out.println(...) and all JVM messages output
657 // Return the length message or -1 if message doesn't exit or is empty
659 int JVMDebug::GetConsoleMessage(std::string
&message
)
663 Data
command(-1, 8), response
;
664 JVMPacket
packet(command
, response
);
666 // Send the command packet
667 packet
.GetConsoleMessage();
669 m_socket
->Packet(packet
);
671 expect
= packet
.Size();
676 // Read the data stream
677 m_socket
->Receive(response
);
679 MAKE_JVMPACKET(dpack
, response
);
681 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
683 // Check the size read into the previous packet
684 if( expect
!= bytereceived
) {
685 ThrowJVMError("JVMDebug::GetModulesList expect", expect
);
688 // Make sure we have a header to read
689 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.msglength
));
692 uint16_t length
= be_btohs(dpack
->u
.msglength
);
697 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.msglength
) + length
);
699 // Parse the ID of nextmodules
700 const unsigned char *ptr
= (response
.GetData() + SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.msglength
));
702 message
.assign((char *) ptr
, length
);
709 // Get list of Java modules
711 void JVMDebug::GetModulesList(JVMModulesList
&mylist
)
718 Data
command(-1, 8), response
;
719 JVMPacket
packet(command
, response
);
722 // Send the command packet
723 packet
.GetModulesList(offset
);
725 m_socket
->Packet(packet
);
727 expect
= packet
.Size();
732 // Read the data stream
733 m_socket
->Receive(response
);
735 MAKE_JVMPACKET(dpack
, response
);
737 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
739 // Check the size read into the previous packet
740 if( expect
!= bytereceived
) {
741 ThrowJVMError("JVMDebug::GetModulesList expect", expect
);
744 // Make sure there's enough for packet header + module list
745 // header + 4 bytes of ID
746 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMMODULES_LIST_HEADER_SIZE
+ 4);
748 // Number of modules entries in the list
749 count
= be_btohl(dpack
->u
.moduleslist
.nbr
);
751 // Size of modules list
752 // I remove the header of packet (contains the field 'number of modules')
753 // and 4 bytes (contains the field 'ID of next modules')
754 size
= bytereceived
- SB_JVMMODULES_LIST_HEADER_SIZE
- 4;
756 // Parse the modules list
757 mylist
.Parse(Data(response
.GetData() + SB_JVMPACKET_HEADER_SIZE
+ SB_JVMMODULES_LIST_HEADER_SIZE
, size
));
759 // Parse the ID of nextmodules
760 size_t id_offset
= SB_JVMPACKET_HEADER_SIZE
+ SB_JVMMODULES_LIST_HEADER_SIZE
+ size
;
761 const unsigned char *ptr
= (response
.GetData() + id_offset
);
762 CheckSize(response
, id_offset
+ sizeof(uint32_t));
763 uint32_t *poffset
= (uint32_t *) ptr
;
765 offset
= be_btohl(*poffset
);
766 } while (offset
!= 0); // When the offset != 0, there is some modules
771 // Get list of Java threads
773 void JVMDebug::GetThreadsList(JVMThreadsList
&mylist
)
779 Data
command(-1, 8), response
;
780 JVMPacket
packet(command
, response
);
782 // Send the command packet
783 packet
.GetThreadsList();
785 m_socket
->Packet(packet
);
787 expect
= packet
.Size();
792 // Read the data stream
793 m_socket
->Receive(response
);
795 MAKE_JVMPACKET(dpack
, response
);
797 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
799 // Check the size read into the previous packet
800 if( expect
!= bytereceived
) {
801 ThrowJVMError("JVMDebug::GetThreadsList expect", expect
);
804 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMTHREADS_LIST_HEADER_SIZE
);
806 // Number of threads entries in the list
807 count
= be_btohl(dpack
->u
.threadslist
.nbr
);
809 // Size of threads list
810 // I remove the header of packet (contains the field 'number of threads')
811 size
= bytereceived
- SB_JVMTHREADS_LIST_HEADER_SIZE
;
813 // Parse the threads list
814 mylist
.Parse(Data(response
.GetData() + SB_JVMPACKET_HEADER_SIZE
+ SB_JVMTHREADS_LIST_HEADER_SIZE
, size
));
816 // Complete threads list
817 JVMThreadsList::iterator b
= mylist
.begin();
818 for( ; b
!= mylist
.end(); b
++ ) {
819 JVMThreadsEntry entry
= (*b
);
822 // Send the command packet
823 packet
.Unknown11(entry
.Id
);
825 m_socket
->Packet(packet
);
827 expect
= packet
.Size();
832 // Read the data stream
833 m_socket
->Receive(response
);
835 MAKE_JVMPACKET(dpack
, response
);
837 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
839 // Check the size read into the previous packet
840 if( expect
!= bytereceived
) {
841 ThrowJVMError("JVMDebug::GetThreadsList (1) expect", expect
);
844 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMUNKNOWN01_HEADER_SIZE
);
847 entry
.Byte
= dpack
->u
.unknown01
.byte
;
848 entry
.Address
= be_btohl(dpack
->u
.unknown01
.address
);
851 if (entry
.Address
!= 0) {
852 // Send the command packet
853 packet
.Unknown12(entry
.Address
);
855 m_socket
->Packet(packet
);
857 expect
= packet
.Size();
862 // Read the data stream
863 m_socket
->Receive(response
);
865 MAKE_JVMPACKET(dpack
, response
);
867 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
869 // Check the size read into the previous packet
870 if( expect
!= bytereceived
) {
871 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
876 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.address
));
877 entry
.Unknown01
= be_btohl(dpack
->u
.address
);
883 // Send the command packet
884 packet
.Unknown13(entry
.Id
);
886 m_socket
->Packet(packet
);
888 expect
= packet
.Size();
893 // Read the data stream
894 m_socket
->Receive(response
);
896 dpack
= (const Protocol::JVMPacket
*) response
.GetData();
898 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
900 // Check the size read into the previous packet
901 if( expect
!= bytereceived
) {
902 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
906 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.address
));
907 entry
.Unknown02
= be_btohl(dpack
->u
.address
);
910 // Send the command packet
911 packet
.Unknown14(entry
.Id
);
913 m_socket
->Packet(packet
);
915 expect
= packet
.Size();
920 // Read the data stream
921 m_socket
->Receive(response
);
923 dpack
= (const Protocol::JVMPacket
*) response
.GetData();
925 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
927 // Check the size read into the previous packet
928 if( expect
!= bytereceived
) {
929 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
933 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMUNKNOWN02_HEADER_SIZE
);
934 entry
.Unknown03
= be_btohl(dpack
->u
.unknown02
.address1
);
935 entry
.Unknown04
= be_btohl(dpack
->u
.unknown02
.address2
);
938 // Send the command packet
939 packet
.Unknown15(entry
.Id
);
941 m_socket
->Packet(packet
);
943 expect
= packet
.Size();
948 // Read the data stream
949 m_socket
->Receive(response
);
951 dpack
= (const Protocol::JVMPacket
*) response
.GetData();
953 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
955 // Check the size read into the previous packet
956 if( expect
!= bytereceived
) {
957 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
961 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMUNKNOWN02_HEADER_SIZE
);
962 entry
.Unknown05
= be_btohl(dpack
->u
.unknown02
.address1
);
963 entry
.Unknown06
= be_btohl(dpack
->u
.unknown02
.address2
);
978 Data
command(-1, 8), response
;
979 JVMPacket
packet(command
, response
);
981 // Send the command packet
983 m_socket
->Packet(packet
);
984 expect
= packet
.Size();
986 while (expect
== 0) {
987 m_socket
->Receive(packet
.GetReceive());
989 expect
= packet
.Size();
992 // Read the data stream
993 m_socket
->Receive(response
);
995 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
997 // Check the size read into the previous packet
998 if( expect
!= bytereceived
) {
999 ThrowJVMError("JVMDebug::Attach expect", expect
);
1007 void JVMDebug::Stop()
1009 uint16_t expect
= 0;
1011 Data
command(-1, 8), response
;
1012 JVMPacket
packet(command
, response
);
1014 // Send the command packet
1016 m_socket
->Packet(packet
);
1017 expect
= packet
.Size();
1019 while (expect
== 0) {
1020 m_socket
->Receive(packet
.GetReceive());
1022 expect
= packet
.Size();
1025 // Read the data stream
1026 m_socket
->Receive(response
);
1028 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
1030 // Check the size read into the previous packet
1031 if( expect
!= bytereceived
) {
1032 ThrowJVMError("JVMDebug::Attach expect", expect
);
1037 }} // namespace Barry::Mode