2020-05-04 12:23:30 +03:00
/*
* Copyright ( c ) 2020 , Itamar S . < itamar8910 @ gmail . com >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2020-05-08 13:32:55 +03:00
# include "VariablesModel.h"
2020-05-30 14:19:49 -04:00
# include <LibGUI/Application.h>
# include <LibGUI/MessageBox.h>
2020-05-04 12:23:30 +03:00
2020-08-17 15:22:30 +02:00
namespace HackStudio {
2020-05-08 13:32:55 +03:00
GUI : : ModelIndex VariablesModel : : index ( int row , int column , const GUI : : ModelIndex & parent_index ) const
2020-05-04 12:23:30 +03:00
{
if ( ! parent_index . is_valid ( ) )
return create_index ( row , column , & m_variables [ row ] ) ;
2020-08-25 04:33:07 +01:00
auto * parent = static_cast < const Debug : : DebugInfo : : VariableInfo * > ( parent_index . internal_data ( ) ) ;
2020-05-04 12:23:30 +03:00
auto * child = & parent - > members [ row ] ;
return create_index ( row , column , child ) ;
}
2020-05-08 13:32:55 +03:00
GUI : : ModelIndex VariablesModel : : parent_index ( const GUI : : ModelIndex & index ) const
2020-05-04 12:23:30 +03:00
{
if ( ! index . is_valid ( ) )
return { } ;
2020-08-25 04:33:07 +01:00
auto * child = static_cast < const Debug : : DebugInfo : : VariableInfo * > ( index . internal_data ( ) ) ;
2020-05-04 12:23:30 +03:00
auto * parent = child - > parent ;
if ( parent = = nullptr )
return { } ;
if ( parent - > parent = = nullptr ) {
for ( size_t row = 0 ; row < m_variables . size ( ) ; row + + )
if ( m_variables . ptr_at ( row ) . ptr ( ) = = parent )
return create_index ( row , 0 , parent ) ;
ASSERT_NOT_REACHED ( ) ;
}
for ( size_t row = 0 ; row < parent - > parent - > members . size ( ) ; row + + ) {
2020-08-25 04:33:07 +01:00
Debug : : DebugInfo : : VariableInfo * child_at_row = parent - > parent - > members . ptr_at ( row ) . ptr ( ) ;
2020-05-04 12:23:30 +03:00
if ( child_at_row = = parent )
return create_index ( row , 0 , parent ) ;
}
ASSERT_NOT_REACHED ( ) ;
}
2020-05-08 13:32:55 +03:00
int VariablesModel : : row_count ( const GUI : : ModelIndex & index ) const
2020-05-04 12:23:30 +03:00
{
if ( ! index . is_valid ( ) )
return m_variables . size ( ) ;
2020-08-25 04:33:07 +01:00
auto * node = static_cast < const Debug : : DebugInfo : : VariableInfo * > ( index . internal_data ( ) ) ;
2020-05-04 12:23:30 +03:00
return node - > members . size ( ) ;
}
2020-08-25 04:33:07 +01:00
static String variable_value_as_string ( const Debug : : DebugInfo : : VariableInfo & variable )
2020-05-04 12:23:30 +03:00
{
2020-08-25 04:33:07 +01:00
if ( variable . location_type ! = Debug : : DebugInfo : : VariableInfo : : LocationType : : Address )
2020-05-04 12:23:30 +03:00
return " N/A " ;
auto variable_address = variable . location_data . address ;
2020-05-31 22:51:12 -04:00
if ( variable . is_enum_type ( ) ) {
auto value = Debugger : : the ( ) . session ( ) - > peek ( ( u32 * ) variable_address ) ;
ASSERT ( value . has_value ( ) ) ;
auto it = variable . type - > members . find ( [ enumerator_value = value . value ( ) ] ( auto & enumerator ) {
return enumerator - > constant_data . as_u32 = = enumerator_value ;
} ) ;
ASSERT ( ! it . is_end ( ) ) ;
return String : : format ( " %s::%s " , variable . type_name . characters ( ) , ( * it ) - > name . characters ( ) ) ;
}
if ( variable . type_name = = " int " ) {
2020-05-04 12:23:30 +03:00
auto value = Debugger : : the ( ) . session ( ) - > peek ( ( u32 * ) variable_address ) ;
ASSERT ( value . has_value ( ) ) ;
return String : : format ( " %d " , static_cast < int > ( value . value ( ) ) ) ;
}
2020-05-31 22:51:12 -04:00
if ( variable . type_name = = " char " ) {
2020-05-04 12:23:30 +03:00
auto value = Debugger : : the ( ) . session ( ) - > peek ( ( u32 * ) variable_address ) ;
ASSERT ( value . has_value ( ) ) ;
return String : : format ( " '%c' (%d) " , static_cast < char > ( value . value ( ) ) , static_cast < char > ( value . value ( ) ) ) ;
}
2020-05-31 22:51:12 -04:00
if ( variable . type_name = = " bool " ) {
2020-05-30 14:19:49 -04:00
auto value = Debugger : : the ( ) . session ( ) - > peek ( ( u32 * ) variable_address ) ;
ASSERT ( value . has_value ( ) ) ;
return ( value . value ( ) & 1 ) ? " true " : " false " ;
}
2020-05-31 22:51:12 -04:00
return String : : format ( " type: %s @ %08x, " , variable . type_name . characters ( ) , variable_address ) ;
2020-05-04 12:23:30 +03:00
}
2020-08-25 04:33:07 +01:00
static Optional < u32 > string_to_variable_value ( const StringView & string_value , const Debug : : DebugInfo : : VariableInfo & variable )
2020-05-30 14:19:49 -04:00
{
2020-05-31 22:51:12 -04:00
if ( variable . is_enum_type ( ) ) {
auto prefix_string = String : : format ( " %s:: " , variable . type_name . characters ( ) ) ;
auto string_to_use = string_value ;
if ( string_value . starts_with ( prefix_string ) )
string_to_use = string_value . substring_view ( prefix_string . length ( ) , string_value . length ( ) - prefix_string . length ( ) ) ;
auto it = variable . type - > members . find ( [ string_to_use ] ( auto & enumerator ) {
return enumerator - > name = = string_to_use ;
} ) ;
if ( it . is_end ( ) )
return { } ;
return ( * it ) - > constant_data . as_u32 ;
}
if ( variable . type_name = = " int " ) {
2020-06-12 21:07:52 +02:00
auto value = string_value . to_int ( ) ;
if ( value . has_value ( ) )
return value . value ( ) ;
return { } ;
2020-05-30 14:19:49 -04:00
}
2020-05-31 22:51:12 -04:00
if ( variable . type_name = = " bool " ) {
2020-05-30 14:19:49 -04:00
if ( string_value = = " true " )
return true ;
if ( string_value = = " false " )
return false ;
return { } ;
}
return { } ;
}
void VariablesModel : : set_variable_value ( const GUI : : ModelIndex & index , const StringView & string_value , GUI : : Window * parent_window )
{
2020-08-25 04:33:07 +01:00
auto variable = static_cast < const Debug : : DebugInfo : : VariableInfo * > ( index . internal_data ( ) ) ;
2020-05-30 14:19:49 -04:00
2020-05-31 22:51:12 -04:00
auto value = string_to_variable_value ( string_value , * variable ) ;
2020-05-30 14:19:49 -04:00
if ( value . has_value ( ) ) {
auto success = Debugger : : the ( ) . session ( ) - > poke ( ( u32 * ) variable - > location_data . address , value . value ( ) ) ;
ASSERT ( success ) ;
return ;
}
2020-07-15 20:45:11 -06:00
GUI : : MessageBox : : show ( parent_window ,
2020-05-31 22:51:12 -04:00
String : : format ( " String value \" %s \" could not be converted to a value of type %s. " , string_value . to_string ( ) . characters ( ) , variable - > type_name . characters ( ) ) ,
2020-05-30 14:19:49 -04:00
" Set value failed " ,
2020-07-15 20:45:11 -06:00
GUI : : MessageBox : : Type : : Error ) ;
2020-05-30 14:19:49 -04:00
}
2020-08-16 16:00:07 +02:00
GUI : : Variant VariablesModel : : data ( const GUI : : ModelIndex & index , GUI : : ModelRole role ) const
2020-05-04 12:23:30 +03:00
{
2020-08-25 04:33:07 +01:00
auto * variable = static_cast < const Debug : : DebugInfo : : VariableInfo * > ( index . internal_data ( ) ) ;
2020-05-04 12:23:30 +03:00
switch ( role ) {
2020-08-16 16:00:07 +02:00
case GUI : : ModelRole : : Display : {
2020-05-04 12:23:30 +03:00
auto value_as_string = variable_value_as_string ( * variable ) ;
return String : : format ( " %s: %s " , variable - > name . characters ( ) , value_as_string . characters ( ) ) ;
}
2020-08-16 16:00:07 +02:00
case GUI : : ModelRole : : Icon :
2020-05-04 12:23:30 +03:00
return m_variable_icon ;
default :
return { } ;
}
}
2020-05-08 13:32:55 +03:00
void VariablesModel : : update ( )
2020-05-04 12:23:30 +03:00
{
did_update ( ) ;
}
2020-05-08 13:32:55 +03:00
RefPtr < VariablesModel > VariablesModel : : create ( const PtraceRegisters & regs )
2020-05-04 12:23:30 +03:00
{
auto variables = Debugger : : the ( ) . session ( ) - > debug_info ( ) . get_variables_in_current_scope ( regs ) ;
2020-05-08 13:32:55 +03:00
return adopt ( * new VariablesModel ( move ( variables ) , regs ) ) ;
2020-05-08 10:59:28 +03:00
}
2020-08-17 15:22:30 +02:00
}