تصحيح أخطاء WebAssembly باستخدام أدوات حديثة

Ingvar Stepanyan
Ingvar Stepanyan

الطريق حتى الآن

قبل عام، أعلن Chrome عن دعمه الأوّلي لتصحيح أخطاء WebAssembly الأصلية في "أدوات مطوري البرامج في Chrome".

عرضنا الدعم الأساسي للخطوات وتحدثنا عن الفرص استخدام معلومات DWARF بدلاً من إتاحة خرائط المصدر لنا في المستقبل:

  • حل أسماء المتغيرات
  • أنواع الطباعة الجميلة
  • تقييم التعبيرات باللغات المصدر
  • ...وغير ذلك الكثير.

يسرّنا اليوم عرض الميزات التي وعدناك بها ومستوى التقدّم الذي أحرزه فريقا Emscripten و"أدوات مطوّري البرامج" في Chrome على مدار هذا العام، لا سيما في ما يتعلّق بتطبيقات C وC++.

قبل البدء، يُرجى العِلم أنّ هذا الإصدار لا يزال تجريبيًا للتجربة الجديدة، وعليك استخدام أحدث إصدار من جميع الأدوات على مسؤوليتك الخاصة، وإذا واجهت أي مشاكل، يُرجى الإبلاغ عنها على الرابط التالي: https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.

لنبدأ بنفس مثال C البسيط كما في المرة الأخيرة:

#include <stdlib.h>

void assert_less(int x, int y) {
  if (x >= y) {
    abort();
  }
}

int main() {
  assert_less(10, 20);
  assert_less(30, 20);
}

لتجميعه، نستخدم أحدث إصدار من Emscripten ونُرسل علامة -g، تمامًا كما هو الحال في المشاركة الأصلية، لتضمين معلومات debugging :

emcc -g temp.c -o temp.html

يمكننا الآن عرض الصفحة التي تم إنشاؤها من خادم HTTP للمضيف المحلي ( مثلًا، باستخدام serve)، و افتحه في أحدث إصدار من Chrome Canary.

سنحتاج هذه المرة أيضًا إلى إضافة مساعدة تتكامل مع Chrome DevTools وتساعده في فهم جميع معلومات تصحيح الأخطاء المُشفَّرة في ملف WebAssembly. يُرجى تثبيته بالانتقال إلى الرابط: goo.gle/wasm-debugging-extension

ستحتاج أيضًا إلى تفعيل تصحيح أخطاء WebAssembly في أدوات مطوّري البرامج التجارب: افتح "أدوات مطوري البرامج في Chrome"، وانقر على رمز الترس () في في أعلى يسار لوحة "أدوات مطوري البرامج"، انتقِل إلى لوحة التجارب. ضَع علامة في المربّع تصحيح أخطاء WebAssembly: تفعيل دعم DWARF.

جزء &quot;التجارب&quot; في إعدادات &quot;أدوات مطوري البرامج&quot;

عند إغلاق الإعدادات، ستقترح "أدوات مطوري البرامج" إعادة تحميل الصفحة من تلقاء نفسها. لتطبيق الإعدادات، لذلك لنفعل ذلك. هذا كل شيء لمرة واحدة الإعداد.

يمكننا الآن الرجوع إلى لوحة المصادر وتفعيل الخيار إيقاف مؤقت على الاستثناءات (رمز ⏸)، ثم ضع علامة في المربّع إيقاف مؤقت عند رصد الاستثناءات أعِد تحميل الصفحة. من المفترض أن تلاحظ إيقاف أدوات مطوري البرامج مؤقتًا عند أحد الاستثناءات:

لقطة شاشة للوحة &quot;المصادر&quot; تعرض كيفية تفعيل ميزة &quot;الإيقاف مؤقتًا عند الاستثناءات التي تم رصدها&quot;

