2 /// \file m_jvmdebug.cc
3 /// Mode class for the JVMDebug mode
7 Copyright (C) 2005-2012, 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
)
717 Data
command(-1, 8), response
;
718 JVMPacket
packet(command
, response
);
721 // Send the command packet
722 packet
.GetModulesList(offset
);
724 m_socket
->Packet(packet
);
726 expect
= packet
.Size();
731 // Read the data stream
732 m_socket
->Receive(response
);
734 // MAKE_JVMPACKET(dpack, response); // unused
736 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
738 // Check the size read into the previous packet
739 if( expect
!= bytereceived
) {
740 ThrowJVMError("JVMDebug::GetModulesList expect", expect
);
743 // Make sure there's enough for packet header + module list
744 // header + 4 bytes of ID
745 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMMODULES_LIST_HEADER_SIZE
+ 4);
747 // Number of modules entries in the list
748 // (Valid, but unused variable... disabled to stop compiler
750 // uint32_t count = be_btohl(dpack->u.moduleslist.nbr);
752 // Size of modules list
753 // I remove the header of packet (contains the field 'number of modules')
754 // and 4 bytes (contains the field 'ID of next modules')
755 size
= bytereceived
- SB_JVMMODULES_LIST_HEADER_SIZE
- 4;
757 // Parse the modules list
758 mylist
.Parse(Data(response
.GetData() + SB_JVMPACKET_HEADER_SIZE
+ SB_JVMMODULES_LIST_HEADER_SIZE
, size
));
760 // Parse the ID of nextmodules
761 size_t id_offset
= SB_JVMPACKET_HEADER_SIZE
+ SB_JVMMODULES_LIST_HEADER_SIZE
+ size
;
762 const unsigned char *ptr
= (response
.GetData() + id_offset
);
763 CheckSize(response
, id_offset
+ sizeof(uint32_t));
764 uint32_t *poffset
= (uint32_t *) ptr
;
766 offset
= be_btohl(*poffset
);
767 } while (offset
!= 0); // When the offset != 0, there is some modules
772 // Get list of Java threads
774 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); // unused
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 // (Valid, but unused variable... disabled to stop compiler warnings)
808 // uint32_t count = be_btohl(dpack->u.threadslist.nbr);
810 // Size of threads list
811 // I remove the header of packet (contains the field 'number of threads')
812 size
= bytereceived
- SB_JVMTHREADS_LIST_HEADER_SIZE
;
814 // Parse the threads list
815 mylist
.Parse(Data(response
.GetData() + SB_JVMPACKET_HEADER_SIZE
+ SB_JVMTHREADS_LIST_HEADER_SIZE
, size
));
817 // Complete threads list
818 JVMThreadsList::iterator b
= mylist
.begin();
819 for( ; b
!= mylist
.end(); b
++ ) {
820 JVMThreadsEntry entry
= (*b
);
823 // Send the command packet
824 packet
.Unknown11(entry
.Id
);
826 m_socket
->Packet(packet
);
828 expect
= packet
.Size();
833 // Read the data stream
834 m_socket
->Receive(response
);
836 MAKE_JVMPACKET(dpack
, response
);
838 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
840 // Check the size read into the previous packet
841 if( expect
!= bytereceived
) {
842 ThrowJVMError("JVMDebug::GetThreadsList (1) expect", expect
);
845 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMUNKNOWN01_HEADER_SIZE
);
848 entry
.Byte
= dpack
->u
.unknown01
.byte
;
849 entry
.Address
= be_btohl(dpack
->u
.unknown01
.address
);
852 if (entry
.Address
!= 0) {
853 // Send the command packet
854 packet
.Unknown12(entry
.Address
);
856 m_socket
->Packet(packet
);
858 expect
= packet
.Size();
863 // Read the data stream
864 m_socket
->Receive(response
);
866 MAKE_JVMPACKET(dpack
, response
);
868 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
870 // Check the size read into the previous packet
871 if( expect
!= bytereceived
) {
872 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
877 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.address
));
878 entry
.Unknown01
= be_btohl(dpack
->u
.address
);
884 // Send the command packet
885 packet
.Unknown13(entry
.Id
);
887 m_socket
->Packet(packet
);
889 expect
= packet
.Size();
894 // Read the data stream
895 m_socket
->Receive(response
);
897 dpack
= (const Protocol::JVMPacket
*) response
.GetData();
899 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
901 // Check the size read into the previous packet
902 if( expect
!= bytereceived
) {
903 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
907 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ sizeof(dpack
->u
.address
));
908 entry
.Unknown02
= be_btohl(dpack
->u
.address
);
911 // Send the command packet
912 packet
.Unknown14(entry
.Id
);
914 m_socket
->Packet(packet
);
916 expect
= packet
.Size();
921 // Read the data stream
922 m_socket
->Receive(response
);
924 dpack
= (const Protocol::JVMPacket
*) response
.GetData();
926 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
928 // Check the size read into the previous packet
929 if( expect
!= bytereceived
) {
930 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
934 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMUNKNOWN02_HEADER_SIZE
);
935 entry
.Unknown03
= be_btohl(dpack
->u
.unknown02
.address1
);
936 entry
.Unknown04
= be_btohl(dpack
->u
.unknown02
.address2
);
939 // Send the command packet
940 packet
.Unknown15(entry
.Id
);
942 m_socket
->Packet(packet
);
944 expect
= packet
.Size();
949 // Read the data stream
950 m_socket
->Receive(response
);
952 dpack
= (const Protocol::JVMPacket
*) response
.GetData();
954 bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
956 // Check the size read into the previous packet
957 if( expect
!= bytereceived
) {
958 ThrowJVMError("JVMDebug::GetThreadsList (2) expect", expect
);
962 CheckSize(response
, SB_JVMPACKET_HEADER_SIZE
+ SB_JVMUNKNOWN02_HEADER_SIZE
);
963 entry
.Unknown05
= be_btohl(dpack
->u
.unknown02
.address1
);
964 entry
.Unknown06
= be_btohl(dpack
->u
.unknown02
.address2
);
979 Data
command(-1, 8), response
;
980 JVMPacket
packet(command
, response
);
982 // Send the command packet
984 m_socket
->Packet(packet
);
985 expect
= packet
.Size();
987 while (expect
== 0) {
988 m_socket
->Receive(packet
.GetReceive());
990 expect
= packet
.Size();
993 // Read the data stream
994 m_socket
->Receive(response
);
996 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
998 // Check the size read into the previous packet
999 if( expect
!= bytereceived
) {
1000 ThrowJVMError("JVMDebug::Attach expect", expect
);
1008 void JVMDebug::Stop()
1010 uint16_t expect
= 0;
1012 Data
command(-1, 8), response
;
1013 JVMPacket
packet(command
, response
);
1015 // Send the command packet
1017 m_socket
->Packet(packet
);
1018 expect
= packet
.Size();
1020 while (expect
== 0) {
1021 m_socket
->Receive(packet
.GetReceive());
1023 expect
= packet
.Size();
1026 // Read the data stream
1027 m_socket
->Receive(response
);
1029 size_t bytereceived
= response
.GetSize() - SB_JVMPACKET_HEADER_SIZE
;
1031 // Check the size read into the previous packet
1032 if( expect
!= bytereceived
) {
1033 ThrowJVMError("JVMDebug::Attach expect", expect
);
1038 }} // namespace Barry::Mode