summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDavid Boddie <dboddie@trolltech.com>2010-07-16 15:46:21 (GMT)
committerDavid Boddie <dboddie@trolltech.com>2010-07-16 15:46:21 (GMT)
commit6b1b666574d6e27efdd3b243de8815a5278c3666 (patch)
tree7a5ac02fe569b3fc497ca8d0a333d10587eb3567 /tools
parenteef1d13743baddf41bd135d98fc2ad12944b8477 (diff)
parentab4dde176cfa314522964e5e5fbf9f2d388f8fdf (diff)
downloadQt-6b1b666574d6e27efdd3b243de8815a5278c3666.zip
Qt-6b1b666574d6e27efdd3b243de8815a5278c3666.tar.gz
Qt-6b1b666574d6e27efdd3b243de8815a5278c3666.tar.bz2
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into 4.7
Conflicts: tools/qdoc3/test/qt.qdocconf
Diffstat (limited to 'tools')
-rw-r--r--tools/assistant/tools/assistant/assistant.pro2
-rw-r--r--tools/assistant/translations/qt_help.pro53
-rw-r--r--tools/assistant/translations/translations.pro54
-rw-r--r--tools/configure/configureapp.cpp16
-rw-r--r--tools/designer/src/components/lib/lib.pro10
-rw-r--r--tools/designer/src/components/objectinspector/objectinspector.pri2
-rw-r--r--tools/designer/src/components/propertyeditor/propertyeditor.pri4
-rw-r--r--tools/designer/src/designer/designer.pro5
-rw-r--r--tools/designer/src/lib/shared/shared.pri10
-rw-r--r--tools/designer/translations/translations.pro141
-rw-r--r--tools/linguist/linguist/linguist.pro12
-rw-r--r--tools/qdoc3/doc/files/qt.qdocconf10
-rw-r--r--tools/qdoc3/htmlgenerator.cpp117
-rw-r--r--tools/qdoc3/htmlgenerator.h8
-rw-r--r--tools/qdoc3/node.cpp18
-rw-r--r--tools/qdoc3/node.h1
-rw-r--r--tools/qdoc3/test/assistant.qdocconf24
-rw-r--r--tools/qdoc3/test/qdeclarative.qdocconf6
-rw-r--r--tools/qdoc3/test/qt-build-docs.qdocconf12
-rw-r--r--tools/qml/deviceorientation_symbian.cpp162
-rw-r--r--tools/qml/main.cpp21
-rw-r--r--tools/qml/qml.pri6
-rw-r--r--tools/qml/qml.pro3
-rw-r--r--tools/qml/qmlruntime.cpp164
-rw-r--r--tools/qml/qmlruntime.h4
-rw-r--r--tools/qtconfig/translations/translations.pro16
-rw-r--r--tools/qvfb/qvfb.pro2
-rw-r--r--tools/qvfb/translations/translations.pro35
-rw-r--r--tools/runonphone/main.cpp18
-rw-r--r--tools/runonphone/serenum.h2
-rw-r--r--tools/runonphone/serenum_unix.cpp107
-rw-r--r--tools/runonphone/serenum_win.cpp2
-rw-r--r--tools/runonphone/symbianutils/json.cpp490
-rw-r--r--tools/runonphone/symbianutils/json.h149
-rw-r--r--tools/runonphone/symbianutils/launcher.cpp180
-rw-r--r--tools/runonphone/symbianutils/launcher.h12
-rw-r--r--tools/runonphone/symbianutils/symbianutils.pri12
-rw-r--r--tools/runonphone/symbianutils/tcftrkdevice.cpp929
-rw-r--r--tools/runonphone/symbianutils/tcftrkdevice.h295
-rw-r--r--tools/runonphone/symbianutils/tcftrkmessage.cpp562
-rw-r--r--tools/runonphone/symbianutils/tcftrkmessage.h296
-rw-r--r--tools/runonphone/symbianutils/trkdevice.cpp5
-rw-r--r--tools/runonphone/symbianutils/trkutils.cpp143
-rw-r--r--tools/runonphone/symbianutils/trkutils.h31
-rw-r--r--tools/runonphone/symbianutils/trkutils_p.h2
-rw-r--r--tools/runonphone/trksignalhandler.cpp180
-rw-r--r--tools/runonphone/trksignalhandler.h8
47 files changed, 3792 insertions, 549 deletions
diff --git a/tools/assistant/tools/assistant/assistant.pro b/tools/assistant/tools/assistant/assistant.pro
index eb8cc51..d9aff7a 100644
--- a/tools/assistant/tools/assistant/assistant.pro
+++ b/tools/assistant/tools/assistant/assistant.pro
@@ -1,4 +1,4 @@
-include($$QT_SOURCE_TREE/tools/shared/fontpanel/fontpanel.pri)
+include(../../../shared/fontpanel/fontpanel.pri)
TEMPLATE = app
LANGUAGE = C++
TARGET = assistant
diff --git a/tools/assistant/translations/qt_help.pro b/tools/assistant/translations/qt_help.pro
deleted file mode 100644
index 6f66876..0000000
--- a/tools/assistant/translations/qt_help.pro
+++ /dev/null
@@ -1,53 +0,0 @@
-# Include those manually as they do not contain any directory specification
-
-SOURCES += ../lib/qhelpcollectionhandler.cpp \
- ../lib/qhelpcontentwidget.cpp \
- ../lib/qhelpdatainterface.cpp \
- ../lib/qhelpdbreader.cpp \
- ../lib/qhelpengine.cpp \
- ../lib/qhelpenginecore.cpp \
- ../lib/qhelpgenerator.cpp \
- ../lib/qhelpindexwidget.cpp \
- ../lib/qhelpprojectdata.cpp \
- ../lib/qhelpsearchengine.cpp \
- ../lib/qhelpsearchindexreader_clucene.cpp \
- ../lib/qhelpsearchindexreader_default.cpp \
- ../lib/qhelpsearchindexwriter_clucene.cpp \
- ../lib/qhelpsearchindexwriter_default.cpp \
- ../lib/qhelpsearchindex_default.cpp \
- ../lib/qhelpsearchquerywidget.cpp \
- ../lib/qhelpsearchresultwidget.cpp
-
-HEADERS += ../lib/qhelpcollectionhandler_p.h \
- ../lib/qhelpcontentwidget.h \
- ../lib/qhelpdatainterface_p.h \
- ../lib/qhelpdbreader_p.h \
- ../lib/qhelpengine.h \
- ../lib/qhelpenginecore.h \
- ../lib/qhelpengine_p.h \
- ../lib/qhelpgenerator_p.h \
- ../lib/qhelpindexwidget.h \
- ../lib/qhelpprojectdata_p.h \
- ../lib/qhelpsearchengine.h \
- ../lib/qhelpsearchindexreader_clucene_p.h \
- ../lib/qhelpsearchindexreader_default_p.h \
- ../lib/qhelpsearchindexwriter_clucene_p.h \
- ../lib/qhelpsearchindexwriter_default_p.h \
- ../lib/qhelpsearchindex_default_p.h \
- ../lib/qhelpsearchquerywidget.h \
- ../lib/qhelpsearchresultwidget.h \
- ../lib/qhelp_global.h
-
-
-TR_DIR = $$PWD/../../../translations
-TRANSLATIONS = \
- $$TR_DIR/qt_help_cs.ts \
- $$TR_DIR/qt_help_da.ts \
- $$TR_DIR/qt_help_de.ts \
- $$TR_DIR/qt_help_hu.ts \
- $$TR_DIR/qt_help_ja.ts \
- $$TR_DIR/qt_help_pl.ts \
- $$TR_DIR/qt_help_ru.ts \
- $$TR_DIR/qt_help_zh_CN.ts \
- $$TR_DIR/qt_help_zh_TW.ts \
- $$TR_DIR/qt_help_fr.ts
diff --git a/tools/assistant/translations/translations.pro b/tools/assistant/translations/translations.pro
deleted file mode 100644
index c692262..0000000
--- a/tools/assistant/translations/translations.pro
+++ /dev/null
@@ -1,54 +0,0 @@
-# Include those manually as they do not contain any directory specification
-
-FORMS += ../tools/assistant/filternamedialog.ui \
- ../tools/assistant/installdialog.ui \
- ../tools/assistant/preferencesdialog.ui \
- ../tools/assistant/topicchooser.ui \
- ../tools/assistant/bookmarkdialog.ui
-
-SOURCES += ../tools/assistant/aboutdialog.cpp \
- ../tools/assistant/bookmarkmanager.cpp \
- ../tools/assistant/centralwidget.cpp \
- ../tools/assistant/cmdlineparser.cpp \
- ../tools/assistant/contentwindow.cpp \
- ../tools/assistant/filternamedialog.cpp \
- ../tools/assistant/helpviewer.cpp \
- ../tools/assistant/indexwindow.cpp \
- ../tools/assistant/installdialog.cpp \
- ../tools/assistant/main.cpp \
- ../tools/assistant/mainwindow.cpp \
- ../tools/assistant/preferencesdialog.cpp \
- ../tools/assistant/remotecontrol.cpp \
- ../tools/assistant/searchwidget.cpp \
- ../tools/assistant/topicchooser.cpp \
-
-SOURCES += ../../shared/fontpanel/fontpanel.cpp
-
-HEADERS += ../tools/assistant/aboutdialog.h \
- ../tools/assistant/bookmarkmanager.h \
- ../tools/assistant/centralwidget.h \
- ../tools/assistant/cmdlineparser.h \
- ../tools/assistant/contentwindow.h \
- ../tools/assistant/filternamedialog.h \
- ../tools/assistant/helpviewer.h \
- ../tools/assistant/indexwindow.h \
- ../tools/assistant/installdialog.h \
- ../tools/assistant/mainwindow.h \
- ../tools/assistant/preferencesdialog.h \
- ../tools/assistant/remotecontrol.h \
- ../tools/assistant/remotecontrol_win.h \
- ../tools/assistant/searchwidget.h \
- ../tools/assistant/topicchooser.h \
-
-TR_DIR = $$PWD/../../../translations
-TRANSLATIONS = \
- $$TR_DIR/assistant_cs.ts \
- $$TR_DIR/assistant_da.ts \
- $$TR_DIR/assistant_de.ts \
- $$TR_DIR/assistant_fr.ts \
- $$TR_DIR/assistant_hu.ts \
- $$TR_DIR/assistant_ja.ts \
- $$TR_DIR/assistant_pl.ts \
- $$TR_DIR/assistant_ru.ts \
- $$TR_DIR/assistant_zh_CN.ts \
- $$TR_DIR/assistant_zh_TW.ts
diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp
index 952d4e0..7f2d53b 100644
--- a/tools/configure/configureapp.cpp
+++ b/tools/configure/configureapp.cpp
@@ -2439,7 +2439,9 @@ void Configure::generateOutputVars()
qmakeFormatPlugins += "gif";
if (dictionary[ "TIFF" ] == "no")
- qtConfig += "no-tiff";
+ qtConfig += "no-tiff";
+ else if (dictionary[ "TIFF" ] == "yes")
+ qtConfig += "tiff";
else if (dictionary[ "TIFF" ] == "plugin")
qmakeFormatPlugins += "tiff";
if (dictionary[ "LIBTIFF" ] == "system")
@@ -2447,6 +2449,8 @@ void Configure::generateOutputVars()
if (dictionary[ "JPEG" ] == "no")
qtConfig += "no-jpeg";
+ else if (dictionary[ "JPEG" ] == "yes")
+ qtConfig += "jpeg";
else if (dictionary[ "JPEG" ] == "plugin")
qmakeFormatPlugins += "jpeg";
if (dictionary[ "LIBJPEG" ] == "system")
@@ -3160,16 +3164,6 @@ void Configure::generateConfigfiles()
QFile::remove(outName);
tmpFile.copy(outName);
tmpFile.close();
-
- if (!QFile::exists(buildPath + "/include/QtCore/qconfig.h")) {
- if (!writeToFile("#include \"../../src/corelib/global/qconfig.h\"\n",
- buildPath + "/include/QtCore/qconfig.h")
- || !writeToFile("#include \"../../src/corelib/global/qconfig.h\"\n",
- buildPath + "/include/Qt/qconfig.h")) {
- dictionary["DONE"] = "error";
- return;
- }
- }
}
// Copy configured mkspec to default directory, but remove the old one first, if there is any
diff --git a/tools/designer/src/components/lib/lib.pro b/tools/designer/src/components/lib/lib.pro
index 8d0e692..0ada845 100644
--- a/tools/designer/src/components/lib/lib.pro
+++ b/tools/designer/src/components/lib/lib.pro
@@ -44,11 +44,11 @@ SOURCES += qdesigner_components.cpp
}
INCLUDEPATH += . .. \
- $$QT_SOURCE_TREE/tools/designer/src/lib/components \
- $$QT_SOURCE_TREE/tools/designer/src/lib/sdk \
- $$QT_SOURCE_TREE/tools/designer/src/lib/extension \
- $$QT_SOURCE_TREE/tools/designer/src/lib/uilib \
- $$QT_SOURCE_TREE/tools/designer/src/lib/shared
+ $$PWD/../../lib/components \
+ $$PWD/../../lib/sdk \
+ $$PWD/../../lib/extension \
+ $$PWD/../../lib/uilib \
+ $$PWD/../../lib/shared
include(../propertyeditor/propertyeditor.pri)
include(../objectinspector/objectinspector.pri)
diff --git a/tools/designer/src/components/objectinspector/objectinspector.pri b/tools/designer/src/components/objectinspector/objectinspector.pri
index 733c4b3..565f78b 100644
--- a/tools/designer/src/components/objectinspector/objectinspector.pri
+++ b/tools/designer/src/components/objectinspector/objectinspector.pri
@@ -3,7 +3,7 @@
contains(CONFIG, static) {
INCLUDEPATH *= $$QT_SOURCE_TREE/tools/shared/findwidget
} else {
- include($$QT_SOURCE_TREE/tools/shared/findwidget/findwidget.pri)
+ include(../../../../shared/findwidget/findwidget.pri)
}
INCLUDEPATH += $$PWD
diff --git a/tools/designer/src/components/propertyeditor/propertyeditor.pri b/tools/designer/src/components/propertyeditor/propertyeditor.pri
index a8ed37e..7d2e7cb 100644
--- a/tools/designer/src/components/propertyeditor/propertyeditor.pri
+++ b/tools/designer/src/components/propertyeditor/propertyeditor.pri
@@ -10,8 +10,8 @@ contains(CONFIG, static) {
INCLUDEPATH *= $$QT_SOURCE_TREE/tools/shared/qtpropertybrowser
INCLUDEPATH *= $$QT_SOURCE_TREE/tools/shared/qtgradienteditor
} else {
- include($$QT_SOURCE_TREE/tools/shared/qtpropertybrowser/qtpropertybrowser.pri)
- include($$QT_SOURCE_TREE/tools/shared/qtgradienteditor/qtcolorbutton.pri)
+ include(../../../../shared/qtpropertybrowser/qtpropertybrowser.pri)
+ include(../../../../shared/qtgradienteditor/qtcolorbutton.pri)
}
FORMS += $$PWD/paletteeditor.ui \
diff --git a/tools/designer/src/designer/designer.pro b/tools/designer/src/designer/designer.pro
index 8590c7b..8564e96 100644
--- a/tools/designer/src/designer/designer.pro
+++ b/tools/designer/src/designer/designer.pro
@@ -25,8 +25,8 @@ contains(CONFIG, static) {
TARGET = designer
-include($$QT_SOURCE_TREE/tools/shared/fontpanel/fontpanel.pri)
-include($$QT_SOURCE_TREE/tools/shared/qttoolbardialog/qttoolbardialog.pri)
+include(../../../shared/fontpanel/fontpanel.pri)
+include(../../../shared/qttoolbardialog/qttoolbardialog.pri)
HEADERS += \
qdesigner.h \
@@ -88,4 +88,3 @@ INSTALLS += target
include(../sharedcomponents.pri)
unix:!mac:LIBS += -lm
-TRANSLATIONS = designer_de.ts
diff --git a/tools/designer/src/lib/shared/shared.pri b/tools/designer/src/lib/shared/shared.pri
index 570b208..8286360 100644
--- a/tools/designer/src/lib/shared/shared.pri
+++ b/tools/designer/src/lib/shared/shared.pri
@@ -2,11 +2,11 @@
INCLUDEPATH += $$PWD
contains(QT_CONFIG, script): QT += script
-include($$QT_SOURCE_TREE/tools/shared/qtpropertybrowser/qtpropertybrowser.pri)
-include($$QT_SOURCE_TREE/tools/shared/deviceskin/deviceskin.pri)
-include($$QT_SOURCE_TREE/src/tools/rcc/rcc.pri)
-include($$QT_SOURCE_TREE/tools/shared/findwidget/findwidget.pri)
-include($$QT_SOURCE_TREE/tools/shared/qtgradienteditor/qtgradienteditor.pri)
+include(../../../../shared/qtpropertybrowser/qtpropertybrowser.pri)
+include(../../../../shared/deviceskin/deviceskin.pri)
+include(../../../../../src/tools/rcc/rcc.pri)
+include(../../../../shared/findwidget/findwidget.pri)
+include(../../../../shared/qtgradienteditor/qtgradienteditor.pri)
# Input
FORMS += $$PWD/addlinkdialog.ui \
diff --git a/tools/designer/translations/translations.pro b/tools/designer/translations/translations.pro
deleted file mode 100644
index 103c1fe..0000000
--- a/tools/designer/translations/translations.pro
+++ /dev/null
@@ -1,141 +0,0 @@
-include(../src/components/buddyeditor/buddyeditor.pri)
-include(../src/components/component.pri)
-include(../src/components/formeditor/formeditor.pri)
-include(../src/components/objectinspector/objectinspector.pri)
-include(../src/components/propertyeditor/propertyeditor.pri)
-include(../src/components/signalsloteditor/signalsloteditor.pri)
-include(../src/components/tabordereditor/tabordereditor.pri)
-include(../src/components/taskmenu/taskmenu.pri)
-include(../src/components/widgetbox/widgetbox.pri)
-include(../src/lib/extension/extension.pri)
-include(../src/lib/sdk/sdk.pri)
-include(../src/lib/shared/shared.pri)
-include(../src/lib/uilib/uilib.pri)
-include(../../shared/qttoolbardialog/qttoolbardialog.pri)
-include(../../shared/qtpropertybrowser/qtpropertybrowser.pri)
-include(../../shared/qtgradienteditor/qtgradienteditor.pri)
-
-# Include ActiveQt plugin
-SOURCES += ../src/plugins/activeqt/qaxwidgetextrainfo.cpp \
- ../src/plugins/activeqt/qaxwidgetplugin.cpp \
- ../src/plugins/activeqt/qaxwidgetpropertysheet.cpp \
- ../src/plugins/activeqt/qaxwidgettaskmenu.cpp \
- ../src/plugins/activeqt/qdesigneraxwidget.cpp
-
-HEADERS += ../src/plugins/activeqt/qaxwidgetextrainfo.h \
- ../src/plugins/activeqt/qaxwidgetplugin.h \
- ../src/plugins/activeqt/qaxwidgetpropertysheet.h \
- ../src/plugins/activeqt/qaxwidgettaskmenu.h \
- ../src/plugins/activeqt/qdesigneraxwidget.h \
- ../../../src/activeqt/shared/qaxtypes.h
-
-
-# Include Qt3Support plugin
-
-SOURCES += ../src/plugins/widgets/qt3supportwidgets.cpp
-HEADERS += ../src/plugins/widgets/q3iconview/q3iconview_extrainfo.h \
- ../src/plugins/widgets/q3iconview/q3iconview_plugin.h \
- ../src/plugins/widgets/q3listview/q3listview_extrainfo.h \
- ../src/plugins/widgets/q3listview/q3listview_plugin.h \
- ../src/plugins/widgets/q3mainwindow/q3mainwindow_container.h \
- ../src/plugins/widgets/q3mainwindow/q3mainwindow_plugin.h \
- ../src/plugins/widgets/q3toolbar/q3toolbar_extrainfo.h \
- ../src/plugins/widgets/q3toolbar/q3toolbar_plugin.h \
- ../src/plugins/widgets/q3widgetstack/q3widgetstack_container.h \
- ../src/plugins/widgets/q3widgetstack/q3widgetstack_plugin.h \
- ../src/plugins/widgets/q3widgetstack/qdesigner_q3widgetstack_p.h \
- ../src/plugins/widgets/q3wizard/q3wizard_container.h \
- ../src/plugins/widgets/q3wizard/q3wizard_plugin.h \
- ../src/plugins/widgets/q3listbox/q3listbox_extrainfo.h \
- ../src/plugins/widgets/q3listbox/q3listbox_plugin.h \
- ../src/plugins/widgets/q3table/q3table_extrainfo.h \
- ../src/plugins/widgets/q3table/q3table_plugin.h \
- ../src/plugins/widgets/q3textedit/q3textedit_extrainfo.h \
- ../src/plugins/widgets/q3textedit/q3textedit_plugin.h \
- ../src/plugins/widgets/q3widgets/q3widget_plugins.h
-
-SOURCES += ../src/plugins/widgets/q3iconview/q3iconview_extrainfo.cpp \
- ../src/plugins/widgets/q3iconview/q3iconview_plugin.cpp \
- ../src/plugins/widgets/q3listview/q3listview_extrainfo.cpp \
- ../src/plugins/widgets/q3listview/q3listview_plugin.cpp \
- ../src/plugins/widgets/q3mainwindow/q3mainwindow_container.cpp \
- ../src/plugins/widgets/q3mainwindow/q3mainwindow_plugin.cpp \
- ../src/plugins/widgets/q3toolbar/q3toolbar_extrainfo.cpp \
- ../src/plugins/widgets/q3toolbar/q3toolbar_plugin.cpp \
- ../src/plugins/widgets/q3widgetstack/q3widgetstack_container.cpp \
- ../src/plugins/widgets/q3widgetstack/q3widgetstack_plugin.cpp \
- ../src/plugins/widgets/q3widgetstack/qdesigner_q3widgetstack.cpp \
- ../src/plugins/widgets/q3wizard/q3wizard_container.cpp \
- ../src/plugins/widgets/q3wizard/q3wizard_plugin.cpp \
- ../src/plugins/widgets/q3listbox/q3listbox_extrainfo.cpp \
- ../src/plugins/widgets/q3listbox/q3listbox_plugin.cpp \
- ../src/plugins/widgets/q3table/q3table_extrainfo.cpp \
- ../src/plugins/widgets/q3table/q3table_plugin.cpp \
- ../src/plugins/widgets/q3textedit/q3textedit_extrainfo.cpp \
- ../src/plugins/widgets/q3textedit/q3textedit_plugin.cpp \
- ../src/plugins/widgets/q3widgets/q3widget_plugins.cpp
-
-# Include those manually as they do not contain any directory specification
-APP_DIR=../src/designer
-SOURCES += $$APP_DIR/appfontdialog.cpp \
- $$APP_DIR/assistantclient.cpp \
- $$APP_DIR/main.cpp \
- $$APP_DIR/mainwindow.cpp \
- $$APP_DIR/newform.cpp \
- $$APP_DIR/preferencesdialog.cpp \
- $$APP_DIR/qdesigner_actions.cpp \
- $$APP_DIR/qdesigner_appearanceoptions.cpp \
- $$APP_DIR/qdesigner.cpp \
- $$APP_DIR/qdesigner_formwindow.cpp \
- $$APP_DIR/qdesigner_server.cpp \
- $$APP_DIR/qdesigner_settings.cpp \
- $$APP_DIR/qdesigner_toolwindow.cpp \
- $$APP_DIR/qdesigner_workbench.cpp \
- $$APP_DIR/saveformastemplate.cpp \
- $$APP_DIR/versiondialog.cpp
-
-HEADERS+= $$APP_DIR/appfontdialog.h \
- $$APP_DIR/assistantclient.h \
- $$APP_DIR/designer_enums.h \
- $$APP_DIR/mainwindow.h \
- $$APP_DIR/newform.h \
- $$APP_DIR/preferencesdialog.h \
- $$APP_DIR/qdesigner_actions.h \
- $$APP_DIR/qdesigner_appearanceoptions.h \
- $$APP_DIR/qdesigner_formwindow.h \
- $$APP_DIR/qdesigner.h \
- $$APP_DIR/qdesigner_pch.h \
- $$APP_DIR/qdesigner_server.h \
- $$APP_DIR/qdesigner_settings.h \
- $$APP_DIR/qdesigner_toolwindow.h \
- $$APP_DIR/qdesigner_workbench.h \
- $$APP_DIR/saveformastemplate.h \
- $$APP_DIR/versiondialog.h
-
-FORMS += $$APP_DIR/preferencesdialog.ui \
- $$APP_DIR/qdesigner_appearanceoptions.ui \
- $$APP_DIR/saveformastemplate.ui
-
-# Shared solutions
-SOURCES += ../../shared/fontpanel/fontpanel.cpp \
- ../../shared/deviceskin/deviceskin.cpp \
- ../../shared/findwidget/abstractfindwidget.cpp \
- ../../shared/findwidget/itemviewfindwidget.cpp \
- ../../shared/findwidget/texteditfindwidget.cpp \
-
-HEADERS += ../../shared/findwidget/abstractfindwidget.h \
- ../../shared/findwidget/itemviewfindwidget.h \
- ../../shared/findwidget/texteditfindwidget.h
-
-TR_DIR = $$PWD/../../../translations
-TRANSLATIONS = \
- $$TR_DIR/designer_cs.ts \
- $$TR_DIR/designer_de.ts \
- $$TR_DIR/designer_fr.ts \
- $$TR_DIR/designer_hu.ts \
- $$TR_DIR/designer_ja.ts \
- $$TR_DIR/designer_pl.ts \
- $$TR_DIR/designer_ru.ts \
- $$TR_DIR/designer_sl.ts \
- $$TR_DIR/designer_zh_CN.ts \
- $$TR_DIR/designer_zh_TW.ts
diff --git a/tools/linguist/linguist/linguist.pro b/tools/linguist/linguist/linguist.pro
index 4f7ed8a..ce8d585 100644
--- a/tools/linguist/linguist/linguist.pro
+++ b/tools/linguist/linguist/linguist.pro
@@ -94,15 +94,3 @@ FORMS += statistics.ui \
translationsettings.ui \
finddialog.ui
RESOURCES += linguist.qrc
-
-TR_DIR = $$PWD/../../../translations
-TRANSLATIONS = \
- $$TR_DIR/linguist_cs.ts \
- $$TR_DIR/linguist_de.ts \
- $$TR_DIR/linguist_fr.ts \
- $$TR_DIR/linguist_hu.ts \
- $$TR_DIR/linguist_ja.ts \
- $$TR_DIR/linguist_pl.ts \
- $$TR_DIR/linguist_ru.ts \
- $$TR_DIR/linguist_zh_CN.ts \
- $$TR_DIR/linguist_zh_TW.ts
diff --git a/tools/qdoc3/doc/files/qt.qdocconf b/tools/qdoc3/doc/files/qt.qdocconf
index 942d023..09c112a 100644
--- a/tools/qdoc3/doc/files/qt.qdocconf
+++ b/tools/qdoc3/doc/files/qt.qdocconf
@@ -8,7 +8,7 @@ project = Qt
versionsym =
version = %VERSION%
description = Qt Reference Documentation
-url = http://qt.nokia.com/doc/4.6
+url = http://qt.nokia.com/doc/4.7
edition.Console.modules = QtCore QtDBus QtNetwork QtScript QtSql QtXml \
QtXmlPatterns QtTest
@@ -22,7 +22,7 @@ edition.DesktopLight.groups = -graphicsview-api
qhp.projects = Qt
qhp.Qt.file = qt.qhp
-qhp.Qt.namespace = com.trolltech.qt.460
+qhp.Qt.namespace = com.trolltech.qt.470
qhp.Qt.virtualFolder = qdoc
qhp.Qt.indexTitle = Qt Reference Documentation
qhp.Qt.indexRoot =
@@ -36,9 +36,9 @@ qhp.Qt.extraFiles = classic.css \
images/dynamiclayouts-example.png \
images/stylesheet-coffee-plastique.png
-qhp.Qt.filterAttributes = qt 4.6.0 qtrefdoc
-qhp.Qt.customFilters.Qt.name = Qt 4.6.0
-qhp.Qt.customFilters.Qt.filterAttributes = qt 4.6.0
+qhp.Qt.filterAttributes = qt 4.7.0 qtrefdoc
+qhp.Qt.customFilters.Qt.name = Qt 4.7.0
+qhp.Qt.customFilters.Qt.filterAttributes = qt 4.7.0
qhp.Qt.subprojects = classes overviews examples
qhp.Qt.subprojects.classes.title = Classes
qhp.Qt.subprojects.classes.indexTitle = Qt's Classes
diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp
index 16b45d6..9977df0 100644
--- a/tools/qdoc3/htmlgenerator.cpp
+++ b/tools/qdoc3/htmlgenerator.cpp
@@ -63,6 +63,12 @@ QT_BEGIN_NAMESPACE
int HtmlGenerator::id = 0;
bool HtmlGenerator::debugging_on = false;
+#if 0
+QString HtmlGenerator::divNavTop = "<div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>";
+#endif
+
+QString HtmlGenerator::divNavTop = "";
+
QString HtmlGenerator::sinceTitles[] =
{
" New Namespaces",
@@ -214,7 +220,7 @@ HtmlGenerator::HtmlGenerator()
numTableRows(0),
threeColumnEnumValueTable(true),
offlineDocs(true),
- creatorDocs(false),
+ creatorDocs(true),
funcLeftParen("\\S(\\()"),
myTree(0),
slow(false),
@@ -277,7 +283,7 @@ void HtmlGenerator::initializeGenerator(const Config &config)
project = config.getString(CONFIG_PROJECT);
offlineDocs = !config.getBool(CONFIG_ONLINE);
- creatorDocs = !config.getBool(CONFIG_CREATOR);
+ creatorDocs = false; //!config.getBool(CONFIG_CREATOR);
projectDescription = config.getString(CONFIG_DESCRIPTION);
if (projectDescription.isEmpty() && !project.isEmpty())
projectDescription = project + " Reference Documentation";
@@ -1055,11 +1061,11 @@ int HtmlGenerator::generateAtom(const Atom *atom,
}
sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1);
}
- out() << "<a name=\"sec-" << sectionNumber.join("-") << "\"></a><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
+ out() << "<a name=\"sec-" << sectionNumber.join("-") << "\"></a>" << divNavTop << "\n";
}
#else
out() << "<a name=\"" << Doc::canonicalTitle(Text::sectionHeading(atom).toString())
- << "\"></a><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
+ << "\"></a>" << divNavTop << "\n";
#endif
break;
case Atom::SectionRight:
@@ -1307,7 +1313,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
// out() << "<hr />\n";
out() << "<a name=\""
<< registerRef((*s).name.toLower())
- << "\"></a><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
+ << "\"></a>" << divNavTop << "\n";
out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
generateSection(s->members, inner, marker, CodeMarker::Summary);
}
@@ -1316,7 +1322,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
// out() << "<hr />\n";
out() << "<a name=\""
<< registerRef(name.toLower())
- << "\"></a><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
+ << "\"></a>" << divNavTop << "\n";
out() << "<h2>" << protectEnc(name) << "</h2>\n";
generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary);
}
@@ -1343,15 +1349,17 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
out() << "</ul>\n";
}
- out() << "<a name=\"" << registerRef("details") << "\"></a><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
+ out() << "<a name=\"" << registerRef("details") << "\"></a>" << divNavTop << "\n";
if (!inner->doc().isEmpty()) {
+ generateExtractionMark(inner, DetailedDescriptionMark);
//out() << "<hr />\n"
- out() << "<div class=\"descr\"/>\n" // QTBUG-9504
+ out() << "<div class=\"descr\">\n" // QTBUG-9504
<< "<h2>" << "Detailed Description" << "</h2>\n";
generateBody(inner, marker);
out() << "</div>\n"; // QTBUG-9504
generateAlsoList(inner, marker);
+ generateExtractionMark(inner, EndMark);
}
sections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
@@ -1359,7 +1367,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
while (s != sections.end()) {
//out() << "<hr />\n";
if (!(*s).divClass.isEmpty())
- out() << "<div class=\"" << (*s).divClass << "\"/>\n"; // QTBUG-9504
+ out() << "<div class=\"" << (*s).divClass << "\">\n"; // QTBUG-9504
out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
NodeList::ConstIterator m = (*s).members.begin();
@@ -1483,12 +1491,12 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
generateStatus(fake, marker);
if (moduleNamespaceMap.contains(fake->name())) {
- out() << "<a name=\"" << registerRef("namespaces") << "\"></a><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
+ out() << "<a name=\"" << registerRef("namespaces") << "\"></a>" << divNavTop << "\n";
out() << "<h2>Namespaces</h2>\n";
generateAnnotatedList(fake, marker, moduleNamespaceMap[fake->name()]);
}
if (moduleClassMap.contains(fake->name())) {
- out() << "<a name=\"" << registerRef("classes") << "\"></a><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
+ out() << "<a name=\"" << registerRef("classes") << "\"></a>" << divNavTop << "\n";
out() << "<h2>Classes</h2>\n";
generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]);
}
@@ -1551,18 +1559,20 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
sections = marker->qmlSections(qml_cn,CodeMarker::Summary);
s = sections.begin();
while (s != sections.end()) {
- out() << "<a name=\"" << registerRef((*s).name) << "\"></a><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
+ out() << "<a name=\"" << registerRef((*s).name) << "\"></a>" << divNavTop << "\n";
out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
generateQmlSummary(*s,fake,marker);
++s;
}
- out() << "<a name=\"" << registerRef("details") << "\"></a><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
+ generateExtractionMark(fake, DetailedDescriptionMark);
+ out() << "<a name=\"" << registerRef("details") << "\"></a>" << divNavTop << "\n";
out() << "<h2>" << "Detailed Description" << "</h2>\n";
generateBody(fake, marker);
if (cn)
generateQmlText(cn->doc().body(), cn, marker, fake->name());
generateAlsoList(fake, marker);
+ generateExtractionMark(fake, EndMark);
//out() << "<hr />\n";
sections = marker->qmlSections(qml_cn,CodeMarker::Detailed);
@@ -1587,7 +1597,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
sections = marker->sections(fake, CodeMarker::Summary, CodeMarker::Okay);
s = sections.begin();
while (s != sections.end()) {
- out() << "<a name=\"" << registerRef((*s).name) << "\"></a><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
+ out() << "<a name=\"" << registerRef((*s).name) << "\"></a>" << divNavTop << "\n";
out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
generateSectionList(*s, fake, marker, CodeMarker::Summary);
++s;
@@ -1595,16 +1605,20 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
Text brief = fake->doc().briefText();
if (fake->subType() == Node::Module && !brief.isEmpty()) {
- out() << "<a name=\"" << registerRef("details") << "\"></a><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
- out() << "<div class=\"descr\"/>\n"; // QTBUG-9504
+ generateExtractionMark(fake, DetailedDescriptionMark);
+ out() << "<a name=\"" << registerRef("details") << "\"></a>" << divNavTop << "\n";
+ out() << "<div class=\"descr\">\n"; // QTBUG-9504
out() << "<h2>" << "Detailed Description" << "</h2>\n";
}
- else
- out() << "<div class=\"descr\"/>\n"; // QTBUG-9504
+ else {
+ generateExtractionMark(fake, DetailedDescriptionMark);
+ out() << "<div class=\"descr\">\n"; // QTBUG-9504
+ }
generateBody(fake, marker);
out() << "</div>\n"; // QTBUG-9504
generateAlsoList(fake, marker);
+ generateExtractionMark(fake, EndMark);
if (!fake->groupMembers().isEmpty()) {
NodeMap groupMembersMap;
@@ -1702,8 +1716,9 @@ void HtmlGenerator::generateBreadCrumbs(const QString& title,
}
}
else if (node->subType() == Node::Page) {
- if (fn->name() == QString("examples.html")) {
- out() << " <li>Examples</li>";
+ if (fn->name() == QString("qdeclarativeexamples.html")) {
+ out() << " <li><a href=\"all-examples.html\">Examples</a></li>";
+ out() << " <li>QML Examples & Demos</li>";
}
else if (fn->name().startsWith("examples-")) {
out() << " <li><a href=\"all-examples.html\">Examples</a></li>";
@@ -1723,10 +1738,14 @@ void HtmlGenerator::generateBreadCrumbs(const QString& title,
else if (node->subType() == Node::Example) {
out() << " <li><a href=\"all-examples.html\">Examples</a></li>";
QStringList sl = fn->name().split('/');
- QString name = "examples-" + sl.at(0) + ".html";
- QString t = CodeParser::titleFromName(name);
- out() << " <li><a href=\"" << name << "\">"
- << t << "</a></li>";
+ if (sl.contains("declarative"))
+ out() << " <li><a href=\"qdeclarativeexamples.html\">QML Examples & Demos</a></li>";
+ else {
+ QString name = "examples-" + sl.at(0) + ".html";
+ QString t = CodeParser::titleFromName(name);
+ out() << " <li><a href=\"" << name << "\">"
+ << t << "</a></li>";
+ }
out() << " <li>" << title << "</li>";
}
}
@@ -1777,16 +1796,14 @@ void HtmlGenerator::generateHeader(const QString& title,
// Setting assistant configuration
if (offlineDocs)
{
- out() << " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/creatorStyle.css\" />"; // Only for Qt Creator
+ out() << " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />"; // Only for Qt Creator
out() << "</head>\n";
- //out() << "<body class=\"offline narrow \">\n"; // offline for Assistant
- out() << "<body class=\"offline narrow creator\">\n"; // offline for Creator
+ out() << "<body class=\"offline \">\n"; // offline for Assistant
}
if (creatorDocs)
{
- out() << " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/creatorStyle.css\" />"; // Only for Qt Creator
+ out() << " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />"; // Only for Qt Creator
out() << "</head>\n";
- //out() << "<body class=\"offline narrow \">\n"; // offline for Assistant
out() << "<body class=\"offline narrow creator\">\n"; // offline for Creator
}
// Setting online doc configuration
@@ -1884,6 +1901,7 @@ void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker,
{
Text brief = node->doc().briefText();
if (!brief.isEmpty()) {
+ generateExtractionMark(node, BriefMark);
out() << "<p>";
generateText(brief, node, marker);
if (!relative || node == relative)
@@ -1891,6 +1909,7 @@ void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker,
else
out() << " <a href=\"" << linkForNode(node, relative) << "#";
out() << registerRef("details") << "\">More...</a></p>\n";
+ generateExtractionMark(node, EndMark);
}
}
@@ -3459,6 +3478,7 @@ void HtmlGenerator::generateDetailedMember(const Node *node,
#ifdef GENERATE_MAC_REFS
generateMacRef(node, marker);
#endif
+ generateExtractionMark(node, MemberMark);
if (node->type() == Node::Enum
&& (enume = static_cast<const EnumNode *>(node))->flagsType()) {
#ifdef GENERATE_MAC_REFS
@@ -3478,7 +3498,7 @@ void HtmlGenerator::generateDetailedMember(const Node *node,
out() << "<h3 class=\"fn\">";
out() << "<a name=\"" + refForNode(node) + "\"></a>";
generateSynopsis(node, relative, marker, CodeMarker::Detailed);
- out() << "</h3><div class=\"navTop\"><a href=\"#toc\"><img src=\"./images/bullet_up.png\"></a></div>\n";
+ out() << "</h3>" << divNavTop << "\n";
}
generateStatus(node, marker);
@@ -3521,6 +3541,7 @@ void HtmlGenerator::generateDetailedMember(const Node *node,
}
}
generateAlsoList(node, marker);
+ generateExtractionMark(node, EndMark);
}
void HtmlGenerator::findAllClasses(const InnerNode *node)
@@ -4067,6 +4088,7 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node,
#ifdef GENERATE_MAC_REFS
generateMacRef(node, marker);
#endif
+ generateExtractionMark(node, MemberMark);
out() << "<div class=\"qmlitem\">";
if (node->subType() == Node::QmlPropertyGroup) {
const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node);
@@ -4138,6 +4160,7 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node,
generateAlsoList(node, marker);
out() << "</div>";
out() << "</div>";
+ generateExtractionMark(node, EndMark);
}
/*!
@@ -4379,6 +4402,40 @@ void HtmlGenerator::generatePageIndex(const QString& fileName, CodeMarker* marke
file.close();
}
+void HtmlGenerator::generateExtractionMark(const Node *node, ExtractionMarkType markType)
+{
+ if (markType != EndMark) {
+ out() << "<!-- $$$" + node->name();
+ if (markType == MemberMark) {
+ if (node->type() == Node::Function) {
+ const FunctionNode *func = static_cast<const FunctionNode *>(node);
+ if (!func->associatedProperty()) {
+ if (func->overloadNumber() == 1)
+ out() << "[overload1]";
+ out() << "$$$" + func->name() + func->rawParameters().remove(' ');
+ }
+ } else if (node->type() == Node::Property) {
+ const PropertyNode *prop = static_cast<const PropertyNode *>(node);
+ out() << "-prop";
+ const NodeList &list = prop->functions();
+ foreach (const Node *propFuncNode, list) {
+ if (propFuncNode->type() == Node::Function) {
+ const FunctionNode *func = static_cast<const FunctionNode *>(propFuncNode);
+ out() << "$$$" + func->name() + func->rawParameters().remove(' ');
+ }
+ }
+ }
+ } else if (markType == BriefMark) {
+ out() << "-brief";
+ } else if (markType == DetailedDescriptionMark) {
+ out() << "-description";
+ }
+ out() << " -->\n";
+ } else {
+ out() << "<!-- @@@" + node->name() + " -->\n";
+ }
+}
+
#endif
QT_END_NAMESPACE
diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h
index abfca60..aaf2318 100644
--- a/tools/qdoc3/htmlgenerator.h
+++ b/tools/qdoc3/htmlgenerator.h
@@ -123,6 +123,12 @@ class HtmlGenerator : public PageGenerator
private:
enum SubTitleSize { SmallSubTitle, LargeSubTitle };
+ enum ExtractionMarkType {
+ BriefMark,
+ DetailedDescriptionMark,
+ MemberMark,
+ EndMark
+ };
const QPair<QString,QString> anchorForNode(const Node *node);
const Node *findNodeForTarget(const QString &target,
@@ -266,6 +272,7 @@ class HtmlGenerator : public PageGenerator
CodeMarker* marker) const;
void generatePageIndex(const QString& fileName,
CodeMarker* marker) const;
+ void generateExtractionMark(const Node *node, ExtractionMarkType markType);
#if 0
NavigationBar currentNavigationBar;
@@ -324,6 +331,7 @@ class HtmlGenerator : public PageGenerator
static int id;
public:
static bool debugging_on;
+ static QString divNavTop;
};
#define HTMLGENERATOR_ADDRESS "address"
diff --git a/tools/qdoc3/node.cpp b/tools/qdoc3/node.cpp
index da62e29..0ca4870 100644
--- a/tools/qdoc3/node.cpp
+++ b/tools/qdoc3/node.cpp
@@ -1246,6 +1246,24 @@ QStringList FunctionNode::parameterNames() const
}
/*!
+ Returns a raw list of parameters. If \a names is true, the
+ names are included. If \a values is true, the default values
+ are included, if any are present.
+ */
+QString FunctionNode::rawParameters(bool names, bool values) const
+{
+ QString raw;
+ foreach (const Parameter &parameter, parameters()) {
+ raw += parameter.leftType() + parameter.rightType();
+ if (names)
+ raw += parameter.name();
+ if (values)
+ raw += parameter.defaultValue();
+ }
+ return raw;
+}
+
+/*!
Returns the list of reconstructed parameters. If \a values
is true, the default values are included, if any are present.
*/
diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h
index e9f2d74..121b818 100644
--- a/tools/qdoc3/node.h
+++ b/tools/qdoc3/node.h
@@ -616,6 +616,7 @@ class FunctionNode : public LeafNode
int numOverloads() const;
const QList<Parameter>& parameters() const { return params; }
QStringList parameterNames() const;
+ QString rawParameters(bool names = false, bool values = false) const;
const FunctionNode* reimplementedFrom() const { return rf; }
const QList<FunctionNode*> &reimplementedBy() const { return rb; }
const PropertyNode* associatedProperty() const { return ap; }
diff --git a/tools/qdoc3/test/assistant.qdocconf b/tools/qdoc3/test/assistant.qdocconf
index 4b52992..8d5fa89 100644
--- a/tools/qdoc3/test/assistant.qdocconf
+++ b/tools/qdoc3/test/assistant.qdocconf
@@ -17,7 +17,10 @@ qhp.Assistant.namespace = com.trolltech.assistant.470
qhp.Assistant.virtualFolder = qdoc
qhp.Assistant.indexTitle = Qt Assistant Manual
qhp.Assistant.extraFiles = images/bg_l.png \
- images/bg_l_blank.png \
+ images/bg_l_blank.png \
+ images/bg_ll_blank.png \
+ images/bg_ul_blank.png \
+ images/header_bg.png \
images/bg_r.png \
images/box_bg.png \
images/breadcrumb.png \
@@ -25,24 +28,27 @@ qhp.Assistant.extraFiles = images/bg_l.png \
images/bullet_dn.png \
images/bullet_sq.png \
images/bullet_up.png \
+ images/arrow_down.png \
images/feedbackground.png \
images/horBar.png \
images/page.png \
images/page_bg.png \
images/sprites-combined.png \
- images/arrow-down.png \
images/spinner.gif \
images/stylesheet-coffee-plastique.png \
images/taskmenuextension-example.png \
images/coloreditorfactoryimage.png \
images/dynamiclayouts-example.png \
- scripts/functions.js \
- scripts/jquery.js \
- style/OfflineStyle.css \
- style/style_ie6.css \
- style/style_ie7.css \
- style/style_ie8.css \
- style/style.css
+ scripts/functions.js \
+ scripts/jquery.js \
+ scripts/narrow.js \
+ scripts/superfish.js \
+ style/narrow.css \
+ style/superfish.css \
+ style/style_ie6.css \
+ style/style_ie7.css \
+ style/style_ie8.css \
+ style/style.css
qhp.Assistant.filterAttributes = qt 4.7.0 tools assistant
qhp.Assistant.customFilters.Assistant.name = Qt Assistant Manual
diff --git a/tools/qdoc3/test/qdeclarative.qdocconf b/tools/qdoc3/test/qdeclarative.qdocconf
index 0433c9f..facec5c 100644
--- a/tools/qdoc3/test/qdeclarative.qdocconf
+++ b/tools/qdoc3/test/qdeclarative.qdocconf
@@ -55,9 +55,9 @@ qhp.Qml.extraFiles = images/bg_l.png \
style/style_ie8.css \
style/style.css
-qhp.Qml.filterAttributes = qt 4.6.0 qtrefdoc
-qhp.Qml.customFilters.Qt.name = Qt 4.6.0
-qhp.Qml.customFilters.Qt.filterAttributes = qt 4.6.0
+qhp.Qml.filterAttributes = qt 4.7.0 qtrefdoc
+qhp.Qml.customFilters.Qt.name = Qt 4.7.0
+qhp.Qml.customFilters.Qt.filterAttributes = qt 4.7.0
qhp.Qml.subprojects = classes
qhp.Qml.subprojects.classes.title = Elements
qhp.Qml.subprojects.classes.indexTitle = Qml Elements
diff --git a/tools/qdoc3/test/qt-build-docs.qdocconf b/tools/qdoc3/test/qt-build-docs.qdocconf
index 140b81f..4ac4f47 100644
--- a/tools/qdoc3/test/qt-build-docs.qdocconf
+++ b/tools/qdoc3/test/qt-build-docs.qdocconf
@@ -24,6 +24,9 @@ qhp.Qt.indexTitle = Qt Reference Documentation
qhp.Qt.extraFiles = index.html \
images/bg_l.png \
images/bg_l_blank.png \
+ images/bg_ll_blank.png \
+ images/bg_ul_blank.png \
+ images/header_bg.png \
images/bg_r.png \
images/box_bg.png \
images/breadcrumb.png \
@@ -31,12 +34,12 @@ qhp.Qt.extraFiles = index.html \
images/bullet_dn.png \
images/bullet_sq.png \
images/bullet_up.png \
+ images/arrow_down.png \
images/feedbackground.png \
images/horBar.png \
images/page.png \
images/page_bg.png \
images/sprites-combined.png \
- images/arrow-down.png \
images/spinner.gif \
images/stylesheet-coffee-plastique.png \
images/taskmenuextension-example.png \
@@ -44,17 +47,10 @@ qhp.Qt.extraFiles = index.html \
images/dynamiclayouts-example.png \
scripts/functions.js \
scripts/jquery.js \
- scripts/shBrushCpp.js \
- scripts/shCore.js \
- scripts/shLegacy.js \
scripts/narrow.js \
scripts/superfish.js \
- style/shCore.css \
- style/shThemeDefault.css \
style/narrow.css \
style/superfish.css \
- style/superfish_skin.css \
- style/OfflineStyle.css \
style/style_ie6.css \
style/style_ie7.css \
style/style_ie8.css \
diff --git a/tools/qml/deviceorientation_symbian.cpp b/tools/qml/deviceorientation_symbian.cpp
new file mode 100644
index 0000000..c305f94
--- /dev/null
+++ b/tools/qml/deviceorientation_symbian.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "deviceorientation.h"
+
+#include <e32base.h>
+#include <sensrvchannelfinder.h>
+#include <sensrvdatalistener.h>
+#include <sensrvchannel.h>
+#include <sensrvorientationsensor.h>
+
+class SymbianOrientation : public DeviceOrientation, public MSensrvDataListener
+{
+ Q_OBJECT
+public:
+ SymbianOrientation()
+ : DeviceOrientation(), m_current(UnknownOrientation), m_sensorChannel(0)
+ {
+ TRAP_IGNORE(initL());
+ if (!m_sensorChannel)
+ qWarning("No valid sensors found.");
+ }
+
+ ~SymbianOrientation()
+ {
+ if (m_sensorChannel) {
+ m_sensorChannel->StopDataListening();
+ m_sensorChannel->CloseChannel();
+ delete m_sensorChannel;
+ }
+ }
+
+ void initL()
+ {
+ CSensrvChannelFinder *channelFinder = CSensrvChannelFinder::NewLC();
+ RSensrvChannelInfoList channelInfoList;
+ CleanupClosePushL(channelInfoList);
+
+ TSensrvChannelInfo searchConditions;
+ searchConditions.iChannelType = KSensrvChannelTypeIdOrientationData;
+ channelFinder->FindChannelsL(channelInfoList, searchConditions);
+
+ for (int i = 0; i < channelInfoList.Count(); ++i) {
+ TRAPD(error, m_sensorChannel = CSensrvChannel::NewL(channelInfoList[i]));
+ if (!error)
+ TRAP(error, m_sensorChannel->OpenChannelL());
+ if (!error) {
+ TRAP(error, m_sensorChannel->StartDataListeningL(this, 1, 1, 0));
+ break;
+ }
+ if (error) {
+ delete m_sensorChannel;
+ m_sensorChannel = 0;
+ }
+ }
+
+ channelInfoList.Close();
+ CleanupStack::Pop(&channelInfoList);
+ CleanupStack::PopAndDestroy(channelFinder);
+ }
+
+ Orientation orientation() const
+ {
+ return m_current;
+ }
+
+ void setOrientation(Orientation) { }
+
+private:
+ DeviceOrientation::Orientation m_current;
+ CSensrvChannel *m_sensorChannel;
+
+ void DataReceived(CSensrvChannel &channel, TInt count, TInt dataLost)
+ {
+ if (channel.GetChannelInfo().iChannelType == KSensrvChannelTypeIdOrientationData) {
+ TSensrvOrientationData data;
+ for (int i = 0; i < count; ++i) {
+ TPckgBuf<TSensrvOrientationData> dataBuf;
+ channel.GetData(dataBuf);
+ data = dataBuf();
+ Orientation o = UnknownOrientation;
+ switch (data.iDeviceOrientation) {
+ case TSensrvOrientationData::EOrientationDisplayUp:
+ o = Portrait;
+ break;
+ case TSensrvOrientationData::EOrientationDisplayRightUp:
+ o = Landscape;
+ break;
+ case TSensrvOrientationData::EOrientationDisplayLeftUp:
+ case TSensrvOrientationData::EOrientationDisplayDown:
+ case TSensrvOrientationData::EOrientationUndefined:
+ case TSensrvOrientationData::EOrientationDisplayUpwards:
+ case TSensrvOrientationData::EOrientationDisplayDownwards:
+ default:
+ break;
+ }
+
+ if (m_current != o && o != UnknownOrientation) {
+ m_current = o;
+ emit orientationChanged();
+ }
+ }
+ }
+ }
+
+ void DataError(CSensrvChannel& /* channel */, TSensrvErrorSeverity /* error */)
+ {
+ }
+
+ void GetDataListenerInterfaceL(TUid /* interfaceUid */, TAny*& /* interface */)
+ {
+ }
+};
+
+
+DeviceOrientation* DeviceOrientation::instance()
+{
+ static SymbianOrientation *o = 0;
+ if (!o)
+ o = new SymbianOrientation;
+ return o;
+}
+
+#include "deviceorientation_symbian.moc"
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp
index 900a464..4b1162e 100644
--- a/tools/qml/main.cpp
+++ b/tools/qml/main.cpp
@@ -49,12 +49,15 @@
#include <QTranslator>
#include <QDebug>
#include <QMessageBox>
+#include <QAtomicInt>
#include "qdeclarativetester.h"
QT_USE_NAMESPACE
QtMsgHandler systemMsgOutput = 0;
+
+
#if defined (Q_OS_SYMBIAN)
#include <unistd.h>
#include <sys/types.h>
@@ -89,19 +92,25 @@ void showWarnings()
}
}
+static QAtomicInt recursiveLock(0);
+
void myMessageOutput(QtMsgType type, const char *msg)
{
- if (!logger.isNull()) {
- QString strMsg = QString::fromAscii(msg);
- QMetaObject::invokeMethod(logger.data(), "append", Q_ARG(QString, strMsg));
+ QString strMsg = QString::fromLatin1(msg);
+
+ if (!logger.isNull() && !QCoreApplication::closingDown()) {
+ if (recursiveLock.testAndSetOrdered(0, 1)) {
+ QMetaObject::invokeMethod(logger.data(), "append", Q_ARG(QString, strMsg));
+ recursiveLock = 0;
+ }
} else {
- warnings += msg;
+ warnings += strMsg;
warnings += QLatin1Char('\n');
}
if (systemMsgOutput) { // Windows
systemMsgOutput(type, msg);
} else { // Unix
- fprintf(stderr, "%s\n",msg);
+ fprintf(stderr, "%s\n", msg);
fflush(stderr);
}
}
@@ -200,6 +209,8 @@ int main(int argc, char ** argv)
app.setOrganizationName("Nokia");
app.setOrganizationDomain("nokia.com");
+
+
QDeclarativeViewer::registerTypes();
QDeclarativeTester::registerTypes();
diff --git a/tools/qml/qml.pri b/tools/qml/qml.pri
index 3e5a88b..80afb45 100644
--- a/tools/qml/qml.pri
+++ b/tools/qml/qml.pri
@@ -17,7 +17,11 @@ SOURCES += $$PWD/qmlruntime.cpp \
$$PWD/loggerwidget.cpp
RESOURCES = $$PWD/qmlruntime.qrc
-maemo5 {
+symbian:!contains(S60_VERSION, 3.1):!contains(S60_VERSION, 3.2) {
+ SOURCES += $$PWD/deviceorientation_symbian.cpp
+ FORMS = $$PWD/recopts.ui \
+ $$PWD/proxysettings.ui
+} else:maemo5 {
QT += dbus
HEADERS += $$PWD/texteditautoresizer_maemo5.h
SOURCES += $$PWD/deviceorientation_maemo5.cpp
diff --git a/tools/qml/qml.pro b/tools/qml/qml.pro
index 63efff1..bb69e8a 100644
--- a/tools/qml/qml.pro
+++ b/tools/qml/qml.pro
@@ -37,6 +37,9 @@ symbian {
include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
TARGET.EPOCHEAPSIZE = 0x20000 0x2000000
TARGET.CAPABILITY = NetworkServices ReadUserData
+ !contains(S60_VERSION, 3.1):!contains(S60_VERSION, 3.2) {
+ LIBS += -lsensrvclient -lsensrvutil
+ }
}
mac {
QMAKE_INFO_PLIST=Info_mac.plist
diff --git a/tools/qml/qmlruntime.cpp b/tools/qml/qmlruntime.cpp
index debc902..951b187 100644
--- a/tools/qml/qmlruntime.cpp
+++ b/tools/qml/qmlruntime.cpp
@@ -431,65 +431,82 @@ private:
mutable QMutex mutex;
};
-class NetworkAccessManagerFactory : public QDeclarativeNetworkAccessManagerFactory
+class SystemProxyFactory : public QNetworkProxyFactory
{
public:
- NetworkAccessManagerFactory() : cacheSize(0) {}
- ~NetworkAccessManagerFactory() {}
-
- QNetworkAccessManager *create(QObject *parent);
+ SystemProxyFactory() : proxyDirty(true), httpProxyInUse(false) {
+ }
- void setupProxy(QNetworkAccessManager *nam)
+ virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
{
- class SystemProxyFactory : public QNetworkProxyFactory
- {
- public:
- virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
- {
- QString protocolTag = query.protocolTag();
- if (httpProxyInUse && (protocolTag == "http" || protocolTag == "https")) {
- QList<QNetworkProxy> ret;
- ret << httpProxy;
- return ret;
- }
+ if (proxyDirty)
+ setupProxy();
+ QString protocolTag = query.protocolTag();
+ if (httpProxyInUse && (protocolTag == "http" || protocolTag == "https")) {
+ QList<QNetworkProxy> ret;
+ ret << httpProxy;
+ return ret;
+ }
#ifdef Q_OS_WIN
- // systemProxyForQuery can take insanely long on Windows (QTBUG-10106)
- return QNetworkProxyFactory::proxyForQuery(query);
+ // systemProxyForQuery can take insanely long on Windows (QTBUG-10106)
+ return QNetworkProxyFactory::proxyForQuery(query);
#else
- return QNetworkProxyFactory::systemProxyForQuery(query);
+ return QNetworkProxyFactory::systemProxyForQuery(query);
#endif
- }
- void setHttpProxy (QNetworkProxy proxy)
- {
- httpProxy = proxy;
- httpProxyInUse = true;
- }
- void unsetHttpProxy ()
- {
- httpProxyInUse = false;
- }
- private:
- bool httpProxyInUse;
- QNetworkProxy httpProxy;
- };
-
- SystemProxyFactory *proxyFactory = new SystemProxyFactory;
- if (ProxySettings::httpProxyInUse())
- proxyFactory->setHttpProxy(ProxySettings::httpProxy());
- else
- proxyFactory->unsetHttpProxy();
- nam->setProxyFactory(proxyFactory);
}
+ void setupProxy() {
+ // Don't bother locking because we know that the proxy only
+ // changes in response to the settings dialog and that
+ // the view will be reloaded.
+ proxyDirty = false;
+ httpProxyInUse = ProxySettings::httpProxyInUse();
+ if (httpProxyInUse)
+ httpProxy = ProxySettings::httpProxy();
+ }
+
+ void proxyChanged() {
+ proxyDirty = true;
+ }
+
+private:
+ volatile bool proxyDirty;
+ bool httpProxyInUse;
+ QNetworkProxy httpProxy;
+};
+
+class NetworkAccessManagerFactory : public QObject, public QDeclarativeNetworkAccessManagerFactory
+{
+ Q_OBJECT
+public:
+ NetworkAccessManagerFactory() : cacheSize(0) {}
+ ~NetworkAccessManagerFactory() {}
+
+ QNetworkAccessManager *create(QObject *parent);
+
void setCacheSize(int size) {
if (size != cacheSize) {
cacheSize = size;
}
}
+ void proxyChanged() {
+ foreach (QNetworkAccessManager *nam, namList) {
+ static_cast<SystemProxyFactory*>(nam->proxyFactory())->proxyChanged();
+ }
+ }
+
static PersistentCookieJar *cookieJar;
+
+private slots:
+ void managerDestroyed(QObject *obj) {
+ namList.removeOne(static_cast<QNetworkAccessManager*>(obj));
+ }
+
+private:
QMutex mutex;
int cacheSize;
+ QList<QNetworkAccessManager*> namList;
};
PersistentCookieJar *NetworkAccessManagerFactory::cookieJar = 0;
@@ -510,7 +527,7 @@ QNetworkAccessManager *NetworkAccessManagerFactory::create(QObject *parent)
}
manager->setCookieJar(cookieJar);
cookieJar->setParent(0);
- setupProxy(manager);
+ manager->setProxyFactory(new SystemProxyFactory);
if (cacheSize > 0) {
QNetworkDiskCache *cache = new QNetworkDiskCache;
cache->setCacheDirectory(QDir::tempPath()+QLatin1String("/qml-viewer-network-cache"));
@@ -519,6 +536,8 @@ QNetworkAccessManager *NetworkAccessManagerFactory::create(QObject *parent)
} else {
manager->setCache(0);
}
+ connect(manager, SIGNAL(destroyed(QObject*)), this, SLOT(managerDestroyed(QObject*)));
+ namList.append(manager);
qDebug() << "created new network access manager for" << parent;
return manager;
}
@@ -777,6 +796,7 @@ void QDeclarativeViewer::showProxySettings()
void QDeclarativeViewer::proxySettingsChanged()
{
+ namFactory->proxyChanged();
reload ();
}
@@ -924,13 +944,7 @@ void QDeclarativeViewer::statusChanged()
if (canvas->status() == QDeclarativeView::Ready) {
initialSize = canvas->initialSize();
- if (canvas->resizeMode() == QDeclarativeView::SizeRootObjectToView) {
- if (!isFullScreen() && !isMaximized()) {
- canvas->setFixedSize(initialSize);
- resize(1, 1); // workaround for QMainWindowLayout NOT shrinking the window if the centralWidget() shrink
- QTimer::singleShot(0, this, SLOT(updateSizeHints()));
- }
- }
+ updateSizeHints(true);
}
}
@@ -1055,13 +1069,9 @@ void QDeclarativeViewer::setRecordRate(int fps)
record_rate = fps;
}
-void QDeclarativeViewer::sceneResized(QSize size)
+void QDeclarativeViewer::sceneResized(QSize)
{
- if (size.width() > 0 && size.height() > 0) {
- if (canvas->resizeMode() == QDeclarativeView::SizeViewToRootObject) {
- updateSizeHints();
- }
- }
+ updateSizeHints();
}
void QDeclarativeViewer::keyPressEvent(QKeyEvent *event)
@@ -1324,17 +1334,7 @@ void QDeclarativeViewer::changeOrientation(QAction *action)
void QDeclarativeViewer::orientationChanged()
{
- if (canvas->resizeMode() == QDeclarativeView::SizeRootObjectToView) {
- if (canvas->rootObject()) {
- QSizeF rootObjectSize = canvas->rootObject()->boundingRect().size();
- if (size() != rootObjectSize.toSize()) {
- canvas->setMinimumSize(rootObjectSize.toSize());
- canvas->resize(rootObjectSize.toSize());
- resize(rootObjectSize.toSize());
- resize(1, 1); // workaround for QMainWindowLayout NOT shrinking the window if the centralWidget() shrinks
- }
- }
- }
+ updateSizeHints();
}
void QDeclarativeViewer::setDeviceKeys(bool on)
@@ -1383,20 +1383,32 @@ void QDeclarativeViewer::setSizeToView(bool sizeToView)
}
}
-void QDeclarativeViewer::updateSizeHints()
+void QDeclarativeViewer::updateSizeHints(bool initial)
{
- if (canvas->resizeMode() == QDeclarativeView::SizeViewToRootObject) {
- QSize newWindowSize = canvas->sizeHint();
+ static bool isRecursive = false;
+
+ if (isRecursive)
+ return;
+ isRecursive = true;
+
+ if (initial || (canvas->resizeMode() == QDeclarativeView::SizeViewToRootObject)) {
+ QSize newWindowSize = initial ? initialSize : canvas->sizeHint();
+ //qWarning() << "USH:" << (initial ? "INIT:" : "V2R:") << "setting fixed size " << newWindowSize;
if (!isFullScreen() && !isMaximized()) {
- canvas->setMinimumSize(newWindowSize);
- canvas->resize(newWindowSize);
- resize(1, 1); // workaround for QMainWindowLayout NOT shrinking the window if the centralWidget() shrinks
- canvas->setMinimumSize(QSize(0, 0));
+ canvas->setFixedSize(newWindowSize);
+ resize(1, 1);
+ layout()->setSizeConstraint(QLayout::SetFixedSize);
+ layout()->activate();
}
- } else { // QDeclarativeView::SizeRootObjectToView
- canvas->setMinimumSize(QSize(0,0));
- canvas->setMaximumSize(QSize(16777215,16777215));
}
+ //qWarning() << "USH: R2V: setting free size ";
+ layout()->setSizeConstraint(QLayout::SetNoConstraint);
+ layout()->activate();
+ setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
+ canvas->setMinimumSize(QSize(0,0));
+ canvas->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
+
+ isRecursive = false;
}
void QDeclarativeViewer::registerTypes()
diff --git a/tools/qml/qmlruntime.h b/tools/qml/qmlruntime.h
index e70e69f..68d3452 100644
--- a/tools/qml/qmlruntime.h
+++ b/tools/qml/qmlruntime.h
@@ -145,9 +145,9 @@ private slots:
void warningsWidgetOpened();
void warningsWidgetClosed();
- void updateSizeHints();
-
private:
+ void updateSizeHints(bool initial = false);
+
QString getVideoFileName();
LoggerWidget *loggerWindow;
diff --git a/tools/qtconfig/translations/translations.pro b/tools/qtconfig/translations/translations.pro
deleted file mode 100644
index 5d35b6a..0000000
--- a/tools/qtconfig/translations/translations.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-# Include those manually as they do not contain any directory specification
-
-SOURCES += ../colorbutton.cpp ../main.cpp ../previewframe.cpp ../previewwidget.cpp ../mainwindow.cpp ../paletteeditoradvanced.cpp \
- ../mainwindowbase.cpp ../paletteeditoradvancedbase.cpp ../previewwidgetbase.cpp
-HEADERS += ../colorbutton.h ../previewframe.h ../previewwidget.h ../mainwindow.h ../paletteeditoradvanced.h \
- ../mainwindowbase.h ../paletteeditoradvancedbase.h ../previewwidgetbase.h
-
-FORMS = ../mainwindowbase.ui ../paletteeditoradvancedbase.ui ../previewwidgetbase.ui
-
-TR_DIR = $$PWD/../../../translations
-TRANSLATIONS = \
- $$TR_DIR/qtconfig_hu.ts \
- $$TR_DIR/qtconfig_pl.ts \
- $$TR_DIR/qtconfig_ru.ts \
- $$TR_DIR/qtconfig_zh_CN.ts \
- $$TR_DIR/qtconfig_zh_TW.ts
diff --git a/tools/qvfb/qvfb.pro b/tools/qvfb/qvfb.pro
index dde7e8d..c101d00 100644
--- a/tools/qvfb/qvfb.pro
+++ b/tools/qvfb/qvfb.pro
@@ -35,7 +35,7 @@ SOURCES = qvfb.cpp \
../../src/gui/embedded/qlock.cpp \
../../src/gui/embedded/qwssignalhandler.cpp
-include($$QT_SOURCE_TREE/tools/shared/deviceskin/deviceskin.pri)
+include(../shared/deviceskin/deviceskin.pri)
contains(QT_CONFIG, opengl) {
QT += opengl
diff --git a/tools/qvfb/translations/translations.pro b/tools/qvfb/translations/translations.pro
deleted file mode 100644
index b0b1af4..0000000
--- a/tools/qvfb/translations/translations.pro
+++ /dev/null
@@ -1,35 +0,0 @@
-# Include those manually as they do not contain any directory specification
-
-FORMS = ../config.ui
-HEADERS = ../qvfb.h \
- ../qvfbview.h \
- ../qvfbratedlg.h \
- ../qanimationwriter.h \
- ../gammaview.h \
- ../qvfbprotocol.h \
- ../qvfbshmem.h \
- ../qvfbmmap.h \
- ../../../src/gui/embedded/qvfbhdr.h \
- ../../../src/gui/embedded/qlock_p.h \
- ../../../src/gui/embedded/qwssignalhandler_p.h \
- ../../shared/deviceskin/deviceskin.h
-
-SOURCES = ../qvfb.cpp \
- ../qvfbview.cpp \
- ../qvfbratedlg.cpp \
- ../main.cpp \
- ../qanimationwriter.cpp \
- ../qvfbprotocol.cpp \
- ../qvfbshmem.cpp \
- ../qvfbmmap.cpp \
- ../../../src/gui/embedded/qlock.cpp \
- ../../../src/gui/embedded/qwssignalhandler.cpp \
- ../../shared/deviceskin/deviceskin.cpp
-
-TR_DIR = $$PWD/../../../translations
-TRANSLATIONS = \
- $$TR_DIR/qvfb_hu.ts \
- $$TR_DIR/qvfb_pl.ts \
- $$TR_DIR/qvfb_ru.ts \
- $$TR_DIR/qvfb_zh_CN.ts \
- $$TR_DIR/qvfb_zh_TW.ts
diff --git a/tools/runonphone/main.cpp b/tools/runonphone/main.cpp
index 885d029..7767e4b 100644
--- a/tools/runonphone/main.cpp
+++ b/tools/runonphone/main.cpp
@@ -62,6 +62,8 @@ void printUsage(QTextStream& outstream, QString exeName)
<< "-v, --verbose show debugging output" << endl
<< "-q, --quiet hide progress messages" << endl
<< "-d, --download <remote file> <local file> copy file from phone to PC after running test" << endl
+ << "--nocrashlog Don't capture call stack if test crashes" << endl
+ << "--crashlogpath <dir> Path to save crash logs (default=working dir)" << endl
<< endl
<< "USB COM ports can usually be autodetected, use -p or -f to force a specific port." << endl
<< "If using System TRK, it is possible to copy the program directly to sys/bin on the phone." << endl
@@ -85,6 +87,8 @@ int main(int argc, char *argv[])
QString downloadLocalFile;
int loglevel=1;
int timeout=0;
+ bool crashlog = true;
+ QString crashlogpath;
QListIterator<QString> it(args);
it.next(); //skip name of program
while (it.hasNext()) {
@@ -126,6 +130,12 @@ int main(int argc, char *argv[])
loglevel=2;
else if (arg == "--quiet" || arg == "-q")
loglevel=0;
+ else if (arg == "--nocrashlog")
+ crashlog = false;
+ else if (arg == "--crashlogpath") {
+ CHECK_PARAMETER_EXISTS
+ crashlogpath = it.next();
+ }
else
errstream << "unknown command line option " << arg << endl;
} else {
@@ -145,7 +155,7 @@ int main(int argc, char *argv[])
if (serialPortName.isEmpty()) {
if (loglevel > 0)
outstream << "Detecting serial ports" << endl;
- foreach (const SerialPortId &id, enumerateSerialPorts()) {
+ foreach (const SerialPortId &id, enumerateSerialPorts(loglevel)) {
if (loglevel > 0)
outstream << "Port Name: " << id.portName << ", "
<< "Friendly Name:" << id.friendlyName << endl;
@@ -199,6 +209,8 @@ int main(int argc, char *argv[])
TrkSignalHandler handler;
handler.setLogLevel(loglevel);
+ handler.setCrashLogging(crashlog);
+ handler.setCrashLogPath(crashlogpath);
QObject::connect(launcher.data(), SIGNAL(copyingStarted()), &handler, SLOT(copyingStarted()));
QObject::connect(launcher.data(), SIGNAL(canNotConnect(const QString &)), &handler, SLOT(canNotConnect(const QString &)));
@@ -215,8 +227,12 @@ int main(int argc, char *argv[])
QObject::connect(launcher.data(), SIGNAL(copyProgress(int)), &handler, SLOT(copyProgress(int)));
QObject::connect(launcher.data(), SIGNAL(stateChanged(int)), &handler, SLOT(stateChanged(int)));
QObject::connect(launcher.data(), SIGNAL(processStopped(uint,uint,uint,QString)), &handler, SLOT(stopped(uint,uint,uint,QString)));
+ QObject::connect(launcher.data(), SIGNAL(libraryLoaded(trk::Library)), &handler, SLOT(libraryLoaded(trk::Library)));
+ QObject::connect(launcher.data(), SIGNAL(libraryUnloaded(trk::Library)), &handler, SLOT(libraryUnloaded(trk::Library)));
+ QObject::connect(launcher.data(), SIGNAL(registersAndCallStackReadComplete(const QList<uint> &,const QByteArray &)), &handler, SLOT(registersAndCallStackReadComplete(const QList<uint> &,const QByteArray &)));
QObject::connect(&handler, SIGNAL(resume(uint,uint)), launcher.data(), SLOT(resumeProcess(uint,uint)));
QObject::connect(&handler, SIGNAL(terminate()), launcher.data(), SLOT(terminate()));
+ QObject::connect(&handler, SIGNAL(getRegistersAndCallStack(uint,uint)), launcher.data(), SLOT(getRegistersAndCallStack(uint,uint)));
QObject::connect(launcher.data(), SIGNAL(finished()), &handler, SLOT(finished()));
QTimer timer;
diff --git a/tools/runonphone/serenum.h b/tools/runonphone/serenum.h
index b794b97..a65c8cb 100644
--- a/tools/runonphone/serenum.h
+++ b/tools/runonphone/serenum.h
@@ -51,6 +51,6 @@ struct SerialPortId
QString friendlyName;
};
-QList<SerialPortId> enumerateSerialPorts();
+QList<SerialPortId> enumerateSerialPorts(int loglevel);
#endif // WIN32SERENUM_H
diff --git a/tools/runonphone/serenum_unix.cpp b/tools/runonphone/serenum_unix.cpp
index b6f0293..db6375e 100644
--- a/tools/runonphone/serenum_unix.cpp
+++ b/tools/runonphone/serenum_unix.cpp
@@ -48,9 +48,32 @@
#include <usb.h>
-QList<SerialPortId> enumerateSerialPorts()
+class InterfaceInfo
{
- QList<QString> eligableInterfaces;
+public:
+ InterfaceInfo(const QString &mf, const QString &pr, int mfid, int prid);
+ QString manufacturer;
+ QString product;
+ int manufacturerid;
+ int productid;
+};
+
+InterfaceInfo::InterfaceInfo(const QString &mf, const QString &pr, int mfid, int prid) :
+ manufacturer(mf),
+ product(pr),
+ manufacturerid(mfid),
+ productid(prid)
+{
+ if(mf.isEmpty())
+ manufacturer = QString("[%1]").arg(mfid, 4, 16, QChar('0'));
+ if(pr.isEmpty())
+ product = QString("[%1]").arg(prid, 4, 16, QChar('0'));
+}
+
+QList<SerialPortId> enumerateSerialPorts(int loglevel)
+{
+ QList<QString> eligibleInterfaces;
+ QList<InterfaceInfo> eligibleInterfacesInfo;
QList<SerialPortId> list;
usb_init();
@@ -85,6 +108,41 @@ QList<SerialPortId> enumerateSerialPorts()
}
}
}
+
+ if (usableInterfaces.isEmpty())
+ continue;
+
+ QString manufacturerString;
+ QString productString;
+
+ usb_dev_handle *devh = usb_open(device);
+ if (devh) {
+ QByteArray buf;
+ buf.resize(256);
+ int err = usb_get_string_simple(devh, device->descriptor.iManufacturer, buf.data(), buf.size());
+ if (err < 0) {
+ if (loglevel > 1)
+ qDebug() << " can't read manufacturer name, error:" << err;
+ } else {
+ manufacturerString = QString::fromAscii(buf);
+ if (loglevel > 1)
+ qDebug() << " manufacturer:" << manufacturerString;
+ }
+
+ buf.resize(256);
+ err = usb_get_string_simple(devh, device->descriptor.iProduct, buf.data(), buf.size());
+ if (err < 0) {
+ if (loglevel > 1)
+ qDebug() << " can't read product name, error:" << err;
+ } else {
+ productString = QString::fromAscii(buf);
+ if (loglevel > 1)
+ qDebug() << " product:" << productString;
+ }
+ usb_close(devh);
+ } else if (loglevel > 0) {
+ qDebug() << " can't open usb device";
+ }
// second loop to find the actual data interface.
foreach (int i, usableInterfaces) {
@@ -94,11 +152,22 @@ QList<SerialPortId> enumerateSerialPorts()
if (descriptor.bInterfaceNumber != i)
continue;
if (descriptor.bInterfaceClass == 10) { // "CDC Data"
- // qDebug() << " found the data port"
- // << "bus:" << bus->dirname
- // << "device" << device->filename
- // << "interface" << descriptor.bInterfaceNumber;
- eligableInterfaces << QString("if%1").arg(QString::number(i), 2, QChar('0')); // fix!
+ if (loglevel > 1) {
+ qDebug() << " found the data port"
+ << "bus:" << bus->dirname
+ << "device" << device->filename
+ << "interface" << descriptor.bInterfaceNumber;
+ }
+ // ### manufacturer and product strings are only readable as root :(
+ if (!manufacturerString.isEmpty() && !productString.isEmpty()) {
+ eligibleInterfaces << QString("usb-%1_%2-if%3")
+ .arg(manufacturerString.replace(QChar(' '), QChar('_')))
+ .arg(productString.replace(QChar(' '), QChar('_')))
+ .arg(i, 2, 16, QChar('0'));
+ } else {
+ eligibleInterfaces << QString("if%1").arg(i, 2, 16, QChar('0')); // fix!
+ }
+ eligibleInterfacesInfo << InterfaceInfo(manufacturerString, productString, device->descriptor.idVendor, device->descriptor.idProduct);
}
}
}
@@ -106,13 +175,18 @@ QList<SerialPortId> enumerateSerialPorts()
}
}
}
+
+ if (loglevel > 1)
+ qDebug() << " searching for interfaces:" << eligibleInterfaces;
QDir dir("/dev/serial/by-id/");
foreach (const QFileInfo &info, dir.entryInfoList()) {
if (!info.isDir()) {
- bool usable = eligableInterfaces.isEmpty();
- foreach (const QString &iface, eligableInterfaces) {
+ bool usable = eligibleInterfaces.isEmpty();
+ foreach (const QString &iface, eligibleInterfaces) {
if (info.fileName().contains(iface)) {
+ if (loglevel > 1)
+ qDebug() << " found device file:" << info.fileName() << endl;
usable = true;
break;
}
@@ -126,6 +200,21 @@ QList<SerialPortId> enumerateSerialPorts()
list << id;
}
}
+
+ if (list.isEmpty() && !eligibleInterfacesInfo.isEmpty() && loglevel > 0) {
+ qDebug() << "Possible USB devices found, but without serial drivers:";
+ foreach(const InterfaceInfo &iface, eligibleInterfacesInfo) {
+ qDebug() << " Manufacturer:"
+ << iface.manufacturer
+ << "Product:"
+ << iface.product
+ << endl
+ << " Load generic driver using:"
+ << QString("sudo modprobe usbserial vendor=0x%1 product=0x%2")
+ .arg(iface.manufacturerid, 4, 16, QChar('0'))
+ .arg(iface.productid, 4, 16, QChar('0'));
+ }
+ }
return list;
}
diff --git a/tools/runonphone/serenum_win.cpp b/tools/runonphone/serenum_win.cpp
index 572161c..070cac2 100644
--- a/tools/runonphone/serenum_win.cpp
+++ b/tools/runonphone/serenum_win.cpp
@@ -53,7 +53,7 @@
//{4d36e978-e325-11ce-bfc1-08002be10318}
//DEFINE_GUID(GUID_DEVCLASS_PORTS, 0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 );
-QList<SerialPortId> enumerateSerialPorts()
+QList<SerialPortId> enumerateSerialPorts(int)
{
DWORD index=0;
SP_DEVINFO_DATA info;
diff --git a/tools/runonphone/symbianutils/json.cpp b/tools/runonphone/symbianutils/json.cpp
new file mode 100644
index 0000000..2d58824
--- /dev/null
+++ b/tools/runonphone/symbianutils/json.cpp
@@ -0,0 +1,490 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "json.h"
+
+#ifdef TODO_USE_CREATOR
+#include <utils/qtcassert.h>
+#endif // TODO_USE_CREATOR
+
+#include <QtCore/QByteArray>
+#include <QtCore/QTextStream>
+#include <QtCore/QDebug>
+#include <QtCore/QStringList>
+
+#include <ctype.h>
+
+//#define DEBUG_JASON
+#ifdef DEBUG_JASON
+#define JDEBUG(s) qDebug() << s
+#else
+#define JDEBUG(s)
+#endif
+
+namespace tcftrk {
+
+static void skipSpaces(const char *&from, const char *to)
+{
+ while (from != to && isspace(*from))
+ ++from;
+}
+
+QTextStream &operator<<(QTextStream &os, const JsonValue &mi)
+{
+ return os << mi.toString();
+}
+
+void JsonValue::parsePair(const char *&from, const char *to)
+{
+ skipSpaces(from, to);
+ JDEBUG("parsePair: " << QByteArray(from, to - from));
+ m_name = parseCString(from, to);
+ skipSpaces(from, to);
+ while (from < to && *from != ':') {
+ JDEBUG("not a colon" << *from);
+ ++from;
+ }
+ ++from;
+ parseValue(from, to);
+ skipSpaces(from, to);
+}
+
+QByteArray JsonValue::parseNumber(const char *&from, const char *to)
+{
+ QByteArray result;
+ if (from < to && *from == '-') // Leading '-'.
+ result.append(*from++);
+ while (from < to && *from >= '0' && *from <= '9')
+ result.append(*from++);
+ return result;
+}
+
+QByteArray JsonValue::parseCString(const char *&from, const char *to)
+{
+ QByteArray result;
+ JDEBUG("parseCString: " << QByteArray(from, to - from));
+ if (*from != '"') {
+ qDebug() << "JSON Parse Error, double quote expected";
+ ++from; // So we don't hang
+ return QByteArray();
+ }
+ const char *ptr = from;
+ ++ptr;
+ while (ptr < to) {
+ if (*ptr == '"') {
+ ++ptr;
+ result = QByteArray(from + 1, ptr - from - 2);
+ break;
+ }
+ if (*ptr == '\\') {
+ ++ptr;
+ if (ptr == to) {
+ qDebug() << "JSON Parse Error, unterminated backslash escape";
+ from = ptr; // So we don't hang
+ return QByteArray();
+ }
+ }
+ ++ptr;
+ }
+ from = ptr;
+
+ int idx = result.indexOf('\\');
+ if (idx >= 0) {
+ char *dst = result.data() + idx;
+ const char *src = dst + 1, *end = result.data() + result.length();
+ do {
+ char c = *src++;
+ switch (c) {
+ case 'a': *dst++ = '\a'; break;
+ case 'b': *dst++ = '\b'; break;
+ case 'f': *dst++ = '\f'; break;
+ case 'n': *dst++ = '\n'; break;
+ case 'r': *dst++ = '\r'; break;
+ case 't': *dst++ = '\t'; break;
+ case 'v': *dst++ = '\v'; break;
+ case '"': *dst++ = '"'; break;
+ case '\\': *dst++ = '\\'; break;
+ default:
+ {
+ int chars = 0;
+ uchar prod = 0;
+ forever {
+ if (c < '0' || c > '7') {
+ --src;
+ break;
+ }
+ prod = prod * 8 + c - '0';
+ if (++chars == 3 || src == end)
+ break;
+ c = *src++;
+ }
+ if (!chars) {
+ qDebug() << "JSON Parse Error, unrecognized backslash escape";
+ return QByteArray();
+ }
+ *dst++ = prod;
+ }
+ }
+ while (src != end) {
+ char c = *src++;
+ if (c == '\\')
+ break;
+ *dst++ = c;
+ }
+ } while (src != end);
+ *dst = 0;
+ result.truncate(dst - result.data());
+ }
+
+ JDEBUG("parseCString, got " << result);
+ return result;
+}
+
+
+
+void JsonValue::parseValue(const char *&from, const char *to)
+{
+ JDEBUG("parseValue: " << QByteArray(from, to - from));
+ switch (*from) {
+ case '{':
+ parseObject(from, to);
+ break;
+ case 't':
+ if (to - from >= 4 && qstrncmp(from, "true", 4) == 0) {
+ m_data = QByteArray(from, 4);
+ from += m_data.size();
+ m_type = Boolean;
+ }
+ break;
+ case 'f':
+ if (to - from >= 5 && qstrncmp(from, "false", 5) == 0) {
+ m_data = QByteArray(from, 5);
+ from += m_data.size();
+ m_type = Boolean;
+ }
+ break;
+ case 'n':
+ if (to - from >= 4 && qstrncmp(from, "null", 4) == 0) {
+ m_data = QByteArray(from, 4);
+ from += m_data.size();
+ m_type = NullObject;
+ }
+ break;
+ case '[':
+ parseArray(from, to);
+ break;
+ case '"':
+ m_type = String;
+ m_data = parseCString(from, to);
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '-':
+ m_type = Number;
+ m_data = parseNumber(from, to);
+ default:
+ break;
+ }
+}
+
+void JsonValue::parseObject(const char *&from, const char *to)
+{
+ JDEBUG("parseObject: " << QByteArray(from, to - from));
+#ifdef TODO_USE_CREATOR
+ QTC_ASSERT(*from == '{', /**/);
+#endif
+ ++from;
+ m_type = Object;
+ while (from < to) {
+ if (*from == '}') {
+ ++from;
+ break;
+ }
+ JsonValue child;
+ child.parsePair(from, to);
+ if (!child.isValid())
+ return;
+ m_children += child;
+ if (*from == ',')
+ ++from;
+ }
+}
+
+void JsonValue::parseArray(const char *&from, const char *to)
+{
+ JDEBUG("parseArray: " << QByteArray(from, to - from));
+#ifdef TODO_USE_CREATOR
+ QTC_ASSERT(*from == '[', /**/);
+#endif
+ ++from;
+ m_type = Array;
+ while (from < to) {
+ if (*from == ']') {
+ ++from;
+ break;
+ }
+ JsonValue child;
+ child.parseValue(from, to);
+ if (child.isValid())
+ m_children += child;
+ if (*from == ',')
+ ++from;
+ }
+}
+
+void JsonValue::setStreamOutput(const QByteArray &name, const QByteArray &content)
+{
+ if (content.isEmpty())
+ return;
+ JsonValue child;
+ child.m_type = String;
+ child.m_name = name;
+ child.m_data = content;
+ m_children += child;
+ if (m_type == Invalid)
+ m_type = Object;
+}
+
+static QByteArray ind(int indent)
+{
+ return QByteArray(2 * indent, ' ');
+}
+
+void JsonValue::dumpChildren(QByteArray * str, bool multiline, int indent) const
+{
+ for (int i = 0; i < m_children.size(); ++i) {
+ if (i != 0) {
+ *str += ',';
+ if (multiline)
+ *str += '\n';
+ }
+ if (multiline)
+ *str += ind(indent);
+ *str += m_children.at(i).toString(multiline, indent);
+ }
+}
+
+class MyString : public QString {
+public:
+ ushort at(int i) const { return constData()[i].unicode(); }
+};
+
+template<class ST, typename CT>
+inline ST escapeCStringTpl(const ST &ba)
+{
+ ST ret;
+ ret.reserve(ba.length() * 2);
+ for (int i = 0; i < ba.length(); ++i) {
+ CT c = ba.at(i);
+ switch (c) {
+ case '\\': ret += "\\\\"; break;
+ case '\a': ret += "\\a"; break;
+ case '\b': ret += "\\b"; break;
+ case '\f': ret += "\\f"; break;
+ case '\n': ret += "\\n"; break;
+ case '\r': ret += "\\r"; break;
+ case '\t': ret += "\\t"; break;
+ case '\v': ret += "\\v"; break;
+ case '"': ret += "\\\""; break;
+ default:
+ if (c < 32 || c == 127) {
+ ret += '\\';
+ ret += '0' + (c >> 6);
+ ret += '0' + ((c >> 3) & 7);
+ ret += '0' + (c & 7);
+ } else {
+ ret += c;
+ }
+ }
+ }
+ return ret;
+}
+
+QString JsonValue::escapeCString(const QString &ba)
+{
+ return escapeCStringTpl<MyString, ushort>(static_cast<const MyString &>(ba));
+}
+
+QByteArray JsonValue::escapeCString(const QByteArray &ba)
+{
+ return escapeCStringTpl<QByteArray, uchar>(ba);
+}
+
+QByteArray JsonValue::toString(bool multiline, int indent) const
+{
+ QByteArray result;
+ switch (m_type) {
+ case Invalid:
+ if (multiline)
+ result += ind(indent) + "Invalid\n";
+ else
+ result += "Invalid";
+ break;
+ case String:
+ if (!m_name.isEmpty())
+ result += m_name + "=";
+ result += '"' + escapeCString(m_data) + '"';
+ break;
+ case Number:
+ if (!m_name.isEmpty())
+ result += '"' + m_name + "\":";
+ result += m_data;
+ break;
+ case Boolean:
+ case NullObject:
+ if (!m_name.isEmpty())
+ result += '"' + m_name + "\":";
+ result += m_data;
+ break;
+ case Object:
+ if (!m_name.isEmpty())
+ result += m_name + '=';
+ if (multiline) {
+ result += "{\n";
+ dumpChildren(&result, multiline, indent + 1);
+ result += '\n' + ind(indent) + "}";
+ } else {
+ result += "{";
+ dumpChildren(&result, multiline, indent + 1);
+ result += "}";
+ }
+ break;
+ case Array:
+ if (!m_name.isEmpty())
+ result += m_name + "=";
+ if (multiline) {
+ result += "[\n";
+ dumpChildren(&result, multiline, indent + 1);
+ result += '\n' + ind(indent) + "]";
+ } else {
+ result += "[";
+ dumpChildren(&result, multiline, indent + 1);
+ result += "]";
+ }
+ break;
+ }
+ return result;
+}
+
+void JsonValue::fromString(const QByteArray &ba)
+{
+ const char *from = ba.constBegin();
+ const char *to = ba.constEnd();
+ parseValue(from, to);
+}
+
+JsonValue JsonValue::findChild(const char *name) const
+{
+ for (int i = 0; i < m_children.size(); ++i)
+ if (m_children.at(i).m_name == name)
+ return m_children.at(i);
+ return JsonValue();
+}
+
+void JsonInputStream::appendCString(const char *s)
+{
+ m_target.append('"');
+ for (const char *p = s; *p; p++) {
+ if (*p == '"' || *p == '\\')
+ m_target.append('\\');
+ m_target.append(*p);
+ }
+ m_target.append('"');
+}
+
+void JsonInputStream::appendString(const QString &in)
+{
+ if (in.isEmpty()) {
+ m_target.append("\"\"");
+ return;
+ }
+
+ const QChar doubleQuote('"');
+ const QChar backSlash('\\');
+ QString rc;
+ const int inSize = in.size();
+ rc.reserve(in.size() + 5);
+ rc.append(doubleQuote);
+ for (int i = 0; i < inSize; i++) {
+ const QChar c = in.at(i);
+ if (c == doubleQuote || c == backSlash)
+ rc.append(backSlash);
+ rc.append(c);
+ }
+ rc.append(doubleQuote);
+ m_target.append(rc.toUtf8());
+ return;
+}
+
+JsonInputStream &JsonInputStream::operator<<(const QStringList &in)
+{
+ m_target.append('[');
+ const int count = in.size();
+ for (int i = 0 ; i < count; i++) {
+ if (i)
+ m_target.append(',');
+ appendString(in.at(i));
+ }
+ m_target.append(']');
+ return *this;
+}
+
+JsonInputStream &JsonInputStream::operator<<(const QVector<QByteArray> &ba)
+{
+ m_target.append('[');
+ const int count = ba.size();
+ for (int i = 0 ; i < count; i++) {
+ if (i)
+ m_target.append(',');
+ appendCString(ba.at(i).constData());
+ }
+ m_target.append(']');
+ return *this;
+}
+
+JsonInputStream &JsonInputStream::operator<<(bool b)
+{
+ m_target.append(b ? "true" : "false");
+ return *this;
+}
+
+} // namespace tcftrk
+
diff --git a/tools/runonphone/symbianutils/json.h b/tools/runonphone/symbianutils/json.h
new file mode 100644
index 0000000..ffcb7ab
--- /dev/null
+++ b/tools/runonphone/symbianutils/json.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SYMBIANUTILS_JSON_H
+#define SYMBIANUTILS_JSON_H
+
+#include "symbianutils_global.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QStringList>
+#include <QtCore/QVector>
+
+namespace tcftrk {
+
+class SYMBIANUTILS_EXPORT JsonValue
+{
+public:
+ JsonValue() : m_type(Invalid) {}
+ explicit JsonValue(const QByteArray &str) { fromString(str); }
+
+ QByteArray m_name;
+ QByteArray m_data;
+ QList<JsonValue> m_children;
+
+ enum Type {
+ Invalid,
+ String,
+ Number,
+ Boolean,
+ Object,
+ NullObject,
+ Array,
+ };
+
+ Type m_type;
+
+ inline Type type() const { return m_type; }
+ inline QByteArray name() const { return m_name; }
+ inline bool hasName(const char *name) const { return m_name == name; }
+
+ inline bool isValid() const { return m_type != Invalid; }
+ inline bool isNumber() const { return m_type == Number; }
+ inline bool isString() const { return m_type == String; }
+ inline bool isObject() const { return m_type == Object; }
+ inline bool isArray() const { return m_type == Array; }
+
+
+ inline QByteArray data() const { return m_data; }
+ inline const QList<JsonValue> &children() const { return m_children; }
+ inline int childCount() const { return m_children.size(); }
+
+ const JsonValue &childAt(int index) const { return m_children[index]; }
+ JsonValue &childAt(int index) { return m_children[index]; }
+ JsonValue findChild(const char *name) const;
+
+ QByteArray toString(bool multiline = false, int indent = 0) const;
+ void fromString(const QByteArray &str);
+ void setStreamOutput(const QByteArray &name, const QByteArray &content);
+
+private:
+ static QByteArray parseCString(const char *&from, const char *to);
+ static QByteArray parseNumber(const char *&from, const char *to);
+ static QByteArray escapeCString(const QByteArray &ba);
+ static QString escapeCString(const QString &ba);
+ void parsePair(const char *&from, const char *to);
+ void parseValue(const char *&from, const char *to);
+ void parseObject(const char *&from, const char *to);
+ void parseArray(const char *&from, const char *to);
+
+ void dumpChildren(QByteArray *str, bool multiline, int indent) const;
+};
+
+/* Thin wrapper around QByteArray for formatting JSON input. Use as in:
+ * JsonInputStream(byteArray) << '{' << "bla" << ':' << "blup" << '}';
+ * Note that strings get double quotes and JSON-escaping, characters should be
+ * used for the array/hash delimiters.
+ * */
+class SYMBIANUTILS_EXPORT JsonInputStream {
+public:
+ explicit JsonInputStream(QByteArray &a) : m_target(a) {}
+
+ JsonInputStream &operator<<(char c) { m_target.append(c); return *this; }
+ JsonInputStream &operator<<(const char *c) { appendCString(c); return *this; }
+ JsonInputStream &operator<<(const QByteArray &a) { appendCString(a.constData()); return *this; }
+ JsonInputStream &operator<<(const QString &c) { appendString(c); return *this; }
+
+ // Format as array
+ JsonInputStream &operator<<(const QStringList &c);
+
+ // Format as array
+ JsonInputStream &operator<<(const QVector<QByteArray> &ba);
+
+ JsonInputStream &operator<<(bool b);
+
+ JsonInputStream &operator<<(int i)
+ { m_target.append(QByteArray::number(i)); return *this; }
+ JsonInputStream &operator<<(unsigned i)
+ { m_target.append(QByteArray::number(i)); return *this; }
+ JsonInputStream &operator<<(quint64 i)
+ { m_target.append(QByteArray::number(i)); return *this; }
+
+private:
+ void appendString(const QString &);
+ void appendCString(const char *c);
+
+ QByteArray &m_target;
+};
+
+} // namespace tcftrk
+
+#endif // SYMBIANUTILS_JSON_H
diff --git a/tools/runonphone/symbianutils/launcher.cpp b/tools/runonphone/symbianutils/launcher.cpp
index ecb067e..ee87480 100644
--- a/tools/runonphone/symbianutils/launcher.cpp
+++ b/tools/runonphone/symbianutils/launcher.cpp
@@ -58,6 +58,33 @@
namespace trk {
+struct CrashReportState {
+ CrashReportState();
+ void clear();
+
+ typedef uint Thread;
+ typedef QList<Thread> Threads;
+ Threads threads;
+
+ QList<uint> registers;
+ QByteArray stack;
+ uint sp;
+ uint fetchingStackPID;
+ uint fetchingStackTID;
+};
+
+CrashReportState::CrashReportState()
+{
+ clear();
+}
+
+void CrashReportState::clear()
+{
+ threads.clear();
+ stack.clear();
+ sp = fetchingStackPID = fetchingStackTID = 0;
+}
+
struct LauncherPrivate {
struct CopyState {
QString sourceFileName;
@@ -86,6 +113,7 @@ struct LauncherPrivate {
int m_verbose;
Launcher::Actions m_startupActions;
bool m_closeDevice;
+ CrashReportState m_crashReportState;
};
LauncherPrivate::LauncherPrivate(const TrkDevicePtr &d) :
@@ -202,6 +230,7 @@ void Launcher::setCloseDevice(bool c)
bool Launcher::startServer(QString *errorMessage)
{
errorMessage->clear();
+ d->m_crashReportState.clear();
if (d->m_verbose) {
QString msg;
QTextStream str(&msg);
@@ -375,7 +404,7 @@ void Launcher::handleResult(const TrkResult &result)
logMessage("TEXT TRACE: " + msg);
}
} else {
- logMessage("APPLICATION OUTPUT: " + result.data);
+ logMessage("APPLICATION OUTPUT: " + stringFromArray(result.data));
msg = result.data;
}
msg.replace("\r\n", "\n");
@@ -416,49 +445,54 @@ void Launcher::handleResult(const TrkResult &result)
// target->host OS notification
case TrkNotifyCreated: { // Notify Created
- /*
- const char *data = result.data.data();
- byte error = result.data.at(0);
- byte type = result.data.at(1); // type: 1 byte; for dll item, this value is 2.
- uint pid = extractInt(data + 2); // ProcessID: 4 bytes;
- uint tid = extractInt(data + 6); //threadID: 4 bytes
- uint codeseg = extractInt(data + 10); //code address: 4 bytes; code base address for the library
- uint dataseg = extractInt(data + 14); //data address: 4 bytes; data base address for the library
- uint len = extractShort(data + 18); //length: 2 bytes; length of the library name string to follow
- QByteArray name = result.data.mid(20, len); // name: library name
-
- logMessage(prefix + "NOTE: LIBRARY LOAD: " + str);
- logMessage(prefix + "TOKEN: " + result.token);
- logMessage(prefix + "ERROR: " + int(error));
- logMessage(prefix + "TYPE: " + int(type));
- logMessage(prefix + "PID: " + pid);
- logMessage(prefix + "TID: " + tid);
- logMessage(prefix + "CODE: " + codeseg);
- logMessage(prefix + "DATA: " + dataseg);
- logMessage(prefix + "LEN: " + len);
- logMessage(prefix + "NAME: " + name);
- */
if (result.data.size() < 10)
break;
+ const char *data = result.data.constData();
+ const byte error = result.data.at(0);
+ Q_UNUSED(error)
+ const byte type = result.data.at(1); // type: 1 byte; for dll item, this value is 2.
+ const uint tid = extractInt(data + 6); //threadID: 4 bytes
+ Q_UNUSED(tid)
+ if (type == kDSOSDLLItem && result.data.size() >=20) {
+ const Library lib = Library(result);
+ d->m_session.libraries.push_back(lib);
+ emit libraryLoaded(lib);
+ }
QByteArray ba;
ba.append(result.data.mid(2, 8));
d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE");
- //d->m_device->sendTrkAck(result.token)
break;
}
case TrkNotifyDeleted: { // NotifyDeleted
const ushort itemType = (unsigned char)result.data.at(1);
- const ushort len = result.data.size() > 12 ? extractShort(result.data.data() + 10) : ushort(0);
+ const uint pid = result.data.size() >= 6 ? extractShort(result.data.constData() + 2) : 0;
+ const uint tid = result.data.size() >= 10 ? extractShort(result.data.constData() + 6) : 0;
+ Q_UNUSED(tid)
+ const ushort len = result.data.size() > 12 ? extractShort(result.data.constData() + 10) : ushort(0);
const QString name = len ? QString::fromAscii(result.data.mid(12, len)) : QString();
logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3").
arg(QString::fromAscii(prefix)).arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")).
arg(name));
d->m_device->sendTrkAck(result.token);
- if (itemType == 0 // process
+ if (itemType == kDSOSProcessItem // process
&& result.data.size() >= 10
&& d->m_session.pid == extractInt(result.data.data() + 6)) {
- copyFileFromRemote();
+ if (d->m_startupActions & ActionDownload)
+ copyFileFromRemote();
+ else
+ disconnectTrk();
+ }
+ else if (itemType == kDSOSDLLItem && len) {
+ // Remove libraries of process.
+ for (QList<Library>::iterator it = d->m_session.libraries.begin(); it != d->m_session.libraries.end(); ) {
+ if ((*it).pid == pid && (*it).name == name) {
+ emit libraryUnloaded(*it);
+ it = d->m_session.libraries.erase(it);
+ } else {
+ ++it;
+ }
+ }
}
break;
}
@@ -705,6 +739,15 @@ void Launcher::handleCreateProcess(const TrkResult &result)
logMessage(msg);
}
emit applicationRunning(d->m_session.pid);
+ //create a "library" entry for the executable which launched the process
+ Library lib;
+ lib.pid = d->m_session.pid;
+ lib.codeseg = d->m_session.codeseg;
+ lib.dataseg = d->m_session.dataseg;
+ lib.name = d->m_fileName.toUtf8();
+ d->m_session.libraries << lib;
+ emit libraryLoaded(lib);
+
QByteArray ba;
appendInt(&ba, d->m_session.pid);
appendInt(&ba, d->m_session.tid);
@@ -856,6 +899,30 @@ QByteArray Launcher::startProcessMessage(const QString &executable,
return ba;
}
+QByteArray Launcher::readMemoryMessage(uint pid, uint tid, uint from, uint len)
+{
+ QByteArray ba;
+ ba.reserve(11);
+ ba.append(char(0x8)); // Options, FIXME: why?
+ appendShort(&ba, len);
+ appendInt(&ba, from);
+ appendInt(&ba, pid);
+ appendInt(&ba, tid);
+ return ba;
+}
+
+QByteArray Launcher::readRegistersMessage(uint pid, uint tid)
+{
+ QByteArray ba;
+ ba.reserve(15);
+ ba.append(char(0)); // Register set, only 0 supported
+ appendShort(&ba, 0); //R0
+ appendShort(&ba, 16); // last register CPSR
+ appendInt(&ba, pid);
+ appendInt(&ba, tid);
+ return ba;
+}
+
void Launcher::startInferiorIfNeeded()
{
emit startingApplication();
@@ -907,4 +974,63 @@ void Launcher::releaseToDeviceManager(Launcher *launcher)
sdm->releaseDevice(launcher->trkServerName());
}
+void Launcher::getRegistersAndCallStack(uint pid, uint tid)
+{
+ d->m_device->sendTrkMessage(TrkReadRegisters,
+ TrkCallback(this, &Launcher::handleReadRegisters),
+ Launcher::readRegistersMessage(pid, tid));
+ d->m_crashReportState.fetchingStackPID = pid;
+ d->m_crashReportState.fetchingStackTID = tid;
+}
+
+void Launcher::handleReadRegisters(const TrkResult &result)
+{
+ if(result.errorCode() || result.data.size() < (17*4)) {
+ terminate();
+ return;
+ }
+ const char* data = result.data.constData() + 1;
+ d->m_crashReportState.registers.clear();
+ d->m_crashReportState.stack.clear();
+ for (int i=0;i<17;i++) {
+ uint r = extractInt(data);
+ data += 4;
+ d->m_crashReportState.registers.append(r);
+ }
+ d->m_crashReportState.sp = d->m_crashReportState.registers.at(13);
+
+ const ushort len = 1024 - (d->m_crashReportState.sp % 1024); //read to 1k boundary first
+ const QByteArray ba = Launcher::readMemoryMessage(d->m_crashReportState.fetchingStackPID,
+ d->m_crashReportState.fetchingStackTID,
+ d->m_crashReportState.sp,
+ len);
+ d->m_device->sendTrkMessage(TrkReadMemory, TrkCallback(this, &Launcher::handleReadStack), ba);
+ d->m_crashReportState.sp += len;
+}
+
+void Launcher::handleReadStack(const TrkResult &result)
+{
+ if (result.errorCode()) {
+ //error implies memory fault when reaching end of stack
+ emit registersAndCallStackReadComplete(d->m_crashReportState.registers, d->m_crashReportState.stack);
+ return;
+ }
+
+ const uint len = extractShort(result.data.constData() + 1);
+ d->m_crashReportState.stack.append(result.data.mid(3, len));
+
+ if (d->m_crashReportState.sp - d->m_crashReportState.registers.at(13) > 0x10000) {
+ //read enough stack, stop here
+ emit registersAndCallStackReadComplete(d->m_crashReportState.registers, d->m_crashReportState.stack);
+ return;
+ }
+ //read 1k more
+ const QByteArray ba = Launcher::readMemoryMessage(d->m_crashReportState.fetchingStackPID,
+ d->m_crashReportState.fetchingStackTID,
+ d->m_crashReportState.sp,
+ 1024);
+ d->m_device->sendTrkMessage(TrkReadMemory, TrkCallback(this, &Launcher::handleReadStack), ba);
+ d->m_crashReportState.sp += 1024;
+}
+
} // namespace trk
diff --git a/tools/runonphone/symbianutils/launcher.h b/tools/runonphone/symbianutils/launcher.h
index 6db69d0..230a122 100644
--- a/tools/runonphone/symbianutils/launcher.h
+++ b/tools/runonphone/symbianutils/launcher.h
@@ -43,6 +43,7 @@
#define LAUNCHER_H
#include "trkdevice.h"
+#include "trkutils.h"
#include <QtCore/QObject>
#include <QtCore/QVariant>
@@ -122,6 +123,9 @@ public:
// Create Trk message to start a process.
static QByteArray startProcessMessage(const QString &executable,
const QStringList &arguments);
+ // Create Trk message to read memory
+ static QByteArray readMemoryMessage(uint pid, uint tid, uint from, uint len);
+ static QByteArray readRegistersMessage(uint pid, uint tid);
// Parse a TrkNotifyStopped message
static bool parseNotifyStopped(const QByteArray &a,
uint *pid, uint *tid, uint *address,
@@ -149,12 +153,18 @@ signals:
void copyProgress(int percent);
void stateChanged(int);
void processStopped(uint pc, uint pid, uint tid, const QString& reason);
+ void processResumed(uint pid, uint tid);
+ void libraryLoaded(const trk::Library &lib);
+ void libraryUnloaded(const trk::Library &lib);
+ void registersAndCallStackReadComplete(const QList<uint>& registers, const QByteArray& stack);
// Emitted by the destructor, for releasing devices of SymbianDeviceManager by name
void destroyed(const QString &serverName);
public slots:
void terminate();
void resumeProcess(uint pid, uint tid);
+ //can be used to obtain traceback after a breakpoint / exception
+ void getRegistersAndCallStack(uint pid, uint tid);
private slots:
void handleResult(const trk::TrkResult &data);
@@ -182,6 +192,8 @@ private:
void handleStop(const TrkResult &result);
void handleSupportMask(const TrkResult &result);
void handleTrkVersion(const TrkResult &result);
+ void handleReadRegisters(const TrkResult &result);
+ void handleReadStack(const TrkResult &result);
void copyFileToRemote();
void copyFileFromRemote();
diff --git a/tools/runonphone/symbianutils/symbianutils.pri b/tools/runonphone/symbianutils/symbianutils.pri
index 6309517..f07e494 100644
--- a/tools/runonphone/symbianutils/symbianutils.pri
+++ b/tools/runonphone/symbianutils/symbianutils.pri
@@ -1,5 +1,7 @@
INCLUDEPATH *= $$PWD
+QT += network
+
# Input
HEADERS += $$PWD/symbianutils_global.h \
$$PWD/callback.h \
@@ -9,14 +11,20 @@ HEADERS += $$PWD/symbianutils_global.h \
$$PWD/launcher.h \
$$PWD/bluetoothlistener.h \
$$PWD/communicationstarter.h \
- $$PWD/symbiandevicemanager.h
+ $$PWD/symbiandevicemanager.h \
+ $$PWD/tcftrkdevice.h \
+ $$PWD/tcftrkmessage.h \
+ $$PWD/json.h
SOURCES += $$PWD/trkutils.cpp \
$$PWD/trkdevice.cpp \
$$PWD/launcher.cpp \
$$PWD/bluetoothlistener.cpp \
$$PWD/communicationstarter.cpp \
- $$PWD/symbiandevicemanager.cpp
+ $$PWD/symbiandevicemanager.cpp \
+ $$PWD/tcftrkdevice.cpp \
+ $$PWD/tcftrkmessage.cpp \
+ $$PWD/json.cpp
# Tests/trklauncher is a console application
contains(QT, gui) {
diff --git a/tools/runonphone/symbianutils/tcftrkdevice.cpp b/tools/runonphone/symbianutils/tcftrkdevice.cpp
new file mode 100644
index 0000000..50e3937
--- /dev/null
+++ b/tools/runonphone/symbianutils/tcftrkdevice.cpp
@@ -0,0 +1,929 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "tcftrkdevice.h"
+#include "json.h"
+
+#include <QtNetwork/QAbstractSocket>
+#include <QtCore/QDebug>
+#include <QtCore/QVector>
+#include <QtCore/QQueue>
+#include <QtCore/QTextStream>
+#include <QtCore/QDateTime>
+#include <QtCore/QFileInfo>
+
+enum { debug = 0 };
+
+static const char messageTerminatorC[] = "\003\001";
+
+namespace tcftrk {
+// ------------- TcfTrkCommandError
+
+TcfTrkCommandError::TcfTrkCommandError() : timeMS(0), code(0), alternativeCode(0)
+{
+}
+
+void TcfTrkCommandError::clear()
+{
+ timeMS = 0;
+ code = alternativeCode = 0;
+ format.clear();
+ alternativeOrganization.clear();
+}
+
+void TcfTrkCommandError::write(QTextStream &str) const
+{
+ if (timeMS) {
+ const QDateTime time(QDate(1970, 1, 1));
+ str << time.addMSecs(timeMS).toString(Qt::ISODate) << ": Error code: " << code
+ << " '" << format << '\'';
+ if (!alternativeOrganization.isEmpty())
+ str << " ('" << alternativeOrganization << "', code: " << alternativeCode << ')';
+ } else{
+ str << "<No error>";
+ }
+}
+
+QString TcfTrkCommandError::toString() const
+{
+ QString rc;
+ QTextStream str(&rc);
+ write(str);
+ return rc;
+}
+
+/* {"Time":1277459762255,"Code":1,"AltCode":-6,"AltOrg":"POSIX","Format":"Unknown error: -6"} */
+bool TcfTrkCommandError::parse(const QVector<JsonValue> &values)
+{
+ // Parse an arbitrary hash (that could as well be a command response)
+ // and check for error elements.
+ unsigned errorKeyCount = 0;
+ clear();
+ do {
+ if (values.isEmpty() || values.front().type() != JsonValue::Object)
+ break;
+ foreach (const JsonValue &c, values.front().children()) {
+ if (c.name() == "Time") {
+ timeMS = c.data().toULongLong();
+ errorKeyCount++;
+ } else if (c.name() == "Code") {
+ code = c.data().toInt();
+ errorKeyCount++;
+ } else if (c.name() == "Format") {
+ format = c.data();
+ errorKeyCount++;
+ } else if (c.name() == "AltCode") {
+ alternativeCode = c.data().toInt();
+ errorKeyCount++;
+ } else if (c.name() == "AltOrg") {
+ alternativeOrganization = c.data();
+ errorKeyCount++;
+ }
+ }
+ } while (false);
+ const bool errorFound = errorKeyCount >= 2u; // Should be at least 'Time', 'Code'.
+ if (!errorFound)
+ clear();
+ if (debug) {
+ qDebug() << "TcfTrkCommandError::parse: Found error: " << errorFound;
+ if (!values.isEmpty())
+ qDebug() << values.front().toString();
+ }
+ return errorFound;
+}
+
+// ------------ TcfTrkCommandResult
+
+TcfTrkCommandResult::TcfTrkCommandResult(Type t) :
+ type(t), service(LocatorService)
+{
+}
+
+TcfTrkCommandResult::TcfTrkCommandResult(char typeChar, Services s,
+ const QByteArray &r,
+ const QVector<JsonValue> &v,
+ const QVariant &ck) :
+ type(FailReply), service(s), request(r), values(v), cookie(ck)
+{
+ switch (typeChar) {
+ case 'N':
+ type = FailReply;
+ break;
+ case 'P':
+ type = ProgressReply;
+ break;
+ case 'R':
+ type = commandError.parse(values) ? CommandErrorReply : SuccessReply;
+ break;
+ default:
+ qWarning("Unknown TCF reply type '%c'", typeChar);
+ }
+}
+
+QString TcfTrkCommandResult::errorString() const
+{
+ QString rc;
+ QTextStream str(&rc);
+
+ switch (type) {
+ case SuccessReply:
+ case ProgressReply:
+ str << "<No error>";
+ return rc;
+ case FailReply:
+ str << "NAK";
+ case CommandErrorReply:
+ commandError.write(str);
+ break;
+ }
+ // Append the failed command for reference
+ str << " (Command was: '";
+ QByteArray printableRequest = request;
+ printableRequest.replace('\0', '|');
+ str << printableRequest << "')";
+ return rc;
+}
+
+QString TcfTrkCommandResult::toString() const
+{
+ QString rc;
+ QTextStream str(&rc);
+ str << "Command answer ";
+ switch (type) {
+ case SuccessReply:
+ str << "[success]";
+ break;
+ case CommandErrorReply:
+ str << "[command error]";
+ break;
+ case FailReply:
+ str << "[fail (NAK)]";
+ break;
+ case ProgressReply:
+ str << "[progress]";
+ break;
+ }
+ str << ", " << values.size() << " values(s) to request: '";
+ QByteArray printableRequest = request;
+ printableRequest.replace('\0', '|');
+ str << printableRequest << "' ";
+ if (cookie.isValid())
+ str << " cookie: " << cookie.toString();
+ str << '\n';
+ for (int i = 0, count = values.size(); i < count; i++)
+ str << '#' << i << ' ' << values.at(i).toString() << '\n';
+ if (type == CommandErrorReply)
+ str << "Error: " << errorString();
+ return rc;
+}
+
+struct TcfTrkSendQueueEntry
+{
+ typedef TcfTrkDevice::MessageType MessageType;
+
+ explicit TcfTrkSendQueueEntry(MessageType mt,
+ int tok,
+ Services s,
+ const QByteArray &d,
+ const TcfTrkCallback &cb= TcfTrkCallback(),
+ const QVariant &ck = QVariant()) :
+ messageType(mt), service(s), data(d), token(tok), cookie(ck), callback(cb) {}
+
+ MessageType messageType;
+ Services service;
+ QByteArray data;
+ int token;
+ QVariant cookie;
+ TcfTrkCallback callback;
+};
+
+struct TcfTrkDevicePrivate {
+ typedef TcfTrkDevice::IODevicePtr IODevicePtr;
+ typedef QHash<int, TcfTrkSendQueueEntry> TokenWrittenMessageMap;
+
+ TcfTrkDevicePrivate();
+
+ const QByteArray m_messageTerminator;
+
+ IODevicePtr m_device;
+ unsigned m_verbose;
+ QByteArray m_readBuffer;
+ int m_token;
+ QQueue<TcfTrkSendQueueEntry> m_sendQueue;
+ TokenWrittenMessageMap m_writtenMessages;
+ QVector<QByteArray> m_registerNames;
+};
+
+TcfTrkDevicePrivate::TcfTrkDevicePrivate() :
+ m_messageTerminator(messageTerminatorC),
+ m_verbose(0), m_token(0)
+{
+}
+
+TcfTrkDevice::TcfTrkDevice(QObject *parent) :
+ QObject(parent), d(new TcfTrkDevicePrivate)
+{
+}
+
+TcfTrkDevice::~TcfTrkDevice()
+{
+ delete d;
+}
+
+QVector<QByteArray> TcfTrkDevice::registerNames() const
+{
+ return d->m_registerNames;
+}
+
+void TcfTrkDevice::setRegisterNames(const QVector<QByteArray>& n)
+{
+ d->m_registerNames = n;
+ if (d->m_verbose) {
+ QString msg;
+ QTextStream str(&msg);
+ const int count = n.size();
+ str << "Registers (" << count << "): ";
+ for (int i = 0; i < count; i++)
+ str << '#' << i << '=' << n.at(i) << ' ';
+ emitLogMessage(msg);
+ }
+}
+
+TcfTrkDevice::IODevicePtr TcfTrkDevice::device() const
+{
+ return d->m_device;
+}
+
+TcfTrkDevice::IODevicePtr TcfTrkDevice::takeDevice()
+{
+ const IODevicePtr old = d->m_device;
+ if (!old.isNull()) {
+ old.data()->disconnect(this);
+ d->m_device = IODevicePtr();
+ }
+ d->m_readBuffer.clear();
+ d->m_token = 0;
+ d->m_sendQueue.clear();
+ return old;
+}
+
+void TcfTrkDevice::setDevice(const IODevicePtr &dp)
+{
+ if (dp.data() == d->m_device.data())
+ return;
+ if (dp.isNull()) {
+ emitLogMessage(QLatin1String("Internal error: Attempt to set NULL device."));
+ return;
+ }
+ takeDevice();
+ d->m_device = dp;
+ connect(dp.data(), SIGNAL(readyRead()), this, SLOT(slotDeviceReadyRead()));
+ if (QAbstractSocket *s = qobject_cast<QAbstractSocket *>(dp.data())) {
+ connect(s, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotDeviceError()));
+ connect(s, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(slotDeviceSocketStateChanged()));
+ }
+}
+
+void TcfTrkDevice::slotDeviceError()
+{
+ const QString message = d->m_device->errorString();
+ emitLogMessage(message);
+ emit error(message);
+}
+
+void TcfTrkDevice::slotDeviceSocketStateChanged()
+{
+ if (const QAbstractSocket *s = qobject_cast<const QAbstractSocket *>(d->m_device.data())) {
+ const QAbstractSocket::SocketState st = s->state();
+ switch (st) {
+ case QAbstractSocket::UnconnectedState:
+ emitLogMessage(QLatin1String("Unconnected"));
+ break;
+ case QAbstractSocket::HostLookupState:
+ emitLogMessage(QLatin1String("HostLookupState"));
+ break;
+ case QAbstractSocket::ConnectingState:
+ emitLogMessage(QLatin1String("Connecting"));
+ break;
+ case QAbstractSocket::ConnectedState:
+ emitLogMessage(QLatin1String("Connected"));
+ break;
+ case QAbstractSocket::ClosingState:
+ emitLogMessage(QLatin1String("Closing"));
+ break;
+ default:
+ emitLogMessage(QString::fromLatin1("State %1").arg(st));
+ break;
+ }
+ }
+}
+
+static inline QString debugMessage(QByteArray message, const char *prefix = 0)
+{
+ message.replace('\0', '|');
+ const QString messageS = QString::fromLatin1(message);
+ return prefix ?
+ (QLatin1String(prefix) + messageS) : messageS;
+}
+
+void TcfTrkDevice::slotDeviceReadyRead()
+{
+ d->m_readBuffer += d->m_device->readAll();
+ // Take complete message off front of readbuffer.
+ do {
+ const int messageEndPos = d->m_readBuffer.indexOf(d->m_messageTerminator);
+ if (messageEndPos == -1)
+ break;
+ const QByteArray message = d->m_readBuffer.left(messageEndPos);
+ if (debug)
+ qDebug("Read:\n%s", qPrintable(formatData(message)));
+ if (const int errorCode = parseMessage(message)) {
+ emitLogMessage(QString::fromLatin1("Parse error %1 for: %2").arg(errorCode).arg(debugMessage(message)));
+ }
+ d->m_readBuffer.remove(0, messageEndPos + d->m_messageTerminator.size());
+ } while (!d->m_readBuffer.isEmpty());
+ checkSendQueue(); // Send off further message
+}
+
+// Split \0-terminated message into tokens, skipping the initial type character
+static inline QVector<QByteArray> splitMessage(const QByteArray &message)
+{
+ QVector<QByteArray> tokens;
+ tokens.reserve(7);
+ const int messageSize = message.size();
+ for (int pos = 2; pos < messageSize; ) {
+ const int nextPos = message.indexOf('\0', pos);
+ if (nextPos == -1)
+ break;
+ tokens.push_back(message.mid(pos, nextPos - pos));
+ pos = nextPos + 1;
+ }
+ return tokens;
+}
+
+int TcfTrkDevice::parseMessage(const QByteArray &message)
+{
+ if (d->m_verbose)
+ emitLogMessage(debugMessage(message, "TCF ->"));
+ // Special JSON parse error message or protocol format error.
+ // The port is usually closed after receiving it.
+ // "\3\2{"Time":1276096098255,"Code":3,"Format": "Protocol format error"}"
+ if (message.startsWith("\003\002")) {
+ QByteArray text = message.mid(2);
+ const QString errorMessage = QString::fromLatin1("Parse error received: %1").arg(QString::fromAscii(text));
+ emit error(errorMessage);
+ return 0;
+ }
+ if (message.size() < 4 || message.at(1) != '\0')
+ return 1;
+ // Split into tokens
+ const char type = message.at(0);
+ const QVector<QByteArray> tokens = splitMessage(message);
+ switch (type) {
+ case 'E':
+ return parseTcfEvent(tokens);
+ case 'R': // Command replies
+ case 'N':
+ case 'P':
+ return parseTcfCommandReply(type, tokens);
+ default:
+ emitLogMessage(QString::fromLatin1("Unhandled message type: %1").arg(debugMessage(message)));
+ return 756;
+ }
+ return 0;
+}
+
+int TcfTrkDevice::parseTcfCommandReply(char type, const QVector<QByteArray> &tokens)
+{
+ typedef TcfTrkDevicePrivate::TokenWrittenMessageMap::iterator TokenWrittenMessageMapIterator;
+ // Find the corresponding entry in the written messages hash.
+ const int tokenCount = tokens.size();
+ if (tokenCount < 1)
+ return 234;
+ bool tokenOk;
+ const int token = tokens.at(0).toInt(&tokenOk);
+ if (!tokenOk)
+ return 235;
+ const TokenWrittenMessageMapIterator it = d->m_writtenMessages.find(token);
+ if (it == d->m_writtenMessages.end()) {
+ qWarning("TcfTrkDevice: Internal error: token %d not found for '%s'",
+ token, qPrintable(joinByteArrays(tokens)));
+ return 236;
+ }
+ // No callback: remove entry from map, happy
+ if (!it.value().callback) {
+ d->m_writtenMessages.erase(it);
+ return 0;
+ }
+ // Parse values into JSON
+ QVector<JsonValue> values;
+ values.reserve(tokenCount);
+ for (int i = 1; i < tokenCount; i++) {
+ if (!tokens.at(i).isEmpty()) { // Strange: Empty tokens occur.
+ const JsonValue value(tokens.at(i));
+ if (value.isValid()) {
+ values.push_back(value);
+ } else {
+ qWarning("JSON parse error for reply to command token %d: #%d '%s'",
+ token, i, tokens.at(i).constData());
+ d->m_writtenMessages.erase(it);
+ return -1;
+ }
+ }
+ }
+
+ // Construct result and invoke callback, remove entry from map.
+ TcfTrkCallback callback = it.value().callback;
+ TcfTrkCommandResult result(type, it.value().service, it.value().data,
+ values, it.value().cookie);
+ d->m_writtenMessages.erase(it);
+ callback(result);
+ return 0;
+}
+
+static const char locatorAnswerC[] = "E\0Locator\0Hello\0[\"Locator\"]";
+
+int TcfTrkDevice::parseTcfEvent(const QVector<QByteArray> &tokens)
+{
+ // Event: Ignore the periodical heartbeat event, answer 'Hello',
+ // emit signal for the rest
+ if (tokens.size() < 3)
+ return 433;
+ const Services service = serviceFromName(tokens.at(0).constData());
+ if (service == LocatorService && tokens.at(1) == "peerHeartBeat")
+ return 0;
+ QVector<JsonValue> values;
+ for (int i = 2; i < tokens.size(); i++) {
+ const JsonValue value(tokens.at(i));
+ if (!value.isValid())
+ return 434;
+ values.push_back(value);
+ }
+ // Parse known events, emit signals
+ QScopedPointer<TcfTrkEvent> knownEvent(TcfTrkEvent::parseEvent(service, tokens.at(1), values));
+ if (!knownEvent.isNull()) {
+ // Answer hello event.
+ if (knownEvent->type() == TcfTrkEvent::LocatorHello)
+ writeMessage(QByteArray(locatorAnswerC, sizeof(locatorAnswerC)));
+ emit tcfEvent(*knownEvent);
+ }
+ emit genericTcfEvent(service, tokens.at(1), values);
+
+ if (debug || d->m_verbose) {
+ QString msg;
+ QTextStream str(&msg);
+ if (knownEvent.isNull()) {
+ str << "Event: " << tokens.at(0) << ' ' << tokens.at(1) << '\n';
+ foreach(const JsonValue &val, values)
+ str << " " << val.toString() << '\n';
+ } else {
+ str << knownEvent->toString();
+ }
+ emitLogMessage(msg);
+ }
+
+ return 0;
+}
+
+unsigned TcfTrkDevice::verbose() const
+{
+ return d->m_verbose;
+}
+
+void TcfTrkDevice::setVerbose(unsigned v)
+{
+ d->m_verbose = v;
+}
+
+void TcfTrkDevice::emitLogMessage(const QString &m)
+{
+ if (debug)
+ qWarning("%s", qPrintable(m));
+ emit logMessage(m);
+}
+
+bool TcfTrkDevice::checkOpen()
+{
+ if (d->m_device.isNull()) {
+ emitLogMessage(QLatin1String("Internal error: No device set on TcfTrkDevice."));
+ return false;
+ }
+ if (!d->m_device->isOpen()) {
+ emitLogMessage(QLatin1String("Internal error: Device not open in TcfTrkDevice."));
+ return false;
+ }
+ return true;
+}
+
+void TcfTrkDevice::sendTcfTrkMessage(MessageType mt, Services service, const char *command,
+ const char *commandParameters, int commandParametersLength,
+ const TcfTrkCallback &callBack,
+ const QVariant &cookie)
+
+{
+ if (!checkOpen())
+ return;
+ // Format the message
+ const int token = d->m_token++;
+ QByteArray data;
+ data.reserve(30 + commandParametersLength);
+ data.append('C');
+ data.append('\0');
+ data.append(QByteArray::number(token));
+ data.append('\0');
+ data.append(serviceName(service));
+ data.append('\0');
+ data.append(command);
+ data.append('\0');
+ if (commandParametersLength)
+ data.append(commandParameters, commandParametersLength);
+ const TcfTrkSendQueueEntry entry(mt, token, service, data, callBack, cookie);
+ d->m_sendQueue.enqueue(entry);
+ checkSendQueue();
+}
+
+void TcfTrkDevice::sendTcfTrkMessage(MessageType mt, Services service, const char *command,
+ const QByteArray &commandParameters,
+ const TcfTrkCallback &callBack,
+ const QVariant &cookie)
+{
+ sendTcfTrkMessage(mt, service, command, commandParameters.constData(), commandParameters.size(),
+ callBack, cookie);
+}
+
+// Enclose in message frame and write.
+void TcfTrkDevice::writeMessage(QByteArray data)
+{
+ if (!checkOpen())
+ return;
+
+ if (d->m_verbose)
+ emitLogMessage(debugMessage(data, "TCF <-"));
+
+ // Ensure \0-termination which easily gets lost in QByteArray CT.
+ if (!data.endsWith('\0'))
+ data.append('\0');
+ data += d->m_messageTerminator;
+
+ if (debug > 1)
+ qDebug("Writing:\n%s", qPrintable(formatData(data)));
+
+ d->m_device->write(data);
+ if (QAbstractSocket *as = qobject_cast<QAbstractSocket *>(d->m_device.data()))
+ as->flush();
+}
+
+void TcfTrkDevice::checkSendQueue()
+{
+ // Fire off messages or invoke noops until a message with reply is found
+ // and an entry to writtenMessages is made.
+ while (d->m_writtenMessages.empty()) {
+ if (d->m_sendQueue.isEmpty())
+ break;
+ TcfTrkSendQueueEntry entry = d->m_sendQueue.dequeue();
+ switch (entry.messageType) {
+ case MessageWithReply:
+ d->m_writtenMessages.insert(entry.token, entry);
+ writeMessage(entry.data);
+ break;
+ case MessageWithoutReply:
+ writeMessage(entry.data);
+ break;
+ case NoopMessage: // Invoke the noop-callback for synchronization
+ if (entry.callback) {
+ TcfTrkCommandResult noopResult(TcfTrkCommandResult::SuccessReply);
+ noopResult.cookie = entry.cookie;
+ entry.callback(noopResult);
+ }
+ break;
+ }
+ }
+}
+
+// Fix slashes
+static inline QString fixFileName(QString in)
+{
+ in.replace(QLatin1Char('/'), QLatin1Char('\\'));
+ return in;
+}
+
+// Start a process (consisting of a non-reply setSettings and start).
+void TcfTrkDevice::sendProcessStartCommand(const TcfTrkCallback &callBack,
+ const QString &binaryIn,
+ unsigned uid,
+ QStringList arguments,
+ QString workingDirectory,
+ bool debugControl,
+ const QStringList &additionalLibraries,
+ const QVariant &cookie)
+{
+ // Obtain the bin directory, expand by c:/sys/bin if missing
+ const QChar backSlash('\\');
+ int slashPos = binaryIn.lastIndexOf(QLatin1Char('/'));
+ if (slashPos == -1)
+ slashPos = binaryIn.lastIndexOf(backSlash);
+ const QString sysBin = QLatin1String("c:/sys/bin");
+ const QString binaryFileName = slashPos == -1 ? binaryIn : binaryIn.mid(slashPos + 1);
+ const QString binaryDirectory = slashPos == -1 ? sysBin : binaryIn.left(slashPos);
+ const QString binary = fixFileName(binaryDirectory + QLatin1Char('/') + binaryFileName);
+
+ // Fixup: Does argv[0] convention exist on Symbian?
+ arguments.push_front(binary);
+ if (workingDirectory.isEmpty())
+ workingDirectory = sysBin;
+
+ // Format settings with empty dummy parameter
+ QByteArray setData;
+ JsonInputStream setStr(setData);
+ setStr << "" << '\0'
+ << '[' << "exeToLaunch" << ',' << "addExecutables" << ',' << "addLibraries" << ']'
+ << '\0' << '['
+ << binary << ','
+ << '{' << binaryFileName << ':' << QString::number(uid, 16) << '}' << ','
+ << additionalLibraries
+ << ']';
+ sendTcfTrkMessage(MessageWithoutReply, SettingsService, "set", setData);
+
+ QByteArray startData;
+ JsonInputStream startStr(startData);
+ startStr << fixFileName(workingDirectory)
+ << '\0' << binary << '\0' << arguments << '\0'
+ << QStringList() << '\0' // Env is an array ["PATH=value"] (non-standard)
+ << debugControl;
+ sendTcfTrkMessage(MessageWithReply, ProcessesService, "start", startData, callBack, cookie);
+}
+
+void TcfTrkDevice::sendProcessTerminateCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ const QVariant &cookie)
+{
+ QByteArray data;
+ JsonInputStream str(data);
+ str << id;
+ sendTcfTrkMessage(MessageWithReply, ProcessesService, "terminate", data, callBack, cookie);
+}
+
+void TcfTrkDevice::sendRunControlTerminateCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ const QVariant &cookie)
+{
+ QByteArray data;
+ JsonInputStream str(data);
+ str << id;
+ sendTcfTrkMessage(MessageWithReply, RunControlService, "terminate", data, callBack, cookie);
+}
+
+// Non-standard: Remove executable from settings
+void TcfTrkDevice::sendSettingsRemoveExecutableCommand(const QString &binaryIn,
+ unsigned uid,
+ const QStringList &additionalLibraries,
+ const QVariant &cookie)
+{
+ QByteArray setData;
+ JsonInputStream setStr(setData);
+ setStr << "" << '\0'
+ << '[' << "removedExecutables" << ',' << "removedLibraries" << ']'
+ << '\0' << '['
+ << '{' << QFileInfo(binaryIn).fileName() << ':' << QString::number(uid, 16) << '}' << ','
+ << additionalLibraries
+ << ']';
+ sendTcfTrkMessage(MessageWithoutReply, SettingsService, "set", setData, TcfTrkCallback(), cookie);
+}
+
+void TcfTrkDevice::sendRunControlResumeCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ RunControlResumeMode mode,
+ unsigned count,
+ quint64 rangeStart,
+ quint64 rangeEnd,
+ const QVariant &cookie)
+{
+ QByteArray resumeData;
+ JsonInputStream str(resumeData);
+ str << id << '\0' << int(mode) << '\0' << count;
+ switch (mode) {
+ case RM_STEP_OVER_RANGE:
+ case RM_STEP_INTO_RANGE:
+ case RM_REVERSE_STEP_OVER_RANGE:
+ case RM_REVERSE_STEP_INTO_RANGE:
+ str << '\0' << '{' << "RANGE_START" << ':' << rangeStart
+ << ',' << "RANGE_END" << ':' << rangeEnd << '}';
+ break;
+ default:
+ break;
+ }
+ sendTcfTrkMessage(MessageWithReply, RunControlService, "resume", resumeData, callBack, cookie);
+}
+
+void TcfTrkDevice::sendRunControlSuspendCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ const QVariant &cookie)
+{
+ QByteArray data;
+ JsonInputStream str(data);
+ str << id;
+ sendTcfTrkMessage(MessageWithReply, RunControlService, "suspend", data, callBack, cookie);
+}
+
+void TcfTrkDevice::sendRunControlResumeCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ const QVariant &cookie)
+{
+ sendRunControlResumeCommand(callBack, id, RM_RESUME, 1, 0, 0, cookie);
+}
+
+void TcfTrkDevice::sendBreakpointsAddCommand(const TcfTrkCallback &callBack,
+ const Breakpoint &bp,
+ const QVariant &cookie)
+{
+ QByteArray data;
+ JsonInputStream str(data);
+ str << bp;
+ sendTcfTrkMessage(MessageWithReply, BreakpointsService, "add", data, callBack, cookie);
+}
+
+void TcfTrkDevice::sendBreakpointsRemoveCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ const QVariant &cookie)
+{
+ sendBreakpointsRemoveCommand(callBack, QVector<QByteArray>(1, id), cookie);
+}
+
+void TcfTrkDevice::sendBreakpointsRemoveCommand(const TcfTrkCallback &callBack,
+ const QVector<QByteArray> &ids,
+ const QVariant &cookie)
+{
+ QByteArray data;
+ JsonInputStream str(data);
+ str << ids;
+ sendTcfTrkMessage(MessageWithReply, BreakpointsService, "remove", data, callBack, cookie);
+}
+
+void TcfTrkDevice::sendBreakpointsEnableCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ bool enable,
+ const QVariant &cookie)
+{
+ sendBreakpointsEnableCommand(callBack, QVector<QByteArray>(1, id), enable, cookie);
+}
+
+void TcfTrkDevice::sendBreakpointsEnableCommand(const TcfTrkCallback &callBack,
+ const QVector<QByteArray> &ids,
+ bool enable,
+ const QVariant &cookie)
+{
+ QByteArray data;
+ JsonInputStream str(data);
+ str << ids;
+ sendTcfTrkMessage(MessageWithReply, BreakpointsService,
+ enable ? "enable" : "disable",
+ data, callBack, cookie);
+}
+
+void TcfTrkDevice::sendMemorySetCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ quint64 start, const QByteArray& data,
+ const QVariant &cookie)
+{
+ QByteArray getData;
+ JsonInputStream str(getData);
+ // start/word size/mode. Mode should ideally be 1 (continue on error?)
+ str << contextId << '\0' << start << '\0' << 1 << '\0' << data.size() << '\0' << 1
+ << '\0' << data.toBase64();
+ sendTcfTrkMessage(MessageWithReply, MemoryService, "set", getData, callBack, cookie);
+}
+
+void TcfTrkDevice::sendMemoryGetCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ quint64 start, quint64 size,
+ const QVariant &cookie)
+{
+ QByteArray data;
+ JsonInputStream str(data);
+ // start/word size/mode. Mode should ideally be 1 (continue on error?)
+ str << contextId << '\0' << start << '\0' << 1 << '\0' << size << '\0' << 1;
+ sendTcfTrkMessage(MessageWithReply, MemoryService, "get", data, callBack, cookie);
+}
+
+QByteArray TcfTrkDevice::parseMemoryGet(const TcfTrkCommandResult &r)
+{
+ if (r.type != TcfTrkCommandResult::SuccessReply || r.values.size() < 1)
+ return QByteArray();
+ const JsonValue &memoryV = r.values.front();
+
+ if (memoryV.type() != JsonValue::String || memoryV.data().size() < 2
+ || !memoryV.data().endsWith('='))
+ return QByteArray();
+ // Catch errors reported as hash:
+ // R.4."TlVMTA==".{"Time":1276786871255,"Code":1,"AltCode":-38,"AltOrg":"POSIX","Format":"BadDescriptor"}
+ // Not sure what to make of it.
+ if (r.values.size() >= 2 && r.values.at(1).type() == JsonValue::Object)
+ qWarning("Error retrieving memory: %s", r.values.at(1).toString(false).constData());
+ // decode
+ const QByteArray memory = QByteArray::fromBase64(memoryV.data());
+ if (memory.isEmpty())
+ qWarning("Base64 decoding of %s failed.", memoryV.data().constData());
+ if (debug)
+ qDebug("TcfTrkDevice::parseMemoryGet: received %d bytes", memory.size());
+ return memory;
+}
+
+void TcfTrkDevice::sendRegistersGetMCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ const QVector<QByteArray> &ids,
+ const QVariant &cookie)
+{
+ // TODO: use "Registers" (which uses base64-encoded values)
+ QByteArray data;
+ JsonInputStream str(data);
+ str << contextId << '\0' << ids;
+ sendTcfTrkMessage(MessageWithReply, SimpleRegistersService, "get", data, callBack, cookie);
+}
+
+void TcfTrkDevice::sendRegistersGetMRangeCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ unsigned start, unsigned count)
+{
+ const unsigned end = start + count;
+ if (end > (unsigned)d->m_registerNames.size()) {
+ qWarning("TcfTrkDevice: No register name set for index %u (size: %d).", end, d->m_registerNames.size());
+ return;
+ }
+
+ QVector<QByteArray> ids;
+ ids.reserve(count);
+ for (unsigned i = start; i < end; i++)
+ ids.push_back(d->m_registerNames.at(i));
+ sendRegistersGetMCommand(callBack, contextId, ids, QVariant(start));
+}
+
+// Set register
+void TcfTrkDevice::sendRegistersSetCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ const QByteArray &id,
+ unsigned value,
+ const QVariant &cookie)
+{
+ // TODO: use "Registers" (which uses base64-encoded values)
+ QByteArray data;
+ JsonInputStream str(data);
+ str << contextId << '\0' << QVector<QByteArray>(1, id)
+ << '\0' << QVector<QByteArray>(1, QByteArray::number(value, 16));
+ sendTcfTrkMessage(MessageWithReply, SimpleRegistersService, "set", data, callBack, cookie);
+}
+
+// Set register
+void TcfTrkDevice::sendRegistersSetCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ unsigned registerNumber,
+ unsigned value,
+ const QVariant &cookie)
+{
+ if (registerNumber >= (unsigned)d->m_registerNames.size()) {
+ qWarning("TcfTrkDevice: No register name set for index %u (size: %d).", registerNumber, d->m_registerNames.size());
+ return;
+ }
+ sendRegistersSetCommand(callBack, contextId,
+ d->m_registerNames[registerNumber],
+ value, cookie);
+}
+
+} // namespace tcftrk
diff --git a/tools/runonphone/symbianutils/tcftrkdevice.h b/tools/runonphone/symbianutils/tcftrkdevice.h
new file mode 100644
index 0000000..67955e5
--- /dev/null
+++ b/tools/runonphone/symbianutils/tcftrkdevice.h
@@ -0,0 +1,295 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TCFTRKENGINE_H
+#define TCFTRKENGINE_H
+
+#include "symbianutils_global.h"
+#include "tcftrkmessage.h"
+#include "callback.h"
+#include "json.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QVector>
+#include <QtCore/QVariant>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+class QIODevice;
+class QTextStream;
+QT_END_NAMESPACE
+
+namespace tcftrk {
+
+struct TcfTrkDevicePrivate;
+struct Breakpoint;
+
+/* Command error handling in TCF:
+ * 1) 'Severe' errors (JSON format, parameter format): Trk emits a
+ * nonstandard message (\3\2 error paramaters) and closes the connection.
+ * 2) Protocol errors: 'N' without error message is returned.
+ * 3) Errors in command execution: 'R' with a TCF error hash is returned
+ * (see TcfTrkCommandError). */
+
+/* Error code return in 'R' reply to command
+ * (see top of 'Services' documentation). */
+struct SYMBIANUTILS_EXPORT TcfTrkCommandError {
+ TcfTrkCommandError();
+ void clear();
+ operator bool() const { return timeMS != 0; }
+ QString toString() const;
+ void write(QTextStream &str) const;
+ bool parse(const QVector<JsonValue> &values);
+
+ quint64 timeMS; // Since 1.1.1970
+ int code;
+ QByteArray format; // message
+ // 'Alternative' meaning, like altOrg="POSIX"/altCode=<some errno>
+ QByteArray alternativeOrganization;
+ int alternativeCode;
+};
+
+/* Answer to a Tcf command passed to the callback. */
+struct SYMBIANUTILS_EXPORT TcfTrkCommandResult {
+ enum Type {
+ SuccessReply, // 'R' and no error -> all happy.
+ CommandErrorReply, // 'R' with TcfTrkCommandError received
+ ProgressReply, // 'P', progress indicator
+ FailReply // 'N' Protocol NAK, severe error
+ };
+
+ explicit TcfTrkCommandResult(Type t = SuccessReply);
+ explicit TcfTrkCommandResult(char typeChar, Services service,
+ const QByteArray &request,
+ const QVector<JsonValue> &values,
+ const QVariant &cookie);
+
+ QString toString() const;
+ QString errorString() const;
+ operator bool() const { return type == SuccessReply || type == ProgressReply; }
+
+ Type type;
+ Services service;
+ QByteArray request;
+ TcfTrkCommandError commandError;
+ QVector<JsonValue> values;
+ QVariant cookie;
+};
+
+typedef trk::Callback<const TcfTrkCommandResult &> TcfTrkCallback;
+
+/* TcfTrkDevice: TCF communication helper using an asynchronous QIODevice
+ * implementing the TCF protocol according to:
+http://dev.eclipse.org/svnroot/dsdp/org.eclipse.tm.tcf/trunk/docs/TCF%20Specification.html
+http://dev.eclipse.org/svnroot/dsdp/org.eclipse.tm.tcf/trunk/docs/TCF%20Services.html
+ * Commands can be sent along with callbacks that are passed a
+ * TcfTrkCommandResult and an opaque QVariant cookie. In addition, events are emitted.
+*/
+
+class SYMBIANUTILS_EXPORT TcfTrkDevice : public QObject
+{
+ Q_PROPERTY(unsigned verbose READ verbose WRITE setVerbose)
+ Q_OBJECT
+public:
+ enum MessageType { MessageWithReply,
+ MessageWithoutReply, /* Non-standard: "Settings:set" command does not reply */
+ NoopMessage };
+
+ typedef QSharedPointer<QIODevice> IODevicePtr;
+
+ explicit TcfTrkDevice(QObject *parent = 0);
+ virtual ~TcfTrkDevice();
+
+ unsigned verbose() const;
+
+ // Mapping of register names for indices
+ QVector<QByteArray> registerNames() const;
+ void setRegisterNames(const QVector<QByteArray>& n);
+
+ IODevicePtr device() const;
+ IODevicePtr takeDevice();
+ void setDevice(const IODevicePtr &dp);
+
+ void sendTcfTrkMessage(MessageType mt, Services service,
+ const char *command,
+ const char *commandParameters, int commandParametersLength,
+ const TcfTrkCallback &callBack = TcfTrkCallback(),
+ const QVariant &cookie = QVariant());
+
+ void sendTcfTrkMessage(MessageType mt, Services service, const char *command,
+ const QByteArray &commandParameters,
+ const TcfTrkCallback &callBack = TcfTrkCallback(),
+ const QVariant &cookie = QVariant());
+
+ // Convenience messages: Start a process
+ void sendProcessStartCommand(const TcfTrkCallback &callBack,
+ const QString &binary,
+ unsigned uid,
+ QStringList arguments = QStringList(),
+ QString workingDirectory = QString(),
+ bool debugControl = true,
+ const QStringList &additionalLibraries = QStringList(),
+ const QVariant &cookie = QVariant());
+
+ // Preferred over Processes:Terminate by TCF TRK.
+ void sendRunControlTerminateCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ const QVariant &cookie = QVariant());
+
+ void sendProcessTerminateCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ const QVariant &cookie = QVariant());
+
+ // Non-standard: Remove executable from settings.
+ // Probably needs to be called after stopping. This command has no response.
+ void sendSettingsRemoveExecutableCommand(const QString &binaryIn,
+ unsigned uid,
+ const QStringList &additionalLibraries = QStringList(),
+ const QVariant &cookie = QVariant());
+
+ void sendRunControlSuspendCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ const QVariant &cookie = QVariant());
+
+ // Resume / Step (see RunControlResumeMode).
+ void sendRunControlResumeCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ RunControlResumeMode mode,
+ unsigned count /* = 1, currently ignored. */,
+ quint64 rangeStart, quint64 rangeEnd,
+ const QVariant &cookie = QVariant());
+
+ // Convenience to resume a suspended process
+ void sendRunControlResumeCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ const QVariant &cookie = QVariant());
+
+ void sendBreakpointsAddCommand(const TcfTrkCallback &callBack,
+ const Breakpoint &b,
+ const QVariant &cookie = QVariant());
+
+ void sendBreakpointsRemoveCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ const QVariant &cookie = QVariant());
+
+ void sendBreakpointsRemoveCommand(const TcfTrkCallback &callBack,
+ const QVector<QByteArray> &id,
+ const QVariant &cookie = QVariant());
+
+ void sendBreakpointsEnableCommand(const TcfTrkCallback &callBack,
+ const QByteArray &id,
+ bool enable,
+ const QVariant &cookie = QVariant());
+
+ void sendBreakpointsEnableCommand(const TcfTrkCallback &callBack,
+ const QVector<QByteArray> &id,
+ bool enable,
+ const QVariant &cookie = QVariant());
+
+
+ void sendMemoryGetCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ quint64 start, quint64 size,
+ const QVariant &cookie = QVariant());
+
+ void sendMemorySetCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ quint64 start, const QByteArray& data,
+ const QVariant &cookie = QVariant());
+
+ // Reply is an array of hexvalues
+ void sendRegistersGetMCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ const QVector<QByteArray> &ids,
+ const QVariant &cookie = QVariant());
+
+ // Convenience to get a range of register "R0" .. "R<n>".
+ // Cookie will be an int containing "start".
+ void sendRegistersGetMRangeCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ unsigned start, unsigned count);
+
+ // Set register
+ void sendRegistersSetCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ const QByteArray &ids,
+ unsigned value,
+ const QVariant &cookie = QVariant());
+ // Set register
+ void sendRegistersSetCommand(const TcfTrkCallback &callBack,
+ const QByteArray &contextId,
+ unsigned registerNumber,
+ unsigned value,
+ const QVariant &cookie = QVariant());
+
+ static QByteArray parseMemoryGet(const TcfTrkCommandResult &r);
+
+signals:
+ void genericTcfEvent(int service, const QByteArray &name, const QVector<tcftrk::JsonValue> &value);
+ void tcfEvent(const tcftrk::TcfTrkEvent &knownEvent);
+
+ void logMessage(const QString &);
+ void error(const QString &);
+
+public slots:
+ void setVerbose(unsigned v);
+
+private slots:
+ void slotDeviceError();
+ void slotDeviceSocketStateChanged();
+ void slotDeviceReadyRead();
+
+private:
+ bool checkOpen();
+ void checkSendQueue();
+ void writeMessage(QByteArray data);
+ void emitLogMessage(const QString &);
+ int parseMessage(const QByteArray &);
+ int parseTcfCommandReply(char type, const QVector<QByteArray> &tokens);
+ int parseTcfEvent(const QVector<QByteArray> &tokens);
+
+ TcfTrkDevicePrivate *d;
+};
+
+} // namespace tcftrk
+
+#endif // TCFTRKENGINE_H
diff --git a/tools/runonphone/symbianutils/tcftrkmessage.cpp b/tools/runonphone/symbianutils/tcftrkmessage.cpp
new file mode 100644
index 0000000..06035ab
--- /dev/null
+++ b/tools/runonphone/symbianutils/tcftrkmessage.cpp
@@ -0,0 +1,562 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "tcftrkmessage.h"
+#include "json.h"
+
+#include <QtCore/QString>
+#include <QtCore/QTextStream>
+
+// Names matching the enum
+static const char *serviceNamesC[] =
+{ "Locator", "RunControl", "Processes", "Memory", "Settings", "Breakpoints",
+ "Registers", "SimpleRegisters",
+ "UnknownService"};
+
+namespace tcftrk {
+
+SYMBIANUTILS_EXPORT QString joinByteArrays(const QVector<QByteArray> &a, char sep)
+{
+ QString rc;
+ const int count = a.size();
+ for (int i = 0; i < count; i++) {
+ if (i)
+ rc += QLatin1Char(sep);
+ rc += QString::fromUtf8(a.at(i));
+ }
+ return rc;
+}
+
+static inline bool jsonToBool(const JsonValue& js)
+{
+ return js.type() == JsonValue::Boolean && js.data() == "true";
+}
+
+SYMBIANUTILS_EXPORT const char *serviceName(Services s)
+{
+ return serviceNamesC[s];
+}
+
+SYMBIANUTILS_EXPORT Services serviceFromName(const char *n)
+{
+ const int count = sizeof(serviceNamesC)/sizeof(char *);
+ for (int i = 0; i < count; i++)
+ if (!qstrcmp(serviceNamesC[i], n))
+ return static_cast<Services>(i);
+ return UnknownService;
+}
+
+SYMBIANUTILS_EXPORT QString formatData(const QByteArray &a)
+{
+ const int columns = 16;
+ QString rc;
+ QTextStream str(&rc);
+ str.setIntegerBase(16);
+ str.setPadChar(QLatin1Char('0'));
+ const unsigned char *start = reinterpret_cast<const unsigned char *>(a.constData());
+ const unsigned char *end = start + a.size();
+ for (const unsigned char *p = start; p < end ; ) {
+ str << "0x";
+ str.setFieldWidth(4);
+ str << (p - start);
+ str.setFieldWidth(0);
+ str << ' ';
+ QString asc;
+ int c = 0;
+ for ( ; c < columns && p < end; c++, p++) {
+ const unsigned u = *p;
+ str.setFieldWidth(2);
+ str << u;
+ str.setFieldWidth(0);
+ str << ' ';
+ switch (u) {
+ case '\n':
+ asc += QLatin1String("\\n");
+ break;
+ case '\r':
+ asc += QLatin1String("\\r");
+ break;
+ case '\t':
+ asc += QLatin1String("\\t");
+ break;
+ default:
+ if (u >= 32 && u < 128) {
+ asc += QLatin1Char(' ');
+ asc += QLatin1Char(u);
+ } else {
+ asc += QLatin1String(" .");
+ }
+ break;
+ }
+ }
+ if (const int remainder = columns - c)
+ str << QString(3 * remainder, QLatin1Char(' '));
+ str << ' ' << asc << '\n';
+ }
+ return rc;
+}
+
+// ----------- RunControlContext
+RunControlContext::RunControlContext() :
+ flags(0), resumeFlags(0)
+{
+}
+
+void RunControlContext::clear()
+{
+ flags =0;
+ resumeFlags = 0;
+ id.clear();
+ osid.clear();
+ parentId.clear();
+}
+
+RunControlContext::Type RunControlContext::typeFromTcfId(const QByteArray &id)
+{
+ // "p12" or "p12.t34"?
+ return id.contains(".t") ? Thread : Process;
+}
+
+unsigned RunControlContext::processId() const
+{
+ return processIdFromTcdfId(id);
+}
+
+unsigned RunControlContext::threadId() const
+{
+ return threadIdFromTcdfId(id);
+}
+
+unsigned RunControlContext::processIdFromTcdfId(const QByteArray &id)
+{
+ // Cut out process id from "p12" or "p12.t34"?
+ if (!id.startsWith('p'))
+ return 0;
+ const int dotPos = id.indexOf('.');
+ const int pLen = dotPos == -1 ? id.size() : dotPos;
+ return id.mid(1, pLen - 1).toUInt();
+}
+
+unsigned RunControlContext::threadIdFromTcdfId(const QByteArray &id)
+{
+ const int tPos = id.indexOf(".t");
+ return tPos != -1 ? id.mid(tPos + 2).toUInt() : uint(0);
+}
+
+QByteArray RunControlContext::tcfId(unsigned processId, unsigned threadId /* = 0 */)
+{
+ QByteArray rc("p");
+ rc += QByteArray::number(processId);
+ if (threadId) {
+ rc += ".t";
+ rc += QByteArray::number(threadId);
+ }
+ return rc;
+}
+
+RunControlContext::Type RunControlContext::type() const
+{
+ return RunControlContext::typeFromTcfId(id);
+}
+
+bool RunControlContext::parse(const JsonValue &val)
+{
+ clear();
+ if (val.type() != JsonValue::Object)
+ return false;
+ foreach(const JsonValue &c, val.children()) {
+ if (c.name() == "ID") {
+ id = c.data();
+ } else if (c.name() == "OSID") {
+ osid = c.data();
+ } else if (c.name() == "ParentID") {
+ parentId = c.data();
+ } else if (c.name() == "IsContainer") {
+ if (jsonToBool(c))
+ flags |= Container;
+ } else if (c.name() == "CanTerminate") {
+ if (jsonToBool(c))
+ flags |= CanTerminate;
+ } else if (c.name() == "CanResume") {
+ resumeFlags = c.data().toUInt();
+ } else if (c.name() == "HasState") {
+ if (jsonToBool(c))
+ flags |= HasState;
+ } else if (c.name() == "CanSuspend") {
+ if (jsonToBool(c))
+ flags |= CanSuspend;
+ }
+ }
+ return true;
+}
+
+QString RunControlContext::toString() const
+{
+ QString rc;
+ QTextStream str(&rc);
+ format(str);
+ return rc;
+}
+
+void RunControlContext::format(QTextStream &str) const
+{
+ str << " id='" << id << "' osid='" << osid
+ << "' parentId='" << parentId <<"' ";
+ if (flags & Container)
+ str << "[container] ";
+ if (flags & HasState)
+ str << "[has state] ";
+ if (flags & CanSuspend)
+ str << "[can suspend] ";
+ if (flags & CanSuspend)
+ str << "[can terminate] ";
+ str.setIntegerBase(16);
+ str << " resume_flags: 0x" << resumeFlags;
+ str.setIntegerBase(10);
+}
+
+// ------ ModuleLoadEventInfo
+ModuleLoadEventInfo::ModuleLoadEventInfo() :
+ loaded(false), codeAddress(0), dataAddress(0), requireResume(false)
+{
+}
+
+void ModuleLoadEventInfo::clear()
+{
+ loaded = requireResume = false;
+ codeAddress = dataAddress =0;
+}
+
+bool ModuleLoadEventInfo::parse(const JsonValue &val)
+{
+ clear();
+ if (val.type() != JsonValue::Object)
+ return false;
+ foreach(const JsonValue &c, val.children()) {
+ if (c.name() == "Name") {
+ name = c.data();
+ } else if (c.name() == "File") {
+ file = c.data();
+ } else if (c.name() == "CodeAddress") {
+ codeAddress = c.data().toULongLong();
+ } else if (c.name() == "DataAddress") {
+ dataAddress = c.data().toULongLong();
+ } else if (c.name() == "Loaded") {
+ loaded = jsonToBool(c);
+ } else if (c.name() == "RequireResume") {
+ requireResume =jsonToBool(c);
+ }
+ }
+ return true;
+}
+void ModuleLoadEventInfo::format(QTextStream &str) const
+{
+ str << "name='" << name << "' file='" << file << "' " <<
+ (loaded ? "[loaded] " : "[not loaded] ");
+ if (requireResume)
+ str << "[requires resume] ";
+ str.setIntegerBase(16);
+ str << " code: 0x" << codeAddress << " data: 0x" << dataAddress;
+ str.setIntegerBase(10);
+}
+
+// ---------------------- Breakpoint
+
+// Types matching enum
+static const char *breakPointTypesC[] = {"Software", "Hardware", "Auto"};
+
+Breakpoint::Breakpoint(quint64 loc) :
+ type(Auto), enabled(true), ignoreCount(0), location(loc), size(1), thumb(true)
+{
+ if (loc)
+ id = idFromLocation(location);
+}
+
+void Breakpoint::setContextId(unsigned processId, unsigned threadId)
+{
+ contextIds = QVector<QByteArray>(1, RunControlContext::tcfId(processId, threadId));
+}
+
+QByteArray Breakpoint::idFromLocation(quint64 loc)
+{
+ return QByteArray("BP_0x") + QByteArray::number(loc, 16);
+}
+
+QString Breakpoint::toString() const
+{
+ QString rc;
+ QTextStream str(&rc);
+ str.setIntegerBase(16);
+ str << "Breakpoint '" << id << "' " << breakPointTypesC[type] << " for contexts '"
+ << joinByteArrays(contextIds, ',') << "' at 0x" << location;
+ str.setIntegerBase(10);
+ str << " size " << size;
+ if (enabled)
+ str << " [enabled]";
+ if (thumb)
+ str << " [thumb]";
+ if (ignoreCount)
+ str << " IgnoreCount " << ignoreCount;
+ return rc;
+}
+
+JsonInputStream &operator<<(JsonInputStream &str, const Breakpoint &b)
+{
+ if (b.contextIds.isEmpty())
+ qWarning("tcftrk::Breakpoint: No context ids specified");
+
+ str << '{' << "ID" << ':' << QString::fromUtf8(b.id) << ','
+ << "BreakpointType" << ':' << breakPointTypesC[b.type] << ','
+ << "Enabled" << ':' << b.enabled << ','
+ << "IgnoreCount" << ':' << b.ignoreCount << ','
+ << "ContextIds" << ':' << b.contextIds << ','
+ << "Location" << ':' << QString::number(b.location) << ','
+ << "Size" << ':' << b.size << ','
+ << "THUMB_BREAKPOINT" << ':' << b.thumb
+ << '}';
+ return str;
+}
+
+// --- Events
+TcfTrkEvent::TcfTrkEvent(Type type) : m_type(type)
+{
+}
+
+TcfTrkEvent::~TcfTrkEvent()
+{
+}
+
+TcfTrkEvent::Type TcfTrkEvent::type() const
+{
+ return m_type;
+}
+
+QString TcfTrkEvent::toString() const
+{
+ return QString();
+}
+
+static const char sharedLibrarySuspendReasonC[] = "Shared Library";
+
+TcfTrkEvent *TcfTrkEvent::parseEvent(Services s, const QByteArray &nameBA, const QVector<JsonValue> &values)
+{
+ switch (s) {
+ case LocatorService:
+ if (nameBA == "Hello" && values.size() == 1 && values.front().type() == JsonValue::Array) {
+ QStringList services;
+ foreach (const JsonValue &jv, values.front().children())
+ services.push_back(QString::fromUtf8(jv.data()));
+ return new TcfTrkLocatorHelloEvent(services);
+ }
+ break;
+ case RunControlService:
+ if (values.empty())
+ return 0;
+ // "id/PC/Reason/Data"
+ if (nameBA == "contextSuspended" && values.size() == 4) {
+ const QByteArray idBA = values.at(0).data();
+ const quint64 pc = values.at(1).data().toULongLong();
+ const QByteArray reasonBA = values.at(2).data();
+ // Module load: Special
+ if (reasonBA == sharedLibrarySuspendReasonC) {
+ ModuleLoadEventInfo info;
+ if (!info.parse(values.at(3)))
+ return 0;
+ return new TcfTrkRunControlModuleLoadContextSuspendedEvent(idBA, reasonBA, pc, info);
+ }
+ return new TcfTrkRunControlContextSuspendedEvent(idBA, reasonBA, pc);
+ } // "contextSuspended"
+ if (nameBA == "contextAdded")
+ return TcfTrkRunControlContextAddedEvent::parseEvent(values);
+ if (nameBA == "contextRemoved" && values.front().type() == JsonValue::Array) {
+ QVector<QByteArray> ids;
+ foreach(const JsonValue &c, values.front().children())
+ ids.push_back(c.data());
+ return new TcfTrkRunControlContextRemovedEvent(ids);
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+// -------------- TcfTrkServiceHelloEvent
+TcfTrkLocatorHelloEvent::TcfTrkLocatorHelloEvent(const QStringList &s) :
+ TcfTrkEvent(LocatorHello),
+ m_services(s)
+{
+}
+
+QString TcfTrkLocatorHelloEvent::toString() const
+{
+ return QLatin1String("ServiceHello: ") + m_services.join(QLatin1String(", "));
+}
+
+// -------------- TcfTrkIdEvent
+TcfTrkIdEvent::TcfTrkIdEvent(Type t, const QByteArray &id) :
+ TcfTrkEvent(t), m_id(id)
+{
+}
+
+// ---------- TcfTrkIdsEvent
+TcfTrkIdsEvent::TcfTrkIdsEvent(Type t, const QVector<QByteArray> &ids) :
+ TcfTrkEvent(t), m_ids(ids)
+{
+}
+
+QString TcfTrkIdsEvent::joinedIdString(const char sep) const
+{
+ return joinByteArrays(m_ids, sep);
+}
+
+// ---------------- TcfTrkRunControlContextAddedEvent
+TcfTrkRunControlContextAddedEvent::TcfTrkRunControlContextAddedEvent(const RunControlContexts &c) :
+ TcfTrkEvent(RunControlContextAdded), m_contexts(c)
+{
+}
+
+TcfTrkRunControlContextAddedEvent
+ *TcfTrkRunControlContextAddedEvent::parseEvent(const QVector<JsonValue> &values)
+{
+ // Parse array of contexts
+ if (values.size() < 1 || values.front().type() != JsonValue::Array)
+ return 0;
+
+ RunControlContexts contexts;
+ foreach (const JsonValue &v, values.front().children()) {
+ RunControlContext context;
+ if (context.parse(v))
+ contexts.push_back(context);
+ }
+ return new TcfTrkRunControlContextAddedEvent(contexts);
+}
+
+QString TcfTrkRunControlContextAddedEvent::toString() const
+{
+ QString rc;
+ QTextStream str(&rc);
+ str << "RunControl: " << m_contexts.size() << " context(s) "
+ << (type() == RunControlContextAdded ? "added" : "removed")
+ << '\n';
+ foreach (const RunControlContext &c, m_contexts) {
+ c.format(str);
+ str << '\n';
+ }
+ return rc;
+}
+
+// --------------- TcfTrkRunControlContextRemovedEvent
+TcfTrkRunControlContextRemovedEvent::TcfTrkRunControlContextRemovedEvent(const QVector<QByteArray> &ids) :
+ TcfTrkIdsEvent(RunControlContextRemoved, ids)
+{
+}
+
+QString TcfTrkRunControlContextRemovedEvent::toString() const
+{
+ return QLatin1String("RunControl: Removed contexts '") + joinedIdString() + ("'.");
+}
+
+// --------------- TcfTrkRunControlContextSuspendedEvent
+TcfTrkRunControlContextSuspendedEvent::TcfTrkRunControlContextSuspendedEvent(const QByteArray &id,
+ const QByteArray &reason,
+ quint64 pc) :
+ TcfTrkIdEvent(RunControlSuspended, id), m_pc(pc), m_reason(reason)
+{
+}
+
+TcfTrkRunControlContextSuspendedEvent::TcfTrkRunControlContextSuspendedEvent(Type t,
+ const QByteArray &id,
+ const QByteArray &reason,
+ quint64 pc) :
+ TcfTrkIdEvent(t, id), m_pc(pc), m_reason(reason)
+{
+}
+
+void TcfTrkRunControlContextSuspendedEvent::format(QTextStream &str) const
+{
+ str.setIntegerBase(16);
+ str << "RunControl: '" << idString() << "' suspended at 0x"
+ << m_pc << ": '" << m_reason << "'.";
+ str.setIntegerBase(10);
+}
+
+QString TcfTrkRunControlContextSuspendedEvent::toString() const
+{
+ QString rc;
+ QTextStream str(&rc);
+ format(str);
+ return rc;
+}
+
+TcfTrkRunControlContextSuspendedEvent::Reason TcfTrkRunControlContextSuspendedEvent::reason() const
+{
+ if (m_reason == sharedLibrarySuspendReasonC)
+ return ModuleLoad;
+ if (m_reason == "Breakpoint")
+ return BreakPoint;
+ // 'Data abort exception'/'Thread has panicked' ... unfortunately somewhat unspecific.
+ if (m_reason.contains("exception") || m_reason.contains("panick"))
+ return Crash;
+ return Other;
+}
+
+TcfTrkRunControlModuleLoadContextSuspendedEvent::TcfTrkRunControlModuleLoadContextSuspendedEvent(const QByteArray &id,
+ const QByteArray &reason,
+ quint64 pc,
+ const ModuleLoadEventInfo &mi) :
+ TcfTrkRunControlContextSuspendedEvent(RunControlModuleLoadSuspended, id, reason, pc),
+ m_mi(mi)
+{
+}
+
+QString TcfTrkRunControlModuleLoadContextSuspendedEvent::toString() const
+{
+ QString rc;
+ QTextStream str(&rc);
+ TcfTrkRunControlContextSuspendedEvent::format(str);
+ str << ' ';
+ m_mi.format(str);
+ return rc;
+}
+
+
+} // namespace tcftrk
diff --git a/tools/runonphone/symbianutils/tcftrkmessage.h b/tools/runonphone/symbianutils/tcftrkmessage.h
new file mode 100644
index 0000000..510b485
--- /dev/null
+++ b/tools/runonphone/symbianutils/tcftrkmessage.h
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TRCFTRKMESSAGE_H
+#define TRCFTRKMESSAGE_H
+
+#include "symbianutils_global.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QVector>
+
+QT_BEGIN_NAMESPACE
+class QTextStream;
+QT_END_NAMESPACE
+
+namespace tcftrk {
+
+class JsonValue;
+class JsonInputStream;
+
+enum Services {
+ LocatorService,
+ RunControlService,
+ ProcessesService,
+ MemoryService,
+ SettingsService, // non-standard, trk specific
+ BreakpointsService,
+ RegistersService,
+ SimpleRegistersService, // non-standard, trk specific
+ UnknownService
+}; // Note: Check string array 'serviceNamesC' of same size when modifying this.
+
+// Modes of RunControl/'Resume' (see EDF documentation).
+// As of 24.6.2010, RM_RESUME, RM_STEP_OVER, RM_STEP_INTO,
+// RM_STEP_OVER_RANGE, RM_STEP_INTO_RANGE are supported with
+// RANG_START/RANGE_END parameters.
+enum RunControlResumeMode {
+ RM_RESUME = 0,
+ RM_STEP_OVER = 1, RM_STEP_INTO = 2,
+ RM_STEP_OVER_LINE = 3, RM_STEP_INTO_LINE = 4,
+ RM_STEP_OUT = 5, RM_REVERSE_RESUME = 6,
+ RM_REVERSE_STEP_OVER = 7, RM_REVERSE_STEP_INTO = 8,
+ RM_REVERSE_STEP_OVER_LINE = 9, RM_REVERSE_STEP_INTO_LINE = 10,
+ RM_REVERSE_STEP_OUT = 11, RM_STEP_OVER_RANGE = 12,
+ RM_STEP_INTO_RANGE = 13, RM_REVERSE_STEP_OVER_RANGE = 14,
+ RM_REVERSE_STEP_INTO_RANGE = 15
+};
+
+SYMBIANUTILS_EXPORT const char *serviceName(Services s);
+SYMBIANUTILS_EXPORT Services serviceFromName(const char *);
+
+// Debug helpers
+SYMBIANUTILS_EXPORT QString formatData(const QByteArray &a);
+SYMBIANUTILS_EXPORT QString joinByteArrays(const QVector<QByteArray> &a, char sep = ',');
+
+// Context used in 'RunControl contextAdded' events and in reply
+// to 'Processes start'. Could be thread or process.
+struct SYMBIANUTILS_EXPORT RunControlContext {
+ enum Flags {
+ Container = 0x1, HasState = 0x2, CanSuspend = 0x4,
+ CanTerminate = 0x8
+ };
+ enum Type { Process, Thread };
+
+ RunControlContext();
+ Type type() const;
+ unsigned processId() const;
+ unsigned threadId() const;
+
+ void clear();
+ bool parse(const JsonValue &v);
+ void format(QTextStream &str) const;
+ QString toString() const;
+
+ // Helper for converting the TCF ids ("p12" or "p12.t34")
+ static Type typeFromTcfId(const QByteArray &id);
+ static unsigned processIdFromTcdfId(const QByteArray &id);
+ static unsigned threadIdFromTcdfId(const QByteArray &id);
+ static QByteArray tcfId(unsigned processId, unsigned threadId = 0);
+
+ unsigned flags;
+ unsigned resumeFlags;
+ QByteArray id; // "p434.t699"
+ QByteArray osid; // Non-standard: Process or thread id
+ QByteArray parentId; // Parent process id of a thread.
+};
+
+// Module load information occuring with 'RunControl contextSuspended' events
+struct SYMBIANUTILS_EXPORT ModuleLoadEventInfo {
+ ModuleLoadEventInfo();
+ void clear();
+ bool parse(const JsonValue &v);
+ void format(QTextStream &str) const;
+
+ QByteArray name;
+ QByteArray file;
+ bool loaded;
+ quint64 codeAddress;
+ quint64 dataAddress;
+ bool requireResume;
+};
+
+// Breakpoint as supported by TcfTrk source June 2010
+// TODO: Add watchpoints,etc once they are implemented
+struct SYMBIANUTILS_EXPORT Breakpoint {
+ enum Type { Software, Hardware, Auto };
+
+ explicit Breakpoint(quint64 loc = 0);
+ void setContextId(unsigned processId, unsigned threadId = 0);
+ QString toString() const;
+
+ static QByteArray idFromLocation(quint64 loc); // Automagically determine from location
+
+ Type type;
+ bool enabled;
+ int ignoreCount;
+ QVector<QByteArray> contextIds; // Process or thread ids.
+ QByteArray id; // Id of the breakpoint;
+ quint64 location;
+ unsigned size;
+ bool thumb;
+};
+
+SYMBIANUTILS_EXPORT JsonInputStream &operator<<(JsonInputStream &str, const Breakpoint &b);
+
+// Event hierarchy
+class SYMBIANUTILS_EXPORT TcfTrkEvent {
+ Q_DISABLE_COPY(TcfTrkEvent)
+public:
+ enum Type { None,
+ LocatorHello,
+ RunControlContextAdded,
+ RunControlContextRemoved,
+ RunControlSuspended,
+ RunControlBreakpointSuspended,
+ RunControlModuleLoadSuspended,
+ RunControlResumed
+ };
+
+ virtual ~TcfTrkEvent();
+
+ Type type() const;
+ virtual QString toString() const;
+
+ static TcfTrkEvent *parseEvent(Services s, const QByteArray &name, const QVector<JsonValue> &val);
+
+protected:
+ explicit TcfTrkEvent(Type type = None);
+
+private:
+ const Type m_type;
+};
+
+// ServiceHello
+class SYMBIANUTILS_EXPORT TcfTrkLocatorHelloEvent : public TcfTrkEvent {
+public:
+ explicit TcfTrkLocatorHelloEvent(const QStringList &);
+
+ const QStringList &services() { return m_services; }
+ virtual QString toString() const;
+
+private:
+ QStringList m_services;
+};
+
+// Base for events that just have one id as parameter
+// (simple suspend)
+class SYMBIANUTILS_EXPORT TcfTrkIdEvent : public TcfTrkEvent {
+protected:
+ explicit TcfTrkIdEvent(Type t, const QByteArray &id);
+public:
+ QByteArray id() const { return m_id; }
+ QString idString() const { return QString::fromUtf8(m_id); }
+
+private:
+ const QByteArray m_id;
+};
+
+// Base for events that just have some ids as parameter
+// (context removed)
+class SYMBIANUTILS_EXPORT TcfTrkIdsEvent : public TcfTrkEvent {
+protected:
+ explicit TcfTrkIdsEvent(Type t, const QVector<QByteArray> &ids);
+
+public:
+ QVector<QByteArray> ids() const { return m_ids; }
+ QString joinedIdString(const char sep = ',') const;
+
+private:
+ const QVector<QByteArray> m_ids;
+};
+
+// RunControlContextAdded
+class SYMBIANUTILS_EXPORT TcfTrkRunControlContextAddedEvent : public TcfTrkEvent {
+public:
+ typedef QVector<RunControlContext> RunControlContexts;
+
+ explicit TcfTrkRunControlContextAddedEvent(const RunControlContexts &c);
+
+ const RunControlContexts &contexts() const { return m_contexts; }
+ virtual QString toString() const;
+
+ static TcfTrkRunControlContextAddedEvent *parseEvent(const QVector<JsonValue> &val);
+
+private:
+ const RunControlContexts m_contexts;
+};
+
+// RunControlContextRemoved
+class SYMBIANUTILS_EXPORT TcfTrkRunControlContextRemovedEvent : public TcfTrkIdsEvent {
+public:
+ explicit TcfTrkRunControlContextRemovedEvent(const QVector<QByteArray> &id);
+ virtual QString toString() const;
+};
+
+// Simple RunControlContextSuspended (process/thread)
+class SYMBIANUTILS_EXPORT TcfTrkRunControlContextSuspendedEvent : public TcfTrkIdEvent {
+public:
+ enum Reason { BreakPoint, ModuleLoad, Crash, Other } ;
+
+ explicit TcfTrkRunControlContextSuspendedEvent(const QByteArray &id,
+ const QByteArray &reason,
+ quint64 pc = 0);
+ virtual QString toString() const;
+
+ quint64 pc() const { return m_pc; }
+ QByteArray reasonID() const { return m_reason; }
+ Reason reason() const;
+
+protected:
+ explicit TcfTrkRunControlContextSuspendedEvent(Type t,
+ const QByteArray &id,
+ const QByteArray &reason,
+ quint64 pc = 0);
+ void format(QTextStream &str) const;
+
+private:
+ const quint64 m_pc;
+ const QByteArray m_reason;
+};
+
+// RunControlContextSuspended due to module load
+class SYMBIANUTILS_EXPORT TcfTrkRunControlModuleLoadContextSuspendedEvent : public TcfTrkRunControlContextSuspendedEvent {
+public:
+ explicit TcfTrkRunControlModuleLoadContextSuspendedEvent(const QByteArray &id,
+ const QByteArray &reason,
+ quint64 pc,
+ const ModuleLoadEventInfo &mi);
+
+ virtual QString toString() const;
+ const ModuleLoadEventInfo &info() const { return m_mi; }
+
+private:
+ const ModuleLoadEventInfo m_mi;
+};
+
+} // namespace tcftrk
+#endif // TRCFTRKMESSAGE_H
diff --git a/tools/runonphone/symbianutils/trkdevice.cpp b/tools/runonphone/symbianutils/trkdevice.cpp
index bd24300..9039184 100644
--- a/tools/runonphone/symbianutils/trkdevice.cpp
+++ b/tools/runonphone/symbianutils/trkdevice.cpp
@@ -636,10 +636,11 @@ private:
void readMessages();
QByteArray m_trkReadBuffer;
+ bool linkEstablishmentMode;
};
ReaderThreadBase::ReaderThreadBase(const QSharedPointer<DeviceContext> &context) :
- m_context(context)
+ m_context(context), linkEstablishmentMode(true)
{
static const int trkResultMetaId = qRegisterMetaType<trk::TrkResult>();
Q_UNUSED(trkResultMetaId)
@@ -662,7 +663,7 @@ void ReaderThreadBase::readMessages()
{
TrkResult r;
QByteArray rawData;
- while (extractResult(&m_trkReadBuffer, m_context->serialFrame, &r, &rawData)) {
+ while (extractResult(&m_trkReadBuffer, m_context->serialFrame, &r, linkEstablishmentMode, &rawData)) {
emit messageReceived(r, rawData);
}
}
diff --git a/tools/runonphone/symbianutils/trkutils.cpp b/tools/runonphone/symbianutils/trkutils.cpp
index 60e391e..d89da20 100644
--- a/tools/runonphone/symbianutils/trkutils.cpp
+++ b/tools/runonphone/symbianutils/trkutils.cpp
@@ -52,6 +52,25 @@
namespace trk {
+Library::Library() : codeseg(0), dataseg(0), pid(0)
+{
+}
+
+Library::Library(const TrkResult &result) : codeseg(0), dataseg(0), pid(0)
+{
+ if (result.data.size() < 20) {
+ qWarning("Invalid trk creation notification received.");
+ return;
+ }
+
+ const char *data = result.data.constData();
+ pid = extractInt(data + 2);
+ codeseg = extractInt(data + 10);
+ dataseg = extractInt(data + 14);
+ const uint len = extractShort(data + 18);
+ name = result.data.mid(20, len);
+}
+
TrkAppVersion::TrkAppVersion()
{
reset();
@@ -77,11 +96,11 @@ void Session::reset()
extended1TypeSize = 0;
extended2TypeSize = 0;
pid = 0;
+ mainTid = 0;
tid = 0;
codeseg = 0;
dataseg = 0;
- currentThread = 0;
libraries.clear();
trkAppVersion.reset();
}
@@ -143,6 +162,90 @@ QString Session::deviceDescription(unsigned verbose) const
return msg.arg(formatTrkVersion(trkAppVersion));
}
+QByteArray Session::gdbLibraryList() const
+{
+ const int count = libraries.size();
+ QByteArray response = "l<library-list>";
+ for (int i = 0; i != count; ++i) {
+ const trk::Library &lib = libraries.at(i);
+ response += "<library name=\"";
+ response += lib.name;
+ response += "\">";
+ response += "<section address=\"0x";
+ response += trk::hexNumber(lib.codeseg);
+ response += "\"/>";
+ response += "<section address=\"0x";
+ response += trk::hexNumber(lib.dataseg);
+ response += "\"/>";
+ response += "<section address=\"0x";
+ response += trk::hexNumber(lib.dataseg);
+ response += "\"/>";
+ response += "</library>";
+ }
+ response += "</library-list>";
+ return response;
+}
+
+QByteArray Session::gdbQsDllInfo(int start, int count) const
+{
+ // Happens with gdb 6.4.50.20060226-cvs / CodeSourcery.
+ // Never made it into FSF gdb that got qXfer:libraries:read instead.
+ // http://sourceware.org/ml/gdb/2007-05/msg00038.html
+ // Name=hexname,TextSeg=textaddr[,DataSeg=dataaddr]
+ const int libraryCount = libraries.size();
+ const int end = count < 0 ? libraryCount : qMin(libraryCount, start + count);
+ QByteArray response(1, end == libraryCount ? 'l' : 'm');
+ for (int i = start; i < end; ++i) {
+ if (i != start)
+ response += ';';
+ const Library &lib = libraries.at(i);
+ response += "Name=";
+ response += lib.name.toHex();
+ response += ",TextSeg=";
+ response += hexNumber(lib.codeseg);
+ response += ",DataSeg=";
+ response += hexNumber(lib.dataseg);
+ }
+ return response;
+}
+
+QString Session::toString() const
+{
+ QString rc;
+ QTextStream str(&rc);
+ str << "Session: " << deviceDescription(false) << '\n'
+ << "pid: " << pid << "main thread: " << mainTid
+ << " current thread: " << tid << ' ';
+ str.setIntegerBase(16);
+ str << " code: 0x" << codeseg << " data: 0x" << dataseg << '\n';
+ if (const int libCount = libraries.size()) {
+ str << "Libraries:\n";
+ for (int i = 0; i < libCount; i++)
+ str << " #" << i << ' ' << libraries.at(i).name
+ << " code: 0x" << libraries.at(i).codeseg
+ << " data: 0x" << libraries.at(i).dataseg << '\n';
+ }
+ if (const int moduleCount = modules.size()) {
+ str << "Modules:\n";
+ for (int i = 0; i < moduleCount; i++)
+ str << " #" << i << ' ' << modules.at(i) << '\n';
+ }
+ str.setIntegerBase(10);
+ if (!addressToBP.isEmpty()) {
+ typedef QHash<uint, uint>::const_iterator BP_ConstIterator;
+ str << "Breakpoints:\n";
+ const BP_ConstIterator cend = addressToBP.constEnd();
+ for (BP_ConstIterator it = addressToBP.constBegin(); it != cend; ++it) {
+ str.setIntegerBase(16);
+ str << " 0x" << it.key();
+ str.setIntegerBase(10);
+ str << ' ' << it.value() << '\n';
+ }
+ }
+
+ return rc;
+}
+
// --------------
QByteArray decode7d(const QByteArray &ba)
@@ -188,18 +291,15 @@ SYMBIANUTILS_EXPORT QString stringFromArray(const QByteArray &ba, int maxLen)
QString ascii;
const int size = maxLen == -1 ? ba.size() : qMin(ba.size(), maxLen);
for (int i = 0; i < size; ++i) {
- //if (i == 5 || i == ba.size() - 2)
- // str += " ";
- int c = byte(ba.at(i));
- str += QString("%1 ").arg(c, 2, 16, QChar('0'));
- if (i >= 8 && i < ba.size() - 2)
- ascii += QChar(c).isPrint() ? QChar(c) : QChar('.');
+ const int c = byte(ba.at(i));
+ str += QString::fromAscii("%1 ").arg(c, 2, 16, QChar('0'));
+ ascii += QChar(c).isPrint() ? QChar(c) : QChar('.');
}
if (size != ba.size()) {
- str += "...";
- ascii += "...";
+ str += QLatin1String("...");
+ ascii += QLatin1String("...");
}
- return str + " " + ascii;
+ return str + QLatin1String(" ") + ascii;
}
SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits)
@@ -299,20 +399,30 @@ ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame, ushort& mux)
return firstDelimiterPos != -1 ? firstDelimiterPos : buffer.size();
}
-bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByteArray *rawData)
+bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, bool &linkEstablishmentMode, QByteArray *rawData)
{
result->clear();
if(rawData)
rawData->clear();
- const ushort len = isValidTrkResult(*buffer, serialFrame, result->multiplex);
- if (!len)
- return false;
+ ushort len = isValidTrkResult(*buffer, serialFrame, result->multiplex);
// handle receiving application output, which is not a regular command
const int delimiterPos = serialFrame ? 4 : 0;
+ if (linkEstablishmentMode) {
+ //when "hot connecting" a device, we can receive partial frames.
+ //this code resyncs by discarding data until a TRK frame is found
+ while (buffer->length() > delimiterPos
+ && result->multiplex != MuxTextTrace
+ && !(result->multiplex == MuxTrk && buffer->at(delimiterPos) == 0x7e)) {
+ buffer->remove(0,1);
+ len = isValidTrkResult(*buffer, serialFrame, result->multiplex);
+ }
+ }
+ if (!len)
+ return false;
if (buffer->at(delimiterPos) != 0x7e) {
result->isDebugOutput = true;
result->data = buffer->mid(delimiterPos, len);
- *buffer->remove(0, delimiterPos + len);
+ buffer->remove(0, delimiterPos + len);
return true;
}
// FIXME: what happens if the length contains 0xfe?
@@ -320,7 +430,7 @@ bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByt
const QByteArray data = decode7d(buffer->mid(delimiterPos + 1, len - 2));
if(rawData)
*rawData = data;
- *buffer->remove(0, delimiterPos + len);
+ buffer->remove(0, delimiterPos + len);
byte sum = 0;
for (int i = 0; i < data.size(); ++i) // 3 = 2 * 0xfe + sum
@@ -335,6 +445,7 @@ bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByt
//logMessage(" CURR DATA: " << stringFromArray(data));
//QByteArray prefix = "READ BUF: ";
//logMessage((prefix + "HEADER: " + stringFromArray(header).toLatin1()).data());
+ linkEstablishmentMode = false; //have received a good TRK packet, therefore in sync
return true;
}
diff --git a/tools/runonphone/symbianutils/trkutils.h b/tools/runonphone/symbianutils/trkutils.h
index e571028..d365f0d 100644
--- a/tools/runonphone/symbianutils/trkutils.h
+++ b/tools/runonphone/symbianutils/trkutils.h
@@ -56,6 +56,7 @@ QT_END_NAMESPACE
namespace trk {
typedef unsigned char byte;
+struct TrkResult;
enum Command {
//meta commands
@@ -135,6 +136,20 @@ enum Command {
TrkDSPositionFile = 0xd4
};
+enum DSOSItemTypes {
+ kDSOSProcessItem = 0x0000,
+ kDSOSThreadItem = 0x0001,
+ kDSOSDLLItem = 0x0002,
+ kDSOSAppItem = 0x0003,
+ kDSOSMemBlockItem = 0x0004,
+ kDSOSProcAttachItem = 0x0005,
+ kDSOSThreadAttachItem = 0x0006,
+ kDSOSProcAttach2Item = 0x0007,
+ kDSOSProcRunItem = 0x0008,
+ /* 0x0009 - 0x00ff reserved for general expansion */
+ /* 0x0100 - 0xffff available for target-specific use */
+};
+
enum SerialMultiplexor {
MuxRaw = 0,
MuxTextTrace = 0x0102,
@@ -164,11 +179,14 @@ SYMBIANUTILS_EXPORT void appendString(QByteArray *ba, const QByteArray &str, End
struct SYMBIANUTILS_EXPORT Library
{
- Library() {}
+ Library();
+ explicit Library(const TrkResult &r);
QByteArray name;
uint codeseg;
uint dataseg;
+ //library addresses are valid for a given process (depending on memory model, they might be loaded at the same address in all processes or not)
+ uint pid;
};
struct SYMBIANUTILS_EXPORT TrkAppVersion
@@ -187,6 +205,11 @@ struct SYMBIANUTILS_EXPORT Session
Session();
void reset();
QString deviceDescription(unsigned verbose) const;
+ QString toString() const;
+ // Answer to qXfer::libraries
+ QByteArray gdbLibraryList() const;
+ // Answer to qsDllInfo, can be sent chunk-wise.
+ QByteArray gdbQsDllInfo(int start = 0, int count = -1) const;
// Trk feedback
byte cpuMajor;
@@ -198,6 +221,7 @@ struct SYMBIANUTILS_EXPORT Session
byte extended2TypeSize;
TrkAppVersion trkAppVersion;
uint pid;
+ uint mainTid;
uint tid;
uint codeseg;
uint dataseg;
@@ -206,12 +230,7 @@ struct SYMBIANUTILS_EXPORT Session
typedef QList<Library> Libraries;
Libraries libraries;
- typedef uint Thread;
- typedef QList<Thread> Threads;
- Threads threads;
-
// Gdb request
- uint currentThread;
QStringList modules;
};
diff --git a/tools/runonphone/symbianutils/trkutils_p.h b/tools/runonphone/symbianutils/trkutils_p.h
index 12b0109..05df83a 100644
--- a/tools/runonphone/symbianutils/trkutils_p.h
+++ b/tools/runonphone/symbianutils/trkutils_p.h
@@ -55,7 +55,7 @@ void appendDateTime(QByteArray *ba, QDateTime dateTime, Endianness = TargetByteO
// returns a QByteArray containing optionally
// the serial frame [0x01 0x90 <len>] and 0x7e encoded7d(ba) 0x7e
QByteArray frameMessage(byte command, byte token, const QByteArray &data, bool serialFrame);
-bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r, QByteArray *rawData = 0);
+bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r, bool& linkEstablishmentMode, QByteArray *rawData = 0);
} // namespace trk
diff --git a/tools/runonphone/trksignalhandler.cpp b/tools/runonphone/trksignalhandler.cpp
index 2abf91f..898692a 100644
--- a/tools/runonphone/trksignalhandler.cpp
+++ b/tools/runonphone/trksignalhandler.cpp
@@ -42,7 +42,19 @@
#include <QDebug>
#include <QCoreApplication>
#include <QObject>
+#include <QFile>
+#include <QDir>
#include "trksignalhandler.h"
+#include "trkutils.h"
+
+class CrashState
+{
+public:
+ uint pid;
+ uint tid;
+ QString crashReason;
+ uint crashPC;
+};
class TrkSignalHandlerPrivate
{
@@ -55,6 +67,14 @@ private:
QTextStream err;
int loglevel;
int lastpercent;
+ QList<trk::Library> libraries;
+ QFile crashlogtextfile;
+ QFile crashstackfile;
+ QList<CrashState> queuedCrashes;
+ QList<int> dyingThreads;
+ QString crashlogPath;
+ bool crashlog;
+ bool terminateNeeded;
};
void TrkSignalHandler::copyingStarted()
@@ -108,6 +128,7 @@ void TrkSignalHandler::startingApplication()
void TrkSignalHandler::applicationRunning(uint pid)
{
+ Q_UNUSED(pid)
if (d->loglevel > 0)
d->out << "Running..." << endl;
}
@@ -155,13 +176,163 @@ void TrkSignalHandler::setLogLevel(int level)
d->loglevel = level;
}
+void TrkSignalHandler::setCrashLogging(bool enabled)
+{
+ d->crashlog = enabled;
+}
+
+void TrkSignalHandler::setCrashLogPath(QString path)
+{
+ d->crashlogPath = path;
+}
+
+bool lessThanCodeBase(const trk::Library& cs1, const trk::Library& cs2)
+{
+ return cs1.codeseg < cs2.codeseg;
+}
+
void TrkSignalHandler::stopped(uint pc, uint pid, uint tid, const QString& reason)
{
d->err << "STOPPED: pc=" << hex << pc << " pid=" << pid
<< " tid=" << tid << dec << " - " << reason << endl;
- // if it was a breakpoint, then we could continue with "emit resume(pid, tid);"
- // since we have set no breakpoints, it will be a just in time debug of a panic / exception
- emit terminate();
+
+ if (d->crashlog) {
+ CrashState cs;
+ cs.pid = pid;
+ cs.tid = tid;
+ cs.crashPC = pc;
+ cs.crashReason = reason;
+
+ if (d->dyingThreads.contains(tid)) {
+ if(d->queuedCrashes.isEmpty())
+ emit terminate();
+ else
+ d->terminateNeeded = true;
+ } else {
+ d->queuedCrashes.append(cs);
+ d->dyingThreads.append(tid);
+
+ if (d->queuedCrashes.count() == 1) {
+ d->err << "Fetching registers and stack..." << endl;
+ emit getRegistersAndCallStack(pid, tid);
+ }
+ }
+ }
+ else
+ emit terminate();
+}
+
+void TrkSignalHandler::registersAndCallStackReadComplete(const QList<uint>& registers, const QByteArray& stack)
+{
+ CrashState cs = d->queuedCrashes.first();
+ QDir dir(d->crashlogPath);
+ d->crashlogtextfile.setFileName(dir.filePath(QString("d_exc_%1.txt").arg(cs.tid)));
+ d->crashstackfile.setFileName(dir.filePath(QString("d_exc_%1.stk").arg(cs.tid)));
+ d->crashlogtextfile.open(QIODevice::WriteOnly);
+ QTextStream crashlog(&d->crashlogtextfile);
+
+ crashlog << "-----------------------------------------------------------------------------" << endl;
+ crashlog << "EKA2 USER CRASH LOG" << endl;
+ crashlog << "Thread Name: " << QString("ProcessID-%1::ThreadID-%2").arg(cs.pid).arg(cs.tid) << endl;
+ crashlog << "Thread ID: " << cs.tid << endl;
+ //this is wrong, but TRK doesn't make stack limit available so we lie
+ crashlog << QString("User Stack %1-%2").arg(registers.at(13), 8, 16, QChar('0')).arg(registers.at(13) + stack.size(), 8, 16, QChar('0')) << endl;
+ //this is also wrong, but TRK doesn't give all information for exceptions
+ crashlog << QString("Panic: PC=%1 ").arg(cs.crashPC, 8, 16, QChar('0')) << cs.crashReason << endl;
+ crashlog << endl;
+ crashlog << "USER REGISTERS:" << endl;
+ crashlog << QString("CPSR=%1").arg(registers.at(16), 8, 16, QChar('0')) << endl;
+ for (int i=0;i<16;i+=4) {
+ crashlog << QString("r%1=%2 %3 %4 %5")
+ .arg(i, 2, 10, QChar('0'))
+ .arg(registers.at(i), 8, 16, QChar('0'))
+ .arg(registers.at(i+1), 8, 16, QChar('0'))
+ .arg(registers.at(i+2), 8, 16, QChar('0'))
+ .arg(registers.at(i+3), 8, 16, QChar('0')) << endl;
+ }
+ crashlog << endl;
+
+ //emit info for post mortem debug
+ qSort(d->libraries.begin(), d->libraries.end(), lessThanCodeBase);
+ d->err << "Code Segments:" << endl;
+ crashlog << "CODE SEGMENTS:" << endl;
+ for(int i=0; i<d->libraries.count(); i++) {
+ const trk::Library& seg = d->libraries.at(i);
+ if(seg.pid != cs.pid)
+ continue;
+ if (d->loglevel > 1) {
+ d->err << QString("Code: %1 Data: %2 Name: ")
+ .arg(seg.codeseg, 8, 16, QChar('0'))
+ .arg(seg.dataseg, 8, 16, QChar('0'))
+ << seg.name << endl;
+ }
+
+ //produce fake code segment end addresses since we don't get the real ones from TRK
+ uint end;
+ if (i+1 < d->libraries.count())
+ end = d->libraries.at(i+1).codeseg - 1;
+ else
+ end = 0xFFFFFFFF;
+
+ crashlog << QString("%1-%2 ")
+ .arg(seg.codeseg, 8, 16, QChar('0'))
+ .arg(end, 8, 16, QChar('0'))
+ << seg.name << endl;
+ }
+
+ d->crashlogtextfile.close();
+
+ if (d->loglevel > 1) {
+ d->err << "Registers:" << endl;
+ for (int i=0;i<16;i++) {
+ d->err << QString("R%1: %2 ").arg(i, 2, 10, QChar('0')).arg(registers.at(i), 8, 16, QChar('0'));
+ if (i % 4 == 3)
+ d->err << endl;
+ }
+ d->err << QString("CPSR: %1").arg(registers.at(16), 8, 16, QChar('0')) << endl;
+
+ d->err << "Stack:" << endl;
+ uint sp = registers.at(13);
+ for(int i=0; i<stack.size(); i+=16, sp+=16) {
+ d->err << QString("%1: ").arg(sp, 8, 16, QChar('0'));
+ d->err << trk::stringFromArray(stack.mid(i,16));
+ d->err << endl;
+ }
+ }
+ d->crashstackfile.open(QIODevice::WriteOnly);
+ d->crashstackfile.write(stack);
+ d->crashstackfile.close();
+
+ if (d->loglevel > 0)
+ d->err << "Crash logs saved to " << d->crashlogtextfile.fileName() << " & " << d->crashstackfile.fileName() << endl;
+
+ // resume the thread to allow Symbian OS to handle the panic normally.
+ // terminate when a non main thread is suspended reboots the phone (TRK bug)
+ emit resume(cs.pid, cs.tid);
+
+ //fetch next crashed thread
+ d->queuedCrashes.removeFirst();
+ if (d->queuedCrashes.count()) {
+ cs = d->queuedCrashes.first();
+ d->err << "Fetching registers and stack..." << endl;
+ emit getRegistersAndCallStack(cs.pid, cs.tid);
+ }
+ else if (d->terminateNeeded)
+ emit terminate();
+
+}
+
+void TrkSignalHandler::libraryLoaded(const trk::Library &lib)
+{
+ d->libraries << lib;
+}
+
+void TrkSignalHandler::libraryUnloaded(const trk::Library &lib)
+{
+ for (QList<trk::Library>::iterator i = d->libraries.begin(); i != d->libraries.end(); i++) {
+ if((*i).name == lib.name && (*i).pid == lib.pid)
+ i = d->libraries.erase(i);
+ }
}
void TrkSignalHandler::timeout()
@@ -174,7 +345,8 @@ TrkSignalHandlerPrivate::TrkSignalHandlerPrivate()
: out(stdout),
err(stderr),
loglevel(0),
- lastpercent(0)
+ lastpercent(0),
+ terminateNeeded(false)
{
}
diff --git a/tools/runonphone/trksignalhandler.h b/tools/runonphone/trksignalhandler.h
index d31e46f..bfe2c3e 100644
--- a/tools/runonphone/trksignalhandler.h
+++ b/tools/runonphone/trksignalhandler.h
@@ -43,6 +43,7 @@
#define TRKSIGNALHANDLER_H
#include <QObject>
#include <QString>
+#include "symbianutils/trkutils.h"
class TrkSignalHandlerPrivate;
class TrkSignalHandler : public QObject
@@ -66,13 +67,20 @@ public slots:
void stateChanged(int);
void stopped(uint pc, uint pid, uint tid, const QString& reason);
void timeout();
+ void libraryLoaded(const trk::Library &lib);
+ void libraryUnloaded(const trk::Library &lib);
+ void registersAndCallStackReadComplete(const QList<uint>& registers, const QByteArray& stack);
signals:
void resume(uint pid, uint tid);
+ void stop(uint pid, uint tid);
void terminate();
+ void getRegistersAndCallStack(uint pid, uint tid);
public:
TrkSignalHandler();
~TrkSignalHandler();
void setLogLevel(int);
+ void setCrashLogging(bool);
+ void setCrashLogPath(QString);
private:
TrkSignalHandlerPrivate *d;
};