يتوقف تلقائيًا على الرمز الملتصق الذي أنشأه Emscripten، ولكن في إلى اليسار، يمكنك مشاهدة عرض حزمة الاتصال التي تمثل تتبع تكديس الخطأ، ويمكنها الانتقال إلى سطر C الأصلي الذي استدعينا abort:

تم إيقاف &quot;أدوات المطوّر&quot; مؤقتًا في الدالة assert_less وعرض قيم x وy في عرض &quot;النطاق&quot;

الآن، إذا نظرت في طريقة عرض النطاق، يمكنك الاطّلاع على الأسماء الأصلية. وقيم المتغيرات في التعليمات البرمجية C/C++، ولم يعد من الضروري معرفة ما الذي تعنيه الأسماء المشوهة مثل $localN وعلاقتها رمز المصدر الذي كتبته.

وهذا لا ينطبق على القيم الأولية مثل الأعداد الصحيحة فحسب، بل يشمل المركّب أنواعًا مثل الهياكل والفئات والصفائف وما إلى ذلك أيضًا!

دعم الكتابة التفاعلية

لنلقِ نظرة على مثال أكثر تعقيدًا لتوضيح ذلك. هذا النمط الوقت، سنرسم كسور ماندلبرو باستخدام رمز C++ التالي:

#include <SDL2/SDL.h>
#include <complex>

int main() {
  // Init SDL.
  int width = 600, height = 600;
  SDL_Init(SDL_INIT_VIDEO);
  SDL_Window* window;
  SDL_Renderer* renderer;
  SDL_CreateWindowAndRenderer(width, height, SDL_WINDOW_OPENGL, &window,
                              &renderer);

  // Generate a palette with random colors.
  enum { MAX_ITER_COUNT = 256 };
  SDL_Color palette[MAX_ITER_COUNT];
  srand(time(0));
  for (int i = 0; i < MAX_ITER_COUNT; ++i) {
    palette[i] = {
        .r = (uint8_t)rand(),
        .g = (uint8_t)rand(),
        .b = (uint8_t)rand(),
        .a = 255,
    };
  }

  // Calculate and draw the Mandelbrot set.
  std::complex<double> center(0.5, 0.5);
  double scale = 4.0;
  for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
      std::complex<double> point((double)x / width, (double)y / height);
      std::complex<double> c = (point - center) * scale;
      std::complex<double> z(0, 0);
      int i = 0;
      for (; i < MAX_ITER_COUNT - 1; i++) {
        z = z * z + c;
        if (abs(z) > 2.0)
          break;
      }
      SDL_Color color = palette[i];
      SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
      SDL_RenderDrawPoint(renderer, x, y);
    }
  }

  // Render everything we've drawn to the canvas.
  SDL_RenderPresent(renderer);

  // SDL_Quit();
}

يمكنك أن تلاحظ أن هذا التطبيق لا يزال صغيرًا إلى حد ما، وهو عبارة عن ملف يحتوي على 50 سطرًا من التعليمات البرمجية - لكنني هذه المرة أستخدم أيضًا بعض واجهات برمجة التطبيقات الخارجية، مثل مكتبة SDL والرسومات بالإضافة إلى الأرقام المعقدة من مكتبة C++ القياسية.

سأقوم بتجميعها باستخدام علامة -g نفسها كما هو موضح أعلاه لتضمينها معلومات تصحيح الأخطاء، وسأطلب أيضًا من Emscripten تقديم SDL2 المكتبة والسماح بالذاكرة ذات الحجم العشوائي:

emcc -g mandelbrot.cc -o mandelbrot.html \
     -s USE_SDL=2 \
     -s ALLOW_MEMORY_GROWTH=1

عندما أزور الصفحة التي تم إنشاؤها في المتصفح، يمكنني رؤية شكل كسري مع بعض الألوان العشوائية:

صفحة الإصدار التجريبي

عندما أفتح أدوات مطوري البرامج، مرة أخرى، يمكنني رؤية ملف C++ الأصلي. هذا النمط الوقت، مع ذلك، ليس لدينا خطأ في التعليمات البرمجية (رائع،!)، لذا هيا نقطة توقف في بداية التعليمة البرمجية بدلاً من ذلك.

عندما نعيد تحميل الصفحة مرة أخرى، سيتوقف برنامج تصحيح الأخطاء مؤقتًا داخل مصدر C++:

تم إيقاف &quot;أدوات مطوري البرامج&quot; مؤقتًا في مكالمة &quot;SDL_Init&quot;

يمكننا الآن الاطّلاع على جميع متغيّراتنا على اليمين، ولكن تمّت بدء width وheight فقط في الوقت الحالي، لذا ليس هناك الكثير مما يمكن فحصه.

دعونا نضع نقطة توقف أخرى داخل حلقة ماندلبرو الرئيسية الخاصة بنا، ونعيد التنفيذ للتخطي إلى الأمام.

تم إيقاف أدوات مطوري البرامج مؤقتًا داخل التكرارات الحلقية المدمجة.

في هذه المرحلة، تم ملء palette ببعض الألوان العشوائية، ويمكننا توسيع النطاق نفسه، بالإضافة إلى SDL_Color الفردية وفحص مكوّناتها للتأكّد من أنّ كل شيء يبدو جيدًا (على سبيل المثال، يتم ضبط قناة "الشفافية" دائمًا على مستوى الشفافية الكامل). وبالمثل، يمكننا التوسع والتحقق من القيم الأجزاء التخيّلية للعدد المركّب المخزّنة في المتغير center.

إذا كنت ترغب في الوصول إلى خاصية متداخلة بعمق يصعب الوصول إليها الانتقال إليها من خلال طريقة عرض النطاق، يمكنك استخدام وحدة التحكّم. التقييم أيضًا! ومع ذلك، لاحظ أن تعبيرات C++ الأكثر تعقيدًا ليست حتى الآن.

لوحة وحدة تحكُّم تعرض نتيجة &quot;palette[10].r&quot;

لنواصل التنفيذ بضع مرات ونرى كيف تعمل ميزة x الداخلية. المتغير أيضًا أو من خلال النظر في طريقة عرض النطاق مرة أخرى، اسم المتغير إلى قائمة المشاهدة، أو تقييمه في وحدة التحكم، أو من خلال التمرير فوق المتغير في رمز المصدر:

تلميح فوق المتغيّر `x` في المصدر يُظهر قيمته `3`

من هنا، يمكننا المتابعة أو التخطّي لبيان C++، وملاحظة كيفية تغيُّر المتغيّرات الأخرى أيضًا:

تلميحات الأدوات وطريقة عرض النطاق التي تُظهر قيم &quot;اللون&quot; و&quot;النقطة&quot; ومتغيّرات أخرى

حسنًا، كل هذا يسير بشكل رائع عند توفُّر معلومات تصحيح الأخطاء، ولكن ماذا لو أردنا تصحيح الأخطاء في رمز غير مضمَّن في عملية تصحيح الأخطاء الخيارات؟

تصحيح أخطاء WebAssembly الأولية

على سبيل المثال، طلبنا من Emscripten تقديم مكتبة SDL مصممة مسبقًا بدلاً من تجميعها من المصدر بأنفسنا في الوقت الحالي، ليس هناك طريقة لبرنامج تصحيح الأخطاء للعثور على المصادر المرتبطة. لندخل مجددًا للدخول في SDL_RenderDrawColor:

أدوات المطوّرين تعرِض عرض التفكيك لملف mandelbrot.wasm

لقد عدنا إلى تجربة تصحيح أخطاء WebAssembly الأوّلية.

يبدو الأمر مخيفًا بعض الشيء، وهو ليس شيئًا يخطر على بال معظم مطوري الويب إلى التعامل معها، ولكن في بعض الأحيان قد تحتاج إلى تصحيح دون معلومات تصحيح الأخطاء - سواء لأنها أي مكتبة تابعة لجهة خارجية لا يمكنك التحكم فيها، أو لأنك إلى أحد تلك الأخطاء التي تحدث فقط في الإنتاج.

للمساعدة في هذه الحالات، أجرينا أيضًا بعض التحسينات على تجربة debugging الأساسية.

أولاً، إذا سبق لك استخدام تصحيح أخطاء WebAssembly الأولية، يمكنك أن عملية التفكيك بالكامل تظهر الآن في ملف واحد المزيد من التخمين بشأن الدالة التي يمكن أن يتطابق معها إدخال المصادر wasm-53834e3e/ wasm-53834e3e-7.

مخطّط جديد لإنشاء الأسماء

تم تحسين الأسماء في طريقة عرض التفكيك أيضًا. في السابق، كان يظهر أمامك فقط فهارس رقمية، أو لا يظهر أي اسم على الإطلاق في حال استخدام الدوالّ.

والآن، ننشئ أسماء مشابهة لأدوات التفكيك الأخرى، من خلال باستخدام تلميحات من قسم اسم WebAssembly، استيراد/تصدير المسارات، وأخيرًا، إذا فشل كل شيء آخر، فإن إنشاء بناءً على نوع العنصر وفهرسته مثل $func123. يمكنك في لقطة الشاشة أعلاه، من المفيد معرفة الطريقة بشكل أكثر قابلية للقراءة والتفكيك.

في حال عدم توفُّر معلومات النوع، قد يكون من الصعب فحصها أي قيم بخلاف الأساسيات - على سبيل المثال، ستظهر المؤشرات كأعداد صحيحة عادية، بدون أي طريقة لمعرفة ما يتم تخزينها خلفها في الذاكرة.

فحص الذاكرة

في السابق، كان بإمكانك توسيع عنصر ذاكرة WebAssembly، الذي يمثله env.memory في طريقة عرض النطاق للبحث. بايت واحد. عمل هذا في بعض السيناريوهات التافهة، لكنه لم يكن ملائمة بشكل خاص لتوسيعها ولا تسمح بإعادة تفسير البيانات بتنسيقات أخرى غير قيم البايت. لقد أضفنا ميزة جديدة للمساعدة باستخدام أداة فحص الذاكرة الخطية.

إذا نقرت بزر الماوس الأيمن على env.memory، ستظهر لك علامة خيار يُسمى فحص الذاكرة:

قائمة السياقات في &quot;env.memory&quot; ضمن لوحة &quot;النطاق&quot; تعرض &quot;فحص الذاكرة&quot; عنصر

بعد النقر، سيتم عرض أداة فحص الذاكرة، في ويمكنك فحص ذاكرة WebAssembly بطرق العرض السداسي العشري وASCII، الانتقال إلى عناوين محددة، بالإضافة إلى تفسير البيانات في بتنسيقات مختلفة:

لوحة &quot;أداة فحص الذاكرة&quot; في &quot;أدوات مطوري البرامج&quot; تعرض طريقتَي العرض السداسي وASCII للذاكرة

السيناريوهات المتقدّمة والتنبيهات

رمز WebAssembly لإنشاء الملفات التعريفية

عند فتح أدوات مطوّري البرامج، يتم "تقسيم" رمز WebAssembly إلى مستويات إلى إصدار غير محسّن لتفعيل تصحيح الأخطاء. هذا الإصدار أبطأ كثيرًا، ما يعني أنّه لا يمكنك الاعتماد على console.time أو performance.now وغيرها من الطرق لقياس سرعة الرمز البرمجي أثناء تنفيذ لأن الأرقام التي تحصل عليها لن تمثل الأداء الفعلي على الإطلاق.

بدلاً من ذلك، يجب استخدام لوحة الأداء في "أدوات مطوري البرامج". سيشغّل الرمز بأقصى سرعة وتزويدك تقسيم مفصل للوقت المستغرق في الدوال المختلفة:

لوحة تحليل تعرض دوال Wasm متنوعة

بدلاً من ذلك، يمكنك تشغيل تطبيقك مع إغلاق "أدوات مطوري البرامج" افتحها بعد الانتهاء لفحص وحدة التحكّم.

سنعمل على تحسين سيناريوهات التحليل في المستقبل، ولكن في الوقت الحالي يجب أن تكون على دراية بها. لمعرفة مزيد من المعلومات حول WebAssembly يمكنك الاطّلاع على مستنداتنا حول مسار تجميع WebAssembly.

الإنشاء وتصحيح الأخطاء على أجهزة مختلفة (بما في ذلك Docker أو المضيف)

عند إنشاء التطبيق في Docker أو على جهاز افتراضي أو على خادم إنشاء عن بُعد، من المحتمل أن تواجه حالات لا تتطابق فيها مسارات الملفات المصدر المستخدَمة أثناء عملية الإنشاء مع المسارات في نظام الملفات الخاص بك الذي يتم فيه تشغيل "أدوات مطوّري تطبيقات Chrome". في هذه الحالة، ستظهر الملفات في لوحة المصادر ولكن يتعذّر تحميلها.

لحلّ هذه المشكلة، نفّذنا وظيفة ربط المسارات في خيارات إضافة C/C++. ويمكنك استخدامه لإعادة ربط المسارات العشوائية و مساعدة أدوات المطوّرين في تحديد مصادر البيانات.

على سبيل المثال، إذا كان المشروع على جهاز المضيف ضمن مسار C:\src\my_project، ولكن تم إنشاؤه داخل حاوية Docker حيث تم تمثيل هذا المسار على أنّه /mnt/c/src/my_project، يمكنك إعادة ربطه مرة أخرى أثناء تصحيح الأخطاء من خلال تحديد هذه المسارات كبادئات:

صفحة الخيارات لإضافة تصحيح الأخطاء C/C++

تكون البادئة الأولى التي تمت مطابقتها هي "البادئة الفائزة". إذا كنت على دراية بلغة C++ الأخرى لبرامج تصحيح الأخطاء، هذا الخيار يشبه الأمر set substitute-path. في GDB أو إعداد target.source-map في LLDB.

تصحيح أخطاء النُسخ المحسَّنة

كما هو الحال مع أي لغات أخرى، يعمل تصحيح الأخطاء بشكل أفضل إذا كانت التحسينات غير مفعّل. قد تؤدي التحسينات إلى تضمين الدوالّ في بعضها أو إعادة ترتيب الرمز أو إزالة أجزاء من الرمز تمامًا، وقد يؤدي كل ذلك إلى إثارة الارتباك لدى مصحِّح الأخطاء وبالتالي لديك بصفتك المستخدم.

إذا كنت لا تمانع في الحصول على تجربة تصحيح أخطاء محدودة وكنت لا تزال تريد وتصحيح الأخطاء في إصدار مُحسَّن، فستعمل معظم التحسينات المتوقع، باستثناء الدوال المضمنة. إننا نخطط لمعالجة الباقي في المستقبل، ولكن في الوقت الحالي، يُرجى استخدام -fno-inline من أجل أوقِفه عند التجميع مع أي تحسينات على مستوى -O، على سبيل المثال:

emcc -g temp.c -o temp.html \
     -O3 -fno-inline

فصل معلومات تصحيح الأخطاء

تحتفظ معلومات تصحيح الأخطاء بالكثير من التفاصيل حول التعليمات البرمجية الخاصة بك، والمتغيرات والدوال والنطاقات والمواقع الجغرافية، أي شيء قد أن تكون مفيدة لبرنامج تصحيح الأخطاء. ونتيجةً لذلك، قد يكون غالبًا أكبر من التعليمة البرمجية نفسها.

ولتسريع تحميل وتجميع وحدة WebAssembly، يمكنك: وتريد تقسيم معلومات تصحيح الأخطاء هذه إلى مجموعة WebAssembly منفصلة. الملف. لإجراء ذلك في Emscripten، أدخِل العلامة -gseparate-dwarf=… مع اسم الملف المطلوب:

emcc -g temp.c -o temp.html \
     -gseparate-dwarf=temp.debug.wasm

في هذه الحالة، سيخزن التطبيق الرئيسي اسم ملف فقط ستتمكن الإضافة "temp.debug.wasm" و"إضافة المساعدة" من تحديد موقعها الجغرافي ثم نحمّله عند فتح أدوات مطوري البرامج.

وعند دمج هذه الميزة مع تحسينات كما هو موضح أعلاه، يمكن لشحن إصدارات إنتاج محسّنة تقريبًا وتصحيح الأخطاء لاحقًا باستخدام ملف جانبي على الجهاز. وفي هذه الحالة، سنحتاج أيضًا إلى إلغاء عنوان URL المخزن لمساعدة الإضافة للعثور على الملف الجانبي، مثل:

emcc -g temp.c -o temp.html \
     -O3 -fno-inline \
     -gseparate-dwarf=temp.debug.wasm \
     -s SEPARATE_DWARF_URL=file://[local path to temp.debug.wasm]

يُرجى المتابعة...

واو، كانت هذه العديد من الميزات الجديدة!

مع كل عمليات الدمج الجديدة هذه، أصبحت "أدوات مطوري البرامج في Chrome" وسيلة فعّالة أداة قوية ومصحح أخطاء، ليس فقط لـ JavaScript بل لتطبيقات C وC++ أيضًا، وهو يسهّل أكثر من أي وقت مضى استخدام التطبيقات، فهي مضمَّنة في مجموعة متنوعة من التقنيات وإيصالها إلى شبكة ويب مشتركة عبر أنظمة أساسية متعددة.

ومع ذلك، فإن رحلتنا لم تنته بعد. بعض الأشياء التي نعمل عليها من هنا في:

  • التخلص من العيوب في تجربة تصحيح الأخطاء
  • إتاحة أدوات تنسيق الأنواع المخصّصة.
  • العمل على تحسينات على تحديد الملفات الشخصية لتطبيقات WebAssembly
  • إتاحة تغطية الرمز لتسهيل العثور على المحتوى رمز غير مستخدم.
  • تحسين توافق التعبيرات في تقييم وحدة التحكّم
  • إضافة مزيد من اللغات
  • …وغير ذلك

في الوقت الحالي، يُرجى مساعدتنا من خلال تجربة الإصدار التجريبي الحالي على الرمز البرمجي الخاص بك والإبلاغ عن أي مشاكل تم رصدها على الرابط التالي: https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.

تنزيل قنوات المعاينة

يمكنك استخدام Chrome كناري أو إصدار مطوّري البرامج أو الإصدار التجريبي من المتصفِّح التلقائي للتطوير. وتتيح لك قنوات المعاينة هذه الوصول إلى أحدث ميزات "أدوات مطوري البرامج" واختبار أحدث واجهات برمجة التطبيقات للأنظمة الأساسية للويب والعثور على المشاكل على موقعك الإلكتروني قبل أن يفعلها المستخدمون.

التواصل مع فريق "أدوات مطوري البرامج في Chrome"

يمكنك استخدام الخيارات التالية لمناقشة الميزات والتغييرات الجديدة في المشاركة أو مناقشة أي معلومات أخرى متعلّقة بأدوات مطوري البرامج.

  • يمكنك إرسال اقتراح أو ملاحظات إلينا عبر crbug.com.
  • الإبلاغ عن مشكلة في "أدوات مطوري البرامج" باستخدام خيارات إضافية   المزيد > مساعدة > الإبلاغ عن مشاكل في "أدوات مطوري البرامج" في "أدوات مطوري البرامج"
  • يمكنك نشر تغريدة على @ChromeDevTools.
  • شارِك في التعليقات على الميزات الجديدة في فيديوهات YouTube أو نصائح حول أدوات مطوّري البرامج فيديوهات على YouTube.